%mathpiper,def="RadSimp"

//Retract("RadSimp",*);

/* Simplification of nested radicals.
*/

10 # RadSimp(_n)_(Length(VarList(n))<1) <--
[
  Local(max, result);
  Bind(max, CeilN(N(Eval(n^2))));
  Bind(result,0);
  Bind(result,RadSimpTry(n,0,1,max));

//Echo("result is ",result);
  if (CheckRadicals(n,result))
    result
  else
    n;
];


20 # RadSimp(_n) <-- n;


/*Echo({"Try ",test}); */

CheckRadicals(_n,_test) <-- Abs(N(Eval(n-test),20)) < 0.000001;

10 # ClampRadicals(_r)_(N(Eval(Abs(r)), 20)<0.000001) <-- 0;
20 # ClampRadicals(_r) <-- r;



RadSimpTry(_n,_result,_current,_max)<--
[
//Echo(result," ",n," ",current);
  if (IsLessThan(N(Eval(result-n)), 0))
  [
    Local(i);

    // First, look for perfect match
    i:=BSearch(max,Hold({{try},ClampRadicals(N(Eval((result+Sqrt(try))-n),20))}));
    If(i>0,
    [
      Bind(result,result+Sqrt(i));
      Bind(i,AddN(max,1));
      Bind(current,AddN(max,1));
    ]);

    // Otherwise, search for another solution
    if (IsLessThan(N(Eval(result-n)), 0))
    [
      For (Bind(i,current),i<=max,Bind(i,AddN(i,1)))
      [
        Local(new, test);
        Bind(test,result+Sqrt(i));

/* Echo({"Full-try ",test}); */

        Bind(new,RadSimpTry(n,test,i,max));
	if (CheckRadicals(n,new))
        [
          Bind(result,new);
          Bind(i,AddN(max,1));
        ];
      ];
    ];
  ];
  result;
];


%/mathpiper

    %output,preserve="false"
      Result: True
.   %/output



%mathpiper_docs,name="RadSimp",categories="User Functions;Expression Simplification"
*CMD RadSimp --- simplify expression with nested radicals
*STD
*CALL
	RadSimp(expr)

*PARMS

{expr} -- an expression containing nested radicals

*DESC

This function tries to write the expression "expr" as a sum of roots
of integers: $Sqrt(e1) + Sqrt(e2) + ...$, where $e1$, $e2$ and
so on are natural numbers. The expression "expr" may not contain
free variables.

It does this by trying all possible combinations for $e1$, $e2$, ...
Every possibility is numerically evaluated using {N} and compared with the numerical evaluation of
"expr". If the approximations are equal (up to a certain margin),
this possibility is returned. Otherwise, the expression is returned
unevaluated.

Note that due to the use of numerical approximations, there is a small
chance that the expression returned by {RadSimp} is
close but not equal to {expr}. The last example underneath
illustrates this problem. Furthermore, if the numerical value of
{expr} is large, the number of possibilities becomes exorbitantly
big so the evaluation may take very long.

*E.G.

In> RadSimp(Sqrt(9+4*Sqrt(2)))
Result: Sqrt(8)+1;
In> RadSimp(Sqrt(5+2*Sqrt(6)) \
	  +Sqrt(5-2*Sqrt(6)))
Result: Sqrt(12);
In> RadSimp(Sqrt(14+3*Sqrt(3+2
	*Sqrt(5-12*Sqrt(3-2*Sqrt(2))))))
Result: Sqrt(2)+3;

But this command may yield incorrect results:

In> RadSimp(Sqrt(1+10^(-6)))
Result: 1;

*SEE Simplify, N
%/mathpiper_docs