1 /* vim: set ft=maxima softtabstop=4 shiftwidth=4 expandtab: */
4 Most of the code in this Maxima package is a rather direct port of Sympy's
6 http://docs.sympy.org/1.0/_modules/sympy/simplify/sqrtdenest.html
7 http://docs.sympy.org/1.0/_modules/sympy/simplify/radsimp.html
8 The code is licensed under the GPL-compatible "3-clause BSD license".
11 /**************************************************************************
12 Copyright (c) 2006-2017 SymPy Development Team (original code)
13 Copyright (c) 2017 Gilles Schintgen (Maxima port and extensions)
17 Redistribution and use in source and binary forms, with or without
18 modification, are permitted provided that the following conditions are met:
20 a. Redistributions of source code must retain the above copyright notice,
21 this list of conditions and the following disclaimer.
22 b. Redistributions in binary form must reproduce the above copyright
23 notice, this list of conditions and the following disclaimer in the
24 documentation and/or other materials provided with the distribution.
25 c. Neither the name of SymPy nor the names of its contributors
26 may be used to endorse or promote products derived from this software
27 without specific prior written permission.
30 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
31 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
34 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
36 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
37 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
41 **************************************************************************/
46 This package denests different classes of expressions with nested
47 roots. Most of the algorithms are specific to square roots, but some
50 The implemented algorithms are documented in the following articles:
52 [1] Allan Borodin, Ronald Fagin, John E. Hopcroft, and Martin Tompa:
53 "Decreasing the Nesting Depth of Expressions Involving Square Roots"
54 J. Symbolic Computation (1985) 1, 169-188
55 http://researcher.watson.ibm.com/researcher/files/us-fagin/symb85.pdf
57 [2] David J. Jeffrey and Albert D. Rich:
58 "Symplifying Square Roots of Square Roots by Denesting"
59 in "Computer Algebra Systems: A Practical Guide",
60 M.J. Wester, Ed., Wiley 1999
61 http://www.cybertester.com/data/denest.pdf
64 "Cardan Polynomials and the Reduction of Radicals"
65 Mathematics Magazine 74(1), Feb. 2001
66 http://www.rowan.edu/open/depts/math/osler/mathmag026-032.pdf
69 "Radical Extensions and Galois Groups", Chapter 3
71 http://www.math.kun.nl/~bosma/students/honsbeek/M_Honsbeek_thesis.pdf
73 As such, the raddenest function should be able to denest some or all
74 of the denestable expressions of the following types:
76 * square roots of sums of (multiple) unnested square roots
79 * expressions of the form sqrt(a + b*sqrt(r)) that denest using square
80 roots can be denested numerically or symbolically
81 (_sqrt_symbolic_denest)
83 * expressions of the form sqrt(a + b*sqrt(r)) where a, b, and r are
84 linear combinations of square roots of positive rationals
85 (_sqrt_biquadratic_denest)
87 * expressions of the form sqrt(a + b*sqrt(r)) that can be denested
90 * n-th roots of a+b*sqrt(r)
93 * square roots of a sum of two cube roots
94 (_rad_denest_ramanujan)
97 INTERPRETATION OF RADICAL EXPRESSIONS
99 In general a^(1/n) has n different values.
101 However Maxima always simplifies such numeric expressions for positive
102 real 'a' and for negative real 'a' in case of a square root:
103 sqrt(-4)=2*%i, 8^(1/3)=2
104 This is independent of the global 'domain' variable.
106 With domain=complex Maxima no longer simplifies a^(1/n) for negative
107 real 'a'. It will only factor out (-1)^(1/n) which is then treated
108 according to the global variable m1pbranch. It also no longer simplifies
111 Raddenest should give results that are consistent with the above.
114 (2-sqrt(5))^(1/3) = 1/2-sqrt(5)/2
115 This denesting is only performed when domain=real and the cube root
116 is interpreted as a real-valued function over the reals.
121 Functions whose names begin with an underscore are internal helper
122 functions. As such the only user-level function is the main command
125 raddenest and _raddenest0 are relatively simple wrapper functions that
126 apply the various algorithm functions to the given expression and its
129 POSSIBLE IMPROVEMENTS AND FURTHER READING
132 "Simplification of Expressions Involving Radicals"
133 J. Symbolic Computation (1985) 1, 189-210
134 http://www.sciencedirect.com/science/article/pii/S0747717185800146
137 "Simplification of Nested Radicals"
139 https://www.researchgate.net/publication/2629046_Simplification_of_Nested_Radicals
141 [7] Johannes Blömer:
142 "Simplifying Expressions Involving Radicals"
144 http://www.cs.nyu.edu/exact/pap/rootBounds/sumOfSqrts/bloemerThesis.pdf
152 /* Returns true iff expr is a literal square root,
156 not atom(expr) and op(expr)="^" and args(expr)[2]=1/2
158 _sqrtpowerp(expr):=block(
159 /* Returns true iff expr can be interpreted as a square root.
160 Maxima automatically simplifies sqrt(125) to 5^(3/2).
161 Negative exponents are rejected.
164 not atom(expr) and op(expr)="^" and denom(args(expr)[2])=2
165 and num(args(expr)[2])>0
168 _algebraicp(p):=block(
169 /* Returns true if p is comprised only of rationals or
170 square(!) roots of rationals and algebraic operations. */
172 if ratnump(p) then return(true)
173 elseif atom(p) then return(false)
174 elseif op(p)="^" then
175 ((args(p)[2]=-1 or denom(args(p)[2])=2)
176 and _algebraicp(args(p)[1]))
178 (operatorp(p,["+","*"])
179 and apply("and",map('_algebraicp,args(p))))
182 _sqrt_depth(p):=block(
183 /* Returns the maximum nesting depth of any square root argument of p,
184 where p is an algebraic expression as defined by _algebraicp.
186 Neither of these square roots contains any other square roots
188 (%i1) _sqrt_depth(1 + sqrt(2)*(1 + sqrt(3)));
190 The sqrt(3) is contained within a square root so the depth is 2:
191 (%i2) _sqrt_depth(1 + sqrt(2)*sqrt(1 + sqrt(3)));
195 if atom(p) or ratnump(p) then return(0)
196 elseif (op(p)="+" or op(p)="*")
197 then apply('max,maplist('_sqrt_depth,p))
198 elseif _sqrtpowerp(p)
199 then _sqrt_depth(args(p)[1])+1
203 _complexity(p):=block(
204 /* Returns a complexity measure of a given expression p.
205 It's similar to _sqrt_depth but increases with any nesting
206 of radicals (not only square roots) and penalize sums
207 of radicals by adding up individual complexities.
208 See [2] for more details.
209 It is used as a secondary recursion termination criterion
210 (after _sqrt_depth) in some algorithms.
213 if atom(p) or ratnump(p) then return(0)
215 then map('_complexity,p)
217 then apply('max,maplist('_complexity,p))
219 and ratnump(e:args(p)[2])
221 then _complexity(args(p)[1])+1
225 _sqrtcontract0(prod):= block(
226 /* Contracts _all_ square roots in a given term/quotient.
228 Maxima's built-in commands sometimes have difficulties
229 handling quotients with square roots in the denominator.
230 Forcing them to contract allows for easier simplification.
232 (%i1) sqrt(2)/(7*sqrt(27));
233 (%o1) sqrt(2)/(7*3^(3/2))
234 (%i2) _sqrtcontract(%);
237 [inflag:true,rootsconmode:false,r,e,rad:1],
238 if atom(prod) or op(prod)#"*" then return(prod),
239 for f in args(prod) do (
240 if not atom(f) and op(f)="^" then (
242 if integerp(r) and ratnump(e) and e<0 and denom(e)=2
246 rootscontract(num(prod)*sqrt(rad))/rootscontract(denom(prod)*sqrt(rad))
248 _sqrtcontract(expr):= scanmap('_sqrtcontract0,expr)$
252 Returns all possible subsets of the set (0, 1, ..., n-1) except the
253 empty set, listed in reversed lexicographical order according to binary
254 representation, so that the case of the fourth root is treated last.
257 (%o2) [[1,0,0],[0,1,0],[1,1,0],[0,0,1],[1,0,1],[0,1,1],[1,1,1]]
259 _ss(n):= if n=1 then [[0],[1]] else
261 apply('append, map(lambda([z], [cons(0,z),cons(1,z)]),r)));
262 _subsets(n):=rest(_ss(n));
265 _splitcoef(p):= block(
266 /* Splits a given term p in two factors:
267 a rational coefficient and the remaining factors.
268 The return value is a list.
269 Note: 7^(3/2) is handled as 7*sqrt(7),
270 contrary to maxima's default.
271 Also: 15/sqrt(2) -> 15/2*sqrt(2)
273 [inflag:true,c,base,expt,r,spl],
274 /* single rational number */
275 if ratnump(p) then return([p,1]),
277 /* single power that can be read as a sqrt
278 e.g. 5^(13/2) -> [5^13, sqrt(5)]
279 2^(-3/2) -> [1/4, sqrt(2)] */
280 if not atom(p) and op(p)="^" and ratnump(base:args(p)[1])
281 and ratnump(expt:args(p)[2]) and denom(expt)=2
284 return([base^quotient(num(expt),2), sqrt(base)])
286 return([base^quotient(num(expt)-2,2), sqrt(base)])
288 /* product with ratnum as first factor.
289 check if second factor is a power -> recurse.
290 this handles e.g. 3*5^(3/2) */
291 elseif not atom(p) and op(p)="*" and ratnump(c:first(args(p)))
294 if not atom(r) and op(r)="^" then (
296 return([c*spl[1], spl[2]])
303 _sqrt_match(p):=block(
304 /* Returns [a, b, r] for _sqrt_match(a + b*sqrt(r)) where, in addition to
305 matching, sqrt(r) also has then maximal _sqrt_depth among addends of p.
306 If p can't be matched, the return value is false.
309 (%o1) _sqrt_match(2*sqrt(sqrt(5)+1)+sqrt(2)*sqrt(3)+sqrt(2)+1);
310 (%o2) [sqrt(2)*sqrt(3)+sqrt(2)+1,2,sqrt(5)+1]
312 [inflag: true, p:expand(p), res,pargs,v,nmax,depth,
313 ar,i,r,b,bv,rv,a1,b1,x2,x2args,a],
314 if numberp(p) then res:[p,0,0]
315 elseif not atom(p) and op(p)="+" then (
317 /* handle "trivial" case without nested radicals: */
318 if apply("and",maplist(lambda([x],ratnump(x)and x>0),pargs^2))
319 then return(reverse(_split_surds(p))),
320 /* to make the process canonical, the argument is included in the tuple
321 so when the max is selected, it will be the largest arg having a
323 v: makelist([_sqrt_depth(pargs[i]),pargs[i],i], i, 1, length(pargs)),
327 or (da[1]=nmax[1] and ordergreatp(da[2],nmax[2]))
330 if nmax[1]=0 then res:false
332 /* select r (term with max. depth)*/
333 [depth, ar, i]: nmax,
335 pargs: delete(r,pargs),
338 /* if product, keep only factor with max. depth for r,
339 other factors will be part of coefficient b */
340 if not atom(r) and op(r)="*" then (
343 for x in args(r) do (
344 if _sqrt_depth(x)<depth then bv:endcons(x,bv)
345 else rv:endcons(x,rv)
350 /* collect terms containing r */
354 if x[1]<depth then a1:endcons(x[2],a1)
357 if x2=r then b1:endcons(1,b1)
359 if not atom(x2) and op(x2)="*" then (
361 if member(r,x2args) then (
362 x2args: delete(r,x2args,1),
363 x2args: apply("*",x2args),
366 else a1:endcons(x[2],a1)
368 else a1:endcons(x[2],a1)
378 [b, r]: _split_coef(p),
379 if _sqrtp(r) then res:[0,b,r^2]
385 _split_gcd(a):= block(
386 /* Splits the list of integers a into two lists of integers, a1 and a2,
387 such that a1 have some common divisor and the integers in a2
388 are not divisible by g=gcd(a1).
389 The result is returned as [g, a1, a2].
393 (%i1) _split_gcd(55, 35, 22, 14, 77, 10);
394 (%o2) [5, [55, 35, 10], [22, 14, 77]]
396 [g:first(a), g1, b1:[], b2:[]],
398 for x in rest(a) do (
400 if g1=1 then push(x,b2)
401 else (g:g1, push(x,b1))
403 [g,reverse(b1),reverse(b2)]
406 _split_surds(expr):= block(
407 /* Splits an expression with terms whose squares are rationals
408 into a sum of terms whose surds squared have gcd equal to g
409 and a sum of terms with surds squared prime with g.
413 (%i1) _split_surds(3*sqrt(3)+sqrt(5)/7+sqrt(6)+sqrt(10)+sqrt(15))
414 (%o1) [3, sqrt(2) + sqrt(5) + 3, sqrt(5)/7 + sqrt(10)]
416 [inflag:false,ar,coeff_muls,surds:[],g,b1,b2,g2,g1,b1n:[],c,s,s1,a1v:[],a2v:[],a,b],
417 ar: args(rootscontract(expr)),
418 coeff_muls: maplist('_splitcoef,ar),
419 for cs in coeff_muls do
420 if _sqrtp(cs[2]) then push(cs[2]^2,surds),
421 [g, b1, b2] : _split_gcd(sort(surds)),
423 if b2=[] and length(b1)>=2 then (
424 for x in b1 do if x#g then b1n:endcons(x/g, b1n),
425 /* only a common factor has been factored; split again */
426 [g1, b1n, b2] : _split_gcd(b1n),
429 for cs in coeff_muls do (
434 then a1v:endcons(c*sqrt(s1/g2),a1v)
435 else a2v:endcons(c*s,a2v)
437 else a2v:endcons(c*s,a2v)
448 raddenest(expr, [max_iter]):= block(
449 /* Denests sqrts in an expression that contain other square roots
450 if possible, otherwise returns the expr unchanged.
452 [algebraic:true, rootsconmode:false, z,res],
453 if max_iter=[] then max_iter: 3
454 else max_iter: max_iter[1],
455 res: for i:1 thru max_iter do (
456 z: _sqrtcontract(_raddenest0(expr)),
461 if res#done then return(res)
465 _raddenest0(expr):= block(
466 /* Returns expr after (recursively) denesting its arguments. */
467 [inflag:true,algebraic:true,ar,ret,radicand,ex],
468 if _sqrtpowerp(expr) then (
469 /* expr could be of the form ( )^(n/2) */
470 radicand: expand(ratsimp(args(expr)[1])),
472 if not atom(radicand) and op(radicand)="+" then (
474 if length(ar)>2 and apply("and",maplist('integerp,ar^2)) then (
475 ret: catch(_sqrtdenest_rec(sqrt(radicand))),
476 if ret#"raddenestStopIteration" then
479 if length(ar)=2 and ratnump(ar[1]^3) and ratnump(ar[2]^3) then (
480 ret: _rad_denest_ramanujan(sqrt(radicand)),
484 radicand: maplist('_raddenest0,ar),
485 radicand: expand(apply("+",radicand))
487 return(_sqrtdenest1(sqrt(radicand),true)^ex)
489 elseif not atom(expr) and op(expr)="^"
490 /* try Cardano polynomials for (a+b*sqrt(r))^(m/n) */
491 and ratnump(ex:args(expr)[2])
492 and not atom(radicand:args(expr)[1])
494 and length(ar:args(radicand))=2
495 and apply("and",maplist(lambda([x],ratnump(x)and x>0),ar^2))
496 then return(_rad_denest_cardano(expr))
497 elseif not atom(expr) and op(expr)="^" and evenp(denom(ex:args(expr)[2]))
498 /* Some fourth roots denest in two steps
499 e.g. (19601-3465*2^(5/2))^(7/4)
500 -> (99-35*2^(3/2))^(7/2)
502 This is only useful if the global nesting depth
503 indeed decreases, but this is not checked by the
505 (Same behaviour as sqdnst.mac) */
507 radicand: expand(ratsimp(args(expr)[1])),
509 return(_raddenest0(sqrt(radicand))^ex)
511 elseif not atom(expr) then (
514 then return(_raddenest0(args(expr)[1])/_raddenest0(args(expr)[2]))
515 else return(map('_raddenest0,expr))
520 _sqrtdenest_rec(expr):= block(
521 /* Helper that denests the square root of three or more surds.
523 It returns the denested expression; if it cannot be denested it
524 throws raddenestStopIteration
526 Algorithm: expr.base is in the extension Q_m = Q(sqrt(r_1),..,sqrt(r_k));
527 split expr.base = a + b*sqrt(r_k), where `a` and `b` are on
528 Q_(m-1) = Q(sqrt(r_1),..,sqrt(r_(k-1))); then a^2 - b^2*r_k is
529 on Q_(m-1); denest sqrt(a^2 - b^2*r_k) and so on.
536 (%i1) _sqrtdenest_rec(sqrt(-72*sqrt(2) + 158*sqrt(5) + 498));
537 (%o1) (-sqrt(10))+9*sqrt(5)+sqrt(2)+9
538 (%i2) w:-6*sqrt(55)-6*sqrt(35)-2*sqrt(22)-2*sqrt(14)
539 +2*sqrt(77)+6*sqrt(10)+65$
540 (%i3) _sqrtdenest_rec(sqrt(w));
541 (%o3) (-sqrt(11))-sqrt(7)+3*sqrt(5)+sqrt(2)
543 [algebraic:true,inflag:true, g,a,b,c2,a1,b1,c2_1,c_1,d_1,c,ac,d,r,f],
544 if atom(expr) or op(expr)#"^" then
545 return(raddenest(expr)),
546 if (r:args(expr)[1]) < 0 then
547 return(%i*_sqrtdenest_rec(sqrt(-r))),
548 [g,a,b]: _split_surds(r),
550 if a<b then [a,b]:[b,a],
551 c2: rootscontract(expand(a^2-b^2)),
552 if not atom(c2) and length(args(c2)) > 2 then (
553 [g,a1,b1]: _split_surds(c2),
555 if a1<b1 then [a1,b1]:[b1,a1],
556 c2_1: rootscontract(expand(a1^2-b1^2)),
557 c_1: _sqrtdenest_rec(sqrt(c2_1)),
558 d_1: _sqrtdenest_rec(sqrt(a1+c_1)),
559 f: _sqrtcontract(expand(ratsimp(b1/d_1))),
560 c: expand(d_1*sqrt(2)/2+f*sqrt(2)/2)
562 else c: _sqrtdenest1(sqrt(c2),true),
563 if _sqrt_depth(c)>1 then
564 throw("raddenestStopIteration"),
565 ac: rootscontract(a+c),
566 /* check for end of recursion */
567 if not atom(ac) and length(args(ac)) >= length(args(expr))
568 and _complexity(ac)>=_complexity(args(expr)[1])
569 then throw("raddenestStopIteration"),
570 d: raddenest(sqrt(ac)),
571 if _sqrt_depth(d) > 1
572 then throw("raddenestStopIteration"),
573 r: rootscontract(expand(ratsimp(b/d))),
574 r: rootscontract(ratsimp(expand(d*sqrt(2)+r*sqrt(2))/2)),
578 _sqrtdenest1(expr, denester):= block(
579 /* Return denested expr after denesting with simpler
580 methods or, that failing, using the denester.
581 'denester' is a boolean indicating if _denester
584 [inflag:true, algebraic: true, a,val,b,r,d2,z,dr2,dr,res,av0],
585 if not _sqrtp(expr) then return(expr),
586 a: args(expr)[1], /*radicand*/
587 if atom(a) then return(expr),
589 if val=false then return(expr),
591 /* try a quick numeric denesting */
592 d2: rootscontract(expand(a^2-b^2*r)),
595 z: _sqrt_numeric_denest(a,b,r,d2),
596 if z#false then return(z)
599 /* fourth root case, e.g.
600 sqrtdenest(sqrt(3+2*sqrt(3)))
601 -> sqrt(2)*3^(1/4)/2+sqrt(2)*3^(3/4)/2 */
604 if ratnump(dr) then (
605 z: _sqrt_numeric_denest(expand(b*r),a,r,dr2),
606 if z#false then return(expand(ratsimp(z/r^(1/4))))
611 z: _sqrt_symbolic_denest(a,b,r),
612 if z#false then return(z)
614 if not denester or not _algebraicp(expr) then
616 res: _sqrt_biquadratic_denest(expr,a,b,r,d2),
617 if res#false then return(res),
618 /* now call the denester */
620 z: _denester([expr^2], av0, 0, _sqrt_depth(expr))[1],
621 /* denester has side-effect on av0! */
622 if av0[2]=false then return(expr),
624 if _sqrt_depth(z)=_sqrt_depth(expr)
625 and _complexity(z)>=_complexity(expr)
632 _sqrt_symbolic_denest(a,b,r):= block(
633 /* Given an expression, sqrt(a + b*sqrt(r)), return the denested
637 Check if the standard denesting formula with d2=a^2-b^2*r
638 can the applied, i.e. check if d2=a^2-b^2*r is a square.
639 For a+b*sqrt(r) = (c+d*sqrt(r))^2, a=c^2+b^2*r and
640 a^2-b^2*r = d^4*r^2-2*c*d^2*r+c^4, quadratic in r.
641 -> Compute the discriminant.
642 a and r must be positive; hence denesting depends on the
646 If r = ra + rb*sqrt(rr), try replacing sqrt(rr) in 'a' with
647 (y^2 - ra)/rb, and if the result is a quadratic, ca*y^2 + cb*y + cc, and
648 (cb + b)^2 - 4*ca*cc is 0, then sqrt(a + b*sqrt(r)) can be rewritten as
649 sqrt(ca*(sqrt(r) + (cb + b)/(2*ca))^2).
653 (%i2) raddenest(sqrt(9*y+6*x^2*sqrt(y)+x^4));
654 (%o2) sqrt(9*y + 6*x^2 sqrt(y) + x^4)
656 (%i4) raddenest(sqrt(9*y+6*x^2*sqrt(y)+x^4));
657 (%o4) 3* sqrt(y) + x^2
662 (%i1) [a,b,r]: [16-2*sqrt(29), 2, -10*sqrt(29)+55]$
663 (%i2) _sqrt_symbolic_denest(a, b, r);
664 (%o2) sqrt(-2*sqrt(29) + 11) + sqrt(5)
666 If the expression is numeric, it will be simplified:
668 (%i3) w: sqrt(sqrt(sqrt(3) + 1) + 1) + 1 + sqrt(2)$
669 (%i4) [a,b,r]: _sqrt_match(expand(w^2))$
670 (%i5) _sqrt_symbolic_denest(a,b,r);
671 (%o5) sqrt(sqrt(sqrt(3)+1)+1)+sqrt(2)+1
673 Otherwise, it will be simplified depending on the value of
674 the global "domain" variable:
676 (%i6) assume(x >= 0)$
677 (%i7) w: sqrt(expand((sqrt(1+sqrt(x))-1)^2));
678 (%o6) sqrt(sqrt(x)-2*sqrt(1+sqrt(x))+2)
679 (%i7) [a,b,r]: _sqrt_match(w^2)$
680 (%i8) _sqrt_symbolic_denest(a,b,r), domain:'real;
681 (%o8) abs(sqrt(1+sqrt(x))-1)
682 (%i9) _sqrt_symbolic_denest(a,b,r), domain:'complex;
683 (%o9) sqrt((sqrt(1+sqrt(x))-1)^2)
685 [algebraic:true, rval,ra,rb,rr,y,newd2,newa,ca,cb,cc,z,cont,d2,d,s],
689 /* make sure a and r are positive */
690 if not (is(r>=0)=true and is(ratsubst(y,r,a)>=0)=true)
692 d2: ratsubst(y,r,a^2-b^2*r),
693 if hipow(d2,y)=2 then (
694 [ca,cb,cc]: [ratcoef(d2,y,2),ratcoef(d2,y,1),ratcoef(d2,y,0)],
695 if is(equal(cb^2-4*ca*cc,0)) then (
696 /* Discriminant is 0, polynomial d2 can be factored
697 as a perfect square. Extract a sqrt. */
698 d: ratsimp(sqrt(ca)*(r+cb/(2*ca))),
699 /* If b is of constant sign (>=0 or <=0), a denesting
700 should not be rejected simply because b could be zero
701 for isolated values of the involved variables. */
702 assume(not equal(b,0)),
704 if not (integerp(s) and s#0 and ratnump(sqrt(ca)))
706 z: sqrt(a/2+d/2)+signum(b)*sqrt(a/2-d/2),
713 rval: _sqrt_match(r),
720 newa: subst((y^2-ra)/rb,sqrt(rr),a),
721 if hipow(newa,y)=2 then (
722 [ca,cb,cc]: [ratcoef(newa,y,2),ratcoef(newa,y,1),ratcoef(newa,y,0)],
724 if is(equal(cb^2-4*ca*cc,0))=true then (
725 z: sqrt(ca*(sqrt(r)+cb/(2*ca))^2),
726 if constantp(z) then z: rootscontract(expand(z)),
736 _sqrt_numeric_denest(a,b,r,d2):=block(
737 /* Helper that denest expr = a + b*sqrt(r),
738 with d2 = a^2 - b^2*r > 0
739 or returns false if not denested.
741 [algebraic:true, depthr,d,vad,vad1],
742 depthr: _sqrt_depth(r),
745 /* _sqrt_depth(res) <= _sqrt_depth(vad) + 1
746 _sqrt_depth(expr) = depthr + 2
747 There is denesting if _sqrt_depth(vad)+1 < depthr + 2;
748 If vad^2 is a rational there is a fourth root */
749 if _sqrt_depth(vad) < depthr + 1 or ratnump(vad^2) then (
750 vad1: ratsimp(1/vad),
751 return(expand(sqrt(vad/2)+signum(b)*sqrt(b^2*r*vad1/2)))
755 _sqrt_biquadratic_denest(expr,a,b,r,d2):= block(
756 /* denest expr = sqrt(a + b*sqrt(r))
757 where a, b, r are linear combinations of square roots of
758 positive rationals on the rationals (SQRR) and r > 0, b != 0,
761 If it cannot denest it returns false.
764 Search for a solution A of type SQRR of the biquadratic equation
765 4*A^4 - 4*a*A^2 + b^2*r = 0 (1)
766 sqd = sqrt(a^2 - b^2*r)
767 Choosing the sqrt to be positive, the possible solutions are
768 A = sqrt(a/2 +/- sqd/2)
769 Since a, b, r are SQRR, then a^2 - b^2*r is a SQRR,
770 so if sqd can be denested, it is done by
771 _sqrtdenest_rec, and the result is a SQRR.
774 Examples of solutions (in both cases a and sqd are positive):
776 Example of expr with solution sqrt(a/2 + sqd/2) but not
777 solution sqrt(a/2 - sqd/2):
778 expr: sqrt(-sqrt(15) - sqrt(2)*sqrt(-sqrt(5) + 5) - sqrt(3) + 8);
779 a: -sqrt(15) - sqrt(3) + 8;
780 sqd = -2*sqrt(5) - 2 + 4*sqrt(3)
782 Example of expr with solution sqrt(a/2 - sqd/2) but not
783 solution sqrt(a/2 + sqd/2):
784 w: 2 + sqrt(2) + sqrt(3) + (1 + sqrt(3))*sqrt(2 + sqrt(2) + 5*sqrt(3))
785 expr: sqrt(expand(w^2))
786 a: 4*sqrt(6) + 8*sqrt(2) + 47 + 28*sqrt(3)
789 Define B = b/(2*A); eq.(1) implies a = A^2 + B^2*r; then
790 expr^2 = a + b*sqrt(r) = (A + B*sqrt(r))^2
794 (%i1) z: sqrt((2*sqrt(2) + 4)*sqrt(2 + sqrt(2)) + 5*sqrt(2) + 8)$
795 [a,b,r] : _sqrt_match(z^2)$
797 _sqrt_biquadratic_denest(z, a, b, r, d2);
798 (%o1) sqrt(2) + sqrt(sqrt(2) + 2) + 2
800 [inflag:true, algebraic:true, res,y2,sqd,x1,x2,A,B,z],
801 if r<=0 or d2<0 or b=0 or _sqrt_depth(args(expr)[1])<2 then
803 /* check that all terms in the linear combinations a, b, r
804 have integer square */
805 res: for x in [a,b,r] do (
806 if atom(x) or op(x)#"+" then x: [x],
807 res: for y in args(x) do (
809 if not integerp(y2) or y2<=0 then
812 if res#done then return(false)
814 if res#done then return(false),
815 /*sqd: expand(raddenest(sqrt(ratsimp(d2)))), */
816 sqd: raddenest(sqrt(d2)),
817 if _sqrt_depth(sqd)>1 then
819 [x1,x2]: [a/2+sqd/2, a/2-sqd/2],
820 /* look for a solution A with depth 1 */
821 res: for x in [x1,x2] do (
822 A: raddenest(sqrt(x)),
823 if not _sqrt_depth(A)>1 then (
825 B: ratsimp(rootscontract(expand(ratsimp(B)))),
831 if res#done then return(res)
835 _denester(nested,av0,h,max_depth_level):= block(
836 /* Denests a list of expressions that contain nested square roots.
838 nested: list of radicands (no top level sqrt!)
839 av0: [a,b,r,d2] (a+b*sqrt(r) and d2=a^2-b^2*r)
840 h: recursion counter, starts at 0
841 max_depth_level: nesting depth
843 Algorithm based on [1].
845 It is assumed that all of the elements of 'nested' share the same
846 bottom-level radicand. (This is stated in the paper, on page 177, in
847 the paragraph immediately preceding the algorithm.)
849 When evaluating all of the arguments in parallel, the bottom-level
850 radicand only needs to be denested once. This means that calling
851 _denester with x arguments results in a recursive invocation with x+1
852 arguments; hence _denester has polynomial complexity.
854 However, if the arguments were evaluated separately, each call would
855 result in two recursive invocations, and the algorithm would have
856 exponential complexity.
858 This is discussed in the paper in the middle paragraph of page 179.
860 The return value is [denested, subset] where subset corresponds
861 to the subset of terms that led to the denesting.
862 Otherwise [false,false] is returned.
864 [algebraic:true,p,sqp,R,vals,nested2,d,f,df,v,vad,sqvad,sqvad1,s2,FR,s,res],
866 then return([false, false]),
868 then return([false, false]),
869 if (av0[1]=false and apply("and", maplist('numberp,nested))) then (
870 /* no arguments are nested */
871 res: for f in _subsets(length(nested)) do (
872 /* test subset 'f' of nested */
874 for i:1 thru length(nested) do (
875 if f[i]=1 then push(nested[i],p)
877 p: expand(apply("*",p)),
878 if apply("+",f)>1 and last(f)=1 then
881 if ratnump(sqp) then (
882 /* Got a perfect square so return its sqrt */
886 if res#done then return(res)
887 else /* ... otherwise, return the radicand
888 from the previous invocation. */
889 return([sqrt(last(nested)), makelist(0,length(nested))])
893 if av0[1]#false then (
894 vals: [[av0[1],av0[2]]],
900 vals: maplist('_sqrt_match,nested),
901 vals: sublist(vals,lambda([x],x#false)),
902 res: for v in vals do (
903 /* if b=0, r is not defined */
908 return([false,false])
914 if res#done then return(res),
916 /* return the radicand of the previous invocation */
917 return([sqrt(last(nested)), makelist(0,length(nested))]),
918 nested2: makelist(expand(v[1]^2)-expand(R*v[2]^2),v,vals),
919 nested2: endcons(R,nested2)
921 [d,f]: _denester(nested2,av0,h+1,max_depth_level),
922 if f=false then return([false,false]),
923 if not member(1,makelist(f[i],i,1,length(nested))) then (
925 return([sqrt(v[1]+expand(v[2]*d)), f])
929 for i:1 thru length(nested) do (
930 if f[i]=1 then push(nested[i],p)
935 and sublist_indices(f,lambda([x],x=1))[1] < length(nested)
936 and f[length(nested)]=1
941 if f[length(nested)+1]=0 then (
942 /* solution denests with square roots */
945 /* return the radicand from the previous invocation */
946 return([sqrt(last(nested)), makelist(0,length(nested))]),
947 if not (_sqrt_depth(vad) <= _sqrt_depth(R)+1
948 or nump((vad)^2)) then (
950 return([false,false])
952 sqvad: _sqrtdenest1(sqrt(vad), false),
953 if not (_sqrt_depth(sqvad) <= _sqrt_depth(R)+1) then (
955 return([false,false])
957 sqvad1: ratsimp(1/sqvad),
958 res: _sqrtcontract(expand(sqvad*sqrt(2)/2 + v[2]*sqrt(R)*sqvad1*sqrt(2)/2)),
962 /* Solution requires a fourth root */
963 s2: expand(v[2]*R) + d,
965 return([sqrt(last(nested)), makelist(0,length(nested))]),
968 return([expand(s/(sqrt(2)*FR)+v[1]*FR/(sqrt(2)*s)), f])
974 _cardano_poly(n,c,x):= block(
975 /* "Cardano" polynomials as defined in [3] */
977 poly2: rat('x), /* degree n-2 */
978 poly1: rat('x^2-2*c), /* degree n-1 */
979 if n=1 then return(poly2)
980 elseif n=2 then return(poly1),
982 poly: 'x*poly1-c*poly2,
989 _rad_denest_cardano(expr):= block(
990 /* Denests expr=(a+b*sqrt(r))^(m/n) using
991 Cardano polynomials. See [3] for details. */
992 [a,b,r,m,n,divs,d,c,p,s,em,res,sig,x,
993 ratprint:false,bftorat:false,fpprec:50,ratepsilon:1e-40],
994 [a,b,r]: _sqrt_match(args(expr)[1]),
995 m: num(args(expr)[2]),
996 n: denom(args(expr)[2]),
997 /* keep sign; reinterpret as a+sqrt(b) as in ref. article */
1000 divs: reverse(rest(listify(divisors(n)))),
1001 /* check each divisor of the radical's index */
1002 res:while divs#[] do (
1005 if ratnump(c) then (
1006 /* expr can be denested if p has a rational root
1007 equal to s. In order to avoid excessive numeric
1008 evaluations of the polynomial a single rational
1009 candidate is checked. This candidate is a rational
1010 approximation of s. The given values for fpprec
1011 and ratepsilon are heuristic in nature. */
1012 p: _cardano_poly(d,c,x)-2*a,
1013 p: horner(p*denom(p)),
1014 s: rat(bfloat((a+sqrt(b))^(1/d)+(a-sqrt(b))^(1/d))),
1015 if subst(s,x,p)=0 then
1016 return(ratsimp((s+sig*sqrt(s^2-4*c))/2)^(d/n))
1019 if res#done then return(expand(res^m))
1023 _rad_denest_ramanujan(expr):= block(
1024 /* Denest expr=sqrt(alpha^(1/3)+beta^(1/3)) using the results
1025 of [4], Chapter 3. If expr can't be denested, return false.
1026 alpha and beta must be rationals; parameter checking must
1027 be done by the calling function. */
1028 [inflag:true,alpha,beta,c,Fba,t,l:[],s,tt,res],
1029 [alpha,beta]: (args(args(expr)[1]))^3,
1030 /* If domain=complex, Maxima interprets a^(1/3) with a>0
1031 as the real branch of the cube root, but leaves the
1032 expression untouched if a<0. */
1033 if domain='complex and (alpha<0 or beta<0) then return(false),
1034 /* The perfect cube case can be trivially denested
1035 but this code segment should, in fact, not be reached
1036 since the simplifier already handles this case. */
1037 if ratnump(c:(beta/alpha)^(1/3)) then
1038 return(sqrt(alpha^(1/3)*sqrt(1+c))),
1039 Fba: t^4+4*t^3+8*beta/alpha*t-4*beta/alpha,
1040 Fba: multthru(denom(4*beta/alpha),Fba),
1041 /* apply the rational root theorem to the polynomial Fba */
1042 for n in divisors(coeff(Fba,t,0)) do
1043 for m in divisors(coeff(Fba,t,4)) do (
1049 if subst(i,t,Fba)=0 then return(i)
1051 if s=done then return(false),
1053 /* Sign: either alpha^(1/3)+beta^(1/3) is positive, then
1054 so is its sqrt, or alpha^(1/3)+beta^(1/3) is negative,
1055 then its sqrt is %i times a positive real.
1056 Both cases are treated correctly by the formula below. */
1057 res: sqrt(1/tt)*abs(-1/2*s^2*(alpha^2)^(1/3)
1058 +s*(alpha*beta)^(1/3)+(beta^2)^(1/3)),
1059 return(ratsimp(res))