In the words of my combinatorics professor, Dave Bayer:
> It is hard to shed prejudices about how code should look, even if learning to see clearly past convention is the only good reason to be a mathematician. I'm already quite sure how I will die: I'll read another article on Hacker News about a new programming language where I see nothing new, and I'll read that they included {}; to make C programmers comfortable. I'll have a massive stroke.
You can use a different pair of symbols (or pair of words, like in Pascal, or whitespace, like in Python). There's certainly nothing fundamental about them.
Also, even in C and C++, they don't indicate branching. You can place a brace block anywhere you can place a normal statement. You might use them in C++ just to delimit the extent of a RAII object. In C89 you might use a block to delay defining a variable until closer to its use, because variables can only be defined at the start of its block (although that no longer applies in C99). Conversely, though it's usually bad practice, you can use if statements and loops with individual statements.
I know it’s arbitrary and I know the symbol has been overloaded since they ran out of them, but at one time there was a certain economy and simplicity. < and > meant less than and greater than; { } were code blocks; even the semicolon was the right thing to use to break statements. I wish they had stuck to that kind of readability because I don’t know what C++ thinks it’s doing anymore.
A pair of words requires more keywords (they also tend to be more verbose) and whitespace has ergonomy issues (specially with copy-pasting). Whitespace may come with intrinsic alignment, but formatting tools do short work of that.
Whether we call it a distribution or not is really a matter of semantics.
The more interesting question is, do people actually want a hyper-opinionated Linux install? Based on the reactions to Omarchy that I've seen, the answer is obviously yes. Broadly, people seem ok with just not using some of the suggested software if the defaults get them most of the way there.
More generally, I would say that configuring one's own Linux installation is not in itself virtuous. It used to be a way to identify people who were "committed" to using it via gatekeeping. The OP says that Omarchy is just DHH "cashing in" on new inexperienced Linux users, but as long as we don't value customizing one's own installation just for the sake of customization (I certainly don't anymore!), why is this a problem?
Futhark is really such a great idea. I'm not convinced that dependent types are worth the cognitive overhead in general, but it's definitely worth it to include the length as part of the type information for dynamic arrays, e.g.:
concat(Vec<T, n>, Vec<T, m>) -> Vec<T, n+m>
matmul(Mat<T, n, m>, Mat<T, m, l>) -> Mat<T, n, l>
head(Vec<T, n+1>) -> (T, Vec<T, n>)
This would have saved me so much headache debugging CUDA kernels and numpy!! I wish it were a first-class feature in those frameworks, and even general-purpose languages, but alas.
The Pyrefly type checker is starting to work on this kind of shape hinting - so far it only works on Torch but I believe the plan is for it to work with other array packages (eg. JAX, NumPy)
I didn't know that, thanks for sharing. It makes sense, but then it also makes me wonder why none of the deep learning libraries (Torch, Jax/NNX, Eigen etc...) make this information available. Instead, ML people all have their own schemes for tracking shape information, like commenting '# (b, n, t)' on every line, or suffixing shapes to variable names - and in my experience it's a common source of bugs.
I think we're talking at cross purposes. The reason I'm excited about the Pyrefly work is that it leverages the type system to infer array shapes statically, which makes it simpler to reason about them when you're writing the code and catch bugs. The fact that people have developed these janky approaches to shape tracking suggests that there's a gap to be filled.
Jax and Torch don't do that statically. They obviously have to do it at runtime, but that doesn't address this particular issue. I mention Eigen because array shape hinting is generally useful for any linalg library, not purely for ML applications.
> Jax and Torch don't do that statically. They obviously have to do it at runtime, but that doesn't address this particular issue.
You don't understand what you're talking about.
Jax is explicitly mentioned in your pyrefly link as having a parallel (but slightly weaker) system. In addition Jax is built on stablehlo which uses shape dialect, which is part of the compiler (and therefore statically known).
Torch has a symbolic shape inference system that I helped build:
> The fact that people have developed these janky approaches to shape tracking suggests that there's a gap to be filled.
I have already said it: the fact that people do not know how to use the tools does not mean the tools are lacking - it means the users are unsophisticated. Let me put it this way: almost everyone that is employed to work with these tools is aware of these features and therefore eschews those kinds of comment strings.
Every single comment you've posted was unhelpful and demeaning and you've constantly had to backtrack every single time you've had to respond. This is extremely poor form and I see zero goodwill here.
ainch doesn't care about the inference engine knowing the shapes. This is obvious. He has been talking about developer ergonomics and you've basically said "only idiots don't know where the ergonomics features are", while linking to a file which explicitly states that it is a experimental/private API that is only needed in niche situations which is basically doubling down on having poor ergonomics.
If you can't understand the problem as a developer working on those features and you had to link to the source you've written rather than the docs, you're basically admitting that you're the problem.
This is the whiniest response I've ever seen on hn. Congrats.
> you had to link to the source you've written rather than the docs, you're basically admitting that you're the problem.
God forbid i expect people using complex tools to know how they actually work.
Edit: there are two categories of devs out there - those that expect code to be a fully perfected product delivered to them on a silver platter (only requiring docs, which must be perfect btw), and those which understand all code is merely a suggestion. For the latter a code pointer is more than enough. I leave you to infer which are more productive.
Thanks for the reply - you're clearly much more experienced with the internals here, but I believe we're still talking at cross-purposes. I believe you're talking about compilers like jax.jit or torch.compile performing symbolic shape inference. I'm talking about the ergonomics of tracking shape information while writing Python code that calls these libraries. I don't use Torch much, so I'll just comment on the Jax side.
> Jax is explicitly mentioned in your pyrefly link as having a parallel (but slightly weaker) system
Jaxtyping is limited to runtime-only checks (which might as well be assert statements), and doesn't infer shapes based on operations. I'm interested in Pyrefly because I've run into the limitations of Jaxtyping in my own usage.
> Jax is built on stablehlo which uses shape dialect, which is part of the compiler (and therefore statically known).
It's true that JAX does shape inference when it compiles down to HLO - but that isn't available to the Python typing system. The Pyrefly development is addressing that, so you get static analysis before even running anything, or without having to add eval_shape calls all over your codebase. I think that's helpful, and will catch bugs. When I say Jax does inference at runtime, I mean that you have to run for the jit compiler to kick in - you don't get feedback as you edit.
> the fact that people do not know how to use the tools does not mean the tools are lacking... almost everyone that is employed to work with these tools is aware of these features and therefore eschews those kinds of comment strings.
The examples I took are from Andrej Karpathy and Noam Shazeer - maybe the disconnect is that they're more on the research side. Perhaps only unsophisticated users rely on these hacks - but as one such user I'm very excited that Pyrefly is addressing a problem I have. I suspect part of the misunderstanding that's evolved here is that these tools serve audiences with different needs.
I use jaxtyping as documentation, but the fact it can only be used for runtime checking (in a slightly clunky manner) and can't infer shapes based on ops really limits its utility imo.
You can do this with templates in C++ and generics in Rust I'm pretty sure. I think the Eigen C++ library supports this. (I have yet to do a linear algebra heavy Rust project, so I can't speak to the options that exist there.)
I'm talking about cases where the array size is not known at compile time. For example, say the user passes in a list of numbers as command line arguments. Then we have
argv: Vec<String, argc>
If I want to map these to ints, then I'd like a compile-time guarantee that the resulting array
nums: Vec<Int, argc>
is the same length as argv. Lean and Idris can do this, but AFAIK no commonly used languages can. But unlike general dependent types, these are not hard to wrap one's head around and would save a lot of frustration, in my experience.
Arrays are not dynamically sized though (handling runtime sizes) and don’t have efficient append/concat. The point of the dependent types is that you can have the type system track that concat creates an M+N length vector, sort preserves length (and adds a sorted guarantee that slice preserves), etc.
Sure you can do a lot with templates, but that’s advanced templates not just “C++ arrays” in a throwaway “literally that” way.
For models as complex as these I'm not confident we can apply arguments from first principles; we could just as easily argue that type information is helpful, from first principles. What is much more useful is empirical evidence, and AutoCodeBench [1] found that LLMs are most proficient in Elixir (dynamic) followed by Kotlin (static), with Rust and PHP at the bottom. So it would seem like, as of publication, typing style doesn't really matter!
Neat, but I think it's deceptive for the website to claim this is a "new type of graphing" [1]. The fuzzy graph of F(x, y) = 0 is simply a 3D plot of z = |F(x, y)|, where z is displayed using color. In other words, F(x, y) is a constraint and z shows us how strongly the constraint is violated. Then the graph given by F(x, y) = 0 is a slice of the 3D graph. If you're claiming that you've discovered visualizing 3D graphs using color, you're about 50 years too late.
Dropping the absolute value makes a better visualization. The 3D graph for Example 4 Shadow Line has an established name, a hyperbolic paraboloid. The color graph for Example 5 Phi Equation doesn't capture the odd symmetry F(x,y)=-F(-x,y). The color graph for Example 6 Underwater Islands looks far inferior to the 3D surface.
No problem. While fuzzy graphing has existed for a long time as contour plots, I'd still like to encourage you to experiment more. The colors look pretty. :)
I have a suggestion. Calculate z=left-right without absolute value, and try mapping [negative limit, 0, positive limit] to [black, red, white], or possibly [negative limit, 0, positive limit, outside of limits] to [red, white, blue, black]. And of course, do variations and have fun!
I'm not sure I've tried that - might good idea. I've actually been playing with all kind so of visualizations - I've done most of my art as stand-alone Python scripts. Here's an open-source starting point for doing this kind of math art in Python: https://github.com/calebmadrigal/truthygraph.py. You might want to try your idea yourself :)
Thanks for the feedback (you and all the others - both positive and negative). HN is such a great way to present ideas to smart people.
I may have been a little hyperbolic in the opening sentence, and may try to tighten up that language. It's true that I've encountered things like visualizing error gradients (in the ML space) in a non-binary way. And yes, mapping 3D to color (and 3D graphing) is nothing novel.
But, I think that the idea of visualizing equations using the question "How different are both sides?" instead of "Are both sides EXACTLY equal - Yes or No?" is a new way to think about it - I don't know of any other graphing app/calculator (besides https://fuzzygraph.com) that does it.
I think some would say that the "Fuzzy graph" of an equation is not a true graph of that equation because a "visualization transform" is being applied, and that only the conventional/binary graph is a valid graph of the equation. But even conventional graphing apps must apply a "visualization transformation" to the equation - something like: 'black' if Boolean(left(x, y)==right(x, y)) else 'white.
Yeah, the opening sentence is very easy to disprove. That's going to spark distrust among people who are "more mathy."
Otherwise ... the plot is obviously engaging, based on the discussion here. For people who haven't seen it before, it's a new way to think about it. It may well be a new "plot type" to most people relying on standard plotting software to visualize equations.
Maybe consider saying it's grounded in "more advanced" math than what others have brought to plotting software. That's still impressive, but it can be made pretty much true. You can cite cool math references about "implicit function theorem" or whatever. Stuff that your target audience really weren't going to just find on their own.
I think your comment is insightful, but it's also a terrible choice of words (and something we probably do too often here). I very much doubt that deception was the intent.
Sometimes, someone just reinvents the wheel (or improves on it). And if it serves to teach several thousand people about a new visualization technique, I think that's a net positive.
You are right but the author's first claim jumped to my eyes (I practice geometry) and burned them... The author seems to be just plotting the values of the implicit function y-f(x,y)...
So, good for him but some historical perspective is needed when making such sweeping claims.
“For all the history of computational mathematical visualization, graphing equations has been done in binary mode...”
Intentional or not, the linked article opens with a comically untrue statement, that, because it is verifiably false, doesn't even escape as puffery. When I encounter this sort of grandstanding in framing (generally from junior engineers or fresh-from-school product managers), I spell out just how negatively such misstatements harm the point being made.
It's a turn-off for readers, and it's unnecessary.
"You may be used to seeing graphs like..."
or
"In grade school, we learned to graph like..."
would probably be more useful than dismissal of the history of visualization of implicit functions. Hopefully, next time, the author will be a bit less grandiose.
There are some truths though that are worth showing.
1. plotting in this way shows areas that are nearly solutions which is really cool.
2. Not mentioned, but this shows gradient around the solution as well, which helps understand attractor/repulsor a bit intuitively
I mean I have generated these plots before to visualize things like error or sensitivity, but this is clean and very cool. So, credit where credit is due for spreading the idea.
I'm wondering if there are topological tools to find the hyperplane of self-intersection from that surface, which is actually the solution of the equation?
Or if given a fuzzy graph z=|F(x,y)| we can use differential geometry to find 0=F(x,y)? Does any of the these questions make sense?
For a general function F, finding the points (x, y) with F(x, y) = 0 has no closed-form solution. The entire field of mathematical optimization is largely dedicated to finding solutions to F(x, y) = 0, in one form or another.
When F has a special structure (say, low-order polynomial), we can actually find the exact solutions. More general structure (e.g. convexity, differentiability) doesn't give us the exact solution, but it lets use use clever numerical algorithms to find them. There are techniques we can use when F has little to no structure, known as "black box" methods, and they work particularly well when we have few variables. In the case of "fuzzy graphs", there are only two variables, so this software takes the approach of computing F(x, y) for every pixel on the screen. In general this doesn't work due to the curse of dimensionality, but it creates good visualizations in low dimensions :)
To answer your question directly, yes we can use differential geometry to speed up optimization. As an example, you've probably heard of gradient descent. Preconditioned gradient descent leverages the geometry of the surface to speed up convergence. In the language of differential geometry, if we're optimizing f(x), then x is "contravariant" but grad(f) is "covariant", so technically we can't just add grad(f) to x since they have different types. We first have to multiply grad(f) by a rank-2 tensor (the "preconditioner") that encodes the local curvature of f around x. This technique is used by the Adam optimizer, with the assumption that the preconditioner is diagonal.
> It is hard to shed prejudices about how code should look, even if learning to see clearly past convention is the only good reason to be a mathematician. I'm already quite sure how I will die: I'll read another article on Hacker News about a new programming language where I see nothing new, and I'll read that they included {}; to make C programmers comfortable. I'll have a massive stroke.
reply