Skip to content

Commit 5a94999

Browse files
committed
slightly enhanced convolution of piecewise functions
1 parent b0f09d9 commit 5a94999

File tree

1 file changed

+58
-34
lines changed

1 file changed

+58
-34
lines changed

src/sage/functions/piecewise.py

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,8 @@ def unextend_zero(self, parameters, variable):
602602
"""
603603
result = [(domain, func) for domain, func in parameters
604604
if func != 0]
605+
if len(result) == len(self):
606+
return self
605607
return piecewise(result, var=variable)
606608

607609
def pieces(self, parameters, variable):
@@ -980,6 +982,17 @@ def convolution(self, parameters, variable, other):
980982
x|-->-x + 6 on (3, 4],
981983
x|-->-2*x + 10 on (4, 5]; x)
982984
985+
Some unbounded but convergent cases now work::
986+
987+
sage: p = piecewise([[(2,oo),exp(-x)]])
988+
sage: q = piecewise([[[2,3],x]])
989+
sage: p.convolution(q)
990+
piecewise(x|-->(x - 3)*e^(-2) - e^(-x + 2) on (4, 5]; x)
991+
sage: q.convolution(p)
992+
piecewise(x|-->(x - 3)*e^(-2) - e^(-x + 2) on (4, 5]; x)
993+
994+
TESTS::
995+
983996
Check that the bugs raised in :issue:`12123` are fixed::
984997
985998
sage: f = piecewise([[(-2, 2), 2]])
@@ -1003,45 +1016,56 @@ def convolution(self, parameters, variable, other):
10031016
fd, f0 = parameters[0]
10041017
gd, g0 = next(other.items())
10051018
if len(f) == 1 == len(g):
1006-
f = f.unextend_zero()
1007-
g = g.unextend_zero()
10081019
a1 = fd[0].lower()
10091020
a2 = fd[0].upper()
10101021
b1 = gd[0].lower()
10111022
b2 = gd[0].upper()
1012-
with SR.temp_var() as tt:
1013-
with SR.temp_var() as uu:
1014-
i1 = f0.subs({variable: uu})
1015-
i2 = g0.subs({variable: tt-uu})
1016-
fg1 = definite_integral(i1*i2, uu, a1, tt-b1).subs({tt: variable})
1017-
fg2 = definite_integral(i1*i2, uu, tt-b2, tt-b1).subs({tt: variable})
1018-
fg3 = definite_integral(i1*i2, uu, tt-b2, a2).subs({tt: variable})
1019-
fg4 = definite_integral(i1*i2, uu, a1, a2).subs({tt: variable})
1020-
if a1-b1 < a2-b2:
1021-
if a2+b1 != a1+b2:
1022-
h = piecewise([[(a1+b1, a1+b2), fg1],
1023-
[(a1+b2, a2+b1), fg2],
1024-
[(a2+b1, a2+b2), fg3]])
1025-
else:
1026-
h = piecewise([[(a1+b1, a1+b2), fg1],
1027-
[(a1+b2, a2+b2), fg3]])
1023+
a1b1 = a1 + b1
1024+
a2b2 = a2 + b2
1025+
delta_a = a2 - a1
1026+
delta_b = b2 - b1
1027+
1028+
# this fails in some unbounded cases:
1029+
a1b2 = a1 + b2
1030+
a2b1 = a2 + b1
1031+
1032+
todo = []
1033+
if delta_a > delta_b:
1034+
if a1b2 is not minus_infinity:
1035+
todo.append((a1b1, a1b2, a1, variable - b1))
1036+
todo.append((a1b2, a2b1, variable - b2, variable - b1))
1037+
if a2b1 is not infinity:
1038+
todo.append((a2b1, a2b2, variable - b2, a2))
1039+
elif delta_a < delta_b:
1040+
if a2b1 is not minus_infinity:
1041+
todo.append((a1b1, a2b1, a1, variable - b1))
1042+
todo.append((a2b1, a1b2, a1, a2))
1043+
if a1b2 is not infinity:
1044+
todo.append((a1b2, a2b2, variable - b2, a2))
10281045
else:
1029-
if a1+b2 != a2+b1:
1030-
h = piecewise([[(a1+b1, a2+b1), fg1],
1031-
[(a2+b1, a1+b2), fg4],
1032-
[(a1+b2, a2+b2), fg3]])
1033-
else:
1034-
h = piecewise([[(a1+b1, a2+b1), fg1],
1035-
[(a2+b1, a2+b2), fg3]])
1036-
return (piecewise([[(minus_infinity, infinity), 0]]).piecewise_add(h)).unextend_zero()
1037-
1038-
if len(f) > 1 or len(g) > 1:
1039-
z = piecewise([[(0, 0), 0]])
1040-
for fpiece in f.pieces():
1041-
for gpiece in g.pieces():
1042-
h = gpiece.convolution(fpiece)
1043-
z = z.piecewise_add(h)
1044-
return z.unextend_zero()
1046+
if a2b1 is not minus_infinity:
1047+
todo.append((a1b1, a2b1, a1, variable - b1))
1048+
todo.append((a2b1, a2b2, variable - b2, a2))
1049+
1050+
if not todo:
1051+
raise ValueError("no domain of integration")
1052+
1053+
with SR.temp_var() as uu:
1054+
i1 = f0.subs({variable: uu})
1055+
i2 = g0.subs({variable: variable - uu})
1056+
expr = i1 * i2
1057+
h = piecewise([[(start, stop),
1058+
definite_integral(expr, uu, mini, maxi)]
1059+
for start, stop, mini, maxi in todo])
1060+
flat_zero = piecewise([[(minus_infinity, infinity), 0]])
1061+
return (flat_zero.piecewise_add(h)).unextend_zero() # why ?
1062+
1063+
z = piecewise([[(0, 0), 0]])
1064+
for fpiece in f.pieces():
1065+
for gpiece in g.pieces():
1066+
h = gpiece.convolution(fpiece)
1067+
z = z.piecewise_add(h)
1068+
return z.unextend_zero()
10451069

10461070
def trapezoid(self, parameters, variable, N):
10471071
"""

0 commit comments

Comments
 (0)