“To get the orbit time in days from the aphelion and perihelion in Kkm, first sum them and divide by 1024. Then from that, subtract one twelfth. Then, to the value, perform a bitwise OR with 0x0C, multiply by the square root, and bit-XOR 0x0C again. Finally, divide by 12, and that will give you the number of days.”
The three problems with the code are that the variable names are all lies, there’s a bunch of redundant rescaling which isn’t consolidated because it’s done in integer math when it should be floating point, and there are a couple bits of overfitting (bitwise operators) that don’t belong. If you convert to SSA and wipe out the misleading names, you get:
If you replace the overfitting with pass-throughs (a6=a5, a8=a7), then pretend it’s floating point so that you can consolidate all the rescaling into a single multiplicative constant, you get
guess = k * (perihelion+aphelion)*sqrt(perihelion+aphelion)
This reminds me of the discussion from last week of the code that a self-modifying AI might produce; I said then that I thought people were not thinking Weirdly enough. This is indeed an example of Weirdness. Obviously no human would come up with such a thing. Yet it works, more or less; although the hardcoded numbers make me suspect that its range of applicability may not be great. Testing it on some numbers typical of, say, solar orbits around the galactic core, might produce some surprising results.
It would also be interesting to compare this for speed, as well as accuracy, with a Kepler’s-law implementation.
No. The posted code has a bit shift right for 12 places. The already optimized code by wmorgan has a bit shift for only 10 bits.
The metacommand $RESCOM if while val_operation inc_dec caused this. Having two constants (10 and 12) would be undesirable be cause of this “val_operation” and therefore only the constant 12 was used.
Those four lines together amount to a shift 10 bits to the right, i.e., division by 1024.
I think you understand what’s going in the code. The point of my refactoring was to make something that was human-readable: something that I could describe in English. And the English for those four lines of code is “divide by 1024.” That’s what those four lines do.
$DECLAREINT aphelion perihelion dif guess temp
$RINVAR aphelion(1000,100000) perihelion(1000,100000)
$RETVAR guess
if (aphelion>guess;
temp=aphelion/guess;
aphelion=aphelion-temp;
dif=sqrt(aphelion);
//aphelion=guess|aphelion;
aphelion=aphelion*dif;
//aphelion=guess^aphelion;
guess=aphelion/guess;
$EES
As you can see, there is no $RESCOM metacommand and the two “overfit” OR and XOR lines has also been commented or neutralized. Random aphelions and perihelions are between 1 million and 100 million km now. If aphelion is greater than perihelion they are swapped first. The intermediate variable “temp” is then reset to 0 before the “Kepler segment” begins. If it wasn’t reset, the simulator would simply use it! Simulator comes out with this in the $BES-$EES section:
aphelion=perihelion+aphelion;
aphelion>>=10;
guess=12;
temp=aphelion/guess;
aphelion=aphelion-temp;
perihelion=sqrt(aphelion);
perihelion=perihelion*aphelion;
guess=perihelion/guess;
Less lines, but now two constants (10 and 12) (approximately) scale days with mega-meters here, where the Sun is this massive. Initially, it was only the 12 constant, which shifted, divided and was also a XOR argument to fit some more.
Both codes here, inside the $BES-$EES segments are exactly equivalent regarding the outputs and are a distant ancestor-descendant pair. Many million generations apart, but not very much different.
As you can see, there is no $RESCOM metacommand and the two “overfit” OR and XOR lines has also been commented or neutralized. Random aphelions and perihelions are between 1 million and 100 million km now. If aphelion is greater than perihelion they are swapped first. The intermediate variable “temp” is then reset to 0 before the “Kepler segment” begins. If it wasn’t, the simulator would simply use it!
Simulator comes out with this in the $BES-$EES section:
Less lines, but now two constants (10 and 12) (approximately) scale days and mega-meters here, where the Sun is so massive. Before, it was only the constant of 12, which shifted, divided and was also a XOR argument to fit some more.
Both codes here, inside the $BES-$EES segment are exactly equivalent regarding the output and are a distant ancestor-descendant pair. Many million generations apart.
Then you have two different constants (10 and 12). One for the shifting and another for the division. It’s nothing wrong with that, but the simulator was prevented to have more constants then absolutely necessary. So everything was done with the “12” and I was discussing that.
The XOR with 12 won’t do much after dividing by 12. For small radii, OR with 12 (in units of about 10^6km) will have an effect. These two constants are probably just overfitting. Indeed, it nails Mercury, the smallest and thus most vulnerable to these effects.* Rounding** the square root is also probably overfitting or just noise. It will have a larger effect, but smooth across planets, so it is probably canceled out by the choice of other numbers. Ignoring those three effects, it is a constant times the 3⁄2 power of average of the axes. The deviation from Kepler’s law is that it should ignore perihelion.*** But for un-eccentric orbits, there’s no difference. Since the training data isn’t eccentric, this failure is unsurprising. That is, the code is unsurprising; that the code is so accurate is surprising. That it correctly calculates the orbital period of Halley’s comet, rather than underestimating by a factor of 2^(3/2) is implausible.***
* The control group is too homogeneous. If it contained something close in, overfitting for Mercury would have been penalized in the final evaluation.
** Are you sure it’s rounding? [Edit: Yes: bitwise operations are strongly suggestive.]
*** These statements are wrong because I confused apehelion with the semi-major axis. So removing the bitwise operations yields exactly Kepler’s law. If you switch from ints to doubles it becomes more accurate. But wmorgan has a constant error: it is divide by 4096, not 1024. This should make the rounding errors pretty bad for Mercury. Maybe the bitwise operations are to fix this, if they aren’t noise. My C compiler does not reproduce the claimed error percentages, so I’m not going to pursue this.
The generated code is bizarre. I refactored it as well as I could, and it still doesn’t make much sense:
“To get the orbit time in days from the aphelion and perihelion in Kkm, first sum them and divide by 1024. Then from that, subtract one twelfth. Then, to the value, perform a bitwise OR with 0x0C, multiply by the square root, and bit-XOR 0x0C again. Finally, divide by 12, and that will give you the number of days.”
The three problems with the code are that the variable names are all lies, there’s a bunch of redundant rescaling which isn’t consolidated because it’s done in integer math when it should be floating point, and there are a couple bits of overfitting (bitwise operators) that don’t belong. If you convert to SSA and wipe out the misleading names, you get:
If you replace the overfitting with pass-throughs (a6=a5, a8=a7), then pretend it’s floating point so that you can consolidate all the rescaling into a single multiplicative constant, you get
Which is Kepler’s third law.
This reminds me of the discussion from last week of the code that a self-modifying AI might produce; I said then that I thought people were not thinking Weirdly enough. This is indeed an example of Weirdness. Obviously no human would come up with such a thing. Yet it works, more or less; although the hardcoded numbers make me suspect that its range of applicability may not be great. Testing it on some numbers typical of, say, solar orbits around the galactic core, might produce some surprising results.
It would also be interesting to compare this for speed, as well as accuracy, with a Kepler’s-law implementation.
Actually by 4096. And it is a rescaling as jimrandomh points out.
Am I crazy? A right shift by 10 is equivalent to a division by 2^10. 2^10 is 1024..
No. The posted code has a bit shift right for 12 places. The already optimized code by wmorgan has a bit shift for only 10 bits.
The metacommand $RESCOM if while val_operation inc_dec caused this. Having two constants (10 and 12) would be undesirable be cause of this “val_operation” and therefore only the constant 12 was used.
This is the generated code segment:
Those four lines together amount to a shift 10 bits to the right, i.e., division by 1024.
I think you understand what’s going in the code. The point of my refactoring was to make something that was human-readable: something that I could describe in English. And the English for those four lines of code is “divide by 1024.” That’s what those four lines do.
We can modify the above code to:
$DECLAREINT aphelion perihelion dif guess temp $RINVAR aphelion(1000,100000) perihelion(1000,100000) $RETVAR guess if (aphelion>guess; temp=aphelion/guess; aphelion=aphelion-temp; dif=sqrt(aphelion); //aphelion=guess|aphelion; aphelion=aphelion*dif; //aphelion=guess^aphelion; guess=aphelion/guess; $EES As you can see, there is no $RESCOM metacommand and the two “overfit” OR and XOR lines has also been commented or neutralized. Random aphelions and perihelions are between 1 million and 100 million km now. If aphelion is greater than perihelion they are swapped first. The intermediate variable “temp” is then reset to 0 before the “Kepler segment” begins. If it wasn’t reset, the simulator would simply use it! Simulator comes out with this in the $BES-$EES section:
aphelion=perihelion+aphelion; aphelion>>=10; guess=12; temp=aphelion/guess; aphelion=aphelion-temp; perihelion=sqrt(aphelion); perihelion=perihelion*aphelion; guess=perihelion/guess; Less lines, but now two constants (10 and 12) (approximately) scale days with mega-meters here, where the Sun is this massive. Initially, it was only the 12 constant, which shifted, divided and was also a XOR argument to fit some more.
Both codes here, inside the $BES-$EES segments are exactly equivalent regarding the outputs and are a distant ancestor-descendant pair. Many million generations apart, but not very much different.
We can modify the above code to:
$DECLAREINT aphelion perihelion dif guess temp $RINVAR aphelion(1000,100000) perihelion(1000,100000) $RETVAR guess
if (aphelion<perihelion) { temp=perihelion; perihelion=aphelion; aphelion=temp; }
temp=0;
$BES aphelion=perihelion+aphelion; aphelion=aphelion+aphelion; aphelion=aphelion+aphelion; guess=12; aphelion=aphelion>>guess; temp=aphelion/guess; aphelion=aphelion-temp; dif=sqrt(aphelion); //aphelion=guess|aphelion; aphelion=aphelion*dif; //aphelion=guess^aphelion; guess=aphelion/guess; $EES
As you can see, there is no $RESCOM metacommand and the two “overfit” OR and XOR lines has also been commented or neutralized. Random aphelions and perihelions are between 1 million and 100 million km now. If aphelion is greater than perihelion they are swapped first. The intermediate variable “temp” is then reset to 0 before the “Kepler segment” begins. If it wasn’t, the simulator would simply use it!
Simulator comes out with this in the $BES-$EES section:
Less lines, but now two constants (10 and 12) (approximately) scale days and mega-meters here, where the Sun is so massive. Before, it was only the constant of 12, which shifted, divided and was also a XOR argument to fit some more.
Both codes here, inside the $BES-$EES segment are exactly equivalent regarding the output and are a distant ancestor-descendant pair. Many million generations apart.
The extra two places of bit shifting cancel with two previous self-additions.
I know and I agree with this.
Then you have two different constants (10 and 12). One for the shifting and another for the division. It’s nothing wrong with that, but the simulator was prevented to have more constants then absolutely necessary. So everything was done with the “12” and I was discussing that.
The XOR with 12 won’t do much after dividing by 12. For small radii, OR with 12 (in units of about 10^6km) will have an effect. These two constants are probably just overfitting. Indeed, it nails Mercury, the smallest and thus most vulnerable to these effects.* Rounding** the square root is also probably overfitting or just noise. It will have a larger effect, but smooth across planets, so it is probably canceled out by the choice of other numbers. Ignoring those three effects, it is a constant times the 3⁄2 power of average of the axes. The deviation from Kepler’s law is that it should ignore perihelion.*** But for un-eccentric orbits, there’s no difference. Since the training data isn’t eccentric, this failure is unsurprising. That is, the code is unsurprising; that the code is so accurate is surprising. That it correctly calculates the orbital period of Halley’s comet, rather than underestimating by a factor of 2^(3/2) is implausible.***
* The control group is too homogeneous. If it contained something close in, overfitting for Mercury would have been penalized in the final evaluation.
** Are you sure it’s rounding? [Edit: Yes: bitwise operations are strongly suggestive.]
*** These statements are wrong because I confused apehelion with the semi-major axis. So removing the bitwise operations yields exactly Kepler’s law. If you switch from ints to doubles it becomes more accurate. But wmorgan has a constant error: it is divide by 4096, not 1024. This should make the rounding errors pretty bad for Mercury. Maybe the bitwise operations are to fix this, if they aren’t noise. My C compiler does not reproduce the claimed error percentages, so I’m not going to pursue this.