Commutation 1.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- commutation/__init__.py +5 -0
- commutation/commutatoralgebra.py +248 -0
- commutation/expression.py +592 -0
- commutation/style.py +30 -0
- commutation-1.5.0.dist-info/METADATA +101 -0
- commutation-1.5.0.dist-info/RECORD +9 -0
- commutation-1.5.0.dist-info/WHEEL +5 -0
- commutation-1.5.0.dist-info/licenses/LICENSE +675 -0
- commutation-1.5.0.dist-info/top_level.txt +1 -0
commutation/__init__.py
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
from .expression import Operator, Term, Expression
|
|
2
|
+
from warnings import warn
|
|
3
|
+
|
|
4
|
+
class CommutatorUnknownException(Exception):
|
|
5
|
+
def __init__(self, o1, o2):
|
|
6
|
+
super().__init__(f"commutator algebra does not know [{o1}, {o2}]_-")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AntiCommutatorUnknownException(Exception):
|
|
10
|
+
def __init__(self, o1, o2):
|
|
11
|
+
super().__init__(f"anticommutator algebra does not know [{o1}, {o2}]_+")
|
|
12
|
+
|
|
13
|
+
class AbstractCommutatorAlgebra:
|
|
14
|
+
def __init__(self, strict=False):
|
|
15
|
+
self.strict = strict
|
|
16
|
+
self.relations = {}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _add_operator(self, op, default_self, default_rel):
|
|
20
|
+
assert isinstance(op, Operator)
|
|
21
|
+
s = str(op)
|
|
22
|
+
|
|
23
|
+
if s not in self.relations:
|
|
24
|
+
col = {}
|
|
25
|
+
for k in self.relations:
|
|
26
|
+
self.relations[k][s] = default_rel
|
|
27
|
+
col[k] = default_rel
|
|
28
|
+
|
|
29
|
+
col[s] = default_self
|
|
30
|
+
self.relations[s] = col
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _move_right(self, r_mover, expr:Expression, A):
|
|
34
|
+
assert isinstance(A, Operator)
|
|
35
|
+
|
|
36
|
+
# Strategy: Go through each term in self.terms
|
|
37
|
+
# Within each term's operator list, iteratively keep moving it up in index using the elementary operation
|
|
38
|
+
# AB -> BA + [A, B]
|
|
39
|
+
# repeat until done
|
|
40
|
+
# expr = Expression(expr)
|
|
41
|
+
|
|
42
|
+
if A.name not in expr.operators:
|
|
43
|
+
return expr
|
|
44
|
+
|
|
45
|
+
extra_terms = Expression()
|
|
46
|
+
for term in expr.terms:
|
|
47
|
+
indices = reversed(term.findall(A))
|
|
48
|
+
|
|
49
|
+
for I in indices:
|
|
50
|
+
for i in range(I, len(term.ops) - 1):
|
|
51
|
+
assert term.ops[i] == A
|
|
52
|
+
extra_terms += r_mover(term, i)
|
|
53
|
+
|
|
54
|
+
self._move_right(r_mover, extra_terms, A)
|
|
55
|
+
expr.terms += extra_terms.terms
|
|
56
|
+
expr.collect()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _move_left(self, l_mover, expr:Expression, A):
|
|
60
|
+
'''
|
|
61
|
+
Moves all instances of the operator 'A' to the left of the expression.
|
|
62
|
+
'''
|
|
63
|
+
assert isinstance(A, Operator)
|
|
64
|
+
|
|
65
|
+
# # Strategy: Go through each term in self.terms
|
|
66
|
+
# # Within each term's operator list, iteratively keep moving it up in index using the elementary operation
|
|
67
|
+
# # AB -> BA + [A, B]
|
|
68
|
+
if A.name not in expr.operators:
|
|
69
|
+
return expr
|
|
70
|
+
|
|
71
|
+
extra_terms = Expression()
|
|
72
|
+
for term in expr.terms:
|
|
73
|
+
indices = term.findall(A)
|
|
74
|
+
for I in indices:
|
|
75
|
+
for i in range(I, 0, -1):
|
|
76
|
+
assert term.ops[i] == A
|
|
77
|
+
extra_terms += l_mover(term, i)
|
|
78
|
+
|
|
79
|
+
self._move_left(l_mover, extra_terms, A)
|
|
80
|
+
expr.terms += extra_terms.terms
|
|
81
|
+
expr.collect()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class CommutatorAlgebra(AbstractCommutatorAlgebra):
|
|
87
|
+
def add_operator(self, op):
|
|
88
|
+
if self.strict:
|
|
89
|
+
self._add_operator(op, 0, None)
|
|
90
|
+
else:
|
|
91
|
+
self._add_operator(op, 0, 0)
|
|
92
|
+
|
|
93
|
+
def set_commutator(self, l_op, r_op):
|
|
94
|
+
assert isinstance(l_op, Operator)
|
|
95
|
+
assert isinstance(r_op, Operator)
|
|
96
|
+
l = l_op.name
|
|
97
|
+
r = r_op.name
|
|
98
|
+
|
|
99
|
+
if l not in self.relations:
|
|
100
|
+
self.add_operator(l_op)
|
|
101
|
+
if r not in self.relations:
|
|
102
|
+
self.add_operator(r_op)
|
|
103
|
+
|
|
104
|
+
def setter(rhs):
|
|
105
|
+
rel = Expression(rhs) if rhs is not None else None
|
|
106
|
+
if l == r:
|
|
107
|
+
s = 'Setting [%s, %s] to something other than default (0) ... are you sure?' % (l, r)
|
|
108
|
+
warn(s)
|
|
109
|
+
if rel is None:
|
|
110
|
+
self.relations[l][r] = None
|
|
111
|
+
self.relations[r][l] = None
|
|
112
|
+
else:
|
|
113
|
+
self.relations[l][r] = rel
|
|
114
|
+
self.relations[r][l] = -rel
|
|
115
|
+
|
|
116
|
+
return setter
|
|
117
|
+
|
|
118
|
+
def get_commutator(self, l: Operator, r: Operator):
|
|
119
|
+
assert isinstance(l, Operator)
|
|
120
|
+
assert isinstance(r, Operator)
|
|
121
|
+
if l.is_scalar or r.is_scalar:
|
|
122
|
+
return 0
|
|
123
|
+
elif l.name not in self.relations:
|
|
124
|
+
s = 'Non-scalar operator "' + \
|
|
125
|
+
str(l)+'" is not in the commutator database, assuming it commutes...'
|
|
126
|
+
if self.strict:
|
|
127
|
+
raise CommutatorUnknownException(l, r)
|
|
128
|
+
else:
|
|
129
|
+
warn(s)
|
|
130
|
+
return 0
|
|
131
|
+
elif r.name not in self.relations:
|
|
132
|
+
s = 'Non-scalar operator "' + \
|
|
133
|
+
str(r)+'" is not in the commutator database, assuming it commutes...'
|
|
134
|
+
if self.strict:
|
|
135
|
+
raise CommutatorUnknownException(l, r)
|
|
136
|
+
else:
|
|
137
|
+
warn(s)
|
|
138
|
+
return 0
|
|
139
|
+
else:
|
|
140
|
+
return self.relations[l.name][r.name]
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _move_operator_right_once(self, term:Term, i):
|
|
144
|
+
front = Term(*term.ops[:i])
|
|
145
|
+
back = Term(*term.ops[i+2:])
|
|
146
|
+
|
|
147
|
+
c = self.get_commutator(term.ops[i], term.ops[i+1])
|
|
148
|
+
extra = front * c * back * term.multiplier
|
|
149
|
+
|
|
150
|
+
term.ops[i], term.ops[i+1] = term.ops[i+1], term.ops[i]
|
|
151
|
+
return extra
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _move_operator_left_once(self, term:Term, i, use_commutator=True):
|
|
155
|
+
A = term.ops[i]
|
|
156
|
+
B = term.ops[i-1]
|
|
157
|
+
front = Term(*term.ops[:i-1])
|
|
158
|
+
back = Term(*term.ops[i+1:])
|
|
159
|
+
|
|
160
|
+
c = self.get_commutator(A, B)
|
|
161
|
+
extra = front * c * back * term.multiplier
|
|
162
|
+
|
|
163
|
+
term.ops[i-1], term.ops[i] = term.ops[i], term.ops[i-1]
|
|
164
|
+
return extra
|
|
165
|
+
|
|
166
|
+
def move_right(self, expr:Expression, A):
|
|
167
|
+
self._move_right(self._move_operator_right_once, expr, A)
|
|
168
|
+
|
|
169
|
+
def move_left(self, expr:Expression, A):
|
|
170
|
+
self._move_left(self._move_operator_left_once, expr, A)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class AntiCommutatorAlgebra(AbstractCommutatorAlgebra):
|
|
175
|
+
def add_operator(self, op):
|
|
176
|
+
if self.strict:
|
|
177
|
+
self._add_operator(op, 2*op, None)
|
|
178
|
+
else:
|
|
179
|
+
self._add_operator(op, 2*op, None)
|
|
180
|
+
|
|
181
|
+
def set_anticommutator(self, l_op, r_op):
|
|
182
|
+
assert isinstance(l_op, Operator)
|
|
183
|
+
assert isinstance(r_op, Operator)
|
|
184
|
+
l = l_op.name
|
|
185
|
+
r = r_op.name
|
|
186
|
+
|
|
187
|
+
if l not in self.relations:
|
|
188
|
+
self.add_operator(l_op)
|
|
189
|
+
if r not in self.relations:
|
|
190
|
+
self.add_operator(r_op)
|
|
191
|
+
|
|
192
|
+
def setter(rhs):
|
|
193
|
+
rel = Expression(rhs) if rhs is not None else None
|
|
194
|
+
if l == r:
|
|
195
|
+
s = 'Setting {%s, %s} to something other than default (2%s) ... are you sure?' % (l, l, l)
|
|
196
|
+
warn(s)
|
|
197
|
+
self.relations[l][r] = rel
|
|
198
|
+
self.relations[r][l] = rel
|
|
199
|
+
|
|
200
|
+
return setter
|
|
201
|
+
|
|
202
|
+
def get_anticommutator(self, l, r):
|
|
203
|
+
assert isinstance(l, Operator)
|
|
204
|
+
assert isinstance(r, Operator)
|
|
205
|
+
if l.is_scalar or r.is_scalar:
|
|
206
|
+
return None # no Grassman for you
|
|
207
|
+
elif not (l.name in self.relations and r.name in self.relations):
|
|
208
|
+
return None # idk how to commute this
|
|
209
|
+
else:
|
|
210
|
+
return self.relations[l.name][r.name]
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def _move_operator_right_once(self, term:Term, i):
|
|
215
|
+
front = Term(*term.ops[:i])
|
|
216
|
+
back = Term(*term.ops[i+2:])
|
|
217
|
+
|
|
218
|
+
c = self.get_anticommutator(
|
|
219
|
+
term.ops[i], term.ops[i+1])
|
|
220
|
+
extra = Expression(front) * \
|
|
221
|
+
c * Expression(back)*term.multiplier
|
|
222
|
+
term.multiplier *= -1
|
|
223
|
+
|
|
224
|
+
term.ops[i], term.ops[i+1] = term.ops[i+1], term.ops[i]
|
|
225
|
+
return extra
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def _move_operator_left_once(self, term:Term, i):
|
|
229
|
+
A = term.ops[i]
|
|
230
|
+
B = term.ops[i-1]
|
|
231
|
+
front = Term(*term.ops[:i-1])
|
|
232
|
+
back = Term(*term.ops[i+1:])
|
|
233
|
+
|
|
234
|
+
c = self.get_anticommutator(A, B)
|
|
235
|
+
if c is None:
|
|
236
|
+
raise AntiCommutatorUnknownException(A, B)
|
|
237
|
+
extra = Expression(front) * c * Expression(back) * term.multiplier
|
|
238
|
+
term.multiplier *= -1
|
|
239
|
+
|
|
240
|
+
term.ops[i-1], term.ops[i] = term.ops[i], term.ops[i-1]
|
|
241
|
+
return extra
|
|
242
|
+
|
|
243
|
+
def move_right(self, expr:Expression, A):
|
|
244
|
+
self._move_right(self._move_operator_right_once, expr, A)
|
|
245
|
+
|
|
246
|
+
def move_left(self, expr:Expression, A):
|
|
247
|
+
self._move_left(self._move_operator_left_once, expr, A)
|
|
248
|
+
|