Skip to content

Commit 8d15ea4

Browse files
authored
Merge pull request #177 from eric-wieser/test-dop
Add tests for Dop and fix bugs found
2 parents 78977e6 + 33ea37a commit 8d15ea4

File tree

2 files changed

+97
-16
lines changed

2 files changed

+97
-16
lines changed

galgebra/mv.py

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1964,16 +1964,20 @@ def __init__(self, *args, **kwargs):
19641964
self.title = None
19651965

19661966
if len(args) == 2:
1967-
if len(args[0]) != len(args[1]):
1967+
coefs, pdiffs = args
1968+
if len(coefs) != len(pdiffs):
19681969
raise ValueError('In Dop.__init__ coefficent list and Pdop list must be same length.')
1969-
self.terms = tuple(zip(args[0], args[1]))
1970+
self.terms = tuple(zip(coefs, pdiffs))
19701971
elif len(args) == 1:
1971-
if isinstance(args[0][0][0], Mv): # Mv expansion [(Mv, Pdop)]
1972-
self.terms = tuple(args[0])
1973-
elif isinstance(args[0][0][0], Sdop): # Sdop expansion [(Sdop, Mv)]
1972+
arg, = args
1973+
if len(arg) == 0:
1974+
self.terms = ()
1975+
elif isinstance(arg[0][0], Mv): # Mv expansion [(Mv, Pdop)]
1976+
self.terms = tuple(arg)
1977+
elif isinstance(arg[0][0], Sdop): # Sdop expansion [(Sdop, Mv)]
19741978
coefs = []
19751979
pdiffs = []
1976-
for (sdop, mv) in args[0]:
1980+
for (sdop, mv) in arg:
19771981
for (coef, pdiff) in sdop.terms:
19781982
if pdiff in pdiffs:
19791983
index = pdiffs.index(pdiff)
@@ -2037,23 +2041,18 @@ def Add(dop1, dop2):
20372041
if dop1.cmpflg != dop2.cmpflg:
20382042
raise ValueError('In Dop.Add complement flags have different values: %s vs. %s' % (dop1.cmpflg, dop2.cmpflg))
20392043

2040-
coefs1, pdiffs1 = list(zip(*dop1.terms))
2041-
coefs2, pdiffs2 = list(zip(*dop2.terms))
2042-
2043-
pdiffs1 = list(pdiffs1)
2044-
pdiffs2 = list(pdiffs2)
2044+
pdiffs1 = [pdiff for _, pdiff in dop1.terms]
2045+
pdiffs2 = [pdiff for _, pdiff in dop2.terms]
20452046

20462047
pdiffs = pdiffs1 + [x for x in pdiffs2 if x not in pdiffs1]
20472048
coefs = len(pdiffs) * [S(0)]
20482049

2049-
for pdiff in pdiffs1:
2050+
for coef, pdiff in dop1.terms:
20502051
index = pdiffs.index(pdiff)
2051-
coef = coefs1[pdiffs1.index(pdiff)]
20522052
coefs[index] += coef
20532053

2054-
for pdiff in pdiffs2:
2054+
for coef, pdiff in dop2.terms:
20552055
index = pdiffs.index(pdiff)
2056-
coef = coefs2[pdiffs2.index(pdiff)]
20572056
coefs[index] += coef
20582057

20592058
return Dop(coefs, pdiffs, cmpflg=dop1.cmpflg, ga=dop1.Ga)
@@ -2149,7 +2148,7 @@ def __truediv__(self, dopr):
21492148
raise TypeError('In Dop.__truediv__ dopr must be a sympy scalar.')
21502149
return Dop([
21512150
(coef / dopr, pdiff) for (coef, pdiff) in self.terms
2152-
], ga=self.Ga)
2151+
], ga=self.Ga, cmpflg=self.cmpflg)
21532152

21542153
if sys.version_info.major < 3:
21552154
__div__ = __truediv__

