# What is wrong with RuleCondition here?

Bug introduced in 9.0 or earlier and fixed in 10.4

Hold@15 /. x_Real :> RuleCondition[N@x, True]
Hold@15 /. x_Real :> RuleCondition[N@25, True]
Hold@25 /. x_Real :> RuleCondition[N@25, True]
Hold@15 /. x_Real :> RuleCondition[N@t, True]


The returned answers, in StandardForm, are:

Hold[1.0000]
Hold[2.]
Hold[2.0000]
Hold[t]


The problem is that the first and third lines should evaluate to machine precision numbers (like the 2nd line), but it appears that Mathematica is executing an approximate numerical equality test to determine whether or not to execute the RuleCondition that doesn't show up during my attempts at tracing. Experts, do you consider this to be a bug? What would your workaround be? The context is that I am tracing a numerical routine that works with high precision numbers. I need to format the trace so that I can actually read it, thus the conversion to machine precision numbers that are inside a Hold (HoldForm in the case of Trace).

For those that don't know, RuleCondition is what the right hand side of a Rule or RuleDelayed evaluates to if that right hand side contains an expression like Block[{},result/;condition], which is transformed to RuleCondition[result,condition] and is evaluated outside of the context of the expression that originally matched the left hand side pattern of the Rule or RuleDelayed. RuleCondition right hand side replacements don't happen if condition is False. However, in this case, it appears that the condition must be True AND the result must not be approximately equal to the left hand side pattern for the rule.

• Welcome to Mathematica.SE! I suggest the following: 1) As you receive help, try to give it too, by answering questions in your area of expertise. 2) Read the faq! 3) When you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge. Also, please remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign! Sep 10, 2015 at 22:59
• I am pretty sure you are the very first new user that asked a question about something as advanced as RuleCondition. Additionally, your post is as clearly written and formatted as one can only wish for! Let me welcome you here and hope, you stay longer. Sep 11, 2015 at 1:55
• Just like you said. This bug is fixed in v10.4. Mar 20, 2016 at 13:46

Here is an observation, not really an answer:

Hold@1.5 /. x_Real :> RuleCondition[N[x] + $MachineEpsilon, True] (* -> Hold[1.0000] *)  But: Block[{Internal$SameQTolerance = -Infinity},


Hold@1.5 /. x_Real :> RuleCondition[N[x] + $MachineEpsilon, True] ] (* -> Hold[1.] *) It does not help your test case because 1.5 is SameQ 1. But I think this makes it a question of SameQ's problem, rather than RuleCondition's. For completeness: Internal$EqualTolerance and Internal$HashTolerance have no effect. The test is definitely SameQ. Since Alexey mentions that things were better in version 5 with respect to a tangentially related bug/oddity, it may be worth noting as well that in versions of Mathematica up to and including 7, we have a different result: Hold@15 /. x_Real :> RuleCondition[N@x, True] (* -> Hold[1.] *) Hold@15 /. x_Real :> RuleCondition[N@25, True] (* -> Hold[2.] *) Hold@25 /. x_Real :> RuleCondition[N@25, True] (* -> Hold[2.] *) Hold@15 /. x_Real :> RuleCondition[N@t, True] (* -> Hold[t] *)  This looks absolutely as one would expect. The optimization of SameQ in version 8 is the clear culprit. Unfortunately, we cannot work around the problem by replacing SameQ with a more stringent test: InternalHashSameQ[1., 1.5] (* -> False *) Block[{SameQ = InternalHashSameQ, Internal$HashTolerance = -Infinity},
Hold@1.5 /. x_Real :> RuleCondition[N[x], True]
]
(* -> Hold[1.0000] *)


It seems that RuleCondition is hard-coded to call the SameQ code no matter how SameQ is defined at the top level. This might be considered a bug in RuleCondition in addition to the one in SameQ.

