IntegralElimination 0.1.0__tar.gz

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.
Files changed (38) hide show
  1. integralelimination-0.1.0/IntegralElimination/IntegralAlgebra.py +312 -0
  2. integralelimination-0.1.0/IntegralElimination/IntegralMonomial.py +107 -0
  3. integralelimination-0.1.0/IntegralElimination/IntegralPolynomial.py +138 -0
  4. integralelimination-0.1.0/IntegralElimination/__init__.py +4 -0
  5. integralelimination-0.1.0/IntegralElimination/convert.py +38 -0
  6. integralelimination-0.1.0/IntegralElimination/critical_pairs.py +372 -0
  7. integralelimination-0.1.0/IntegralElimination/exponentials.py +191 -0
  8. integralelimination-0.1.0/IntegralElimination/integral_elimination.py +72 -0
  9. integralelimination-0.1.0/IntegralElimination/ordering.py +58 -0
  10. integralelimination-0.1.0/IntegralElimination/reduction.py +193 -0
  11. integralelimination-0.1.0/IntegralElimination/utils.py +63 -0
  12. integralelimination-0.1.0/IntegralElimination.egg-info/PKG-INFO +17 -0
  13. integralelimination-0.1.0/IntegralElimination.egg-info/SOURCES.txt +36 -0
  14. integralelimination-0.1.0/IntegralElimination.egg-info/dependency_links.txt +1 -0
  15. integralelimination-0.1.0/IntegralElimination.egg-info/requires.txt +4 -0
  16. integralelimination-0.1.0/IntegralElimination.egg-info/top_level.txt +1 -0
  17. integralelimination-0.1.0/LICENSE +304 -0
  18. integralelimination-0.1.0/PKG-INFO +17 -0
  19. integralelimination-0.1.0/README.md +2 -0
  20. integralelimination-0.1.0/setup.cfg +4 -0
  21. integralelimination-0.1.0/setup.py +23 -0
  22. integralelimination-0.1.0/tests/test01.py +19 -0
  23. integralelimination-0.1.0/tests/test02.py +19 -0
  24. integralelimination-0.1.0/tests/test03.py +19 -0
  25. integralelimination-0.1.0/tests/test04_LM_LC.py +20 -0
  26. integralelimination-0.1.0/tests/test05_internal_sympy_repr.py +18 -0
  27. integralelimination-0.1.0/tests/test06_cut_P.py +18 -0
  28. integralelimination-0.1.0/tests/test07_get_PI_PN.py +26 -0
  29. integralelimination-0.1.0/tests/test08_monomials_product.py +23 -0
  30. integralelimination-0.1.0/tests/test09_polynomials_product.py +24 -0
  31. integralelimination-0.1.0/tests/test10_integrate.py +24 -0
  32. integralelimination-0.1.0/tests/test11_reduced_product.py +23 -0
  33. integralelimination-0.1.0/tests/test12_power.py +26 -0
  34. integralelimination-0.1.0/tests/test13_reduced_power.py +24 -0
  35. integralelimination-0.1.0/tests/test14_reduce_simple_case.py +48 -0
  36. integralelimination-0.1.0/tests/test15_reduce_reduced_power.py +40 -0
  37. integralelimination-0.1.0/tests/test16_1_algo_reduce.py +27 -0
  38. integralelimination-0.1.0/tests/test16_2_algo_reduce.py +29 -0
