Live data from Hacker News

Solving Sudoku in Python Packaging

github.com

51–56 of 56 posts

Re: Solving Sudoku in Python Packaging

#51
post #3

No way pip actually is a really inefficient SAT solver!

For a long time it was not because there was no backtracking. Now it is just an exhaustive, recursive search: for the current package try using versions from newest to oldest, enqueue its dependencies, if satisfied return, if conflict continue.

If there was no backtracking, that implies it couldn't solve every sudoku? That is rather amusing with the implication that it couldn't solve every dependency, as well?

Re: Solving Sudoku in Python Packaging

#52
post #19
post #7

I love this so much. I dug around a bit and figured out how it works - I have an explanation (with an illustrative diagram) here: https://simonwillison.net/2024/Oct/21/sudoku-in-python-packa... Figuring out how it works is a great way to learn a bit more about how Python packaging works under the hood. I learned that .whl files contain a METADATA file listing dependency constraints as "Requires-Dist" rules. I ran a s…

People keep trying to sell the speed of such solutions as a killer feature for uv, but I think I must not be anywhere near the target audience. The constraint-solving required for the sorts of projects I would typically work on is not even remotely as complex, while I'm bottlenecked by a slow, unreliable Internet connection (and the lack of a good way to tell Pip not to check PyPI for new versions and only consider w…

More significant than the speed improvement in my opinion is the space saving.

The reason uv is fast is that it creates hard links from each of your virtual environments to a single shared cached copy of the dependencies (using copy-on-write in case you want to edit them).

This means that if you have 100 projects on your machine that all use PyTorch you still only have one copy of PyTorch!

Re: Solving Sudoku in Python Packaging

#53
post #31

Earlier quoted context omitted.

Correct, if the complexity guys talk about NP-complete sudoku, it's always about solving Sudokus of an arbitrary, but fixed and finite size. The problem class of "Solve an arbitrary Sudoku of Size 9" might even be constant runtime, since it's a finite set to search through.

Does the Sudoku size have to be perfect square, or can other sizes exist? I suppose you could leave some blank and make the squares the next largest perfect square

Hm. The biggest problem there are the definition of "diagonal" and "box".

I mean non-square sudokus are still in NP. If a solution can be validated in polynomial time, a problem is in NP.

And to validate a (x, y) sized sudoku, you need to check (x * y) [ number of total squares] * (x [row] + y [column] + max(x, y)ish [diagonal-ish] + ((x/3) + (y/3)) [box]). The boxes might be weird, but boxes are smaller than the overall sudoku, so we are looking at some max(x, y)^4 or so. Same for the diagonals. The input is x*y numbers, so max(x, y)^2. Very much polynomial in the size of the input[1]

And it should also be easy to show that if an (n, n) sized sudoku has a solution, an (n+k, n+k) sized sudoku has a solution. You kinda shove in the new numbers in knights-kinda moves and that's it.

1: this can be a bit weird, because you need to be careful "what you're polynomial in". If your input is a number or two, you might be polynomial in the magnitude of the number, which however is exponential with the input length.

In this case however, we wouldn't have encoding shenanigans, since we're just placing abstract symbols from the turing machine's alphabet onto an imagined grid.

Re: Solving Sudoku in Python Packaging

#54
post #52
post #19

Earlier quoted context omitted.

People keep trying to sell the speed of such solutions as a killer feature for uv, but I think I must not be anywhere near the target audience. The constraint-solving required for the sorts of projects I would typically work on is not even remotely as complex, while I'm bottlenecked by a slow, unreliable Internet connection (and the lack of a good way to tell Pip not to check PyPI for new versions and only consider w…

More significant than the speed improvement in my opinion is the space saving. The reason uv is fast is that it creates hard links from each of your virtual environments to a single shared cached copy of the dependencies (using copy-on-write in case you want to edit them). This means that if you have 100 projects on your machine that all use PyTorch you still only have one copy of PyTorch!

This is definitely a feature I wanted to have in my own attempt (hopefully I can start work on it before the end of the year; I think I'll bump up my mental priority for blogging about the design). I also have considered symlink (not sure if this really works) and .pth file-based approaches.

(TIL `os.link` has been supported on Windows since 3.2.)

Re: Solving Sudoku in Python Packaging

#55
post #31
post #22

Earlier quoted context omitted.

I think for Sudoku to be NP-Complete, it needs to be generalized to arbitrary board sizes (at the very least)

Correct, if the complexity guys talk about NP-complete sudoku, it's always about solving Sudokus of an arbitrary, but fixed and finite size. The problem class of "Solve an arbitrary Sudoku of Size 9" might even be constant runtime, since it's a finite set to search through.

I looked it up, and there are 6.6e21 9x9 sudokus, which I wouldn't consider constant time practically

Re: Solving Sudoku in Python Packaging

#56
post #55
post #31

Earlier quoted context omitted.

Correct, if the complexity guys talk about NP-complete sudoku, it's always about solving Sudokus of an arbitrary, but fixed and finite size. The problem class of "Solve an arbitrary Sudoku of Size 9" might even be constant runtime, since it's a finite set to search through.

I looked it up, and there are 6.6e21 9x9 sudokus, which I wouldn't consider constant time practically

That is another very interesting part of complexity theory, yeah.

Like, "Constant time" means, "Runtime independent from input". And, well, solving any sudoku of size 9 or less is a constant times 6.6e21. Maybe a bit more in the exponent, but meh.

Like in graph theory, there are some algorithms for I think maxflow, which solve the thing in O(node_count^4). Theory can push this down to like O(node_count^3) or O(node_count^2.7) or less. That's amazing - you can lose almost 2 orders of magnitude.

Well, implementation of these algorithms and more detailed analysis point out _huge_ precomputations necessary to achieve the speedups. In practice, you'd only see speedups if you had graphs with multiple billions of nodes. In practice, if you deal with a boring subset like "realistically relevant", asymptotically worse algorithms may be the objectively better choice.

Like in this case. Here, some O(n^5) - O(n^9) depending on what the solver does can be better than O(1) for many practical purposes.

In such areas, intuition is little more than a lie.

Post reply on HN