test/test_differential_ops.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
from sympy import symbols
2+
import pytest
3+
4+
from galgebra.ga import Ga
5+
from galgebra.mv import Dop
6+
7+
8+
class TestDop(object):
9+
10+
def test_associativity_and_distributivity(self):
11+
coords = x, y, z = symbols('x y z', real=True)
12+
ga, ex, ey, ez = Ga.build('e*x|y|z', g=[1, 1, 1], coords=coords)
13+
v = ga.mv('v', 'vector', f=True)
14+
laplacian = ga.grad * ga.grad
15+
rlaplacian = ga.rgrad * ga.rgrad
16+
17+
# check addition distributes
18+
assert (laplacian + ga.grad) * v == laplacian * v + ga.grad * v != 0
19+
assert (laplacian + 1234567) * v == laplacian * v + 1234567 * v != 0
20+
# check subtraction distributes
21+
assert (laplacian - ga.grad) * v == laplacian * v - ga.grad * v != 0
22+
assert (laplacian - 1234567) * v == laplacian * v - 1234567 * v != 0
23+
# check unary subtraction distributes
24+
assert (-ga.grad) * v == -(ga.grad * v) != 0
25+
# check division is associative
26+
assert v * (ga.rgrad / 2) == (v * ga.rgrad) / 2 != 0
27+
# check multiplication is associative
28+
assert (20 * ga.grad) * v == 20 * (ga.grad * v) != 0
29+
assert v * (ga.rgrad * 20) == (v * ga.rgrad) * 20 != 0
30+
assert (ex ^ ga.grad) ^ v == ex ^ (ga.grad ^ v) != 0
31+
assert (20 ^ ga.grad) ^ v == 20 ^ (ga.grad ^ v) != 0
32+
assert v ^ (ga.rgrad ^ ex) == (v ^ ga.rgrad) ^ ex != 0
33+
assert v ^ (ga.rgrad ^ 20) == (v ^ ga.rgrad) ^ 20 != 0
34+
35+
def test_empty_dop(self):
36+
""" Test that dop with zero terms is equivalent to multiplying by zero """
37+
coords = x, y, z = symbols('x y z', real=True)
38+
ga, ex, ey, ez = Ga.build('e*x|y|z', g=[1, 1, 1], coords=coords)
39+
v = ga.mv('v', 'vector', f=True)
40+
41+
make_zero = Dop([], ga=ga)
42+
assert make_zero * v == 0
43+
assert make_zero * make_zero * v == 0
44+
assert (make_zero + make_zero) * v == 0
45+
assert (-make_zero) * v == 0
46+
47+
def test_misc(self):
48+
""" Other miscellaneous tests """
49+
coords = x, y, z = symbols('x y z', real=True)
50+
ga, ex, ey, ez = Ga.build('e*x|y|z', g=[1, 1, 1], coords=coords)
51+
v = ga.mv('v', 'vector', f=True)
52+
laplacian = ga.grad * ga.grad
53+
rlaplacian = ga.rgrad * ga.rgrad
54+
55+
# laplacian is a scalar operator, so applying it from either side
56+
# is the same
57+
assert laplacian * v == v * rlaplacian
58+
59+
assert laplacian.is_scalar()
60+
assert not ga.grad.is_scalar()
61+
62+
# inconsistent cmpflg, not clear which side the operator goes on
63+
with pytest.raises(ValueError):
64+
ga.grad + ga.rgrad
65+
with pytest.raises(ValueError):
66+
ga.grad * ga.rgrad
67+
68+
def test_mixed_algebras(self):
69+
coords = x, y, z = symbols('x y z', real=True)
70+
ga1, ex1, ey1, ez1 = Ga.build('e1*x|y|z', g=[1, 1, 1], coords=coords)
71+
ga2, ex2, ey2, ez2 = Ga.build('e2*x|y|z', g=[1, 1, 1], coords=coords)
72+
assert ga1 != ga2
73+
74+
v1 = ga1.mv('v', 'vector', f=True)
75+
v2 = ga2.mv('v', 'vector', f=True)
76+
77+
with pytest.raises(ValueError):
78+
ga1.grad * v2
79+
with pytest.raises(ValueError):
80+
v1 * ga2.rgrad
81+
with pytest.raises(ValueError):
82+
ga1.grad * ga2.grad

0 commit comments

Comments
 (0)