Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

(I suspect this question is a duplicate, but I didn't find a sufficiently similar question with an answer to it.)

I'm having trouble with comparisons of symbolic Reals that are equal, but which Mathematica has trouble recognising them as equal, apparently because it uses N to compare these (apparently after some simple symbolic manipulation). Typically these issues creep up in conditions like one (greatly simplified) below:

x > y /. {x -> Sqrt[(2 - Sqrt[3])^2 + (-3 + 2*Sqrt[3])^2], y -> 4 - 2*Sqrt[3]}

N::meprec: "Internal precision limit $MaxExtraPrecision = 50.` reached while evaluating -4+2\ Sqrt[3]+Sqrt[(2-Sqrt[3])^2+(-3+2 Sqrt[3])^2]."

Sqrt[(2 - Sqrt[3])^2 + (-3 + 2*Sqrt[3])^2] > 4 - 2*Sqrt[3]

This is in no way undocumented feature; it is discussed under Possible Issues section of $MaxExtraPrecision.

What I really want is Mathematica to try a bit harder on solving these (in)equalities numerically in a block of code. How do I accomplish this? As a workaround for specific problem above, this does work (while Simplify on inequality part doesn't):

x > y /. Simplify @ {x -> Sqrt[(2 - Sqrt[3])^2 + (-3 + 2*Sqrt[3])^2], y -> 4 - 2*Sqrt[3]}

False

I would be happy to see a solution that could wrap up around a block of code, and which could possibly work also on non-algebraics that FullSimplify can handle.

EDIT:

To clarify my question: I want first example to evaluate like the expression below, and in general Greater to evaluate for NumericQ argument list similarly inside a code block where I want this feature to be used:

  Simplify[Sqrt[(2 - Sqrt[3])^2 + (-3 + 2*Sqrt[3])^2]] > Simplify[4 - 2*Sqrt[3]]

False

share|improve this question
    
@Artes My specific question here is how to make comparisons work this way; typically this stuff creeps up in my case in complicated equation systems Mathematica has generated itself. –  kirma Sep 7 '13 at 9:26
    
@Artes N appears only in the error message, not in my code. This is exactly the inconvenience I'm trying to get rid of. –  kirma Sep 7 '13 at 9:31
2  
I do not know if following will work for you or not, but myself, I like to keep everything in MachinePrecision only to be able to compare things with Matlab and Fortran when I want to. You can force all computation to be in MachinePrecision by putting this at the top of the notebook or in your init.m $MinPrecision = $MachinePrecision; $MaxPrecision = $MachinePrecision; Now your example runs with no warnings: !Mathematica graphics again, do not know if this is what you want, or this will work for what you are doing. –  Nasser Sep 7 '13 at 9:31
2  
@kirma You should use PossibleZeroQ, with Method -> "ExactAlgebraics". This post Most efficient way to determine conclusively whether an algebraic number is zero discusses the issue. –  Artes Sep 7 '13 at 9:38
1  
@Nasser regardless of its applicability to this question, that sort of comparison may be inherently unreliable. MATLAB and Fortran follow IEEE754, while Mathematica does not, so one cannot expect to obtain the same results from different systems. –  Oleksandr R. Sep 8 '13 at 14:50

1 Answer 1

up vote 3 down vote accepted

This solution uses trick to redefine internal functions presented in this earlier answer by Leonid Shifrin.

(* Code run as an argument of WithFullySimplifiedComparisons tries
   harder to symbolically resolve equality and inequality tests. *)

ClearAll[WithFullySimplifiedComparisons];
WithFullySimplifiedComparisons =
  Module[
   {withReplacedFunctions, fullSimplifiedTest, testMappings, 
    splitInequality, wrapper},

   (* Runs code with functions in { old -> new, ... } mappings list
      executing new function in place of old, but old definitions
      working inside new implementations. *)

   SetAttributes[withReplacedFunctions, HoldRest];
   withReplacedFunctions[mappings_List, code_] :=
    Module[{outer = True},
     Internal`InheritedBlock[Evaluate@mappings[[All, 1]],
      (Unprotect[#1];
         #1[args___] :=
          Block[{outer = False}, #2[args]] /; outer;
         Protect[#1];) & @@@ mappings;
      code]];

   (* Returns a version of comparison function fun that attempts to
      simplify numeric comparisons in domain dom with FullSimplify. *)

   fullySimplifiedTest[fun_, dom_] :=
    Module[{test},
     test[] := True;
     test[_] := True;
     test[a_, b_, r___] :=
      With[{bn = FullSimplify[b]},
        If[fun[0, FullSimplify[bn - a]],
          test[bn, r], False, test[a, bn] && test[bn, r]]] /; 
       NumericQ[a] && NumericQ[b] && (a | b) \[Element] dom;
     test[a_, b_, r___] := fun[a, b] && test[b, r];
     test];

   (* Mappings for normal comparison functions. *)

   testMappings = 
    #1 -> fullySimplifiedTest[##] & @@@ 
     Join[{#, Complexes} & /@ {Equal, Unequal},
       {#, Reals} & /@ {Greater, GreaterEqual, Less, LessEqual}];

   (* Conversion function from Inequality to chain of simple tests. *)

   splitInequality[_] := True;
   splitInequality[a_, test_, b_, r___] := test[a, b] && splitInequality[b, r];

   (* Actual wrapper to be used.
      splitInequality uses new comparison functions. *)

   SetAttributes[wrapper, HoldFirst];
   wrapper[code_] :=
     withReplacedFunctions[testMappings,
       withReplacedFunctions[{Inequality -> splitInequality},
         code]];

   wrapper];

Now earlier problematic tests can run purely symbolically:

WithFullySimplifiedComparisons[
  x > y /. {x -> Sqrt[(2 - Sqrt[3])^2 + (-3 + 2*Sqrt[3])^2], y -> 4 - 2*Sqrt[3]}]

False

share|improve this answer
    
Accepted as answer as it solves the example, and no other attempts appeared... I'm a bit suspicious of reliability of withReplacedFunctions, but it's an attempt better than nothing. –  kirma Sep 9 '13 at 9:21

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.