Is rust ~~slow~~ too fast ?!

Hi ...

I'm not a rust/c expert at all !

But I'm trying to implement a "python sudoku resolver" in different languages, to compare "run times" only. (to resolve 100 easy sudoku grids)

I've made some good version for mojo, C, java, nodejs, nim .. and got great results

I used chatgpt 3.5 to convert the java version to rust .... (the c version was created in the same manner)
it worked OOTB ... but the result seems very very slow ...

Is there any rust expert which could help me to find what is wrong ?!
all codes are here (see makefile to run tests)

It can't be slower than py3 or java ... no ?!
Perhaps GPT doesn't reach to do the better optim ?!

1 Like

Obligatory "did you run with --release?"

4 Likes

I used rustc (1.71) under ubuntu 23.10 ...

rustc --release  sudoku.rs && ./sudoku
error: Unrecognized option: 'release'

so I try with
rustc -C opt-level=3 -C target-cpu=native sudoku.rs && ./sudoku

The Rust version is doing a lot of linear scans like g.chars().skip(y * 9).take(9).collect(). These are necessary because of how &str and String work in Rust, but those datatypes are really unsuited for this application. &[u8] and Vec<u8> would at least let you direct-index, even if not necessarily the most idiomatic solution.

7 Likes

Yeah. On the one hand, it's impressive it translated the code at all. On the other hand, it clearly has no idea what it's doing. :smiley:

Plus, all those compound iterators being glued together, then collected into a new allocation, only to be pulled back apart... probably much less of an issue than the repeated linear scans, but still unpleasant.

--release is a cargo flag. Most people will assume your code is part of a Cargo project.

7 Likes

Yeah. On the one hand, it's impressive it translated the code at all.

yes ! bard never reach to make a working solution ootb.... but gpt3.5 is magic !

Plus, all those compound iterators being glued together, then collected into a new allocation, only to be pulled back apart... probably much less of an issue than the repeated linear scans, but still unpleasant.

Yes, but it's the same constraints for all the implementations ...
But the rust version is very slow ;-(

Of course, with Vec<u8> & co ... it could be a lot faster ! ( like this mojo version, which uses vectors, is incredibly fast ... compared to barebone/C version).

Has anything changed since you asked for help for translating your sudoku resolver 2 years ago?

Why are you using AI then if 2 years ago someone helped you to translate it?

8 Likes

I spent a little bit of time and wrote a more idiomatic Rust implementation of your algorithm. No idea how it compares to the others, and I haven't checked its output for correctness beyond seeing that the first example leaves no empty values.


Edit: On the playground, in release mode, your first 100 test cases get solved in 1019 ms (sample of 1).

7 Likes

In C a string is just a sequence of null-terminated bytes and you just treat it as such, which is fine because you know it will just store ascii characters.

In Javascript instead a string stores a UTF-16 encoded string and you treat it as a collection of 16 bit code units. But Javascript also has byte arrays, so why didn't you use them if you used a byte array in C?

In Rust a string is stored as UTF-8, and .chars() gives you an iterator over Unicode code points. This makes sense if you're working for text, where it usually makes no sense getting the nth character (also, what do you consider as a character? There are probably more possible answers than you might think). Again, you could just treat the string as a sequence of bytes (which they are, you can use .as_bytes() if you want) like you did in C.

In the end there's no such thing as "same constraints". Every language has been written with different expectations for what the user will do, and will be optimized accordingly. So yes, Rust is slow if you use it in a way that it wasn't designed for. You can still make it fast by doing those optimizations yourself, but here you're explicitly restricting yourself to not do them. Other languages will do some optimizations automatically, at the expense of other optimizations, usecases or sometimes correctness, but this is not reflected in your example.

IMO it would be more reasonable to replicate the same algorithm, but in a way that's more idiomatic for each language.

10 Likes

By choosing the most constrained digit each iteration, the runtime drops to 18ms total for the first hundred test samples. That's a major algorithmic change, though, so it's probably not a fair comparison with the others.

1 Like

oh thanks ! I've totally forget this !
But it explains why chatgpt reach to transpile it !

@ 2e71828

thanks a lot !
your version is incredibly fast ! (0.3s)

I will dig into the code, to understand the tricks

finally I've take your first version, as reference.
(on my computer, it takes 16s for the 100 first grids!)

I will study your optimized version ... and will probaly adapt your constraint (choosing the most constrained digit each iteration) to all other versions ... (but need to adapt the py one first)
And run it with the 1000 first grids !

Thanks a lot for ur work !!!
Your optimized version takes 280ms on my computer for the 1st 100 ... it's amazing !
this constraint is a game changer !

Sudoku is one of those problems that is well suited for solving as an exact cover problem with Algorithm X.

Here's a hastily slapped together example using the solver from https://crates.io/crates/xcov and the sample data posted earlier:, which runs in under 10ms.
Rust Playground

4 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.