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