If you did not solve the Rubik cube (or did not investigate it in general), I highly advice you to try solving it on your own. Just read nothing about it.
I did it with the help of programming and it is one of the coolest problems I solved (finding an algorithm to solve any instance).
Although I used a computer, it took me something like one or two month to really crack it and lots of RAM to come up with a working solution.
Fun fact: My first approach (I just knew, there was this colorful cube problem, but not that it's that hard) was a simple recursive Haskell program where I thought I could just brute force the solution in an afternoon (I did not know about the problem's math at that point, but looked it up afterwards) ... damn, was I wrong.
I remember that the approach involved restricting the operations (turning a specific side) on the cube, and by allowing just 1 side to rotate one gets len([0, pi/2, pi, 3pi/2]) == 4 solutions, but by allowing _2_ rotations the number jumps to something like ~4*10^7 combinations already.
At that point my simple wonderful Haskell program just ate up memory, and I had to rewrite it in another language (after first solving the 2x2x2 cube to keep my motivation). I tried Python (very slow) and Java (which was the fastest), but could not get rid of some GC panics, so in the end it was good old C which found the solution by encoding one state into 24 Bytes and building various fat, unbalanced binary trees, that provided a lookup-table for specific phases of the algorithm.
Granted my solution was not the best, but my point is that I would not have found it via Haskell, as I was interested in specific upper bounds to sub-problems and being memory constrained was a nightmare with Haskell (my initial program was nice, it type-checked and for sure terminated, but termination required probably a Petabyte - in any case a too big number - of RAM).
Being lazy evaluated, Haskell, makes it hard to reason about performance in more than trivial code (as a rubik cube solver would be).
All those suspended computations may eat your RAM for no good reason at all. For example:
sum (replicate n 0)
has a space leak O(n). While:
foldl' (+) 0 (replicate n 0)
works fine O(1) space wise.
My point is that it is easy to eat all your RAM using haskell even in the simple `sum` case above. More so in more involved computations.
Of course, if you can compute your solution in constant space using C, you can also do it in haskell. But writing it in Haskell would require careful thought in how your code is evaluated.
EDIT: It is about trade offs.
If you want declarative and readabe code, with little memory layout noise (allocate memory, assign variables, etc...) then haskell is a reasonable choise. You can write fairly readable clode for complex algorithms. If you are an expert, you can also make it efficient on the first go (speed and space wise). If speed is of upmost importance, then you can write more compiler specific code but with a lot of added noise.
Or you can start with C, write less (than haskell) declarative code and less readable code. It would be harder to get right(the more complex the computation the harder to debug), but when you are done you probably have efficent code. If you have the experience, you may be able to make it fairly readable too.
Also, Haskell has a nice LANGUAGE Strict pragma since recently. Won't save you from things like lazy pairs or other imported things, of course, but at least can be good for one-file scripts where you want to solve Rubic's cube.
But if you try it on ghci you will see that it breaks. (ghc 8.0.1). So it dependes on how you "interpret" the code. `ghc -O` is sophisticated enough to make the right decisions when compiling your code. You probably don't want a space leak, so it doesn't generate one.
GHC will have more trouble making the right choice in more involved computations. It will revert to "just do what the coder says".
Consider this C code for example:
unsigned int sum = 0;
const unsigned int n = 1000;
for(int i = 0; i<n; i++) {
sum += 0;
}
If you look at it, you can tell this is O(1) in space for any valid `n`. A spohisticated enough compiler may replace it by
unsigned int sum = 0;
and be done with it. But even an unsophisticated(but correct) compiler will produce O(1) space wise code.
EDIT: format
EDIT: What I was trying to say in my original comment is that, in haskell, space leaks my appear even in the most innocent looking code. And that it may require a bit of experience to identify and avoid them.
Well, sure, running code in interpreter does less optimizations than doing full compilation. I can write an interpreter for your C code which runs out of memory if you want :) So your "you can tell" depends on particular compiler or interpreter implementation, and no, you can't tell what my compiler will do.
I'll have to agree with that. But then I would also say that I had to make some assumptions, right? :)
I think GHCi is helpful in this situation, however. It clearly distinguishes between leaky and non-leaky code. This leak is a product of "just doing what the coder says" (go to "Data.Monoid.sum" and do what it says there with such and such...). I'm assuming that, for this code, GHCi is bug-free.
I think
sum (replicate n 0)
is as dangerous as
foldl (+) 0 (replicate n 0)
or
foldr (+) 0 (replicate n 0)
. `sum (replicate n 0)` may be the right thing to do in some cases unknown to me.
There is `{-# LANGUAGE Strict #-}`, as you mention, and BangPatterns for strict arguments. But I would assume, those are used only by coders already familiar with haskell and its leaky pitfalls.
This is one of my biggest regrets: learning to solve it at a young age (10) and not actually solving it, but rather learning an existing algorithm. I have had much satisfaction as an adult in solving 4x4 and 5x5 cubes, but even that tends to be derivative of existing 3x3 solutions (though I did create some sequences myself and those proved easier to scale that traditional ones).
Even then <spoiler alert>, I recall vividly the moment my 10 year old self understood the 3 dimensional nature of "a side", and how a side was not solved until the top row of the each of its neighbors was also correct. It was quite an intellectual thrill for a 10 year old to make that transition.
These days I try to focus on block building rather than memorized sequences. It's a little more intellectually stimulating. If I do go the memorized sequence route, I try to string 2 such sequences together.
See what's happening here boys and girls ? Here I am barely remembering the first steps of a `simple` algorithm to solve the cube and someone from the Internet regales us with a story of how he did not only solve the cube but wrote some recursive haskell mathemagic that would do it for him.
They say we shouldn't compare to others too much but you're sometimes kind of making it real heard HN :).
You don't really need to be a mathematician to do it. All it takes is patience and being good at spotting patterns and observing in general. My brother-in-law solved one before the Internet era all by himself. It took him few months, but he eventually did it.
Funny story: When the Rubik's Cube first came out, the box proudly proclaimed: "More than 20 million combinations!"
Even in those days, it was known that it had vastly more than 20 million positions. I've wondered about the marketing guy's rationale. Obviously, "43 quintillion combinations" would not make sense to most people. But why not write, "20 billion" or "20 trillion"? Maybe it was too discouraging.
Douglas Hofstadter apparently published a correct analysis of the number of configurations in Scientific American in 1981... It's not as if it was anywhere remotely near being beyond the tools available to mathematics at the time.
sometimes, an algorithm is so intricate that it can only be understood by reading the paper. in this case, it's much more useful to make the variable names match the paper than to attempt semantic variable names.
Wow, yet another result found by computer proof. Mathematics is getting weird. Maybe there is some metamathematical proof that the computer proof was produced in the correct fashion. My puny human brain wants reassurance that this proof is correct.
It is not unheard of that widely accepted results turn out to be false. It's rare, but it has happened. Here are some examples:
I think in this case, the lower bound was theoretically proven, and now exhaustively it has been determined that there are no positions which exceed the theoretical lower bound. I'm pretty comfortable with that conclusion.
From what I understand, the 12 million positions that require 20 moves is not considered definitive not completely accurate. They stated that the searches weren't looking for the optimal solution, but rather any solution that took 20 or less moves. Without the theoretical lower bound, all the exhaustive proof would demonstrate is that the upper bound is 20. I feel like the exhaustive proof of establishing a given upper bound is much easier than finding the optimal solutions for every possible position.
And how do you know the exhaustion was done correctly? What was the process that lead to it? Is that process correct? Could they have forgot to check some cases? How do we know they didn't?
There are still questions pending. If you and I write bugs into our programs, they may well have done the same thing for their program that supposedly checks all cases.
Isn't that the same weak point of theoretical proof? Papers get accepted, peer reviewed, published without anyone detecting the flaw. A good example is Hyman's mutual exclusion algorithm, which passed all the usual review without issue but later discovered to be flawed.
The source is available and can,should be, and has been peer reviewed.
There are just many more points of failure in a computer proof than a human proof (I don't like calling it "theoretical", that doesn't seem like a useful distinction, and it has connotations of not being "real" when it's opposed to "practical"). Maybe they used numbers so big that there was an overflow. Maybe they relied on some library that itself had bugs that didn't express itself until they tried it on large numbers. Hell, even bits flipping due to cosmic rays is a legitimate concern and not as far-fetched as you might think.
There are different kinds of pitfalls in computer proofs, and I wonder how can we account for them. The errors in a computer program are far less forgiving than the errors in a human proof. A typo in a human proof doesn't grind the whole proof to a halt and usually the human reader can quickly mentally correct the typo, but computer proofs are more brittle.
Eh... A decent compiler will cause a proof to grind to a halt on a typo.
I don't really see the difference honestly, besides quantitative complexity. A computer run exhaustive proof is less brittle than a manual exhaustive proof. I think complexity of the proof is just a function of the length. And for a computer proof, that length includes the toolchain.
This is years old and I'm not familiar with it, but generally, the proof is among the simplest and most straightforward, right? If I read it right, it's proof by exhaustion. The trick is that it was previously impractical.
I have a cube that I got as conference swag which they made unintentionally harder to solve. There are two sides where the three middle pieces (number 4, 5 and 6 if you think of the arrangement of numbers on a numeric keypad) have a logo printed across them - 'Samsung' in fact. The middle of the three pieces is therefore constrained to be in a certain orientation (normally rotations of that square would not matter) and therefore symmetry is broken.
So, there are four extra positions for each of the rotations of the logo centre piece, and two of these pieces. Intuitively, it seems obvious this makes it harder, but I'm not sure by how much. Any ideas?
There's some math in the regular wikipedia entry, not exactly your case but one for all sides requiring the right rotation relative to neighbors, which increases the state space by a factor of 4^6/2, or 2048x.
(Edit - I originally naively thought your configuration would increase the space by 16x, but the calculation is more complicated, as some configurations aren't attainable from a given starting arrangement without disassembly. So it would depend on how the two labelled faces were positioned relative to each other (ie, are they in adjacent or opposite faces), and if your definition of a solution only requires the logos to be restored per face but not the same orientation relative to the initial configuration.)
That wouldn't make it any harder. Sides only have a single orientation, with the opposite side suited to the center piece of one of the neighboring sides. Placing the piece with the correct neighboring side addresses the issue automatically.
Corner pieces can be rotationally incorrect, through the solving process, and is one of the harder areas to sove on the puzzle.
No, the center piece on a particular side has a preferred orientation with regards to the pieces on its left and right assuming the cube is like this, with S M G standing for the Samsung logo and o being a standard plain coloured square:
o o o
S M G
o o o
The M piece must be correctly positioned to align with the S and G pieces, if it is rotated the logo will look wrong. Obviously if they were plain coloured squares the rotation would not matter.
At some point before 1985, an algorithm was found that could solve it in 21 "twists". (Just checked in my old copy of Hofstadter's Metamagical Themas.)
Those interested in the field of Algebra, the Rubik's cube makes a great topic of research. You'll learn about the Rubik's cube group and how it is a subgroup of S_{48}. For a project I had this semester, I wanted to use Algebraic components of the cube to come up with algorithms for solving it, but I did not have the time.
The quality of the comments is surprisingly high: a AWS analysis, some maths, etc.
My favorite being:
> If you disassemble your cube and put it back together, there
> are 12 possible sets that you can land in. Those sets are
> not reachable from each other.
> The proof is quite elementary.
I always hesitate - some people hate it, others appreciate it. I think it's worth cross-connecting previous conversations, because I see the HN discussions as a resource. Others seem to think it should all be ephemeral and throw-away.
Having said all that, I hope this gets some new discussion.
The experiential difference of seeing the contextualization you put in the top-level post here, and just seeing a list of links (like you used to do) is huge. This way feels friendly like being invited into a larger conversation. A "sterile" list of previous discussion feels a little too much like "OMG repost".
I can't speak for others - but I think you hit the sweet spot of how to do the cross-connecting.
The idea of this is that an omniscient being would know the best possible move in any configuration, and therefore might solve the puzzle in a strikingly more efficient way than an ordinary solver.
I don't know who originated the term but, if I remember correctly, it already appeared in Douglas Hofstadter's discussion of the Rubik's cube in the 1980s, so it was already current then. It was a big topic of Rubik's cube research until it was definitely solved (by the people whose work is linked above).
True! I guess in this case the Rubik's cube enthusiasts first coined the term, and the question was most discussed and studied in that community, so for them the intended reference was still clear even though the concept had also been applied to other puzzles.
There's a link in the article to Wikipedia. Basically that an omniscient being would know the shortest number of moves on a Rubik's cube, so the most number of moves "God" would take to solve a Rubik's cube would be 20.
https://en.m.wikipedia.org/wiki/God's_algorithm
Why? I remember using a simple program in 2000 to see how many moves were canonically required, and most positions I came up with were resolved in 13 moves.
On the other hand, I would have thought 19 steps were enough because they already cover the full space of positions. To wit: There are 12 possible choices at each step, 19 steps cover 12^19 possibilities, which is 8 times more than the 43,000,000,000,000,000,000 positions.
I did it with the help of programming and it is one of the coolest problems I solved (finding an algorithm to solve any instance).
Although I used a computer, it took me something like one or two month to really crack it and lots of RAM to come up with a working solution.
Fun fact: My first approach (I just knew, there was this colorful cube problem, but not that it's that hard) was a simple recursive Haskell program where I thought I could just brute force the solution in an afternoon (I did not know about the problem's math at that point, but looked it up afterwards) ... damn, was I wrong.
I remember that the approach involved restricting the operations (turning a specific side) on the cube, and by allowing just 1 side to rotate one gets len([0, pi/2, pi, 3pi/2]) == 4 solutions, but by allowing _2_ rotations the number jumps to something like ~4*10^7 combinations already.
At that point my simple wonderful Haskell program just ate up memory, and I had to rewrite it in another language (after first solving the 2x2x2 cube to keep my motivation). I tried Python (very slow) and Java (which was the fastest), but could not get rid of some GC panics, so in the end it was good old C which found the solution by encoding one state into 24 Bytes and building various fat, unbalanced binary trees, that provided a lookup-table for specific phases of the algorithm.
Granted my solution was not the best, but my point is that I would not have found it via Haskell, as I was interested in specific upper bounds to sub-problems and being memory constrained was a nightmare with Haskell (my initial program was nice, it type-checked and for sure terminated, but termination required probably a Petabyte - in any case a too big number - of RAM).