I am of the view that the SameQ behavior is a bug, because while I have always thought that the value of Internal$SameQTolerance being anything other than -Infinity is a bad idea, for numbers with different Precision to compare as being the same is an explicit violation of Mathematica's numerical model of floating-point numbers being distributions. I think one cannot have a serious conceptual inconsistency like this and not call it a bug. • +1 Beat me to it by seconds. RuleCondition is unnecessary to demonstrate the behaviour. It appears that the SameQ "optimization" only occurs if a structure needs to be rebuilt. For example, contrast the results of evaluating 25 /. 25 -> 2. and {25} /. 25 -> 2.. The need to rebuild the list in the second case is enough to trigger the "optimization". Sep 10, 2015 at 23:31 • @WReach You need to double quote your code. Start and end with two backticks, then you can use one backtick in the middle and it is displayed correctly. Sep 10, 2015 at 23:32 • @halirutan I got the same. Two bugs for the price of one? Sep 10, 2015 at 23:35 • @AlexeyPopkov I found a similar bug myself some time ago. When I copy and paste this 25.6*^1.5 into a notebook, I end up with this which translates to Times[5,Repeated] and is complete non-sense. You need to know that it should be parsed as 25.6*^1 * 0.5 because only integers are allowed as exponent with *^. It is done correctly when you type it in. I could not convince the support@WRI that this is a bug and eventually, I gave up. Sep 11, 2015 at 0:51 • @halirutan I just checked both cases in Mathematica 5.2 and both are pasted correctly! Moreover, the evaluation behavior is different, see screenshot. So I was wrong: these bugs were not present in version 5 and are not related to the well known whitespace bug I described above. Sep 11, 2015 at 1:01 Update Jan 22nd: WRI Tech Support indicates that the fixes for all the test cases below, including the ones that don't depend on SameQ, may land in the next point release. The fixes could miss the point release if they cause other problems with higher severity. It appears that there may be some indirect dependence on RuleCondition as well as other structures. I found this out while trying to explain the problem to WRI technical support. In all cases, these answers should be a number (1. or 2.) followed by answers with that same number in a list. The spots where the number has extra zeroes indicate a rule that went unused when it should have been. Note the difference between the second to last cases for 1. vs. 2., which appear to depend on the use of RuleCondition and the size of the number (which affects the SameQ code). In:=$Version
Out= "10.0 for Microsoft Windows (64-bit) (June 29, 2014)"

In:= 15 /. {15 :> 1.}
Out= 1.

In:= {15} /. {15 :> 1.}
Out= {1.0000}

In:= {15} /. {15 :> 1. + 0}
Out= {1.}

In:= {15} /. {15 :> 1. + $MachineEpsilon} Out= {1.} In:= Block[{Internal$SameQTolerance = -Infinity}, {15} /. {15 :>1. + $MachineEpsilon}] Out= {1.} In:= Block[{Internal$SameQTolerance = -Infinity}, {1.5} /. x_Real :> RuleCondition[N[x] + $MachineEpsilon, True]] Out= {1.} In:= Block[{Internal$SameQTolerance = -Infinity}, {1.5} /. x_Real :> N[x] + $MachineEpsilon] Out= {1.} In:= 25 /. {25 :> 2.} Out= 2. In:= {25} /. {25 :> 2.} Out= {2.0000} In:= {25} /. {25 :> 2. + 0} Out= {2.} In:= {25} /. {25 :> 2. +$MachineEpsilon}
Out= {2.}

In:= Block[{Internal$SameQTolerance = -Infinity}, {25} /. {25 :>2. +$MachineEpsilon}]
Out= {2.}

In:= Block[{Internal$SameQTolerance = -Infinity}, {2.5} /. x_Real :> RuleCondition[N[x] +$MachineEpsilon, True]]
Out= {2.0000}

In:= Block[{Internal$SameQTolerance = -Infinity}, {2.5} /. x_Real :> N[x] +$MachineEpsilon]
Out= {2.}

• BTW, the complete, and completely-ridiculous-it's-required, workaround is, as Oleksandr hinted, related to the size of an Ulp. Block[{Internal$SameQTolerance = -Infinity}, Hold@7.26776695296636881100211090526212259821208984422118509147084967 2488415598077633798562984417909551965918767307788640371281156045069813 4215158051518709271734133.50224952160673 /. x_Real :> RuleCondition[N@x + Ulp@x, True]] actually fires and rounds correctly. Sep 11, 2015 at 16:58 • Yes, 2. +$MachineEpsilon is still 2., but 1. + $MachineEpsilon is slightly bigger than 1. I added $MachineEpsilon in my answer because the value was 1, but in general one should of course multiply by (1. + $MachineEpsilon) to get a result that is one ulp bigger. Sep 11, 2015 at 19:00 • Log[10^Internal$SameQTolerance]/Log == 1., i.e. SameQ applies by default a 1-bit tolerance (requires a 2-ulp difference for comparands to differ). I always thought this tolerance should be zero for SameQ, which of course is possible only with Internal\$SameQTolerance = -Infinity. Sep 11, 2015 at 19:06
• @OleksandrR. did you see the last two examples for 2. (Out@14 and Out@15)? They show a difference in the presence and absence of RuleCondition. Also, Out@11 vs. Out@10 shows other types of structural differences that cause the rule to trigger. There seem to be times when SameQ by itself isn't the deciding factor for numeric replacements. Sep 11, 2015 at 19:37
• Yes, and I can't explain why that is. Perhaps RuleCondition uses some numerical tests additional to SameQ. I think the only people who can answer this properly are at WRI, so it's good that you have raised this with them. Please post an answer with their comments/response when you get it. Sep 11, 2015 at 19:46