Skip to content

Commit 8f2e91f

Browse files
eric-wieserutensil
authored andcommitted
Fix heterogeneous sdop.Add (#157)
Before this change, any addition other than `Sdop + Sdop` would raise a NameError, since the variable `coef` is not defined in the `elif` and `else` branch. The intent of the old code was fairly clear - it was to insert a multiplicative term for `sdop2.Ga.Pdop_identity`, such that `(sdop + 2)(x) == sdop(x) + 2*x`, which is reflected by the repr in a shell. This change just copies the code from `Dop`, which succeeds in doing exactly the same thing This also adds a bunch more tests for both Sdop and Dop operations
1 parent 76309ff commit 8f2e91f

File tree

2 files changed

+43
-24
lines changed

2 files changed

+43
-24
lines changed

galgebra/mv.py

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,28 +1609,20 @@ def Add(sdop1, sdop2):
16091609
if isinstance(sdop1, Sdop) and isinstance(sdop2, Sdop):
16101610
if sdop1.Ga != sdop2.Ga:
16111611
raise ValueError('In Sdop.Add sdop1.Ga != sdop2.Ga.')
1612-
1613-
sdop_sum = Sdop(_merge_terms(sdop1.terms, sdop2.terms), ga=sdop1.Ga)
1614-
elif isinstance(sdop1, Sdop):
1615-
coefs, pdiffs = list(zip(*sdop1.terms))
1616-
if sdop1.Ga.Pdop_identity in pdiffs:
1617-
index = pdiffs.index(sdop1.Ga.Pdop_identity)
1618-
coef[index] += sdop2
1619-
else:
1620-
coef.append(sdop2)
1621-
pdiff.append(sdop1.Ga.Pdop_identity)
1622-
return Sdop(coefs, pdiffs, ga=sdop1.Ga)
1612+
return Sdop(_merge_terms(sdop1.terms, sdop2.terms), ga=sdop1.Ga)
16231613
else:
1624-
coefs, pdiffs = list(zip(*sdop2.terms))
1625-
if sdop2.Ga.Pdop_identity in pdiffs:
1626-
index = pdiffs.index(sdop2.Ga.Pdop_identity)
1627-
coef[index] += sdop1
1614+
# convert values to multiplicative operators
1615+
if isinstance(sdop1, Sdop):
1616+
if not isinstance(sdop2, Mv):
1617+
sdop2 = sdop1.Ga.mv(sdop2)
1618+
sdop2 = Sdop([(sdop2, sdop1.Ga.Pdop_identity)], ga=sdop1.Ga)
1619+
elif isinstance(sdop2, Sdop):
1620+
if not isinstance(sdop1, Mv):
1621+
sdop1 = sdop2.Ga.mv(sdop1)
1622+
sdop1 = Sdop([(sdop1, sdop2.Ga.Pdop_identity)], ga=sdop2.Ga)
16281623
else:
1629-
coef.append(sdop1)
1630-
pdiff.append(sdop2.Ga.Pdop_identity)
1631-
sdop_sum = Sdop(coefs, pdiffs, ga=sdop2.Ga)
1632-
1633-
return Sdop.consolidate_coefs(sdop_sum)
1624+
raise TypeError("Neither argument is a Dop instance")
1625+
return Sdop.Add(sdop1, sdop2)
16341626

16351627
def __eq__(self, sdop):
16361628
if isinstance(sdop, Sdop):
@@ -2033,14 +2025,17 @@ def Add(dop1, dop2):
20332025

20342026
return Dop(_merge_terms(dop1.terms, dop2.terms), cmpflg=dop1.cmpflg, ga=dop1.Ga)
20352027
else:
2036-
if isinstance(dop1, Dop): # dop1 is Dop
2028+
# convert values to multiplicative operators
2029+
if isinstance(dop1, Dop):
20372030
if not isinstance(dop2, Mv):
20382031
dop2 = dop1.Ga.mv(dop2)
2039-
dop2 = Dop([dop2], [dop1.Ga.Pdop_identity], cmpflg=dop1.cmpflg, ga=dop1.Ga)
2040-
else: # dop2 is Dop
2032+
dop2 = Dop([(dop2, dop1.Ga.Pdop_identity)], cmpflg=dop1.cmpflg, ga=dop1.Ga)
2033+
elif isinstance(dop2, Dop):
20412034
if not isinstance(dop1, Mv):
20422035
dop1 = dop2.Ga.mv(dop1)
2043-
dop1 = Dop([dop1], [dop2.Ga.Pdop_identity], cmpflg=dop2.cmpflg, ga=dop2.Ga)
2036+
dop1 = Dop([(dop1, dop2.Ga.Pdop_identity)], cmpflg=dop2.cmpflg, ga=dop2.Ga)
2037+
else:
2038+
raise TypeError("Neither argument is a Dop instance")
20442039
return Dop.Add(dop1, dop2)
20452040

20462041
def __add__(self, dop):

test/test_differential_ops.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,22 @@ def test_associativity_and_distributivity(self):
1717
# check addition distributes
1818
assert (laplacian + ga.grad) * v == laplacian * v + ga.grad * v != 0
1919
assert (laplacian + 1234567) * v == laplacian * v + 1234567 * v != 0
20+
assert (1234 * ex + ga.grad) * v == 1234 * ex * v + ga.grad * v != 0
2021
# check subtraction distributes
2122
assert (laplacian - ga.grad) * v == laplacian * v - ga.grad * v != 0
2223
assert (laplacian - 1234567) * v == laplacian * v - 1234567 * v != 0
24+
assert (1234 * ex - ga.grad) * v == 1234 * ex * v - ga.grad * v != 0
2325
# check unary subtraction distributes
2426
assert (-ga.grad) * v == -(ga.grad * v) != 0
2527
# check division is associative
2628
assert v * (ga.rgrad / 2) == (v * ga.rgrad) / 2 != 0
2729
# check multiplication is associative
30+
assert (ex * ga.grad) * v == ex * (ga.grad * v) != 0
2831
assert (20 * ga.grad) * v == 20 * (ga.grad * v) != 0
32+
assert v * (ga.rgrad * ex) == (v * ga.rgrad) * ex != 0
2933
assert v * (ga.rgrad * 20) == (v * ga.rgrad) * 20 != 0
34+
assert (laplacian * ga.grad) * v == laplacian * (ga.grad * v) != 0
35+
# check wedge is associative
3036
assert (ex ^ ga.grad) ^ v == ex ^ (ga.grad ^ v) != 0
3137
assert (20 ^ ga.grad) ^ v == 20 ^ (ga.grad ^ v) != 0
3238
assert v ^ (ga.rgrad ^ ex) == (v ^ ga.rgrad) ^ ex != 0
@@ -128,3 +134,21 @@ def test_deprecation(self):
128134
with pytest.warns(DeprecationWarning):
129135
p = Pdop(None, ga=ga)
130136
assert p == Pdop({}, ga=ga)
137+
138+
def test_associativity_and_distributivity(self):
139+
coords = x, y, z = symbols('x y z', real=True)
140+
ga, ex, ey, ez = Ga.build('e*x|y|z', g=[1, 1, 1], coords=coords)
141+
v = ga.mv('v', 'vector', f=True)
142+
laplacian = Sdop((ga.grad * ga.grad).terms, ga=ga)
143+
144+
# check addition distributes
145+
assert (laplacian + 20) * v == laplacian * v + 20 * v != 0
146+
assert (20 + laplacian) * v == laplacian * v + 20 * v != 0
147+
# check subtraction distributes
148+
assert (laplacian - 20) * v == laplacian * v - 20 * v != 0
149+
assert (20 - laplacian) * v == 20 * v - laplacian * v != 0
150+
# check unary subtraction distributes
151+
assert (-laplacian) * v == -(laplacian * v) != 0
152+
# check multiplication is associative
153+
assert (20 * laplacian) * v == 20 * (laplacian * v) != 0
154+
assert (laplacian * laplacian) * v == laplacian * (laplacian * v) != 0

0 commit comments

Comments
 (0)