1/* 2 Copyright 2008, 2009, 2010, 2011, 2012, 2014, 2015 by Barton Willis 3 Maxima code for integration of signum, abs, max, min, floor, ceiling, and unit_step. 4 5 This is free software; you can redistribute it and/or 6 modify it under the terms of the GNU General Public License, 7 http://www.gnu.org/copyleft/gpl.html. 8 9 This software has NO WARRANTY, not even the implied warranty of 10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 12I gratefully thank Robert Dodier and Richard Fateman for their suggestions, advice, assistance, and bug fixes. 13Also, Richard Hennessy identified several bugs in this code. */ 14 15qput(abs_integrate, 1, version); 16 17eval_when(translate, error("abs_integrate does not translate or compile correctly.")); 18 19load("opsubst"); 20load("unwind_protect"); 21load("to_poly_solve_extra"); 22load("partition"); 23load("lrats"); 24 25matchdeclare(x, symbolp, [q,%a,%b], lambda([s], true)); 26block([simp : false], tellsimpafter('integrate(q,x), extra_integrate(q,x)), 27 tellsimpafter('integrate(q,x,%a,%b), extra_definite_integrate(q,x,%a,%b))); 28 29extra_integration_methods : ['intfudu, 'intfugudu, 'signum_int, 'abs_integrate_use_if, 'floor_int, 'if_int]; 30 31sine_p(x) :=safe_op(x) = 'sin; 32cosine_p(x) := safe_op(x) = 'cos; 33tangent_p(x) := safe_op(x) = 'tan; 34 35/* additional intable values for intfudu */ 36(intable[abs_sin] : lambda([u], [2*floor(u/%pi)-cos(u)*cos(%pi*floor(u/%pi)), diff(u, %voi)]), 37intable[abs_cos] : lambda([u], [sin(u)*cos(%pi*floor(u/%pi+1/2))+2*floor(u/%pi+1/2),diff(u, %voi)]), 38intable[triangle_wave] : lambda([u], [block([u : mod(u,1)], -(4*u-1)*abs(4*u-1)/8+(4*u-3)*abs(4*u-3)/8+2*u^2-2*u+1), diff(u,%voi)]), 39intable[sawtooth_wave] : lambda([u], [sawtooth_wave(u)^2/2-sawtooth_wave(u)/2+u/2, diff(u,%voi)])); 40 41/* Before attempting to integrate, replace (here X matches with any expression): 42 (1) mod = lambda([x,y], x - y * floor(x / y)),q) 43 (2) abs(cos(X)) = abs_cos(X), abs(sin(X)) = abs_sin(X), 44 (3) acos(X) = %pi/2 - asin(x), 45 (4) asin(sin(X)) = (%pi/2)*triangle_wave(X/(2*%pi)), asin(cos(X)) = -(%pi/2)*triangle_wave((x - %pi/2)/(2*%pi)), 46 (5) acos(cos(X)) = (%pi/2)*triangle_wave((x - %pi/2)/(2*%pi)) + %pi/2, 47 (6) atan(tan(X)) = %pi * sawtooth_wave((X-%pi/2)/(%pi)) - %pi/2 -> -%pi*floor((2*X-%pi)/(2*%pi))+X-%p 48Where triangle_wave(x) = block([x : mod(x,1)], -abs(4*x-1) + abs(4*x-3) + 4*x-2) and sawtooth_wave(x) = x - floor(x).*/ 49 50extra_integrate(q,x) := block([l, i, ii : funmake(nounify('integrate),[q,x])], 51 l : extra_integration_methods, 52 q : subst('mod = lambda([x,y], x - y * floor(x / y)),q), 53 q : subst('abs = lambda([x], if sine_p(x) then abs_sin(first(x)) elseif cosine_p(x) then abs_cos(first(x)) else abs(x)),q), 54 q : subst('acos = lambda([x], %pi/2 - asin(x)), q), 55 q : subst('asin = lambda([x], if sine_p(x) then (%pi/2)*triangle_wave(first(x)/(2*%pi)) else asin(x)), q), 56 q : subst('asin = lambda([x], if cosine_p(x) then -(%pi/2)*triangle_wave((x - %pi/2)/(2*%pi)) else asin(x)), q), 57 q : subst('atan = lambda([x], if tangent_p(x) then block([x : first(x)], -%pi*floor((2*x-%pi)/(2*%pi))+x-%pi) else atan(x)),q), 58 while l # [ ] do ( 59 i : first(l)(q,x), 60 l : rest(l), 61 if (i # false and freeof('integrate, nounify('integrate), i)) then ( 62 ii : i, /* accept i as a simplification of ii. */ 63 l : [])), 64 subst(['abs_sin = lambda([x], abs(sin(x))), 'abs_cos = lambda([x], abs(cos(x)))], ii)); 65 66extra_definite_integration_methods : ['abs_defint]; 67 68extra_definite_integrate(q,x,lo,hi) := block([l,i, ii : funmake(nounify('integrate),[q,x, lo, hi])], 69 l : extra_definite_integration_methods, 70 while l # [] do ( 71 i : first(l)(q,x, lo, hi), 72 l : rest(l), 73 if (i # false) and freeof('integrate, i) then return(ii : i)), 74 ii); 75 76safe_op(e) := block([inflag : true], if mapatom(e) then false else op(e)); 77 78/* If e factors into a product of linear factors, return the list of factors; otherwise return false. */ 79real_linear_factors(e,x) := ( 80 e : factor(e), 81 e : if (safe_op(e) = "*") then args(e) else [e], 82 if every(lambda([w], polynomialp(w, [x], lambda([s], freeof(x,s)),lambda([k],is(k=0 or k=1)))),e) then ( 83 e : sublist(args(e), lambda([s], is(is(equal(s, conjugate(s))) = true) and not freeof(x,s))), 84 map(lambda([s], rhs(first(linsolve(s,x)))), e)) 85 else false); 86 87/* Convert abs, max, min, and unit_step to signum expressions */ 88convert_to_signum(e) := block([opsubst : true], 89 e : unit_step_mult_simp(e), 90 e : subst('unit_step = lambda([s], (signum(s)*(signum(s)+1))/2), e), 91 e : subst('max = lambda([[x]], xreduce(lambda([a,b], (a + b +abs(a-b))/2),x)),e), 92 e : subst('min = lambda([[x]], xreduce(lambda([a,b], (a + b -abs(a-b))/2),x)),e), 93 subst('abs = lambda([s], s * signum(s)), e)); 94 95/* Do unit_step(a) * unit_step(b) --> unit_step(min(a,b)). This is an identity 96for either a left or right continuous unit_step. */ 97 98unit_step_mult_simp(e) := block([p : [], q : 1, inflag : true], 99 if mapatom(e) then e 100 else if safe_op(e) = "*" then ( 101 for ek in e do ( 102 if safe_op(ek) = 'unit_step then p : cons(first(ek),p) else q : q * ek), 103 p : xreduce('min, p), 104 if freeof('max, 'min, 'inf, p) then q * unit_step(p) else e) 105 else map('unit_step_mult_simp, e)); 106 107/* Do e * signum(e) --> abs(e) */ 108 109signum_to_abs(e) := block([l : flatten(gatherargs(e,'signum))], 110 fullratsubst(map(lambda([s], s*signum(s)=abs(s)), l), e)); 111 112/* If e has the form w * signum(p1(x)) * signum(p2(x)) * ... * signum(pn(x)), where w 113is either freeof signum terms or free of x, return [w, append(q1,q2,...,qn)], 114where qk are the factors of pk; otherwise, return false. */ 115 116partition_as_signum(e,x) := block([w : 1, acc : [], OK : true, inflag : true, sgn], 117 e : factor(e), 118 e : if safe_op(e) = 'signum then [e] else if safe_op(e) = "*" then args(e) else OK : false, 119 if e # false then ( 120 for ek in e while OK do ( 121 if freeof('signum, ek) or freeof(x,ek) then w : w * ek 122 else if safe_op(ek) = 'signum then ( 123 ek : factor(first(ek)), 124 ek : if safe_op(ek) = "*" then args(ek) else [ek], 125 acc : append(ek,acc)) 126 else OK : false)), 127 if OK = true and acc # [ ] then [w, acc] else false); 128 129linear_in_p(e,x) := 130 polynomialp(e,[x], lambda([s], freeof(x,s)), lambda([k], is(k=0) or is(k = 1))) and numberp(diff(e,x)); 131 132signum_int(q,x) := block([w : 1, acc : [], sgn, v, f, listconstvars : true], 133 q : convert_to_signum(q), 134 if freeof('signum, q) then ( 135 q : block([extra_integration_methods : []], integrate(trigsimp(q),x)), 136 if freeof('integrate, nounify('integrate),q) then q else false) 137 else ( 138 q : almost_everywhere_simp(q), 139 v : listofvars(q), 140 q : block([expandwrt_denom : true], expandwrt(q,'signum)), 141 if (f : abs_int_extra(q,x)) # false then f 142 else if (f : partition_as_signum(q,x)) # false then ( 143 w : first(f), 144 acc : second(f), 145 if every(lambda([s], linear_in_p(s,x)), acc) then ( 146 sgn : xreduce("*", map(lambda([s], diff(s,x)),acc)), 147 acc : map(lambda([s], rhs(first(linsolve(s, x)))),acc), 148 signum_int_helper(signum(sgn) * w, sort(acc), x))) 149 else if (safe_op(q) = "+") then ( 150 f : map(lambda([s], signum_int(s,x)), args(q)), 151 if member(false, f) then false else xreduce("+", f)) 152 else block([extra_integration_methods : [], extra_definite_integration_methods : []], false))); 153 154/* integrate(q(x) * signum(x - l[1]) * signum(x - l[2]) * ...,x). The list l is nonempty. */ 155 156signum_int_helper(q,l,x) := block([v, xo, f, x%], 157 if emptyp(rest(l)) then ( 158 f : integrate(q,x), 159 if not(freeof('integrate, f)) then ( 160 v : new_variable('general), 161 f : funmake(nounify('integrate), [subst(x = v, q), v, first(l), x])), 162 signum(x - first(l)) * (f - subst(x = first(l), f))) 163 else ( 164 xo : first(l), 165 f : signum_int_helper(q, rest(l), x), 166 signum(x - xo) * (f - subst(x = xo, f)))); 167 168/* The function dint is based on code I wrote and placed in the public domain.*/ 169 170dint(e,x,l) := block([xo, acc : 0, i, cntx], 171 xo : first(l), 172 l : rest(l), 173 for xi in l do ( 174 cntx : supcontext(), 175 i : unwind_protect(( 176 apply('assume,[xo < x, x < xi, xo < xi]), 177 errcatch(integrate(expand(e,0,0),x,xo,xi))), 178 killcontext(cntx)), 179 if i = [ ] then return(acc : false) else acc : acc + first(i), 180 xo : xi), 181 acc); 182 183partitions_interval_p(l,[endpts]) := block([ok,lo,hi], 184 ok : if length(endpts) = 2 then ( 185 [lo,hi] : endpts, 186 every(lambda([s], (is(lo <= s) = true) and (is(s <= hi) = true)), l)) 187 else endpts = [], 188 if listp(l) and ok then ( 189 l : listify(setify(append(endpts, l))), 190 l : sort(l, lambda([a,b], csign(b-a) = 'pos)), 191 if every(lambda([a,b], is(a <= b)=true), l, endcons('inf, rest(l))) then l else false) 192 else false); 193 194abs_defint(e,x,lo,hi) := block([f,l, prederror : false, cntx], 195 if is(hi < lo)=true then -abs_defint(e,x,hi,lo) 196 else if is(lo = hi) then 0 197 else ( 198 unwind_protect(( 199 cntx : supcontext(), 200 assume(lo <= x, x <= hi), 201 e : expand(e,0,0), 202 e : convert_to_signum(e), 203 e : almost_everywhere_simp(e), 204 l : xreduce('append, (gatherargs(e, 'signum))), 205 l : flatten(map(lambda([s], real_linear_factors(s,x)), l)), /* flatten([[1], false]) --> [1,false] */ 206 l : sublist(l, lambda([s], lo <= s and s <= hi)), 207 l : delete(false,l), 208 l : partitions_interval_p(l,lo,hi), 209 if l # false then ( 210 f : dint(e,x,l), 211 if f = false then false else f) 212 else false), 213 killcontext(cntx)))); 214 215/* Replace signum(z)^2 --> 1, where z is nonzero and a polynomial. For a nonzero polynomial z, 216signum(z)^2 -1 is zero everywhere except at each zero of z. The almost_everywhere_simp simplification 217is OK for an integrand--thus integrate(e,x) = integrate(almost_everywhere_simp(e),x). 218 219This function could be extended to do signum(z) --> 1, when z is a nonzero polynomial and csign(z) = 'pn, 220for example. Another extension is %if(x=0,xxx,zzz) --> zzz. I'll save these for another day.*/ 221 222almost_everywhere_simp(e) := block([l], 223 l : sublist(flatten(gatherargs(e,'signum)), lambda([s], s # 0 and polynomialp(s,listofvars(s)))), 224 fullratsubst(map(lambda([s], signum(s)^2=1),l), ratexpand(e))); 225 226/* For integrands of the form F(x, |x-c|), integrate F(x,-x+c) and F(x,x-c). Return a signum expression 227that is continuous at c; when the integrand doesn't have this form, return false. The error catch 228on integrate is needed: try integrate(1/(x + abs(x)),x), for example. 229 230The function sublis does all substitutions before simplification. This allows things such as 231sublis([x = 0], %if(x < 1, 5, log(x))) --> 5. The subst function simplifies along the way 232so subst([x = 0], %if(x < 1, 5, log(x))) --> error. */ 233 234abs_int_extra(q,x) := block([q1,q2,k,xo,kk, cntx], 235 q : convert_to_signum(q), 236 k : sublist(gatherargs(q,'signum),lambda([s], not freeof(x,s))), 237 if k # [] and emptyp(rest(k)) then ( 238 k : first(first(k)), 239 if polynomialp(k, [x], lambda([s], freeof(x,s)),lambda([k],is(k=0 or k=1))) then ( 240 kk : rhs(first(linsolve(k,x))), 241 cntx : supcontext(), 242 q1 : unwind_protect((assume(x < kk), errcatch(integrate(expand(q,0,0),x))),killcontext(cntx)), 243 cntx : supcontext(), 244 q2 : unwind_protect((assume(x > kk), errcatch(integrate(expand(q,0,0),x))),killcontext(cntx)), 245 if freeof('integrate, 'limit, 'diff, q1) and freeof('integrate, 'limit, 'diff, q2) and 246 q1 # [] and q2 # [] then ( 247 q1 : first(q1), 248 q2 : first(q2), 249 xo : linsolve(k,x), 250 /* make both q1 and q2 vanish at xo */ 251 q1 : errcatch(q1 - sublis(xo, q1)), 252 q2 : errcatch(q2 - sublis(xo, q2)), 253 xo : first(xo), 254 xo : rhs(xo) - lhs(xo), 255 if q1 = [] or q2 = [] then false else ( 256 q1 : first(q1), 257 q2 : first(q2), 258 (q1 + q2)/2 - (q2 - q1) * signum(xo)/2)) 259 else false)) 260 else false); 261 262abs_integrate_use_if(q,x) := block([k,%x,xo], 263 q : convert_to_signum(q), 264 k : flatten(gatherargs(q,'signum)), 265 if k # [] and every(lambda([s], polynomialp(s,[x], 'numberp, lambda([k],is(k=0 or k=1)))), k) then ( 266 k : map(lambda([s], rhs(first(linsolve(s,x)))),k), 267 %x : new_variable('general), 268 q : sublis([x = %x],q), 269 k : listify(setify(k)), 270 k : partitions_interval_p(k), 271 q : if k # false then errcatch(interval_integrate(q,%x,k)) else [], 272 if q = [] then false else subst(%x = x, first(q))) 273 else false); 274 275interval_integrate(q,x,l) := block([xo,q1,q2,i1, cntx, extra_integration_methods : []], 276 if l = [ ] then integrate(q,x) 277 else ( 278 xo : first(l), 279 cntx : supcontext(), 280 q1 : unwind_protect((assume(x < xo),integrate(expand(q,0,0),x)), killcontext(cntx)), 281 cntx : supcontext(), 282 q : unwind_protect((assume(x > xo),expand(q,0,0)),killcontext(cntx)), 283 q2 : interval_integrate(q,x,rest(l)), 284 285 if freeof(nounify('integrate), q2 - q1) then ( 286 i1 : errcatch(sublis([x = xo], q2 - q1))) 287 else i1 : [ ], 288 if i1 = [ ] then false else %if(x < xo, q1 + first(i1), q2))); 289 290''(buildq([z : ?gensym()], gradef(floor(z), %if(%integerp(z), 'und, 0)))); 291''(buildq([z : ?gensym()], gradef(ceiling(z),%if(%integerp(z), 'und, 0)))); 292''(buildq([z : ?gensym()], gradef(signum(z), 0))); 293''(buildq([z : ?gensym()], gradef(sawtooth_wave(z), %if(%integerp(z), 'und, 1)))); 294 295floor_int(q, x) := block([l, fl : gensym(), cl : gensym(), k : gensym(), cntx, simpsum : true], 296 l : setify(xreduce('append, gatherargs(q,'floor))), 297 l : union(l, setify(xreduce('append, gatherargs(q,'ceiling)))), 298 l : subset(l, lambda([s], not(freeof(x, s)))), 299 if l = set(x) then ( 300 unwind_protect( 301 (cntx : supcontext(), 302 apply('declare,[[fl,cl,k],integer]), 303 assume(fl <= cl, cl < fl+1), 304 q : subst([floor(x) = fl, ceiling(x) = cl], q), 305 q : integrate(q, x), 306 q : subst([fl = floor(x), cl = ceiling(x)], q) 307 + sum(subst([fl = k-1, cl = k,x = k], q) - subst([fl = k, cl = k,x = k], q),k,0, floor(x)) 308 + sum(subst([fl = k-1, cl = k-1,x = k-1], q) - subst([fl = k-1, cl = k,x = k-1], q),k,0,ceiling(x)), 309 if freeof('integrate,'sum,q) then q else false), 310 killcontext(cntx))) 311 else false); 312 313if_int(q,x) := block([p,f,g,fi,gi,c], 314 if safe_op(q) = '%if then ( 315 p : first(q), 316 if safe_op(p) = ">" or freeof(x,p) then ( 317 f : second(q), 318 g : third(q), 319 fi : integrate(f,x), 320 gi : integrate(g,x), 321 /* ahhh, I'm not sure why it seems that extra_integrate isn't automatically called? */ 322 if not(freeof('integrate, gi)) then gi : extra_integrate(g,x), 323 if not(freeof('integrate, fi)) then fi : extra_integrate(f,x), 324 if freeof(x,p) then ( 325 %if(p,fi,gi)) 326 else if linear_in_p(lhs(p),x) and rhs(p) = 0 and freeof('integrate, 'limit, [fi,gi]) then ( 327 c : sublis(linsolve(lhs(p),x), fi - gi), 328 if freeof(x,c) then %if(p,fi, gi + c) else false) 329 else false) 330 else false)); 331 332/* If p is a product, remove factors of p that are constant; otherwise, return p. */ 333 334remove_const_factors(p) := block([inflag : true], 335 p : factor(p), 336 if mapatom(p) or not op(p) = "*" then p else map(lambda([s], if constantp(s) then 1 else s),p)); 337 338/* On exiting from sign or csign, temporary assumptions are not immediately forgotten. This function 339 removes these temporary assumptions before returning. */ 340 341forgetful_csign(e) := unwind_protect(csign(e), ?clearsign()); 342 343/* Do basic simplifications on the equation e = 0. This function is conservative-- 344 since, for example, 1/x = 1/x isn't the same as 0 = 0, this function doesn't do 345 e <-- rhs(e)-lhs(e). For a similar reason, this function doesn't return the numerator 346 of a quotient either.*/ 347 348eq_reduce(e) := block([ ], 349 e : factor(e), 350 if constantp(e) then if csign(e) = 'zero then 0 else 1 351 else if mapatom(e) then e 352 else if op(e) = 'abs then eq_reduce(first(e)) 353 else if op(e) = 'log then eq_reduce(first(e)-1) 354 else if op(e) = "*" then map('eq_reduce, e) 355 else if op(e) = "^" and numberp(second(e)) and is(second(e) > 0) then eq_reduce(first(e)) 356 else if op(e) = 'gamma then set() /* 0 isn't in the range of the gamma function */ 357 else e); 358 359/* Try to find a set of expressions {q1,q2,...,qn} such that if any q vanishes, the expression 360 e is undefined. This function misses things such as gamma(x) -- we would need {0,-1,-2,-3,...} */ 361 362possible_singular_pts(e) := block([inflag : true], 363 e : factor(e), 364 if mapatom(e) then set() 365 else if op(e) = "^" and forgetful_csign(second(e)) # 'pos and not constantp(first(e)) then 366 set(eq_reduce(first(e))) 367 else if op(e) = 'log then set(eq_reduce(first(e))) 368 else xreduce('union, map('possible_singular_pts, args(e)))); 369 370 371/* This function tries to return integrate(e,x) without calling asksign. If asksign does 372 get called, this function removes any new assumptions in the fact database. 373 374 To avoid some calls to asksign, forgetful_integrate first tries to integrate using intfudu. The check that the arguments 375 of the summand are freeof abs, floor, ... is a compromise that keeps Maxima from stalling when integrating, for example, 376 log(abs(sin(x)),x) with conditional_integrate as a member of extra_integration_methods.*/ 377 378forgetful_integrate(e,x) := block([ee : false, cntx], 379 unwind_protect(( 380 cntx : supcontext(), 381 if freeof('abs,'floor,'ceiling,'mod,'signum, if mapatom(e) then e else args(e)) then ( 382 ee : intfudu(e,x), 383 if ee # false then ee else block([extra_integration_methods : [], extra_definite_integration_methods : []], integrate(trigsimp(e),x)))), 384 killcontext(cntx))); 385 386/* Let l be a list of first degree polynomials. Solve l and substitute into e. 387 When the substitutions are inconsistent, signal an error, but don't print 388 a message. Linear_subst isn't intended to be a user-level function--this 389 function doesn't check that each expression in the list l is linear. It would 390 be good to hide this function from the user, but Maxima doesn't have a way 391 to do that.*/ 392 393linear_subst(l,e) := block([linsolve_params : false, globalsolve : false, backsubst : false, 394 programmode : true], 395 if emptyp(l) then e else ( 396 l : linsolve(l, listofvars(l)), 397 if emptyp(l) then error() else subst(l,e))); 398 399/* Return the first n bits of a binary representation for the positive integer k. */ 400 401bits(k,n) := block([b : []], 402 while n > 0 do ( 403 n : n -1, 404 push(mod(k,2),b), 405 k : floor(k/2)), 406 reverse(b)); 407 408/* Return true if the expression e is linear in the variables in the list var; otherwise, return false. */ 409 410linear_p(e,var) := polynomialp(e, var, lambda([s], lfreeof(var,s)), lambda([k],is(k=0 or k=1))); 411 412/* Try to return an antiderivative that is valid for all parameters. 413 414 (1) Integrate normally--well almost normally. The function forgetful_integrate tries 415 to integrate without calling asksign and it cleans the fact database on exit. 416 The call to trigsimp cleans up antiderivatives such as integrate(cos(m*x) * sin(x - m),x). 417 418 (2) Locate the singularities of the antiderivative that are not singularities of the 419 integrand--collect these singularities into a set npoles (new poles). 420 421 (3) When all the singularities are linear, loop through the possibilities and collect 422 the results. When conditional_integrate is unable to find an antiderivative, return 423 false. */ 424 425conditional_integrate(e,x) := block([ee, eee, npoles, vars, n, m, k, cnd, eq, q, ok : true], 426 ee : trigsimp(forgetful_integrate(e,x)), 427 if freeof('integrate, nounify('integrate),ee) then ( 428 npoles : setdifference(possible_singular_pts(ee), possible_singular_pts(e)), 429 npoles : subset(npoles, lambda([s], freeof(x,s))), 430 vars : listofvars(npoles), 431 if emptyp(npoles) then ee 432 else if every(lambda([s], linear_p(s,vars)), npoles) then ( 433 m : cardinality(npoles), 434 n : 2^m-1, 435 q : [[xreduce("%and", map(lambda([s], s # 0), listify(npoles))), ee]], 436 for k : 1 thru n while ok do ( 437 cnd : map(lambda([s,w], if s = 0 then w # 0 else w = 0), reverse(bits(k,m)), listify(npoles)), 438 eq : sublist(cnd, lambda([s], is(op(s) = "="))), 439 ee : errcatch(linear_subst(eq,e)), 440 if ee # [] then ( /* skip when eq is inconsistent.*/ 441 ee : first(ee), 442 ee : conditional_integrate(ee,x), 443 if ee # false then push([xreduce("%and", cnd), ee], q) else ok : false)), 444 if ok then ( 445 rreduce(lambda([a,b], %if(first(a), second(a), b)), reverse(rest(q)), second(first(q)))) 446 else false) 447 else false) 448 else false); 449 450