@@ -0,0 +1,312 @@
1
+ import sympy as sp
2
+ from ordered_set import OrderedSet
3
+ from IPython.display import display, Math
4
+
5
+ from .ordering import IMO
6
+ from .IntegralMonomial import IM
7
+ from .utils import (
8
+ is_int,
9
+ ShuffleList
10
+ )
11
+ from .IntegralPolynomial import IntegralPolynomial
12
+ from .reduction import (
13
+ reduction_M_by_P_simple_case,
14
+ reduction_M_by_P_reduced_power,
15
+ reduction_M_by_P,
16
+ reduce,auto_reduce
17
+ )
18
+ from .critical_pairs import (
19
+ critical_pairs_PI_QI,
20
+ critical_pairs_PI_QN,
21
+ critical_pairs_PN_QN,
22
+ critical_pairs
23
+ )
24
+ from .exponentials import (
25
+ find_A_A0_G_F,
26
+ update_exp,
27
+ extend_X_with_exp
28
+ )
29
+ from .integral_elimination import integral_elimination
30
+
31
+ class IntegralAlgebra():
32
+ """
33
+ integral polynomials will be represented as follows :
34
+ eq = {IM(x(t):3, IM(y(t),1,y(t)):theta+lambda}
35
+ using eq.as_coefficients_dict(IM)
36
+ It means that eq is the sum of the two tuples
37
+ """
38
+ def __init__(self, order, parameters):
39
+ self.order = order
40
+ self.t = sp.Symbol("t")
41
+ self.used_order = order
42
+ self.IMO_le = lambda m1, m2 : IMO(m1, m2, self.used_order)
43
+ self.parameters = parameters
44
+
45
+
46
+ def update_IMO(self, order):
47
+ self.used_order = order
48
+ self.IMO = lambda m1, m2 : IMO(m1, m2, self.used_order)
49
+
50
+
51
+ def LM_LC(self, P:IntegralPolynomial) -> tuple[IM, sp.Expr]:
52
+ """
53
+ get leading monomials and coeff
54
+ """
55
+ L = list(P.dict.items())
56
+ LC, LM = L[0][1], L[0][0]
57
+ for M,coeff in L:
58
+ #if True then M <= LM, else M > LM
59
+ if self.IMO_le(M, LM) == False:
60
+ LM = M # im > LM
61
+ LC = coeff
62
+ return LM, LC
63
+
64
+
65
+ def display_rules(self, sys):
66
+ display(Math(r"\{"))
67
+ for eq in sys:
68
+ LM, LC = self.LM_LC(eq)
69
+ key = IntegralPolynomial(LC*LM)
70
+ value = self.polynomials_subtraction(eq, key)
71
+ arrow = r"{\Huge \color{red} \mathbf{\rightarrow}}"
72
+ key_repr = key.repr_display_math()
73
+ value_repr = value.repr_display_math()
74
+ export = Math(f"{key_repr} {arrow} {value_repr}")
75
+ display(export)
76
+ display(Math(r"\}"))
77
+
78
+
79
+ def normalize_LC_of_P(self,
80
+ P: IntegralPolynomial) -> IntegralPolynomial:
81
+ _, LC = self.LM_LC(P)
82
+ normalized_P = {}
83
+ for M, coeff in P.dict.items():
84
+ normalized_P[M] = coeff/LC
85
+ # Since we only have division
86
+ # coeffs can't be zero after
87
+ # a simplification process
88
+ # then, using copy=True, we disable de simplification
89
+ # to optimize the reduction process
90
+ return IntegralPolynomial(normalized_P,copy=True), LC
91
+
92
+ def monomials_product(self, M: IM, N: IM )-> IntegralPolynomial:
93
+ e = M.get_nb_int()
94
+ f = N.get_nb_int()
95
+ m0n0 = M.get_content()[0]*N.get_content()[0]
96
+ if e == f == 0:
97
+ MN = IM(m0n0)
98
+ elif e == 0 and f != 0:
99
+ N1p = N.cut("1+").get_content() #N1plus
100
+ MN = IM(m0n0,*N1p)
101
+ elif e != 0 and f== 0 :
102
+ M1p = M.cut("1+").get_content() #N1plus
103
+ MN = IM(m0n0,*M1p)
104
+ else:
105
+ N1p = N.cut("1+").get_content() #N1plus
106
+ M1p = M.cut("1+").get_content() #N1plus
107
+ sh = ShuffleList(M1p,N1p)
108
+ MN = sp.Add(*[IM(m0n0,*elem) for elem in sh])
109
+ return IntegralPolynomial(MN)
110
+
111
+ def product_P_Coeff(self,
112
+ P: IntegralPolynomial,
113
+ alpha: sp.Expr) -> IntegralPolynomial:
114
+ """
115
+ alpha is cst
116
+ """
117
+ alpha_P = {}
118
+ for M in P.dict:
119
+ alpha_P[M] = P.dict[M]*alpha
120
+ return IntegralPolynomial(alpha_P)
121
+
122
+ def polynomials_add(self,
123
+ P: IntegralPolynomial,
124
+ Q: IntegralPolynomial) -> IntegralPolynomial:
125
+ PplusQ = P.copy().dict
126
+ for N in Q.dict:
127
+ c_N = Q.dict[N]
128
+ if N not in PplusQ:
129
+ PplusQ[N] = c_N
130
+ else:
131
+ PplusQ[N] += c_N
132
+ PplusQ = {M:coeff for M, coeff in PplusQ.items() if coeff != 0}
133
+ return IntegralPolynomial(PplusQ)
134
+
135
+ def polynomials_subtraction(self,
136
+ P: IntegralPolynomial,
137
+ Q: IntegralPolynomial) -> IntegralPolynomial:
138
+ PminusQ = P.copy().dict
139
+ for N in Q.dict:
140
+ c_N = Q.dict[N]
141
+ if N not in PminusQ:
142
+ PminusQ[N] = -c_N
143
+ else:
144
+ PminusQ[N] -= c_N
145
+ PminusQ = {M:coeff for M, coeff in PminusQ.items() if coeff != 0}
146
+ return IntegralPolynomial(PminusQ)
147
+
148
+ def polynomials_product(self,
149
+ P: IntegralPolynomial,
150
+ Q: IntegralPolynomial) -> IntegralPolynomial:
151
+ PQ = IntegralPolynomial(0)
152
+ for M_P, c_P in P.dict.items():
153
+ for M_Q, c_Q in Q.dict.items():
154
+ M_PdotM_Q = self.monomials_product(M_P,M_Q)
155
+ c_P_c_Q_M_PdotM_Q = self.product_P_Coeff(M_PdotM_Q, c_P*c_Q)
156
+ PQ = self.polynomials_add(PQ, c_P_c_Q_M_PdotM_Q)
157
+ return PQ
158
+
159
+ def integrate_monomial(self, M: IM):
160
+ return IM(1,*M.get_content())
161
+
162
+ def integrate_polynomial(self,
163
+ P: IntegralPolynomial) -> IntegralPolynomial:
164
+ Int_P = {}
165
+ for M, coeff in P.dict.items():
166
+ Int_M = self.integrate_monomial(M)
167
+ Int_P[Int_M] = coeff
168
+ return IntegralPolynomial(Int_P)
169
+
170
+ def add_prefix_to_polynomial(self,
171
+ prefix: IM,
172
+ P: IntegralPolynomial) -> IntegralPolynomial:
173
+ new_P = {}
174
+ for M, coeff in P.dict.items():
175
+ pref_M = M.add_prefix(prefix)
176
+ new_P[pref_M] = coeff
177
+ return IntegralPolynomial(new_P)
178
+
179
+ def reduced_product(self,
180
+ P:IntegralPolynomial,
181
+ M:IM) -> IntegralPolynomial:
182
+ """
183
+ see section 3.1
184
+
185
+ reduced_product = (P \cdot \int M) - \int (M \cdot P)
186
+ """
187
+ M = IntegralPolynomial(M)
188
+ IntM = self.integrate_polynomial(M)
189
+
190
+ #(P \cdot \int M)
191
+ PdotIntM = self.polynomials_product(P,IntM)
192
+
193
+ #\int (M \cdot P)
194
+ IntMdotP = self.integrate_polynomial(
195
+ self.polynomials_product(M,P)
196
+ )
197
+
198
+ reduced_product = self.polynomials_add(
199
+ PdotIntM ,self.product_P_Coeff(IntMdotP, -1)
200
+ )
201
+ return reduced_product
202
+
203
+ def polynomial_power(self,
204
+ P:IntegralPolynomial,
205
+ n:int) -> IntegralPolynomial:
206
+ assert is_int(n)
207
+ assert isinstance(P,IntegralPolynomial)
208
+ if n == 0: return IntegralPolynomial(IM(1))
209
+ P_pow_n = P
210
+ for _ in range(n-1):
211
+ P_pow_n = self.polynomials_product(P_pow_n,P)
212
+ return P_pow_n
213
+
214
+ def reduced_power(self,
215
+ P:IntegralPolynomial,
216
+ n:int) -> IntegralPolynomial:
217
+ """
218
+ see section 3.2
219
+
220
+ P^{\circled{n}} = n (\int (P_I[cut{1+}] cdot P_N^{n-1})) + P_N^n
221
+ """
222
+ assert is_int(n) and n >= 1
223
+ P_I = P.get_P_I()
224
+ P_N = P.get_P_N()
225
+ P_I_1plus = P_I.cut_P("1+")
226
+ P_N_pow_n_minus_one = self.polynomial_power(P_N, n-1)
227
+ P_N_pow_n = self.polynomials_product(P_N_pow_n_minus_one, P_N)
228
+
229
+ #lets compute n (\int (P_I[cut{1+}] cdot P_N^{n-1})) in temp
230
+ temp = self.integrate_polynomial(
231
+ self.polynomials_product(P_I_1plus, P_N_pow_n_minus_one)
232
+ )
233
+ temp = self.product_P_Coeff(temp, n)
234
+
235
+ reduced_power = self.polynomials_add(temp, P_N_pow_n)
236
+ return reduced_power
237
+
238
+ def reduction_M_by_P_simple_case(self,
239
+ M: IM,
240
+ P: IntegralPolynomial
241
+ ) -> IntegralPolynomial:
242
+ return reduction_M_by_P_simple_case(self, M, P)
243
+
244
+ def reduction_M_by_P_reduced_power(self,
245
+ M: IM,
246
+ P: IntegralPolynomial
247
+ ) -> IntegralPolynomial:
248
+ return reduction_M_by_P_reduced_power(self, M, P)
249
+
250
+ def reduction_M_by_P(self,
251
+ M: IM,
252
+ P: IntegralPolynomial
253
+ ) -> IntegralPolynomial:
254
+ return reduction_M_by_P(self,M,P)
255
+
256
+ def reduce(self,
257
+ Q: IntegralPolynomial,
258
+ T: OrderedSet[IntegralPolynomial]
259
+ ) -> IntegralPolynomial:
260
+ return reduce(self,Q,T)
261
+
262
+ def auto_reduce(self,
263
+ T:OrderedSet[IntegralPolynomial]
264
+ ) -> OrderedSet[IntegralPolynomial]:
265
+ return auto_reduce(self,T)
266
+
267
+ def critical_pairs_PI_QI(self,
268
+ P: IntegralPolynomial,
269
+ Q: IntegralPolynomial) -> IntegralPolynomial:
270
+ return critical_pairs_PI_QI(self,P,Q)
271
+
272
+ def critical_pairs_PI_QN(self,
273
+ P: IntegralPolynomial,
274
+ Q: IntegralPolynomial) -> IntegralPolynomial:
275
+ return critical_pairs_PI_QN(self,P,Q)
276
+
277
+ def critical_pairs_PN_QN(self,
278
+ P: IntegralPolynomial,
279
+ Q: IntegralPolynomial) -> IntegralPolynomial:
280
+ return critical_pairs_PN_QN(self,P,Q)
281
+
282
+ def critical_pairs(self,
283
+ R: OrderedSet[IntegralPolynomial]
284
+ ) -> OrderedSet [IntegralPolynomial]:
285
+ return critical_pairs(self,R)
286
+
287
+ def find_A_A0_G_F(self,
288
+ P:IntegralPolynomial
289
+ ) -> tuple[IntegralPolynomial]:
290
+ return find_A_A0_G_F(self,P)
291
+
292
+ def update_exp(self,
293
+ T_prime: OrderedSet[IntegralPolynomial],
294
+ E: OrderedSet[sp.Function, sp.Function, IntegralPolynomial]
295
+ ) -> tuple:
296
+ return update_exp(self,T_prime,E)
297
+
298
+ def extend_X_with_exp(self,
299
+ E: set[sp.Function, sp.Function, IntegralPolynomial]
300
+ ) -> list:
301
+ return extend_X_with_exp(self, E)
302
+
303
+ def integral_elimination(self,
304
+ F: OrderedSet[IntegralPolynomial],
305
+ disable_exp: bool = False,
306
+ disable_critical_pairs: bool = False,
307
+ nb_iter: int = 0) -> tuple:
308
+ return integral_elimination(self,
309
+ F,
310
+ disable_exp=disable_exp,
311
+ disable_critical_pairs=disable_critical_pairs,
312
+ nb_iter=nb_iter)
@@ -0,0 +1,107 @@
1
+ import sympy as sp
2
+
3
+ from .utils import (
4
+ has_add_in_list,
5
+ is_float
6
+ )
7
+
8
+ def has_multiplicative_constant(expr):
9
+ """
10
+ Search if expr has a multiplicative cst != than 1
11
+ """
12
+ if is_float(expr):
13
+ if expr == 1:
14
+ return False
15
+ else:
16
+ return True
17
+ elif expr.is_Mul:
18
+ factors = expr.as_ordered_factors()
19
+ for factor in factors:
20
+ if factor.is_number and factor != 1:
21
+ return True
22
+ return False
23
+
24
+
25
+ class IM(sp.Function):
26
+ def __init__(self, *args):
27
+ self.c = (*args,)
28
+ self.t = sp.Symbol("t")
29
+
30
+ assert "IM" not in str(self.c)
31
+ assert not has_add_in_list(self.c)
32
+
33
+ #check if parameters (symbols) are in self.c
34
+ assert not any([
35
+ len(elem.free_symbols - {self.t})
36
+ for elem in self.c if not is_float(elem)
37
+ ])
38
+ #check that every multiplicative csts are 1
39
+ assert not any([
40
+ has_multiplicative_constant(elem)
41
+ for elem in self.c
42
+ ])
43
+
44
+ def get_nb_int(self):
45
+ return len(self.c) - 1
46
+
47
+ def get_content(self):
48
+ return self.c
49
+
50
+ def cut(self, cut_type):
51
+ """
52
+ See Definition 7
53
+ """
54
+ if cut_type == "0":
55
+ return IM(self.c[0])
56
+
57
+ elif cut_type == "1":
58
+ assert self.get_nb_int() >= 1
59
+ return IM(self.c[1])
60
+
61
+ elif cut_type == "1+":
62
+ assert self.get_nb_int() >= 1
63
+ return IM(*self.c[1:])
64
+
65
+ elif cut_type == "i1+":
66
+ if self.get_nb_int() == 0:
67
+ return IM(1)
68
+ else:
69
+ return IM(1,*self.c[1:])
70
+
71
+ elif cut_type == "i2+":
72
+ if self.get_nb_int() == 1:
73
+ return IM(1)
74
+ else:
75
+ assert self.get_nb_int() >= 2
76
+ return IM(1,*self.c[2:])
77
+ else:
78
+ raise NotImplementedError
79
+
80
+ def get_suffix(self, i):
81
+ assert 0 <= i <= self.get_nb_int()
82
+ return IM(*self.get_content()[i:])
83
+
84
+ def get_prefix(self, i):
85
+ assert 0 <= i <= self.get_nb_int()
86
+ return IM(*self.get_content()[:i])
87
+
88
+ def add_prefix(self, M):
89
+ prefixed_M = IM(*M.get_content(),*self.get_content())
90
+ return prefixed_M
91
+
92
+ def __str__(self):
93
+ return f"IM({str(self.c)[1:-1]})"
94
+
95
+ def get_sympy_repr(self):
96
+ if len(self.c) > 1:
97
+ expr = sp.Integral(self.c[-1], self.t)
98
+ for e in reversed(self.c[1:-1]):
99
+ expr = (sp.Integral(e*expr, self.t))
100
+ expr = self.c[0]*expr
101
+ elif len(self.c) == 1:
102
+ expr = self.c[0]
103
+ return expr
104
+
105
+ def _latex(self, printer=None):
106
+ return f"{printer.doprint(self.get_sympy_repr())}"
107
+
@@ -0,0 +1,138 @@
1
+ import sympy as sp
2
+ import sympy.printing as printing
3
+
4
+ from .IntegralMonomial import IM
5
+ from .utils import is_float
6
+
7
+
8
+ class IntegralPolynomial():
9
+
10
+ def __init__(self,
11
+ P,
12
+ copy=False):
13
+ if type(P) == dict:
14
+ self.dict = {}
15
+ if not copy:
16
+ for M, coeff in P.items():
17
+ coeff = sp.cancel(coeff)
18
+ if coeff != 0:
19
+ self.dict[M] = coeff
20
+ else:
21
+ for k,coeff in P.items():
22
+ self.dict[k] = coeff
23
+ elif isinstance(P, sp.Expr):
24
+ self.dict = dict(P.as_coefficients_dict(IM))
25
+ elif P == 0:
26
+ self.dict = {}
27
+ else:
28
+ raise SyntaxError
29
+
30
+ def get_sympy_repr(self):
31
+ L = self.dict.items()
32
+ sympy_repr = sp.Add(*[coeff*M for M,coeff in L])
33
+ return sympy_repr
34
+
35
+ def add_alpha_M(self, alpha, M):
36
+ if M in self.dict:
37
+ new_coeff = sp.cancel(alpha + self.dict[M])
38
+ if new_coeff !=0:
39
+ self.dict[M] = new_coeff
40
+ else:
41
+ del self.dict[M]
42
+ else:
43
+ self.dict[M] = alpha
44
+
45
+ def is_zero(self):
46
+ return len(self.dict) ==0
47
+
48
+ def __repr__(self):
49
+ return f"IntegralPolynomial({self.get_sympy_repr()})"
50
+
51
+ def repr_display_math(self):
52
+ return '{}'.format(printing.latex(self.get_sympy_repr()))
53
+
54
+ def _repr_latex_(self):
55
+ return '${}$'.format(printing.latex(self.get_sympy_repr()))
56
+
57
+ def copy(self):
58
+ # d = copy.deepcopy(self.dict)
59
+ d = self.dict
60
+ #avoid sp simplify on coeff when copy
61
+ return IntegralPolynomial(d, copy=True)
62
+
63
+ def cut_P(self, cut_type: str):
64
+ """
65
+ Definition 8 of Contribution to Integral Elimination
66
+ We simply extend the cut method of the Integral Monomial class to
67
+ integral polynomials
68
+
69
+ Disclaimer: this method will throw an error if you use it on
70
+ polynomial that can't be cutted
71
+ for exemple, trying to cut a pol with monomials of depth < 2 will
72
+ throw an error if you cut using i2+
73
+ """
74
+ P_cutted = {}
75
+ P = self.dict.items()
76
+ for M,coeff in P:
77
+ M_cutted = M.cut(cut_type)
78
+ if P_cutted.get(M_cutted) is None:
79
+ P_cutted[M_cutted] = coeff
80
+ else:
81
+ P_cutted[M_cutted] += coeff
82
+ return IntegralPolynomial(P_cutted)
83
+
84
+ def get_P_I(self):
85
+ P_I = {}
86
+ P = self.dict.items()
87
+ for M,coeff in P:
88
+ M0 = M.cut("0")
89
+ if M.get_nb_int() >= 1 and M0 == IM(1):
90
+ if M not in P_I:
91
+ P_I[M] = coeff
92
+ else:
93
+ # we are not supposed to have this case
94
+ raise ValueError
95
+ # we avoid the simplification process of the coeffs
96
+ # by using copy=True
97
+ return IntegralPolynomial(P_I, copy=True)
98
+
99
+ def get_P_N(self):
100
+ P_N = {}
101
+ P = self.dict.items()
102
+ for M,coeff in P:
103
+ M0 = M.cut("0")
104
+ if M==IM(1): #cst
105
+ P_N[M] = coeff
106
+ elif M0 != IM(1):
107
+ if M not in P_N:
108
+ P_N[M] = coeff
109
+ else:
110
+ # we are not supposed to have this case
111
+ raise ValueError
112
+ # we avoid the simplification process of the coeffs
113
+ # by using copy=True
114
+ return IntegralPolynomial(P_N, copy=True)
115
+
116
+ def get_cst_terms(self):
117
+ CST = {}
118
+ P = self.dict.items()
119
+ for M,coeff in P:
120
+ if M == IM(1):
121
+ if M in CST:
122
+ CST[M] += coeff
123
+ else:
124
+ CST[M] = coeff
125
+ return IntegralPolynomial(CST)
126
+
127
+ def get_time_dependant_functions(self):
128
+ """
129
+ example: if you have
130
+ P = IntegralPolynomial(IM(x(t)) - x(0)*IM(1)
131
+ - theta*IM(1,x(t)*y(t)**2) - IM(1,y(t)))
132
+ it will return {x,y}
133
+ """
134
+ res = set()
135
+ for f in self.get_sympy_repr().atoms(sp.Function):
136
+ if f.func != IM and not is_float(f.args[0]):
137
+ res.add(f)
138
+ return res
@@ -0,0 +1,4 @@
1
+ from .IntegralAlgebra import *
2
+ from .IntegralMonomial import *
3
+ from .IntegralPolynomial import *
4
+ from .convert import *
@@ -0,0 +1,38 @@
1
+ import sympy as sp
2
+ from ordered_set import OrderedSet
3
+
4
+ from .utils import expr_has_symbol
5
+ from .IntegralMonomial import IM
6
+ from .IntegralPolynomial import IntegralPolynomial
7
+
8
+
9
+ def first_order_ODE_to_IntegralPolynomial(
10
+ expr:sp.Expr,
11
+ var=sp.Symbol("t")
12
+ ) -> IntegralPolynomial:
13
+ expr = sp.expand(expr)
14
+ dict_coeff = dict(expr.as_coefficients_dict(var))
15
+ P = IntegralPolynomial(0)
16
+ if expr_has_symbol(expr, sp.Integral): raise ValueError
17
+ expr_has_der = expr_has_symbol(expr,sp.Derivative)
18
+ for mons, coeff in dict_coeff.items():
19
+ if mons.func == sp.Derivative :
20
+ assert mons.args[1][1] == 1
21
+ m = mons.args[0]
22
+ CI = sp.Symbol(f"{m.func}0")
23
+ M = IM(m)
24
+ P.add_alpha_M(coeff, M)
25
+ P.add_alpha_M(-CI,IM(1))
26
+ else:
27
+ if expr_has_der:
28
+ M = IM(1,mons)
29
+ P.add_alpha_M(coeff,M)
30
+ else:
31
+ M = IM(mons)
32
+ P.add_alpha_M(coeff,M)
33
+ return P
34
+
35
+ def ODE_sys_to_Integral_sys(sys: list[sp.Expr]
36
+ ) -> OrderedSet[IntegralPolynomial]:
37
+ sys = OrderedSet([first_order_ODE_to_IntegralPolynomial(eq) for eq in sys])
38
+ return sys