RKkit 0.1.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.
RKkit/README.md ADDED
@@ -0,0 +1,2 @@
1
+
2
+ The kernel is here.
RKkit/RKExceptions.py ADDED
@@ -0,0 +1,74 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Exceptions for the package RKkit
4
+ """
5
+ from sage.structure.sage_object import SageObject
6
+ from builtins import Exception
7
+ #
8
+ class DimensionsAreIncompatible(SageObject,Exception):
9
+ r"""
10
+ Exception raised when the sizes of A , B and C
11
+ in a Runge-Kutta are not equal.
12
+ """
13
+ def __init__(self,A,B,C):
14
+ self.An = A.dimensions()[0]
15
+ self.Bn = len(B)
16
+ self.Cn = len(C)
17
+ def __str__(self):
18
+ ret = "Butcher Array: dimension of A and B (or C) are not equal: " \
19
+ +str(self.An)+" , "+str(self.Bn)
20
+ if self.Cn != 0: ret+= " , "+str(self.Cn)
21
+ class RootsException(Exception):
22
+ r"""
23
+ Exception raised when the roots of a given polynomial
24
+ could not be *all* computed (with their multiplicity).
25
+ (We generally compute in QQbar, and we can meet Evariste Gallois).
26
+ """
27
+ def __init__(self,ncomp,pol):
28
+ self.ncomp = ncomp
29
+ self.degree = pol.degree
30
+ self.pol = pol
31
+ def __str__(self):
32
+ return "for " + str(self.pol) + " (degree= " + \
33
+ str(self.degree) + " ), only " \
34
+ +str(self.ncomp)+ " where computed."
35
+ class MatrixIsSingular(Exception):
36
+ """
37
+ Exception raised when a matrix is singular.
38
+ """
39
+ def __init__(self,t):
40
+ self.t = t
41
+ def __str__(self):
42
+ return "for the method "+self.t+ " is a singular matrix"
43
+ class GraphicProblem(Exception):
44
+ """
45
+ Exception raised when an error happens in a graphic.
46
+ """
47
+ def __init__(self,t):
48
+ self.t = t
49
+ def __str__(self):
50
+ return "Graphic problem: "+self.t
51
+ class MustBeExact(Exception):
52
+ """
53
+ Raised if we try to compute in a non exact set (RealField, for example).
54
+ """
55
+ def __init__(self,t):
56
+ self.t=t
57
+ def __str__(self):
58
+ return self.t
59
+ class NotA(Exception):
60
+ """
61
+ Raised if an object is not a matrix, vector, etc...
62
+ """
63
+ def __init__(self,t):
64
+ self.t=t
65
+ def __str__(self):
66
+ return self.t
67
+ class CollocPointNotGood(Exception):
68
+ """
69
+ Raised if a collocation point is not in [0,1]
70
+ """
71
+ def __init__(self,t):
72
+ self.t=t
73
+ def __str__(self):
74
+ return self.t
@@ -0,0 +1,52 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Implement somme non implemented computations (in Sage) for polynomials.
4
+ """
5
+ from sage.arith.power import generic_power
6
+ from sage.rings.qqbar import QQbar
7
+ from sage.rings.imaginary_unit import I
8
+
9
+ #
10
+ def conj(P):
11
+ """
12
+ Conjugate of a polynomial P.
13
+ """
14
+ Pc = P.coefficients()
15
+ x = P.parent().gen()
16
+ return sum([Pc[p] * generic_power(x,p) for p in range(0,len(Pc))\
17
+ if Pc[p].imag() == 0]) - \
18
+ sum([Pc[p] * generic_power(x,p) for p in range(0,len(Pc)) \
19
+ if Pc[p].imag() != 0])
20
+ def impart(P):
21
+ """
22
+ Imaginary part of a polynomial P.
23
+
24
+ (ie: compute sum Im P_i x^i only for P_i imaginary).
25
+
26
+ """
27
+ Pc = P.coefficients()
28
+ x = P.parent().gen()
29
+ Im = QQbar(I)
30
+ return sum([-Im * Pc[p]*generic_power(x,p) \
31
+ for p in range(0,len(Pc)) if Pc[p].imag() != 0])
32
+ def realpart(P):
33
+ """
34
+ Real part of a polynomial P.
35
+
36
+ (ie: compute sum P_i x^i only for P_i real).
37
+
38
+ """
39
+ x = P.parent().gen()
40
+ Pc = P.coefficients()
41
+ return sum([Pc[p] * generic_power(x,p) for p in range(0,len(Pc)) \
42
+ if Pc[p].imag() == 0])
43
+ def roots_checked(pol,R):
44
+ """
45
+ Check that, computing in the ring R, we can compute n roots (with their
46
+ multiplicity) for a polynomial pol of degree n.
47
+ """
48
+ q = pol.change_ring(R)
49
+ rac = q.roots()
50
+ n = sum([s[1] for s in rac])
51
+ return rac,pol.degree()== n, n
52
+
RKkit/RKRungeKutta.py ADDED
@@ -0,0 +1,30 @@
1
+ from sage.structure.sage_object import SageObject
2
+ from sage.structure.element import Matrix,Vector
3
+ from .RKExceptions import *
4
+ class RungeKutta(SageObject):
5
+ """
6
+ Base class for all Runge-Kutta methods.
7
+
8
+ """
9
+ def __init__(self,A,B,Title,C=[]):
10
+ if not A.parent().is_exact():
11
+ raise MustBeExact("RungeKutta: parent of A is not exact")
12
+ if not B.parent().is_exact():
13
+ raise MustBeExact("RungeKutta: parent of B is not exact")
14
+ if not isinstance(A,Matrix):
15
+ raise NotA("RungeKutta: A is not a matrix")
16
+ if not isinstance(B,Vector):
17
+ raise NotA("RungeKutta: B is not a vector")
18
+ if A.dimensions()[0] != A.dimensions()[1]\
19
+ or A.dimensions()[0] != len(B):
20
+ raise DimensionsAreIncompatible(A,B,C)
21
+ if C != [] and len(C) != A.dimensions()[0]:
22
+ raise DimensionsAreIncompatible(A,B,C)
23
+
24
+
25
+ self.A = A
26
+ self.B = B
27
+ self.Title = Title
28
+ self.C = C
29
+ def __str__(self):
30
+ return self.Title+"\n"+str(self.A)+"\n"+str(self.B)
RKkit/RKTrees.py ADDED
@@ -0,0 +1,114 @@
1
+ # -*- coding: utf-8 -*-
2
+ #*
3
+ from sage.structure.sage_object import SageObject
4
+ from sage.combinat.rooted_tree import RootedTree as RT
5
+ from sage.combinat.rooted_tree import RootedTrees_size as RTS
6
+ from sage.categories.sets_cat import cartesian_product
7
+ from sage.misc.misc_c import prod
8
+ #
9
+ class RKTrees(SageObject):
10
+ r"""
11
+ The rooted trees machinery.
12
+ EXAMPLES:
13
+
14
+ sage: R= RKTrees(n)
15
+
16
+ n is the maximum depth of the rooted trees you will use (the
17
+ built dictionary will be enlarged if necessary (lazzy evaluation)).
18
+
19
+ Bibliography: HW are the books of Hairer, Wanner and co-workers.
20
+ """
21
+ def __init__(self):
22
+ self.n = 1
23
+ self.dtrees = {}
24
+ self.expand(1)
25
+ def expand(self,l):
26
+ r"""
27
+ Extend the list of rooted trees up to depth l
28
+ """
29
+ for i in range(1,l+1):
30
+ if not i in self.dtrees:
31
+ self.dtrees[i] = RTS(i).list()
32
+ self.n=l
33
+ def gamma(self,t):
34
+ r"""
35
+ The gamma coefficient (see HW referenced books).
36
+ """
37
+ tn = t.node_number()
38
+ if tn == 1:
39
+ return 1
40
+ else:
41
+ return tn*prod([self.gamma(s) for s in t])
42
+ def _LabelledTree_to_formula(self,rtc,root_label,faclist):
43
+ if rtc.node_number() == 1:
44
+ faclist.append((root_label,rtc.label()))
45
+ else:
46
+ for t in rtc:
47
+ faclist.append((root_label,t.label()))
48
+ if t.node_number() > 1:
49
+ self._LabelledTree_to_formula(t,t.label(),faclist)
50
+ def tree_to_order_formula(self,rt):
51
+ rtc = rt.canonical_labelling()
52
+ faclist = []
53
+ self._LabelledTree_to_formula(rtc,rtc.label(),faclist)
54
+ return faclist
55
+ def eval_sum_prod(self,A,B,formula,v):
56
+ return B[v[0]] * prod( [A[v[i[0]-1],v[i[1]-1]] for i in formula] )
57
+ def tree_order_form(self,A,B,rt):
58
+ n = len(B)
59
+ s = set(range(0,n))
60
+ S = cartesian_product([s for i in range(0,rt.node_number())])
61
+ #
62
+ f = self.tree_to_order_formula(rt)
63
+ #
64
+ s = sum([self.eval_sum_prod(A,B,f,v) for v in S])
65
+ return s*self.gamma(rt)
66
+ def check_tree_order(self,A,B,rt):
67
+ return self.tree_order_form(A,B,rt) == 1
68
+ def check_order(self,A,B,order):
69
+ """
70
+ Prove that the rooted trees of order 'order' fullfill
71
+ the requirements.
72
+
73
+ To check if a Runge-Kutta formula as order 'n', one must call
74
+ check_order(A,B,i) for i in range(1,n+1).
75
+ """
76
+ if order == 1:
77
+ s = sum(B)
78
+ s.exactify()#should make sometime more readable results, may be.
79
+ return s == 1
80
+ else:
81
+ for i in range(len(self.dtrees)+1,order+1):
82
+ self.expand(i)
83
+ for t in self.dtrees[order]:
84
+ tc = t.canonical_labelling()
85
+ ok = self.check_tree_order(A,B,tc)
86
+ if not ok:
87
+ return False
88
+ return True
89
+
90
+ def symetry_coefficient(self,rt):
91
+ rt1 = RT(rt)
92
+ if rt1 == RT([]):
93
+ return 1
94
+ else:
95
+ l = [t for t in rt1]
96
+ l.sort()
97
+ ft = 1
98
+ f = 1
99
+ for i in range(0,len(l)-1):
100
+ if l[i] == l[i+1]:
101
+ f+= 1
102
+ else:
103
+ ft*= factorial(f)
104
+ f=1
105
+ if f != 1: ft*= factorial(f)
106
+ return prod([self.symetry_coefficient(s) for s in l])*ft
107
+ def compute_gamma(self):
108
+ r"""
109
+ This returns the '\gamma' coefficients (see HW).
110
+ """
111
+ self.gamma={}
112
+ for i in range(1,self.n+1):
113
+ for s in self.dtrees[i]:
114
+ self.gamma[s] = self.symetry_coefficient(s)
RKkit/RKcolloc.py ADDED
@@ -0,0 +1,71 @@
1
+ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
2
+ from sage.matrix.constructor import Matrix,matrix
3
+ from sage.modules.free_module_element import free_module_element,vector
4
+ from sage.rings.qqbar import QQbar, AA
5
+ from sage.functions.orthogonal_polys import legendre_P
6
+ from .RKRungeKutta import RungeKutta
7
+ from .RKExceptions import *
8
+ def colloc(c,P,title):
9
+ """
10
+ Given a list C of collocation points in [0,1], and an univariate polynomial
11
+ ring P (over an exact field -actually over AA-), build the A and B part
12
+ of the Butcher array of an associated Runge-Kutta method and return a
13
+ Runge-Kutta method class.
14
+
15
+ The "title" parameter is the name given to the generated Runge-Kurtta
16
+ method.
17
+
18
+ AUTHOR::
19
+
20
+ Thierry Dumont (2016, 2020).
21
+
22
+ EXAMPLES::
23
+
24
+ sage: R = PolynomialRing(AA,"x")
25
+ sage: n = 4
26
+ sage: x = P.gen()
27
+ sage: c = [(s[0]+1)/2 for s in R(legendre_P(n,x)).roots()]
28
+ sage: A,B = colloc(c,R,"Gauss 4")
29
+ """
30
+
31
+ Pb= P.base()
32
+ x = P.gen()
33
+ n = len(c)
34
+ #
35
+ for s in c:
36
+ if s <0 or s >1:
37
+ raise CollocPointNotGood(
38
+ "colloc: collocation point ",s," is out of [0,1]")
39
+ pols=[]
40
+ for i in range(0,n):
41
+ ploc=P(1)
42
+ for p in range(0,n):
43
+ if i!=p:
44
+ ploc *= P((x-c[p])/(Pb(c[i])-Pb(c[p])))
45
+ pols.append(ploc)
46
+
47
+ prims = [p.integral(x) for p in pols]
48
+ prims0 = [p(x = 0) for p in prims]
49
+ A = matrix(Pb,[ [prims[j](x = c[i]) - prims0[j] for j in range(0,n)] \
50
+ for i in range(0,n)])
51
+
52
+ B = [prims[j](x = 1) - prims0[j] for j in range(0,n)]
53
+ # exactify to improve lisibility, if possible!
54
+ if Pb is AA or Pb is QQbar:
55
+ for i in range(0,n):
56
+ for j in range(0,n):
57
+ A[i,j].exactify()
58
+ B[i].exactify()
59
+ B=vector(B)
60
+
61
+ def constructor(self):
62
+ # this will be the contructor of the class returned below.
63
+ self.Title=title
64
+ self.A = A
65
+ self.B = vector(B)
66
+ RungeKutta.__init__(self,A,B,self.Title)
67
+
68
+ return type("Colloc"+str(len(c)),(RungeKutta,),{
69
+ "__init__": constructor,
70
+ })
71
+