Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- lib/python3.10/site-packages/sympy/categories/__pycache__/baseclasses.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/categories/__pycache__/diagram_drawing.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/categories/tests/__init__.py +0 -0
- lib/python3.10/site-packages/sympy/categories/tests/test_baseclasses.py +209 -0
- lib/python3.10/site-packages/sympy/categories/tests/test_drawing.py +919 -0
- lib/python3.10/site-packages/sympy/codegen/__pycache__/__init__.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/__pycache__/abstract_nodes.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/__pycache__/algorithms.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/__pycache__/approximations.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/__pycache__/ast.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/__pycache__/cfunctions.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/__pycache__/cnodes.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/__pycache__/cutils.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/__pycache__/cxxnodes.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/__pycache__/fnodes.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/__pycache__/futils.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/__pycache__/matrix_nodes.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/__pycache__/numpy_nodes.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/__pycache__/pynodes.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/__pycache__/pyutils.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/__pycache__/rewriting.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/__pycache__/scipy_nodes.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/tests/__init__.py +0 -0
- lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/__init__.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_abstract_nodes.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_algorithms.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_applications.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_approximations.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_ast.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_cfunctions.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_cnodes.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_cxxnodes.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_fnodes.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_matrix_nodes.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_numpy_nodes.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_pynodes.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_pyutils.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_rewriting.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_scipy_nodes.cpython-310.pyc +0 -0
- lib/python3.10/site-packages/sympy/codegen/tests/test_abstract_nodes.py +14 -0
- lib/python3.10/site-packages/sympy/codegen/tests/test_algorithms.py +179 -0
- lib/python3.10/site-packages/sympy/codegen/tests/test_applications.py +57 -0
- lib/python3.10/site-packages/sympy/codegen/tests/test_approximations.py +53 -0
- lib/python3.10/site-packages/sympy/codegen/tests/test_ast.py +661 -0
- lib/python3.10/site-packages/sympy/codegen/tests/test_cfunctions.py +165 -0
- lib/python3.10/site-packages/sympy/codegen/tests/test_cnodes.py +112 -0
- lib/python3.10/site-packages/sympy/codegen/tests/test_cxxnodes.py +14 -0
- lib/python3.10/site-packages/sympy/codegen/tests/test_fnodes.py +213 -0
- lib/python3.10/site-packages/sympy/codegen/tests/test_matrix_nodes.py +50 -0
- lib/python3.10/site-packages/sympy/codegen/tests/test_numpy_nodes.py +50 -0
lib/python3.10/site-packages/sympy/categories/__pycache__/baseclasses.cpython-310.pyc
ADDED
|
Binary file (28.3 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/categories/__pycache__/diagram_drawing.cpython-310.pyc
ADDED
|
Binary file (65.5 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/categories/tests/__init__.py
ADDED
|
File without changes
|
lib/python3.10/site-packages/sympy/categories/tests/test_baseclasses.py
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.categories import (Object, Morphism, IdentityMorphism,
|
| 2 |
+
NamedMorphism, CompositeMorphism,
|
| 3 |
+
Diagram, Category)
|
| 4 |
+
from sympy.categories.baseclasses import Class
|
| 5 |
+
from sympy.testing.pytest import raises
|
| 6 |
+
from sympy.core.containers import (Dict, Tuple)
|
| 7 |
+
from sympy.sets import EmptySet
|
| 8 |
+
from sympy.sets.sets import FiniteSet
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def test_morphisms():
|
| 12 |
+
A = Object("A")
|
| 13 |
+
B = Object("B")
|
| 14 |
+
C = Object("C")
|
| 15 |
+
D = Object("D")
|
| 16 |
+
|
| 17 |
+
# Test the base morphism.
|
| 18 |
+
f = NamedMorphism(A, B, "f")
|
| 19 |
+
assert f.domain == A
|
| 20 |
+
assert f.codomain == B
|
| 21 |
+
assert f == NamedMorphism(A, B, "f")
|
| 22 |
+
|
| 23 |
+
# Test identities.
|
| 24 |
+
id_A = IdentityMorphism(A)
|
| 25 |
+
id_B = IdentityMorphism(B)
|
| 26 |
+
assert id_A.domain == A
|
| 27 |
+
assert id_A.codomain == A
|
| 28 |
+
assert id_A == IdentityMorphism(A)
|
| 29 |
+
assert id_A != id_B
|
| 30 |
+
|
| 31 |
+
# Test named morphisms.
|
| 32 |
+
g = NamedMorphism(B, C, "g")
|
| 33 |
+
assert g.name == "g"
|
| 34 |
+
assert g != f
|
| 35 |
+
assert g == NamedMorphism(B, C, "g")
|
| 36 |
+
assert g != NamedMorphism(B, C, "f")
|
| 37 |
+
|
| 38 |
+
# Test composite morphisms.
|
| 39 |
+
assert f == CompositeMorphism(f)
|
| 40 |
+
|
| 41 |
+
k = g.compose(f)
|
| 42 |
+
assert k.domain == A
|
| 43 |
+
assert k.codomain == C
|
| 44 |
+
assert k.components == Tuple(f, g)
|
| 45 |
+
assert g * f == k
|
| 46 |
+
assert CompositeMorphism(f, g) == k
|
| 47 |
+
|
| 48 |
+
assert CompositeMorphism(g * f) == g * f
|
| 49 |
+
|
| 50 |
+
# Test the associativity of composition.
|
| 51 |
+
h = NamedMorphism(C, D, "h")
|
| 52 |
+
|
| 53 |
+
p = h * g
|
| 54 |
+
u = h * g * f
|
| 55 |
+
|
| 56 |
+
assert h * k == u
|
| 57 |
+
assert p * f == u
|
| 58 |
+
assert CompositeMorphism(f, g, h) == u
|
| 59 |
+
|
| 60 |
+
# Test flattening.
|
| 61 |
+
u2 = u.flatten("u")
|
| 62 |
+
assert isinstance(u2, NamedMorphism)
|
| 63 |
+
assert u2.name == "u"
|
| 64 |
+
assert u2.domain == A
|
| 65 |
+
assert u2.codomain == D
|
| 66 |
+
|
| 67 |
+
# Test identities.
|
| 68 |
+
assert f * id_A == f
|
| 69 |
+
assert id_B * f == f
|
| 70 |
+
assert id_A * id_A == id_A
|
| 71 |
+
assert CompositeMorphism(id_A) == id_A
|
| 72 |
+
|
| 73 |
+
# Test bad compositions.
|
| 74 |
+
raises(ValueError, lambda: f * g)
|
| 75 |
+
|
| 76 |
+
raises(TypeError, lambda: f.compose(None))
|
| 77 |
+
raises(TypeError, lambda: id_A.compose(None))
|
| 78 |
+
raises(TypeError, lambda: f * None)
|
| 79 |
+
raises(TypeError, lambda: id_A * None)
|
| 80 |
+
|
| 81 |
+
raises(TypeError, lambda: CompositeMorphism(f, None, 1))
|
| 82 |
+
|
| 83 |
+
raises(ValueError, lambda: NamedMorphism(A, B, ""))
|
| 84 |
+
raises(NotImplementedError, lambda: Morphism(A, B))
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
def test_diagram():
|
| 88 |
+
A = Object("A")
|
| 89 |
+
B = Object("B")
|
| 90 |
+
C = Object("C")
|
| 91 |
+
|
| 92 |
+
f = NamedMorphism(A, B, "f")
|
| 93 |
+
g = NamedMorphism(B, C, "g")
|
| 94 |
+
id_A = IdentityMorphism(A)
|
| 95 |
+
id_B = IdentityMorphism(B)
|
| 96 |
+
|
| 97 |
+
empty = EmptySet
|
| 98 |
+
|
| 99 |
+
# Test the addition of identities.
|
| 100 |
+
d1 = Diagram([f])
|
| 101 |
+
|
| 102 |
+
assert d1.objects == FiniteSet(A, B)
|
| 103 |
+
assert d1.hom(A, B) == (FiniteSet(f), empty)
|
| 104 |
+
assert d1.hom(A, A) == (FiniteSet(id_A), empty)
|
| 105 |
+
assert d1.hom(B, B) == (FiniteSet(id_B), empty)
|
| 106 |
+
|
| 107 |
+
assert d1 == Diagram([id_A, f])
|
| 108 |
+
assert d1 == Diagram([f, f])
|
| 109 |
+
|
| 110 |
+
# Test the addition of composites.
|
| 111 |
+
d2 = Diagram([f, g])
|
| 112 |
+
homAC = d2.hom(A, C)[0]
|
| 113 |
+
|
| 114 |
+
assert d2.objects == FiniteSet(A, B, C)
|
| 115 |
+
assert g * f in d2.premises.keys()
|
| 116 |
+
assert homAC == FiniteSet(g * f)
|
| 117 |
+
|
| 118 |
+
# Test equality, inequality and hash.
|
| 119 |
+
d11 = Diagram([f])
|
| 120 |
+
|
| 121 |
+
assert d1 == d11
|
| 122 |
+
assert d1 != d2
|
| 123 |
+
assert hash(d1) == hash(d11)
|
| 124 |
+
|
| 125 |
+
d11 = Diagram({f: "unique"})
|
| 126 |
+
assert d1 != d11
|
| 127 |
+
|
| 128 |
+
# Make sure that (re-)adding composites (with new properties)
|
| 129 |
+
# works as expected.
|
| 130 |
+
d = Diagram([f, g], {g * f: "unique"})
|
| 131 |
+
assert d.conclusions == Dict({g * f: FiniteSet("unique")})
|
| 132 |
+
|
| 133 |
+
# Check the hom-sets when there are premises and conclusions.
|
| 134 |
+
assert d.hom(A, C) == (FiniteSet(g * f), FiniteSet(g * f))
|
| 135 |
+
d = Diagram([f, g], [g * f])
|
| 136 |
+
assert d.hom(A, C) == (FiniteSet(g * f), FiniteSet(g * f))
|
| 137 |
+
|
| 138 |
+
# Check how the properties of composite morphisms are computed.
|
| 139 |
+
d = Diagram({f: ["unique", "isomorphism"], g: "unique"})
|
| 140 |
+
assert d.premises[g * f] == FiniteSet("unique")
|
| 141 |
+
|
| 142 |
+
# Check that conclusion morphisms with new objects are not allowed.
|
| 143 |
+
d = Diagram([f], [g])
|
| 144 |
+
assert d.conclusions == Dict({})
|
| 145 |
+
|
| 146 |
+
# Test an empty diagram.
|
| 147 |
+
d = Diagram()
|
| 148 |
+
assert d.premises == Dict({})
|
| 149 |
+
assert d.conclusions == Dict({})
|
| 150 |
+
assert d.objects == empty
|
| 151 |
+
|
| 152 |
+
# Check a SymPy Dict object.
|
| 153 |
+
d = Diagram(Dict({f: FiniteSet("unique", "isomorphism"), g: "unique"}))
|
| 154 |
+
assert d.premises[g * f] == FiniteSet("unique")
|
| 155 |
+
|
| 156 |
+
# Check the addition of components of composite morphisms.
|
| 157 |
+
d = Diagram([g * f])
|
| 158 |
+
assert f in d.premises
|
| 159 |
+
assert g in d.premises
|
| 160 |
+
|
| 161 |
+
# Check subdiagrams.
|
| 162 |
+
d = Diagram([f, g], {g * f: "unique"})
|
| 163 |
+
|
| 164 |
+
d1 = Diagram([f])
|
| 165 |
+
assert d.is_subdiagram(d1)
|
| 166 |
+
assert not d1.is_subdiagram(d)
|
| 167 |
+
|
| 168 |
+
d = Diagram([NamedMorphism(B, A, "f'")])
|
| 169 |
+
assert not d.is_subdiagram(d1)
|
| 170 |
+
assert not d1.is_subdiagram(d)
|
| 171 |
+
|
| 172 |
+
d1 = Diagram([f, g], {g * f: ["unique", "something"]})
|
| 173 |
+
assert not d.is_subdiagram(d1)
|
| 174 |
+
assert not d1.is_subdiagram(d)
|
| 175 |
+
|
| 176 |
+
d = Diagram({f: "blooh"})
|
| 177 |
+
d1 = Diagram({f: "bleeh"})
|
| 178 |
+
assert not d.is_subdiagram(d1)
|
| 179 |
+
assert not d1.is_subdiagram(d)
|
| 180 |
+
|
| 181 |
+
d = Diagram([f, g], {f: "unique", g * f: "veryunique"})
|
| 182 |
+
d1 = d.subdiagram_from_objects(FiniteSet(A, B))
|
| 183 |
+
assert d1 == Diagram([f], {f: "unique"})
|
| 184 |
+
raises(ValueError, lambda: d.subdiagram_from_objects(FiniteSet(A,
|
| 185 |
+
Object("D"))))
|
| 186 |
+
|
| 187 |
+
raises(ValueError, lambda: Diagram({IdentityMorphism(A): "unique"}))
|
| 188 |
+
|
| 189 |
+
|
| 190 |
+
def test_category():
|
| 191 |
+
A = Object("A")
|
| 192 |
+
B = Object("B")
|
| 193 |
+
C = Object("C")
|
| 194 |
+
|
| 195 |
+
f = NamedMorphism(A, B, "f")
|
| 196 |
+
g = NamedMorphism(B, C, "g")
|
| 197 |
+
|
| 198 |
+
d1 = Diagram([f, g])
|
| 199 |
+
d2 = Diagram([f])
|
| 200 |
+
|
| 201 |
+
objects = d1.objects | d2.objects
|
| 202 |
+
|
| 203 |
+
K = Category("K", objects, commutative_diagrams=[d1, d2])
|
| 204 |
+
|
| 205 |
+
assert K.name == "K"
|
| 206 |
+
assert K.objects == Class(objects)
|
| 207 |
+
assert K.commutative_diagrams == FiniteSet(d1, d2)
|
| 208 |
+
|
| 209 |
+
raises(ValueError, lambda: Category(""))
|
lib/python3.10/site-packages/sympy/categories/tests/test_drawing.py
ADDED
|
@@ -0,0 +1,919 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.categories.diagram_drawing import _GrowableGrid, ArrowStringDescription
|
| 2 |
+
from sympy.categories import (DiagramGrid, Object, NamedMorphism,
|
| 3 |
+
Diagram, XypicDiagramDrawer, xypic_draw_diagram)
|
| 4 |
+
from sympy.sets.sets import FiniteSet
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def test_GrowableGrid():
|
| 8 |
+
grid = _GrowableGrid(1, 2)
|
| 9 |
+
|
| 10 |
+
# Check dimensions.
|
| 11 |
+
assert grid.width == 1
|
| 12 |
+
assert grid.height == 2
|
| 13 |
+
|
| 14 |
+
# Check initialization of elements.
|
| 15 |
+
assert grid[0, 0] is None
|
| 16 |
+
assert grid[1, 0] is None
|
| 17 |
+
|
| 18 |
+
# Check assignment to elements.
|
| 19 |
+
grid[0, 0] = 1
|
| 20 |
+
grid[1, 0] = "two"
|
| 21 |
+
|
| 22 |
+
assert grid[0, 0] == 1
|
| 23 |
+
assert grid[1, 0] == "two"
|
| 24 |
+
|
| 25 |
+
# Check appending a row.
|
| 26 |
+
grid.append_row()
|
| 27 |
+
|
| 28 |
+
assert grid.width == 1
|
| 29 |
+
assert grid.height == 3
|
| 30 |
+
|
| 31 |
+
assert grid[0, 0] == 1
|
| 32 |
+
assert grid[1, 0] == "two"
|
| 33 |
+
assert grid[2, 0] is None
|
| 34 |
+
|
| 35 |
+
# Check appending a column.
|
| 36 |
+
grid.append_column()
|
| 37 |
+
assert grid.width == 2
|
| 38 |
+
assert grid.height == 3
|
| 39 |
+
|
| 40 |
+
assert grid[0, 0] == 1
|
| 41 |
+
assert grid[1, 0] == "two"
|
| 42 |
+
assert grid[2, 0] is None
|
| 43 |
+
|
| 44 |
+
assert grid[0, 1] is None
|
| 45 |
+
assert grid[1, 1] is None
|
| 46 |
+
assert grid[2, 1] is None
|
| 47 |
+
|
| 48 |
+
grid = _GrowableGrid(1, 2)
|
| 49 |
+
grid[0, 0] = 1
|
| 50 |
+
grid[1, 0] = "two"
|
| 51 |
+
|
| 52 |
+
# Check prepending a row.
|
| 53 |
+
grid.prepend_row()
|
| 54 |
+
assert grid.width == 1
|
| 55 |
+
assert grid.height == 3
|
| 56 |
+
|
| 57 |
+
assert grid[0, 0] is None
|
| 58 |
+
assert grid[1, 0] == 1
|
| 59 |
+
assert grid[2, 0] == "two"
|
| 60 |
+
|
| 61 |
+
# Check prepending a column.
|
| 62 |
+
grid.prepend_column()
|
| 63 |
+
assert grid.width == 2
|
| 64 |
+
assert grid.height == 3
|
| 65 |
+
|
| 66 |
+
assert grid[0, 0] is None
|
| 67 |
+
assert grid[1, 0] is None
|
| 68 |
+
assert grid[2, 0] is None
|
| 69 |
+
|
| 70 |
+
assert grid[0, 1] is None
|
| 71 |
+
assert grid[1, 1] == 1
|
| 72 |
+
assert grid[2, 1] == "two"
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def test_DiagramGrid():
|
| 76 |
+
# Set up some objects and morphisms.
|
| 77 |
+
A = Object("A")
|
| 78 |
+
B = Object("B")
|
| 79 |
+
C = Object("C")
|
| 80 |
+
D = Object("D")
|
| 81 |
+
E = Object("E")
|
| 82 |
+
|
| 83 |
+
f = NamedMorphism(A, B, "f")
|
| 84 |
+
g = NamedMorphism(B, C, "g")
|
| 85 |
+
h = NamedMorphism(D, A, "h")
|
| 86 |
+
k = NamedMorphism(D, B, "k")
|
| 87 |
+
|
| 88 |
+
# A one-morphism diagram.
|
| 89 |
+
d = Diagram([f])
|
| 90 |
+
grid = DiagramGrid(d)
|
| 91 |
+
|
| 92 |
+
assert grid.width == 2
|
| 93 |
+
assert grid.height == 1
|
| 94 |
+
assert grid[0, 0] == A
|
| 95 |
+
assert grid[0, 1] == B
|
| 96 |
+
assert grid.morphisms == {f: FiniteSet()}
|
| 97 |
+
|
| 98 |
+
# A triangle.
|
| 99 |
+
d = Diagram([f, g], {g * f: "unique"})
|
| 100 |
+
grid = DiagramGrid(d)
|
| 101 |
+
|
| 102 |
+
assert grid.width == 2
|
| 103 |
+
assert grid.height == 2
|
| 104 |
+
assert grid[0, 0] == A
|
| 105 |
+
assert grid[0, 1] == B
|
| 106 |
+
assert grid[1, 0] == C
|
| 107 |
+
assert grid[1, 1] is None
|
| 108 |
+
assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(),
|
| 109 |
+
g * f: FiniteSet("unique")}
|
| 110 |
+
|
| 111 |
+
# A triangle with a "loop" morphism.
|
| 112 |
+
l_A = NamedMorphism(A, A, "l_A")
|
| 113 |
+
d = Diagram([f, g, l_A])
|
| 114 |
+
grid = DiagramGrid(d)
|
| 115 |
+
|
| 116 |
+
assert grid.width == 2
|
| 117 |
+
assert grid.height == 2
|
| 118 |
+
assert grid[0, 0] == A
|
| 119 |
+
assert grid[0, 1] == B
|
| 120 |
+
assert grid[1, 0] is None
|
| 121 |
+
assert grid[1, 1] == C
|
| 122 |
+
assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), l_A: FiniteSet()}
|
| 123 |
+
|
| 124 |
+
# A simple diagram.
|
| 125 |
+
d = Diagram([f, g, h, k])
|
| 126 |
+
grid = DiagramGrid(d)
|
| 127 |
+
|
| 128 |
+
assert grid.width == 3
|
| 129 |
+
assert grid.height == 2
|
| 130 |
+
assert grid[0, 0] == A
|
| 131 |
+
assert grid[0, 1] == B
|
| 132 |
+
assert grid[0, 2] == D
|
| 133 |
+
assert grid[1, 0] is None
|
| 134 |
+
assert grid[1, 1] == C
|
| 135 |
+
assert grid[1, 2] is None
|
| 136 |
+
assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), h: FiniteSet(),
|
| 137 |
+
k: FiniteSet()}
|
| 138 |
+
|
| 139 |
+
assert str(grid) == '[[Object("A"), Object("B"), Object("D")], ' \
|
| 140 |
+
'[None, Object("C"), None]]'
|
| 141 |
+
|
| 142 |
+
# A chain of morphisms.
|
| 143 |
+
f = NamedMorphism(A, B, "f")
|
| 144 |
+
g = NamedMorphism(B, C, "g")
|
| 145 |
+
h = NamedMorphism(C, D, "h")
|
| 146 |
+
k = NamedMorphism(D, E, "k")
|
| 147 |
+
d = Diagram([f, g, h, k])
|
| 148 |
+
grid = DiagramGrid(d)
|
| 149 |
+
|
| 150 |
+
assert grid.width == 3
|
| 151 |
+
assert grid.height == 3
|
| 152 |
+
assert grid[0, 0] == A
|
| 153 |
+
assert grid[0, 1] == B
|
| 154 |
+
assert grid[0, 2] is None
|
| 155 |
+
assert grid[1, 0] is None
|
| 156 |
+
assert grid[1, 1] == C
|
| 157 |
+
assert grid[1, 2] == D
|
| 158 |
+
assert grid[2, 0] is None
|
| 159 |
+
assert grid[2, 1] is None
|
| 160 |
+
assert grid[2, 2] == E
|
| 161 |
+
assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), h: FiniteSet(),
|
| 162 |
+
k: FiniteSet()}
|
| 163 |
+
|
| 164 |
+
# A square.
|
| 165 |
+
f = NamedMorphism(A, B, "f")
|
| 166 |
+
g = NamedMorphism(B, D, "g")
|
| 167 |
+
h = NamedMorphism(A, C, "h")
|
| 168 |
+
k = NamedMorphism(C, D, "k")
|
| 169 |
+
d = Diagram([f, g, h, k])
|
| 170 |
+
grid = DiagramGrid(d)
|
| 171 |
+
|
| 172 |
+
assert grid.width == 2
|
| 173 |
+
assert grid.height == 2
|
| 174 |
+
assert grid[0, 0] == A
|
| 175 |
+
assert grid[0, 1] == B
|
| 176 |
+
assert grid[1, 0] == C
|
| 177 |
+
assert grid[1, 1] == D
|
| 178 |
+
assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), h: FiniteSet(),
|
| 179 |
+
k: FiniteSet()}
|
| 180 |
+
|
| 181 |
+
# A strange diagram which resulted from a typo when creating a
|
| 182 |
+
# test for five lemma, but which allowed to stop one extra problem
|
| 183 |
+
# in the algorithm.
|
| 184 |
+
A = Object("A")
|
| 185 |
+
B = Object("B")
|
| 186 |
+
C = Object("C")
|
| 187 |
+
D = Object("D")
|
| 188 |
+
E = Object("E")
|
| 189 |
+
A_ = Object("A'")
|
| 190 |
+
B_ = Object("B'")
|
| 191 |
+
C_ = Object("C'")
|
| 192 |
+
D_ = Object("D'")
|
| 193 |
+
E_ = Object("E'")
|
| 194 |
+
|
| 195 |
+
f = NamedMorphism(A, B, "f")
|
| 196 |
+
g = NamedMorphism(B, C, "g")
|
| 197 |
+
h = NamedMorphism(C, D, "h")
|
| 198 |
+
i = NamedMorphism(D, E, "i")
|
| 199 |
+
|
| 200 |
+
# These 4 morphisms should be between primed objects.
|
| 201 |
+
j = NamedMorphism(A, B, "j")
|
| 202 |
+
k = NamedMorphism(B, C, "k")
|
| 203 |
+
l = NamedMorphism(C, D, "l")
|
| 204 |
+
m = NamedMorphism(D, E, "m")
|
| 205 |
+
|
| 206 |
+
o = NamedMorphism(A, A_, "o")
|
| 207 |
+
p = NamedMorphism(B, B_, "p")
|
| 208 |
+
q = NamedMorphism(C, C_, "q")
|
| 209 |
+
r = NamedMorphism(D, D_, "r")
|
| 210 |
+
s = NamedMorphism(E, E_, "s")
|
| 211 |
+
|
| 212 |
+
d = Diagram([f, g, h, i, j, k, l, m, o, p, q, r, s])
|
| 213 |
+
grid = DiagramGrid(d)
|
| 214 |
+
|
| 215 |
+
assert grid.width == 3
|
| 216 |
+
assert grid.height == 4
|
| 217 |
+
assert grid[0, 0] is None
|
| 218 |
+
assert grid[0, 1] == A
|
| 219 |
+
assert grid[0, 2] == A_
|
| 220 |
+
assert grid[1, 0] == C
|
| 221 |
+
assert grid[1, 1] == B
|
| 222 |
+
assert grid[1, 2] == B_
|
| 223 |
+
assert grid[2, 0] == C_
|
| 224 |
+
assert grid[2, 1] == D
|
| 225 |
+
assert grid[2, 2] == D_
|
| 226 |
+
assert grid[3, 0] is None
|
| 227 |
+
assert grid[3, 1] == E
|
| 228 |
+
assert grid[3, 2] == E_
|
| 229 |
+
|
| 230 |
+
morphisms = {}
|
| 231 |
+
for m in [f, g, h, i, j, k, l, m, o, p, q, r, s]:
|
| 232 |
+
morphisms[m] = FiniteSet()
|
| 233 |
+
assert grid.morphisms == morphisms
|
| 234 |
+
|
| 235 |
+
# A cube.
|
| 236 |
+
A1 = Object("A1")
|
| 237 |
+
A2 = Object("A2")
|
| 238 |
+
A3 = Object("A3")
|
| 239 |
+
A4 = Object("A4")
|
| 240 |
+
A5 = Object("A5")
|
| 241 |
+
A6 = Object("A6")
|
| 242 |
+
A7 = Object("A7")
|
| 243 |
+
A8 = Object("A8")
|
| 244 |
+
|
| 245 |
+
# The top face of the cube.
|
| 246 |
+
f1 = NamedMorphism(A1, A2, "f1")
|
| 247 |
+
f2 = NamedMorphism(A1, A3, "f2")
|
| 248 |
+
f3 = NamedMorphism(A2, A4, "f3")
|
| 249 |
+
f4 = NamedMorphism(A3, A4, "f3")
|
| 250 |
+
|
| 251 |
+
# The bottom face of the cube.
|
| 252 |
+
f5 = NamedMorphism(A5, A6, "f5")
|
| 253 |
+
f6 = NamedMorphism(A5, A7, "f6")
|
| 254 |
+
f7 = NamedMorphism(A6, A8, "f7")
|
| 255 |
+
f8 = NamedMorphism(A7, A8, "f8")
|
| 256 |
+
|
| 257 |
+
# The remaining morphisms.
|
| 258 |
+
f9 = NamedMorphism(A1, A5, "f9")
|
| 259 |
+
f10 = NamedMorphism(A2, A6, "f10")
|
| 260 |
+
f11 = NamedMorphism(A3, A7, "f11")
|
| 261 |
+
f12 = NamedMorphism(A4, A8, "f11")
|
| 262 |
+
|
| 263 |
+
d = Diagram([f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12])
|
| 264 |
+
grid = DiagramGrid(d)
|
| 265 |
+
|
| 266 |
+
assert grid.width == 4
|
| 267 |
+
assert grid.height == 3
|
| 268 |
+
assert grid[0, 0] is None
|
| 269 |
+
assert grid[0, 1] == A5
|
| 270 |
+
assert grid[0, 2] == A6
|
| 271 |
+
assert grid[0, 3] is None
|
| 272 |
+
assert grid[1, 0] is None
|
| 273 |
+
assert grid[1, 1] == A1
|
| 274 |
+
assert grid[1, 2] == A2
|
| 275 |
+
assert grid[1, 3] is None
|
| 276 |
+
assert grid[2, 0] == A7
|
| 277 |
+
assert grid[2, 1] == A3
|
| 278 |
+
assert grid[2, 2] == A4
|
| 279 |
+
assert grid[2, 3] == A8
|
| 280 |
+
|
| 281 |
+
morphisms = {}
|
| 282 |
+
for m in [f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12]:
|
| 283 |
+
morphisms[m] = FiniteSet()
|
| 284 |
+
assert grid.morphisms == morphisms
|
| 285 |
+
|
| 286 |
+
# A line diagram.
|
| 287 |
+
A = Object("A")
|
| 288 |
+
B = Object("B")
|
| 289 |
+
C = Object("C")
|
| 290 |
+
D = Object("D")
|
| 291 |
+
E = Object("E")
|
| 292 |
+
|
| 293 |
+
f = NamedMorphism(A, B, "f")
|
| 294 |
+
g = NamedMorphism(B, C, "g")
|
| 295 |
+
h = NamedMorphism(C, D, "h")
|
| 296 |
+
i = NamedMorphism(D, E, "i")
|
| 297 |
+
d = Diagram([f, g, h, i])
|
| 298 |
+
grid = DiagramGrid(d, layout="sequential")
|
| 299 |
+
|
| 300 |
+
assert grid.width == 5
|
| 301 |
+
assert grid.height == 1
|
| 302 |
+
assert grid[0, 0] == A
|
| 303 |
+
assert grid[0, 1] == B
|
| 304 |
+
assert grid[0, 2] == C
|
| 305 |
+
assert grid[0, 3] == D
|
| 306 |
+
assert grid[0, 4] == E
|
| 307 |
+
assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), h: FiniteSet(),
|
| 308 |
+
i: FiniteSet()}
|
| 309 |
+
|
| 310 |
+
# Test the transposed version.
|
| 311 |
+
grid = DiagramGrid(d, layout="sequential", transpose=True)
|
| 312 |
+
|
| 313 |
+
assert grid.width == 1
|
| 314 |
+
assert grid.height == 5
|
| 315 |
+
assert grid[0, 0] == A
|
| 316 |
+
assert grid[1, 0] == B
|
| 317 |
+
assert grid[2, 0] == C
|
| 318 |
+
assert grid[3, 0] == D
|
| 319 |
+
assert grid[4, 0] == E
|
| 320 |
+
assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), h: FiniteSet(),
|
| 321 |
+
i: FiniteSet()}
|
| 322 |
+
|
| 323 |
+
# A pullback.
|
| 324 |
+
m1 = NamedMorphism(A, B, "m1")
|
| 325 |
+
m2 = NamedMorphism(A, C, "m2")
|
| 326 |
+
s1 = NamedMorphism(B, D, "s1")
|
| 327 |
+
s2 = NamedMorphism(C, D, "s2")
|
| 328 |
+
f1 = NamedMorphism(E, B, "f1")
|
| 329 |
+
f2 = NamedMorphism(E, C, "f2")
|
| 330 |
+
g = NamedMorphism(E, A, "g")
|
| 331 |
+
|
| 332 |
+
d = Diagram([m1, m2, s1, s2, f1, f2], {g: "unique"})
|
| 333 |
+
grid = DiagramGrid(d)
|
| 334 |
+
|
| 335 |
+
assert grid.width == 3
|
| 336 |
+
assert grid.height == 2
|
| 337 |
+
assert grid[0, 0] == A
|
| 338 |
+
assert grid[0, 1] == B
|
| 339 |
+
assert grid[0, 2] == E
|
| 340 |
+
assert grid[1, 0] == C
|
| 341 |
+
assert grid[1, 1] == D
|
| 342 |
+
assert grid[1, 2] is None
|
| 343 |
+
|
| 344 |
+
morphisms = {g: FiniteSet("unique")}
|
| 345 |
+
for m in [m1, m2, s1, s2, f1, f2]:
|
| 346 |
+
morphisms[m] = FiniteSet()
|
| 347 |
+
assert grid.morphisms == morphisms
|
| 348 |
+
|
| 349 |
+
# Test the pullback with sequential layout, just for stress
|
| 350 |
+
# testing.
|
| 351 |
+
grid = DiagramGrid(d, layout="sequential")
|
| 352 |
+
|
| 353 |
+
assert grid.width == 5
|
| 354 |
+
assert grid.height == 1
|
| 355 |
+
assert grid[0, 0] == D
|
| 356 |
+
assert grid[0, 1] == B
|
| 357 |
+
assert grid[0, 2] == A
|
| 358 |
+
assert grid[0, 3] == C
|
| 359 |
+
assert grid[0, 4] == E
|
| 360 |
+
assert grid.morphisms == morphisms
|
| 361 |
+
|
| 362 |
+
# Test a pullback with object grouping.
|
| 363 |
+
grid = DiagramGrid(d, groups=FiniteSet(E, FiniteSet(A, B, C, D)))
|
| 364 |
+
|
| 365 |
+
assert grid.width == 3
|
| 366 |
+
assert grid.height == 2
|
| 367 |
+
assert grid[0, 0] == E
|
| 368 |
+
assert grid[0, 1] == A
|
| 369 |
+
assert grid[0, 2] == B
|
| 370 |
+
assert grid[1, 0] is None
|
| 371 |
+
assert grid[1, 1] == C
|
| 372 |
+
assert grid[1, 2] == D
|
| 373 |
+
assert grid.morphisms == morphisms
|
| 374 |
+
|
| 375 |
+
# Five lemma, actually.
|
| 376 |
+
A = Object("A")
|
| 377 |
+
B = Object("B")
|
| 378 |
+
C = Object("C")
|
| 379 |
+
D = Object("D")
|
| 380 |
+
E = Object("E")
|
| 381 |
+
A_ = Object("A'")
|
| 382 |
+
B_ = Object("B'")
|
| 383 |
+
C_ = Object("C'")
|
| 384 |
+
D_ = Object("D'")
|
| 385 |
+
E_ = Object("E'")
|
| 386 |
+
|
| 387 |
+
f = NamedMorphism(A, B, "f")
|
| 388 |
+
g = NamedMorphism(B, C, "g")
|
| 389 |
+
h = NamedMorphism(C, D, "h")
|
| 390 |
+
i = NamedMorphism(D, E, "i")
|
| 391 |
+
|
| 392 |
+
j = NamedMorphism(A_, B_, "j")
|
| 393 |
+
k = NamedMorphism(B_, C_, "k")
|
| 394 |
+
l = NamedMorphism(C_, D_, "l")
|
| 395 |
+
m = NamedMorphism(D_, E_, "m")
|
| 396 |
+
|
| 397 |
+
o = NamedMorphism(A, A_, "o")
|
| 398 |
+
p = NamedMorphism(B, B_, "p")
|
| 399 |
+
q = NamedMorphism(C, C_, "q")
|
| 400 |
+
r = NamedMorphism(D, D_, "r")
|
| 401 |
+
s = NamedMorphism(E, E_, "s")
|
| 402 |
+
|
| 403 |
+
d = Diagram([f, g, h, i, j, k, l, m, o, p, q, r, s])
|
| 404 |
+
grid = DiagramGrid(d)
|
| 405 |
+
|
| 406 |
+
assert grid.width == 5
|
| 407 |
+
assert grid.height == 3
|
| 408 |
+
assert grid[0, 0] is None
|
| 409 |
+
assert grid[0, 1] == A
|
| 410 |
+
assert grid[0, 2] == A_
|
| 411 |
+
assert grid[0, 3] is None
|
| 412 |
+
assert grid[0, 4] is None
|
| 413 |
+
assert grid[1, 0] == C
|
| 414 |
+
assert grid[1, 1] == B
|
| 415 |
+
assert grid[1, 2] == B_
|
| 416 |
+
assert grid[1, 3] == C_
|
| 417 |
+
assert grid[1, 4] is None
|
| 418 |
+
assert grid[2, 0] == D
|
| 419 |
+
assert grid[2, 1] == E
|
| 420 |
+
assert grid[2, 2] is None
|
| 421 |
+
assert grid[2, 3] == D_
|
| 422 |
+
assert grid[2, 4] == E_
|
| 423 |
+
|
| 424 |
+
morphisms = {}
|
| 425 |
+
for m in [f, g, h, i, j, k, l, m, o, p, q, r, s]:
|
| 426 |
+
morphisms[m] = FiniteSet()
|
| 427 |
+
assert grid.morphisms == morphisms
|
| 428 |
+
|
| 429 |
+
# Test the five lemma with object grouping.
|
| 430 |
+
grid = DiagramGrid(d, FiniteSet(
|
| 431 |
+
FiniteSet(A, B, C, D, E), FiniteSet(A_, B_, C_, D_, E_)))
|
| 432 |
+
|
| 433 |
+
assert grid.width == 6
|
| 434 |
+
assert grid.height == 3
|
| 435 |
+
assert grid[0, 0] == A
|
| 436 |
+
assert grid[0, 1] == B
|
| 437 |
+
assert grid[0, 2] is None
|
| 438 |
+
assert grid[0, 3] == A_
|
| 439 |
+
assert grid[0, 4] == B_
|
| 440 |
+
assert grid[0, 5] is None
|
| 441 |
+
assert grid[1, 0] is None
|
| 442 |
+
assert grid[1, 1] == C
|
| 443 |
+
assert grid[1, 2] == D
|
| 444 |
+
assert grid[1, 3] is None
|
| 445 |
+
assert grid[1, 4] == C_
|
| 446 |
+
assert grid[1, 5] == D_
|
| 447 |
+
assert grid[2, 0] is None
|
| 448 |
+
assert grid[2, 1] is None
|
| 449 |
+
assert grid[2, 2] == E
|
| 450 |
+
assert grid[2, 3] is None
|
| 451 |
+
assert grid[2, 4] is None
|
| 452 |
+
assert grid[2, 5] == E_
|
| 453 |
+
assert grid.morphisms == morphisms
|
| 454 |
+
|
| 455 |
+
# Test the five lemma with object grouping, but mixing containers
|
| 456 |
+
# to represent groups.
|
| 457 |
+
grid = DiagramGrid(d, [(A, B, C, D, E), {A_, B_, C_, D_, E_}])
|
| 458 |
+
|
| 459 |
+
assert grid.width == 6
|
| 460 |
+
assert grid.height == 3
|
| 461 |
+
assert grid[0, 0] == A
|
| 462 |
+
assert grid[0, 1] == B
|
| 463 |
+
assert grid[0, 2] is None
|
| 464 |
+
assert grid[0, 3] == A_
|
| 465 |
+
assert grid[0, 4] == B_
|
| 466 |
+
assert grid[0, 5] is None
|
| 467 |
+
assert grid[1, 0] is None
|
| 468 |
+
assert grid[1, 1] == C
|
| 469 |
+
assert grid[1, 2] == D
|
| 470 |
+
assert grid[1, 3] is None
|
| 471 |
+
assert grid[1, 4] == C_
|
| 472 |
+
assert grid[1, 5] == D_
|
| 473 |
+
assert grid[2, 0] is None
|
| 474 |
+
assert grid[2, 1] is None
|
| 475 |
+
assert grid[2, 2] == E
|
| 476 |
+
assert grid[2, 3] is None
|
| 477 |
+
assert grid[2, 4] is None
|
| 478 |
+
assert grid[2, 5] == E_
|
| 479 |
+
assert grid.morphisms == morphisms
|
| 480 |
+
|
| 481 |
+
# Test the five lemma with object grouping and hints.
|
| 482 |
+
grid = DiagramGrid(d, {
|
| 483 |
+
FiniteSet(A, B, C, D, E): {"layout": "sequential",
|
| 484 |
+
"transpose": True},
|
| 485 |
+
FiniteSet(A_, B_, C_, D_, E_): {"layout": "sequential",
|
| 486 |
+
"transpose": True}},
|
| 487 |
+
transpose=True)
|
| 488 |
+
|
| 489 |
+
assert grid.width == 5
|
| 490 |
+
assert grid.height == 2
|
| 491 |
+
assert grid[0, 0] == A
|
| 492 |
+
assert grid[0, 1] == B
|
| 493 |
+
assert grid[0, 2] == C
|
| 494 |
+
assert grid[0, 3] == D
|
| 495 |
+
assert grid[0, 4] == E
|
| 496 |
+
assert grid[1, 0] == A_
|
| 497 |
+
assert grid[1, 1] == B_
|
| 498 |
+
assert grid[1, 2] == C_
|
| 499 |
+
assert grid[1, 3] == D_
|
| 500 |
+
assert grid[1, 4] == E_
|
| 501 |
+
assert grid.morphisms == morphisms
|
| 502 |
+
|
| 503 |
+
# A two-triangle disconnected diagram.
|
| 504 |
+
f = NamedMorphism(A, B, "f")
|
| 505 |
+
g = NamedMorphism(B, C, "g")
|
| 506 |
+
f_ = NamedMorphism(A_, B_, "f")
|
| 507 |
+
g_ = NamedMorphism(B_, C_, "g")
|
| 508 |
+
d = Diagram([f, g, f_, g_], {g * f: "unique", g_ * f_: "unique"})
|
| 509 |
+
grid = DiagramGrid(d)
|
| 510 |
+
|
| 511 |
+
assert grid.width == 4
|
| 512 |
+
assert grid.height == 2
|
| 513 |
+
assert grid[0, 0] == A
|
| 514 |
+
assert grid[0, 1] == B
|
| 515 |
+
assert grid[0, 2] == A_
|
| 516 |
+
assert grid[0, 3] == B_
|
| 517 |
+
assert grid[1, 0] == C
|
| 518 |
+
assert grid[1, 1] is None
|
| 519 |
+
assert grid[1, 2] == C_
|
| 520 |
+
assert grid[1, 3] is None
|
| 521 |
+
assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), f_: FiniteSet(),
|
| 522 |
+
g_: FiniteSet(), g * f: FiniteSet("unique"),
|
| 523 |
+
g_ * f_: FiniteSet("unique")}
|
| 524 |
+
|
| 525 |
+
# A two-morphism disconnected diagram.
|
| 526 |
+
f = NamedMorphism(A, B, "f")
|
| 527 |
+
g = NamedMorphism(C, D, "g")
|
| 528 |
+
d = Diagram([f, g])
|
| 529 |
+
grid = DiagramGrid(d)
|
| 530 |
+
|
| 531 |
+
assert grid.width == 4
|
| 532 |
+
assert grid.height == 1
|
| 533 |
+
assert grid[0, 0] == A
|
| 534 |
+
assert grid[0, 1] == B
|
| 535 |
+
assert grid[0, 2] == C
|
| 536 |
+
assert grid[0, 3] == D
|
| 537 |
+
assert grid.morphisms == {f: FiniteSet(), g: FiniteSet()}
|
| 538 |
+
|
| 539 |
+
# Test a one-object diagram.
|
| 540 |
+
f = NamedMorphism(A, A, "f")
|
| 541 |
+
d = Diagram([f])
|
| 542 |
+
grid = DiagramGrid(d)
|
| 543 |
+
|
| 544 |
+
assert grid.width == 1
|
| 545 |
+
assert grid.height == 1
|
| 546 |
+
assert grid[0, 0] == A
|
| 547 |
+
|
| 548 |
+
# Test a two-object disconnected diagram.
|
| 549 |
+
g = NamedMorphism(B, B, "g")
|
| 550 |
+
d = Diagram([f, g])
|
| 551 |
+
grid = DiagramGrid(d)
|
| 552 |
+
|
| 553 |
+
assert grid.width == 2
|
| 554 |
+
assert grid.height == 1
|
| 555 |
+
assert grid[0, 0] == A
|
| 556 |
+
assert grid[0, 1] == B
|
| 557 |
+
|
| 558 |
+
|
| 559 |
+
def test_DiagramGrid_pseudopod():
|
| 560 |
+
# Test a diagram in which even growing a pseudopod does not
|
| 561 |
+
# eventually help.
|
| 562 |
+
A = Object("A")
|
| 563 |
+
B = Object("B")
|
| 564 |
+
C = Object("C")
|
| 565 |
+
D = Object("D")
|
| 566 |
+
E = Object("E")
|
| 567 |
+
F = Object("F")
|
| 568 |
+
A_ = Object("A'")
|
| 569 |
+
B_ = Object("B'")
|
| 570 |
+
C_ = Object("C'")
|
| 571 |
+
D_ = Object("D'")
|
| 572 |
+
E_ = Object("E'")
|
| 573 |
+
|
| 574 |
+
f1 = NamedMorphism(A, B, "f1")
|
| 575 |
+
f2 = NamedMorphism(A, C, "f2")
|
| 576 |
+
f3 = NamedMorphism(A, D, "f3")
|
| 577 |
+
f4 = NamedMorphism(A, E, "f4")
|
| 578 |
+
f5 = NamedMorphism(A, A_, "f5")
|
| 579 |
+
f6 = NamedMorphism(A, B_, "f6")
|
| 580 |
+
f7 = NamedMorphism(A, C_, "f7")
|
| 581 |
+
f8 = NamedMorphism(A, D_, "f8")
|
| 582 |
+
f9 = NamedMorphism(A, E_, "f9")
|
| 583 |
+
f10 = NamedMorphism(A, F, "f10")
|
| 584 |
+
d = Diagram([f1, f2, f3, f4, f5, f6, f7, f8, f9, f10])
|
| 585 |
+
grid = DiagramGrid(d)
|
| 586 |
+
|
| 587 |
+
assert grid.width == 5
|
| 588 |
+
assert grid.height == 3
|
| 589 |
+
assert grid[0, 0] == E
|
| 590 |
+
assert grid[0, 1] == C
|
| 591 |
+
assert grid[0, 2] == C_
|
| 592 |
+
assert grid[0, 3] == E_
|
| 593 |
+
assert grid[0, 4] == F
|
| 594 |
+
assert grid[1, 0] == D
|
| 595 |
+
assert grid[1, 1] == A
|
| 596 |
+
assert grid[1, 2] == A_
|
| 597 |
+
assert grid[1, 3] is None
|
| 598 |
+
assert grid[1, 4] is None
|
| 599 |
+
assert grid[2, 0] == D_
|
| 600 |
+
assert grid[2, 1] == B
|
| 601 |
+
assert grid[2, 2] == B_
|
| 602 |
+
assert grid[2, 3] is None
|
| 603 |
+
assert grid[2, 4] is None
|
| 604 |
+
|
| 605 |
+
morphisms = {}
|
| 606 |
+
for f in [f1, f2, f3, f4, f5, f6, f7, f8, f9, f10]:
|
| 607 |
+
morphisms[f] = FiniteSet()
|
| 608 |
+
assert grid.morphisms == morphisms
|
| 609 |
+
|
| 610 |
+
|
| 611 |
+
def test_ArrowStringDescription():
|
| 612 |
+
astr = ArrowStringDescription("cm", "", None, "", "", "d", "r", "_", "f")
|
| 613 |
+
assert str(astr) == "\\ar[dr]_{f}"
|
| 614 |
+
|
| 615 |
+
astr = ArrowStringDescription("cm", "", 12, "", "", "d", "r", "_", "f")
|
| 616 |
+
assert str(astr) == "\\ar[dr]_{f}"
|
| 617 |
+
|
| 618 |
+
astr = ArrowStringDescription("cm", "^", 12, "", "", "d", "r", "_", "f")
|
| 619 |
+
assert str(astr) == "\\ar@/^12cm/[dr]_{f}"
|
| 620 |
+
|
| 621 |
+
astr = ArrowStringDescription("cm", "", 12, "r", "", "d", "r", "_", "f")
|
| 622 |
+
assert str(astr) == "\\ar[dr]_{f}"
|
| 623 |
+
|
| 624 |
+
astr = ArrowStringDescription("cm", "", 12, "r", "u", "d", "r", "_", "f")
|
| 625 |
+
assert str(astr) == "\\ar@(r,u)[dr]_{f}"
|
| 626 |
+
|
| 627 |
+
astr = ArrowStringDescription("cm", "", 12, "r", "u", "d", "r", "_", "f")
|
| 628 |
+
assert str(astr) == "\\ar@(r,u)[dr]_{f}"
|
| 629 |
+
|
| 630 |
+
astr = ArrowStringDescription("cm", "", 12, "r", "u", "d", "r", "_", "f")
|
| 631 |
+
astr.arrow_style = "{-->}"
|
| 632 |
+
assert str(astr) == "\\ar@(r,u)@{-->}[dr]_{f}"
|
| 633 |
+
|
| 634 |
+
astr = ArrowStringDescription("cm", "_", 12, "", "", "d", "r", "_", "f")
|
| 635 |
+
astr.arrow_style = "{-->}"
|
| 636 |
+
assert str(astr) == "\\ar@/_12cm/@{-->}[dr]_{f}"
|
| 637 |
+
|
| 638 |
+
|
| 639 |
+
def test_XypicDiagramDrawer_line():
|
| 640 |
+
# A linear diagram.
|
| 641 |
+
A = Object("A")
|
| 642 |
+
B = Object("B")
|
| 643 |
+
C = Object("C")
|
| 644 |
+
D = Object("D")
|
| 645 |
+
E = Object("E")
|
| 646 |
+
|
| 647 |
+
f = NamedMorphism(A, B, "f")
|
| 648 |
+
g = NamedMorphism(B, C, "g")
|
| 649 |
+
h = NamedMorphism(C, D, "h")
|
| 650 |
+
i = NamedMorphism(D, E, "i")
|
| 651 |
+
d = Diagram([f, g, h, i])
|
| 652 |
+
grid = DiagramGrid(d, layout="sequential")
|
| 653 |
+
drawer = XypicDiagramDrawer()
|
| 654 |
+
assert drawer.draw(d, grid) == "\\xymatrix{\n" \
|
| 655 |
+
"A \\ar[r]^{f} & B \\ar[r]^{g} & C \\ar[r]^{h} & D \\ar[r]^{i} & E \n" \
|
| 656 |
+
"}\n"
|
| 657 |
+
|
| 658 |
+
# The same diagram, transposed.
|
| 659 |
+
grid = DiagramGrid(d, layout="sequential", transpose=True)
|
| 660 |
+
drawer = XypicDiagramDrawer()
|
| 661 |
+
assert drawer.draw(d, grid) == "\\xymatrix{\n" \
|
| 662 |
+
"A \\ar[d]^{f} \\\\\n" \
|
| 663 |
+
"B \\ar[d]^{g} \\\\\n" \
|
| 664 |
+
"C \\ar[d]^{h} \\\\\n" \
|
| 665 |
+
"D \\ar[d]^{i} \\\\\n" \
|
| 666 |
+
"E \n" \
|
| 667 |
+
"}\n"
|
| 668 |
+
|
| 669 |
+
|
| 670 |
+
def test_XypicDiagramDrawer_triangle():
|
| 671 |
+
# A triangle diagram.
|
| 672 |
+
A = Object("A")
|
| 673 |
+
B = Object("B")
|
| 674 |
+
C = Object("C")
|
| 675 |
+
f = NamedMorphism(A, B, "f")
|
| 676 |
+
g = NamedMorphism(B, C, "g")
|
| 677 |
+
|
| 678 |
+
d = Diagram([f, g], {g * f: "unique"})
|
| 679 |
+
grid = DiagramGrid(d)
|
| 680 |
+
drawer = XypicDiagramDrawer()
|
| 681 |
+
assert drawer.draw(d, grid) == "\\xymatrix{\n" \
|
| 682 |
+
"A \\ar[d]_{g\\circ f} \\ar[r]^{f} & B \\ar[ld]^{g} \\\\\n" \
|
| 683 |
+
"C & \n" \
|
| 684 |
+
"}\n"
|
| 685 |
+
|
| 686 |
+
# The same diagram, transposed.
|
| 687 |
+
grid = DiagramGrid(d, transpose=True)
|
| 688 |
+
drawer = XypicDiagramDrawer()
|
| 689 |
+
assert drawer.draw(d, grid) == "\\xymatrix{\n" \
|
| 690 |
+
"A \\ar[r]^{g\\circ f} \\ar[d]_{f} & C \\\\\n" \
|
| 691 |
+
"B \\ar[ru]_{g} & \n" \
|
| 692 |
+
"}\n"
|
| 693 |
+
|
| 694 |
+
# The same diagram, with a masked morphism.
|
| 695 |
+
assert drawer.draw(d, grid, masked=[g]) == "\\xymatrix{\n" \
|
| 696 |
+
"A \\ar[r]^{g\\circ f} \\ar[d]_{f} & C \\\\\n" \
|
| 697 |
+
"B & \n" \
|
| 698 |
+
"}\n"
|
| 699 |
+
|
| 700 |
+
# The same diagram with a formatter for "unique".
|
| 701 |
+
def formatter(astr):
|
| 702 |
+
astr.label = "\\exists !" + astr.label
|
| 703 |
+
astr.arrow_style = "{-->}"
|
| 704 |
+
|
| 705 |
+
drawer.arrow_formatters["unique"] = formatter
|
| 706 |
+
assert drawer.draw(d, grid) == "\\xymatrix{\n" \
|
| 707 |
+
"A \\ar@{-->}[r]^{\\exists !g\\circ f} \\ar[d]_{f} & C \\\\\n" \
|
| 708 |
+
"B \\ar[ru]_{g} & \n" \
|
| 709 |
+
"}\n"
|
| 710 |
+
|
| 711 |
+
# The same diagram with a default formatter.
|
| 712 |
+
def default_formatter(astr):
|
| 713 |
+
astr.label_displacement = "(0.45)"
|
| 714 |
+
|
| 715 |
+
drawer.default_arrow_formatter = default_formatter
|
| 716 |
+
assert drawer.draw(d, grid) == "\\xymatrix{\n" \
|
| 717 |
+
"A \\ar@{-->}[r]^(0.45){\\exists !g\\circ f} \\ar[d]_(0.45){f} & C \\\\\n" \
|
| 718 |
+
"B \\ar[ru]_(0.45){g} & \n" \
|
| 719 |
+
"}\n"
|
| 720 |
+
|
| 721 |
+
# A triangle diagram with a lot of morphisms between the same
|
| 722 |
+
# objects.
|
| 723 |
+
f1 = NamedMorphism(B, A, "f1")
|
| 724 |
+
f2 = NamedMorphism(A, B, "f2")
|
| 725 |
+
g1 = NamedMorphism(C, B, "g1")
|
| 726 |
+
g2 = NamedMorphism(B, C, "g2")
|
| 727 |
+
d = Diagram([f, f1, f2, g, g1, g2], {f1 * g1: "unique", g2 * f2: "unique"})
|
| 728 |
+
|
| 729 |
+
grid = DiagramGrid(d, transpose=True)
|
| 730 |
+
drawer = XypicDiagramDrawer()
|
| 731 |
+
assert drawer.draw(d, grid, masked=[f1*g1*g2*f2, g2*f2*f1*g1]) == \
|
| 732 |
+
"\\xymatrix{\n" \
|
| 733 |
+
"A \\ar[r]^{g_{2}\\circ f_{2}} \\ar[d]_{f} \\ar@/^3mm/[d]^{f_{2}} " \
|
| 734 |
+
"& C \\ar@/^3mm/[l]^{f_{1}\\circ g_{1}} \\ar@/^3mm/[ld]^{g_{1}} \\\\\n" \
|
| 735 |
+
"B \\ar@/^3mm/[u]^{f_{1}} \\ar[ru]_{g} \\ar@/^3mm/[ru]^{g_{2}} & \n" \
|
| 736 |
+
"}\n"
|
| 737 |
+
|
| 738 |
+
|
| 739 |
+
def test_XypicDiagramDrawer_cube():
|
| 740 |
+
# A cube diagram.
|
| 741 |
+
A1 = Object("A1")
|
| 742 |
+
A2 = Object("A2")
|
| 743 |
+
A3 = Object("A3")
|
| 744 |
+
A4 = Object("A4")
|
| 745 |
+
A5 = Object("A5")
|
| 746 |
+
A6 = Object("A6")
|
| 747 |
+
A7 = Object("A7")
|
| 748 |
+
A8 = Object("A8")
|
| 749 |
+
|
| 750 |
+
# The top face of the cube.
|
| 751 |
+
f1 = NamedMorphism(A1, A2, "f1")
|
| 752 |
+
f2 = NamedMorphism(A1, A3, "f2")
|
| 753 |
+
f3 = NamedMorphism(A2, A4, "f3")
|
| 754 |
+
f4 = NamedMorphism(A3, A4, "f3")
|
| 755 |
+
|
| 756 |
+
# The bottom face of the cube.
|
| 757 |
+
f5 = NamedMorphism(A5, A6, "f5")
|
| 758 |
+
f6 = NamedMorphism(A5, A7, "f6")
|
| 759 |
+
f7 = NamedMorphism(A6, A8, "f7")
|
| 760 |
+
f8 = NamedMorphism(A7, A8, "f8")
|
| 761 |
+
|
| 762 |
+
# The remaining morphisms.
|
| 763 |
+
f9 = NamedMorphism(A1, A5, "f9")
|
| 764 |
+
f10 = NamedMorphism(A2, A6, "f10")
|
| 765 |
+
f11 = NamedMorphism(A3, A7, "f11")
|
| 766 |
+
f12 = NamedMorphism(A4, A8, "f11")
|
| 767 |
+
|
| 768 |
+
d = Diagram([f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12])
|
| 769 |
+
grid = DiagramGrid(d)
|
| 770 |
+
drawer = XypicDiagramDrawer()
|
| 771 |
+
assert drawer.draw(d, grid) == "\\xymatrix{\n" \
|
| 772 |
+
"& A_{5} \\ar[r]^{f_{5}} \\ar[ldd]_{f_{6}} & A_{6} \\ar[rdd]^{f_{7}} " \
|
| 773 |
+
"& \\\\\n" \
|
| 774 |
+
"& A_{1} \\ar[r]^{f_{1}} \\ar[d]^{f_{2}} \\ar[u]^{f_{9}} & A_{2} " \
|
| 775 |
+
"\\ar[d]^{f_{3}} \\ar[u]_{f_{10}} & \\\\\n" \
|
| 776 |
+
"A_{7} \\ar@/_3mm/[rrr]_{f_{8}} & A_{3} \\ar[r]^{f_{3}} \\ar[l]_{f_{11}} " \
|
| 777 |
+
"& A_{4} \\ar[r]^{f_{11}} & A_{8} \n" \
|
| 778 |
+
"}\n"
|
| 779 |
+
|
| 780 |
+
# The same diagram, transposed.
|
| 781 |
+
grid = DiagramGrid(d, transpose=True)
|
| 782 |
+
drawer = XypicDiagramDrawer()
|
| 783 |
+
assert drawer.draw(d, grid) == "\\xymatrix{\n" \
|
| 784 |
+
"& & A_{7} \\ar@/^3mm/[ddd]^{f_{8}} \\\\\n" \
|
| 785 |
+
"A_{5} \\ar[d]_{f_{5}} \\ar[rru]^{f_{6}} & A_{1} \\ar[d]^{f_{1}} " \
|
| 786 |
+
"\\ar[r]^{f_{2}} \\ar[l]^{f_{9}} & A_{3} \\ar[d]_{f_{3}} " \
|
| 787 |
+
"\\ar[u]^{f_{11}} \\\\\n" \
|
| 788 |
+
"A_{6} \\ar[rrd]_{f_{7}} & A_{2} \\ar[r]^{f_{3}} \\ar[l]^{f_{10}} " \
|
| 789 |
+
"& A_{4} \\ar[d]_{f_{11}} \\\\\n" \
|
| 790 |
+
"& & A_{8} \n" \
|
| 791 |
+
"}\n"
|
| 792 |
+
|
| 793 |
+
|
| 794 |
+
def test_XypicDiagramDrawer_curved_and_loops():
|
| 795 |
+
# A simple diagram, with a curved arrow.
|
| 796 |
+
A = Object("A")
|
| 797 |
+
B = Object("B")
|
| 798 |
+
C = Object("C")
|
| 799 |
+
D = Object("D")
|
| 800 |
+
|
| 801 |
+
f = NamedMorphism(A, B, "f")
|
| 802 |
+
g = NamedMorphism(B, C, "g")
|
| 803 |
+
h = NamedMorphism(D, A, "h")
|
| 804 |
+
k = NamedMorphism(D, B, "k")
|
| 805 |
+
d = Diagram([f, g, h, k])
|
| 806 |
+
grid = DiagramGrid(d)
|
| 807 |
+
drawer = XypicDiagramDrawer()
|
| 808 |
+
assert drawer.draw(d, grid) == "\\xymatrix{\n" \
|
| 809 |
+
"A \\ar[r]_{f} & B \\ar[d]^{g} & D \\ar[l]^{k} \\ar@/_3mm/[ll]_{h} \\\\\n" \
|
| 810 |
+
"& C & \n" \
|
| 811 |
+
"}\n"
|
| 812 |
+
|
| 813 |
+
# The same diagram, transposed.
|
| 814 |
+
grid = DiagramGrid(d, transpose=True)
|
| 815 |
+
drawer = XypicDiagramDrawer()
|
| 816 |
+
assert drawer.draw(d, grid) == "\\xymatrix{\n" \
|
| 817 |
+
"A \\ar[d]^{f} & \\\\\n" \
|
| 818 |
+
"B \\ar[r]^{g} & C \\\\\n" \
|
| 819 |
+
"D \\ar[u]_{k} \\ar@/^3mm/[uu]^{h} & \n" \
|
| 820 |
+
"}\n"
|
| 821 |
+
|
| 822 |
+
# The same diagram, larger and rotated.
|
| 823 |
+
assert drawer.draw(d, grid, diagram_format="@+1cm@dr") == \
|
| 824 |
+
"\\xymatrix@+1cm@dr{\n" \
|
| 825 |
+
"A \\ar[d]^{f} & \\\\\n" \
|
| 826 |
+
"B \\ar[r]^{g} & C \\\\\n" \
|
| 827 |
+
"D \\ar[u]_{k} \\ar@/^3mm/[uu]^{h} & \n" \
|
| 828 |
+
"}\n"
|
| 829 |
+
|
| 830 |
+
# A simple diagram with three curved arrows.
|
| 831 |
+
h1 = NamedMorphism(D, A, "h1")
|
| 832 |
+
h2 = NamedMorphism(A, D, "h2")
|
| 833 |
+
k = NamedMorphism(D, B, "k")
|
| 834 |
+
d = Diagram([f, g, h, k, h1, h2])
|
| 835 |
+
grid = DiagramGrid(d)
|
| 836 |
+
drawer = XypicDiagramDrawer()
|
| 837 |
+
assert drawer.draw(d, grid) == "\\xymatrix{\n" \
|
| 838 |
+
"A \\ar[r]_{f} \\ar@/^3mm/[rr]^{h_{2}} & B \\ar[d]^{g} & D \\ar[l]^{k} " \
|
| 839 |
+
"\\ar@/_7mm/[ll]_{h} \\ar@/_11mm/[ll]_{h_{1}} \\\\\n" \
|
| 840 |
+
"& C & \n" \
|
| 841 |
+
"}\n"
|
| 842 |
+
|
| 843 |
+
# The same diagram, transposed.
|
| 844 |
+
grid = DiagramGrid(d, transpose=True)
|
| 845 |
+
drawer = XypicDiagramDrawer()
|
| 846 |
+
assert drawer.draw(d, grid) == "\\xymatrix{\n" \
|
| 847 |
+
"A \\ar[d]^{f} \\ar@/_3mm/[dd]_{h_{2}} & \\\\\n" \
|
| 848 |
+
"B \\ar[r]^{g} & C \\\\\n" \
|
| 849 |
+
"D \\ar[u]_{k} \\ar@/^7mm/[uu]^{h} \\ar@/^11mm/[uu]^{h_{1}} & \n" \
|
| 850 |
+
"}\n"
|
| 851 |
+
|
| 852 |
+
# The same diagram, with "loop" morphisms.
|
| 853 |
+
l_A = NamedMorphism(A, A, "l_A")
|
| 854 |
+
l_D = NamedMorphism(D, D, "l_D")
|
| 855 |
+
l_C = NamedMorphism(C, C, "l_C")
|
| 856 |
+
d = Diagram([f, g, h, k, h1, h2, l_A, l_D, l_C])
|
| 857 |
+
grid = DiagramGrid(d)
|
| 858 |
+
drawer = XypicDiagramDrawer()
|
| 859 |
+
assert drawer.draw(d, grid) == "\\xymatrix{\n" \
|
| 860 |
+
"A \\ar[r]_{f} \\ar@/^3mm/[rr]^{h_{2}} \\ar@(u,l)[]^{l_{A}} " \
|
| 861 |
+
"& B \\ar[d]^{g} & D \\ar[l]^{k} \\ar@/_7mm/[ll]_{h} " \
|
| 862 |
+
"\\ar@/_11mm/[ll]_{h_{1}} \\ar@(r,u)[]^{l_{D}} \\\\\n" \
|
| 863 |
+
"& C \\ar@(l,d)[]^{l_{C}} & \n" \
|
| 864 |
+
"}\n"
|
| 865 |
+
|
| 866 |
+
# The same diagram with "loop" morphisms, transposed.
|
| 867 |
+
grid = DiagramGrid(d, transpose=True)
|
| 868 |
+
drawer = XypicDiagramDrawer()
|
| 869 |
+
assert drawer.draw(d, grid) == "\\xymatrix{\n" \
|
| 870 |
+
"A \\ar[d]^{f} \\ar@/_3mm/[dd]_{h_{2}} \\ar@(r,u)[]^{l_{A}} & \\\\\n" \
|
| 871 |
+
"B \\ar[r]^{g} & C \\ar@(r,u)[]^{l_{C}} \\\\\n" \
|
| 872 |
+
"D \\ar[u]_{k} \\ar@/^7mm/[uu]^{h} \\ar@/^11mm/[uu]^{h_{1}} " \
|
| 873 |
+
"\\ar@(l,d)[]^{l_{D}} & \n" \
|
| 874 |
+
"}\n"
|
| 875 |
+
|
| 876 |
+
# The same diagram with two "loop" morphisms per object.
|
| 877 |
+
l_A_ = NamedMorphism(A, A, "n_A")
|
| 878 |
+
l_D_ = NamedMorphism(D, D, "n_D")
|
| 879 |
+
l_C_ = NamedMorphism(C, C, "n_C")
|
| 880 |
+
d = Diagram([f, g, h, k, h1, h2, l_A, l_D, l_C, l_A_, l_D_, l_C_])
|
| 881 |
+
grid = DiagramGrid(d)
|
| 882 |
+
drawer = XypicDiagramDrawer()
|
| 883 |
+
assert drawer.draw(d, grid) == "\\xymatrix{\n" \
|
| 884 |
+
"A \\ar[r]_{f} \\ar@/^3mm/[rr]^{h_{2}} \\ar@(u,l)[]^{l_{A}} " \
|
| 885 |
+
"\\ar@/^3mm/@(l,d)[]^{n_{A}} & B \\ar[d]^{g} & D \\ar[l]^{k} " \
|
| 886 |
+
"\\ar@/_7mm/[ll]_{h} \\ar@/_11mm/[ll]_{h_{1}} \\ar@(r,u)[]^{l_{D}} " \
|
| 887 |
+
"\\ar@/^3mm/@(d,r)[]^{n_{D}} \\\\\n" \
|
| 888 |
+
"& C \\ar@(l,d)[]^{l_{C}} \\ar@/^3mm/@(d,r)[]^{n_{C}} & \n" \
|
| 889 |
+
"}\n"
|
| 890 |
+
|
| 891 |
+
# The same diagram with two "loop" morphisms per object, transposed.
|
| 892 |
+
grid = DiagramGrid(d, transpose=True)
|
| 893 |
+
drawer = XypicDiagramDrawer()
|
| 894 |
+
assert drawer.draw(d, grid) == "\\xymatrix{\n" \
|
| 895 |
+
"A \\ar[d]^{f} \\ar@/_3mm/[dd]_{h_{2}} \\ar@(r,u)[]^{l_{A}} " \
|
| 896 |
+
"\\ar@/^3mm/@(u,l)[]^{n_{A}} & \\\\\n" \
|
| 897 |
+
"B \\ar[r]^{g} & C \\ar@(r,u)[]^{l_{C}} \\ar@/^3mm/@(d,r)[]^{n_{C}} \\\\\n" \
|
| 898 |
+
"D \\ar[u]_{k} \\ar@/^7mm/[uu]^{h} \\ar@/^11mm/[uu]^{h_{1}} " \
|
| 899 |
+
"\\ar@(l,d)[]^{l_{D}} \\ar@/^3mm/@(d,r)[]^{n_{D}} & \n" \
|
| 900 |
+
"}\n"
|
| 901 |
+
|
| 902 |
+
|
| 903 |
+
def test_xypic_draw_diagram():
|
| 904 |
+
# A linear diagram.
|
| 905 |
+
A = Object("A")
|
| 906 |
+
B = Object("B")
|
| 907 |
+
C = Object("C")
|
| 908 |
+
D = Object("D")
|
| 909 |
+
E = Object("E")
|
| 910 |
+
|
| 911 |
+
f = NamedMorphism(A, B, "f")
|
| 912 |
+
g = NamedMorphism(B, C, "g")
|
| 913 |
+
h = NamedMorphism(C, D, "h")
|
| 914 |
+
i = NamedMorphism(D, E, "i")
|
| 915 |
+
d = Diagram([f, g, h, i])
|
| 916 |
+
|
| 917 |
+
grid = DiagramGrid(d, layout="sequential")
|
| 918 |
+
drawer = XypicDiagramDrawer()
|
| 919 |
+
assert drawer.draw(d, grid) == xypic_draw_diagram(d, layout="sequential")
|
lib/python3.10/site-packages/sympy/codegen/__pycache__/__init__.cpython-310.pyc
ADDED
|
Binary file (1.12 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/__pycache__/abstract_nodes.cpython-310.pyc
ADDED
|
Binary file (976 Bytes). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/__pycache__/algorithms.cpython-310.pyc
ADDED
|
Binary file (6.81 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/__pycache__/approximations.cpython-310.pyc
ADDED
|
Binary file (6.36 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/__pycache__/ast.cpython-310.pyc
ADDED
|
Binary file (60.5 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/__pycache__/cfunctions.cpython-310.pyc
ADDED
|
Binary file (14.1 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/__pycache__/cnodes.cpython-310.pyc
ADDED
|
Binary file (4.92 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/__pycache__/cutils.cpython-310.pyc
ADDED
|
Binary file (744 Bytes). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/__pycache__/cxxnodes.cpython-310.pyc
ADDED
|
Binary file (727 Bytes). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/__pycache__/fnodes.cpython-310.pyc
ADDED
|
Binary file (21.3 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/__pycache__/futils.cpython-310.pyc
ADDED
|
Binary file (2.04 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/__pycache__/matrix_nodes.cpython-310.pyc
ADDED
|
Binary file (2.79 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/__pycache__/numpy_nodes.cpython-310.pyc
ADDED
|
Binary file (3.87 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/__pycache__/pynodes.cpython-310.pyc
ADDED
|
Binary file (695 Bytes). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/__pycache__/pyutils.cpython-310.pyc
ADDED
|
Binary file (1.19 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/__pycache__/rewriting.cpython-310.pyc
ADDED
|
Binary file (13.5 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/__pycache__/scipy_nodes.cpython-310.pyc
ADDED
|
Binary file (3.29 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/tests/__init__.py
ADDED
|
File without changes
|
lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/__init__.cpython-310.pyc
ADDED
|
Binary file (210 Bytes). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_abstract_nodes.cpython-310.pyc
ADDED
|
Binary file (896 Bytes). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_algorithms.cpython-310.pyc
ADDED
|
Binary file (7.12 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_applications.cpython-310.pyc
ADDED
|
Binary file (2.37 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_approximations.cpython-310.pyc
ADDED
|
Binary file (2.13 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_ast.cpython-310.pyc
ADDED
|
Binary file (22.6 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_cfunctions.cpython-310.pyc
ADDED
|
Binary file (4.9 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_cnodes.cpython-310.pyc
ADDED
|
Binary file (3.79 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_cxxnodes.cpython-310.pyc
ADDED
|
Binary file (690 Bytes). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_fnodes.cpython-310.pyc
ADDED
|
Binary file (7.05 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_matrix_nodes.cpython-310.pyc
ADDED
|
Binary file (2.51 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_numpy_nodes.cpython-310.pyc
ADDED
|
Binary file (1.85 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_pynodes.cpython-310.pyc
ADDED
|
Binary file (866 Bytes). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_pyutils.cpython-310.pyc
ADDED
|
Binary file (599 Bytes). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_rewriting.cpython-310.pyc
ADDED
|
Binary file (14.8 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/tests/__pycache__/test_scipy_nodes.cpython-310.pyc
ADDED
|
Binary file (1.71 kB). View file
|
|
|
lib/python3.10/site-packages/sympy/codegen/tests/test_abstract_nodes.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.core.symbol import symbols
|
| 2 |
+
from sympy.codegen.abstract_nodes import List
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
def test_List():
|
| 6 |
+
l = List(2, 3, 4)
|
| 7 |
+
assert l == List(2, 3, 4)
|
| 8 |
+
assert str(l) == "[2, 3, 4]"
|
| 9 |
+
x, y, z = symbols('x y z')
|
| 10 |
+
l = List(x**2,y**3,z**4)
|
| 11 |
+
# contrary to python's built-in list, we can call e.g. "replace" on List.
|
| 12 |
+
m = l.replace(lambda arg: arg.is_Pow and arg.exp>2, lambda p: p.base-p.exp)
|
| 13 |
+
assert m == [x**2, y-3, z-4]
|
| 14 |
+
hash(m)
|
lib/python3.10/site-packages/sympy/codegen/tests/test_algorithms.py
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import tempfile
|
| 2 |
+
from sympy import log, Min, Max, sqrt
|
| 3 |
+
from sympy.core.numbers import Float
|
| 4 |
+
from sympy.core.symbol import Symbol, symbols
|
| 5 |
+
from sympy.functions.elementary.trigonometric import cos
|
| 6 |
+
from sympy.codegen.ast import Assignment, Raise, RuntimeError_, QuotedString
|
| 7 |
+
from sympy.codegen.algorithms import newtons_method, newtons_method_function
|
| 8 |
+
from sympy.codegen.cfunctions import expm1
|
| 9 |
+
from sympy.codegen.fnodes import bind_C
|
| 10 |
+
from sympy.codegen.futils import render_as_module as f_module
|
| 11 |
+
from sympy.codegen.pyutils import render_as_module as py_module
|
| 12 |
+
from sympy.external import import_module
|
| 13 |
+
from sympy.printing.codeprinter import ccode
|
| 14 |
+
from sympy.utilities._compilation import compile_link_import_strings, has_c, has_fortran
|
| 15 |
+
from sympy.utilities._compilation.util import may_xfail
|
| 16 |
+
from sympy.testing.pytest import skip, raises
|
| 17 |
+
|
| 18 |
+
cython = import_module('cython')
|
| 19 |
+
wurlitzer = import_module('wurlitzer')
|
| 20 |
+
|
| 21 |
+
def test_newtons_method():
|
| 22 |
+
x, dx, atol = symbols('x dx atol')
|
| 23 |
+
expr = cos(x) - x**3
|
| 24 |
+
algo = newtons_method(expr, x, atol, dx)
|
| 25 |
+
assert algo.has(Assignment(dx, -expr/expr.diff(x)))
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
@may_xfail
|
| 29 |
+
def test_newtons_method_function__ccode():
|
| 30 |
+
x = Symbol('x', real=True)
|
| 31 |
+
expr = cos(x) - x**3
|
| 32 |
+
func = newtons_method_function(expr, x)
|
| 33 |
+
|
| 34 |
+
if not cython:
|
| 35 |
+
skip("cython not installed.")
|
| 36 |
+
if not has_c():
|
| 37 |
+
skip("No C compiler found.")
|
| 38 |
+
|
| 39 |
+
compile_kw = {"std": 'c99'}
|
| 40 |
+
with tempfile.TemporaryDirectory() as folder:
|
| 41 |
+
mod, info = compile_link_import_strings([
|
| 42 |
+
('newton.c', ('#include <math.h>\n'
|
| 43 |
+
'#include <stdio.h>\n') + ccode(func)),
|
| 44 |
+
('_newton.pyx', ("#cython: language_level={}\n".format("3") +
|
| 45 |
+
"cdef extern double newton(double)\n"
|
| 46 |
+
"def py_newton(x):\n"
|
| 47 |
+
" return newton(x)\n"))
|
| 48 |
+
], build_dir=folder, compile_kwargs=compile_kw)
|
| 49 |
+
assert abs(mod.py_newton(0.5) - 0.865474033102) < 1e-12
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
@may_xfail
|
| 53 |
+
def test_newtons_method_function__fcode():
|
| 54 |
+
x = Symbol('x', real=True)
|
| 55 |
+
expr = cos(x) - x**3
|
| 56 |
+
func = newtons_method_function(expr, x, attrs=[bind_C(name='newton')])
|
| 57 |
+
|
| 58 |
+
if not cython:
|
| 59 |
+
skip("cython not installed.")
|
| 60 |
+
if not has_fortran():
|
| 61 |
+
skip("No Fortran compiler found.")
|
| 62 |
+
|
| 63 |
+
f_mod = f_module([func], 'mod_newton')
|
| 64 |
+
with tempfile.TemporaryDirectory() as folder:
|
| 65 |
+
mod, info = compile_link_import_strings([
|
| 66 |
+
('newton.f90', f_mod),
|
| 67 |
+
('_newton.pyx', ("#cython: language_level={}\n".format("3") +
|
| 68 |
+
"cdef extern double newton(double*)\n"
|
| 69 |
+
"def py_newton(double x):\n"
|
| 70 |
+
" return newton(&x)\n"))
|
| 71 |
+
], build_dir=folder)
|
| 72 |
+
assert abs(mod.py_newton(0.5) - 0.865474033102) < 1e-12
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def test_newtons_method_function__pycode():
|
| 76 |
+
x = Symbol('x', real=True)
|
| 77 |
+
expr = cos(x) - x**3
|
| 78 |
+
func = newtons_method_function(expr, x)
|
| 79 |
+
py_mod = py_module(func)
|
| 80 |
+
namespace = {}
|
| 81 |
+
exec(py_mod, namespace, namespace)
|
| 82 |
+
res = eval('newton(0.5)', namespace)
|
| 83 |
+
assert abs(res - 0.865474033102) < 1e-12
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
@may_xfail
|
| 87 |
+
def test_newtons_method_function__ccode_parameters():
|
| 88 |
+
args = x, A, k, p = symbols('x A k p')
|
| 89 |
+
expr = A*cos(k*x) - p*x**3
|
| 90 |
+
raises(ValueError, lambda: newtons_method_function(expr, x))
|
| 91 |
+
use_wurlitzer = wurlitzer
|
| 92 |
+
|
| 93 |
+
func = newtons_method_function(expr, x, args, debug=use_wurlitzer)
|
| 94 |
+
|
| 95 |
+
if not has_c():
|
| 96 |
+
skip("No C compiler found.")
|
| 97 |
+
if not cython:
|
| 98 |
+
skip("cython not installed.")
|
| 99 |
+
|
| 100 |
+
compile_kw = {"std": 'c99'}
|
| 101 |
+
with tempfile.TemporaryDirectory() as folder:
|
| 102 |
+
mod, info = compile_link_import_strings([
|
| 103 |
+
('newton_par.c', ('#include <math.h>\n'
|
| 104 |
+
'#include <stdio.h>\n') + ccode(func)),
|
| 105 |
+
('_newton_par.pyx', ("#cython: language_level={}\n".format("3") +
|
| 106 |
+
"cdef extern double newton(double, double, double, double)\n"
|
| 107 |
+
"def py_newton(x, A=1, k=1, p=1):\n"
|
| 108 |
+
" return newton(x, A, k, p)\n"))
|
| 109 |
+
], compile_kwargs=compile_kw, build_dir=folder)
|
| 110 |
+
|
| 111 |
+
if use_wurlitzer:
|
| 112 |
+
with wurlitzer.pipes() as (out, err):
|
| 113 |
+
result = mod.py_newton(0.5)
|
| 114 |
+
else:
|
| 115 |
+
result = mod.py_newton(0.5)
|
| 116 |
+
|
| 117 |
+
assert abs(result - 0.865474033102) < 1e-12
|
| 118 |
+
|
| 119 |
+
if not use_wurlitzer:
|
| 120 |
+
skip("C-level output only tested when package 'wurlitzer' is available.")
|
| 121 |
+
|
| 122 |
+
out, err = out.read(), err.read()
|
| 123 |
+
assert err == ''
|
| 124 |
+
assert out == """\
|
| 125 |
+
x= 0.5
|
| 126 |
+
x= 1.1121 d_x= 0.61214
|
| 127 |
+
x= 0.90967 d_x= -0.20247
|
| 128 |
+
x= 0.86726 d_x= -0.042409
|
| 129 |
+
x= 0.86548 d_x= -0.0017867
|
| 130 |
+
x= 0.86547 d_x= -3.1022e-06
|
| 131 |
+
x= 0.86547 d_x= -9.3421e-12
|
| 132 |
+
x= 0.86547 d_x= 3.6902e-17
|
| 133 |
+
""" # try to run tests with LC_ALL=C if this assertion fails
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
def test_newtons_method_function__rtol_cse_nan():
|
| 137 |
+
a, b, c, N_geo, N_tot = symbols('a b c N_geo N_tot', real=True, nonnegative=True)
|
| 138 |
+
i = Symbol('i', integer=True, nonnegative=True)
|
| 139 |
+
N_ari = N_tot - N_geo - 1
|
| 140 |
+
delta_ari = (c-b)/N_ari
|
| 141 |
+
ln_delta_geo = log(b) + log(-expm1((log(a)-log(b))/N_geo))
|
| 142 |
+
eqb_log = ln_delta_geo - log(delta_ari)
|
| 143 |
+
|
| 144 |
+
def _clamp(low, expr, high):
|
| 145 |
+
return Min(Max(low, expr), high)
|
| 146 |
+
|
| 147 |
+
meth_kw = {
|
| 148 |
+
'clamped_newton': {'delta_fn': lambda e, x: _clamp(
|
| 149 |
+
(sqrt(a*x)-x)*0.99,
|
| 150 |
+
-e/e.diff(x),
|
| 151 |
+
(sqrt(c*x)-x)*0.99
|
| 152 |
+
)},
|
| 153 |
+
'halley': {'delta_fn': lambda e, x: (-2*(e*e.diff(x))/(2*e.diff(x)**2 - e*e.diff(x, 2)))},
|
| 154 |
+
'halley_alt': {'delta_fn': lambda e, x: (-e/e.diff(x)/(1-e/e.diff(x)*e.diff(x,2)/2/e.diff(x)))},
|
| 155 |
+
}
|
| 156 |
+
args = eqb_log, b
|
| 157 |
+
for use_cse in [False, True]:
|
| 158 |
+
kwargs = {
|
| 159 |
+
'params': (b, a, c, N_geo, N_tot), 'itermax': 60, 'debug': True, 'cse': use_cse,
|
| 160 |
+
'counter': i, 'atol': 1e-100, 'rtol': 2e-16, 'bounds': (a,c),
|
| 161 |
+
'handle_nan': Raise(RuntimeError_(QuotedString("encountered NaN.")))
|
| 162 |
+
}
|
| 163 |
+
func = {k: newtons_method_function(*args, func_name=f"{k}_b", **dict(kwargs, **kw)) for k, kw in meth_kw.items()}
|
| 164 |
+
py_mod = {k: py_module(v) for k, v in func.items()}
|
| 165 |
+
namespace = {}
|
| 166 |
+
root_find_b = {}
|
| 167 |
+
for k, v in py_mod.items():
|
| 168 |
+
ns = namespace[k] = {}
|
| 169 |
+
exec(v, ns, ns)
|
| 170 |
+
root_find_b[k] = ns[f'{k}_b']
|
| 171 |
+
ref = Float('13.2261515064168768938151923226496')
|
| 172 |
+
reftol = {'clamped_newton': 2e-16, 'halley': 2e-16, 'halley_alt': 3e-16}
|
| 173 |
+
guess = 4.0
|
| 174 |
+
for meth, func in root_find_b.items():
|
| 175 |
+
result = func(guess, 1e-2, 1e2, 50, 100)
|
| 176 |
+
req = ref*reftol[meth]
|
| 177 |
+
if use_cse:
|
| 178 |
+
req *= 2
|
| 179 |
+
assert abs(result - ref) < req
|
lib/python3.10/site-packages/sympy/codegen/tests/test_applications.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file contains tests that exercise multiple AST nodes
|
| 2 |
+
|
| 3 |
+
import tempfile
|
| 4 |
+
|
| 5 |
+
from sympy.external import import_module
|
| 6 |
+
from sympy.printing.codeprinter import ccode
|
| 7 |
+
from sympy.utilities._compilation import compile_link_import_strings, has_c
|
| 8 |
+
from sympy.utilities._compilation.util import may_xfail
|
| 9 |
+
from sympy.testing.pytest import skip
|
| 10 |
+
from sympy.codegen.ast import (
|
| 11 |
+
FunctionDefinition, FunctionPrototype, Variable, Pointer, real, Assignment,
|
| 12 |
+
integer, CodeBlock, While
|
| 13 |
+
)
|
| 14 |
+
from sympy.codegen.cnodes import void, PreIncrement
|
| 15 |
+
from sympy.codegen.cutils import render_as_source_file
|
| 16 |
+
|
| 17 |
+
cython = import_module('cython')
|
| 18 |
+
np = import_module('numpy')
|
| 19 |
+
|
| 20 |
+
def _mk_func1():
|
| 21 |
+
declars = n, inp, out = Variable('n', integer), Pointer('inp', real), Pointer('out', real)
|
| 22 |
+
i = Variable('i', integer)
|
| 23 |
+
whl = While(i<n, [Assignment(out[i], inp[i]), PreIncrement(i)])
|
| 24 |
+
body = CodeBlock(i.as_Declaration(value=0), whl)
|
| 25 |
+
return FunctionDefinition(void, 'our_test_function', declars, body)
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def _render_compile_import(funcdef, build_dir):
|
| 29 |
+
code_str = render_as_source_file(funcdef, settings={"contract": False})
|
| 30 |
+
declar = ccode(FunctionPrototype.from_FunctionDefinition(funcdef))
|
| 31 |
+
return compile_link_import_strings([
|
| 32 |
+
('our_test_func.c', code_str),
|
| 33 |
+
('_our_test_func.pyx', ("#cython: language_level={}\n".format("3") +
|
| 34 |
+
"cdef extern {declar}\n"
|
| 35 |
+
"def _{fname}({typ}[:] inp, {typ}[:] out):\n"
|
| 36 |
+
" {fname}(inp.size, &inp[0], &out[0])").format(
|
| 37 |
+
declar=declar, fname=funcdef.name, typ='double'
|
| 38 |
+
))
|
| 39 |
+
], build_dir=build_dir)
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
@may_xfail
|
| 43 |
+
def test_copying_function():
|
| 44 |
+
if not np:
|
| 45 |
+
skip("numpy not installed.")
|
| 46 |
+
if not has_c():
|
| 47 |
+
skip("No C compiler found.")
|
| 48 |
+
if not cython:
|
| 49 |
+
skip("Cython not found.")
|
| 50 |
+
|
| 51 |
+
info = None
|
| 52 |
+
with tempfile.TemporaryDirectory() as folder:
|
| 53 |
+
mod, info = _render_compile_import(_mk_func1(), build_dir=folder)
|
| 54 |
+
inp = np.arange(10.0)
|
| 55 |
+
out = np.empty_like(inp)
|
| 56 |
+
mod._our_test_function(inp, out)
|
| 57 |
+
assert np.allclose(inp, out)
|
lib/python3.10/site-packages/sympy/codegen/tests/test_approximations.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import math
|
| 2 |
+
from sympy.core.symbol import symbols
|
| 3 |
+
from sympy.functions.elementary.exponential import exp
|
| 4 |
+
from sympy.codegen.rewriting import optimize
|
| 5 |
+
from sympy.codegen.approximations import SumApprox, SeriesApprox
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def test_SumApprox_trivial():
|
| 9 |
+
x = symbols('x')
|
| 10 |
+
expr1 = 1 + x
|
| 11 |
+
sum_approx = SumApprox(bounds={x: (-1e-20, 1e-20)}, reltol=1e-16)
|
| 12 |
+
apx1 = optimize(expr1, [sum_approx])
|
| 13 |
+
assert apx1 - 1 == 0
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def test_SumApprox_monotone_terms():
|
| 17 |
+
x, y, z = symbols('x y z')
|
| 18 |
+
expr1 = exp(z)*(x**2 + y**2 + 1)
|
| 19 |
+
bnds1 = {x: (0, 1e-3), y: (100, 1000)}
|
| 20 |
+
sum_approx_m2 = SumApprox(bounds=bnds1, reltol=1e-2)
|
| 21 |
+
sum_approx_m5 = SumApprox(bounds=bnds1, reltol=1e-5)
|
| 22 |
+
sum_approx_m11 = SumApprox(bounds=bnds1, reltol=1e-11)
|
| 23 |
+
assert (optimize(expr1, [sum_approx_m2])/exp(z) - (y**2)).simplify() == 0
|
| 24 |
+
assert (optimize(expr1, [sum_approx_m5])/exp(z) - (y**2 + 1)).simplify() == 0
|
| 25 |
+
assert (optimize(expr1, [sum_approx_m11])/exp(z) - (y**2 + 1 + x**2)).simplify() == 0
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def test_SeriesApprox_trivial():
|
| 29 |
+
x, z = symbols('x z')
|
| 30 |
+
for factor in [1, exp(z)]:
|
| 31 |
+
x = symbols('x')
|
| 32 |
+
expr1 = exp(x)*factor
|
| 33 |
+
bnds1 = {x: (-1, 1)}
|
| 34 |
+
series_approx_50 = SeriesApprox(bounds=bnds1, reltol=0.50)
|
| 35 |
+
series_approx_10 = SeriesApprox(bounds=bnds1, reltol=0.10)
|
| 36 |
+
series_approx_05 = SeriesApprox(bounds=bnds1, reltol=0.05)
|
| 37 |
+
c = (bnds1[x][1] + bnds1[x][0])/2 # 0.0
|
| 38 |
+
f0 = math.exp(c) # 1.0
|
| 39 |
+
|
| 40 |
+
ref_50 = f0 + x + x**2/2
|
| 41 |
+
ref_10 = f0 + x + x**2/2 + x**3/6
|
| 42 |
+
ref_05 = f0 + x + x**2/2 + x**3/6 + x**4/24
|
| 43 |
+
|
| 44 |
+
res_50 = optimize(expr1, [series_approx_50])
|
| 45 |
+
res_10 = optimize(expr1, [series_approx_10])
|
| 46 |
+
res_05 = optimize(expr1, [series_approx_05])
|
| 47 |
+
|
| 48 |
+
assert (res_50/factor - ref_50).simplify() == 0
|
| 49 |
+
assert (res_10/factor - ref_10).simplify() == 0
|
| 50 |
+
assert (res_05/factor - ref_05).simplify() == 0
|
| 51 |
+
|
| 52 |
+
max_ord3 = SeriesApprox(bounds=bnds1, reltol=0.05, max_order=3)
|
| 53 |
+
assert optimize(expr1, [max_ord3]) == expr1
|
lib/python3.10/site-packages/sympy/codegen/tests/test_ast.py
ADDED
|
@@ -0,0 +1,661 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import math
|
| 2 |
+
from sympy.core.containers import Tuple
|
| 3 |
+
from sympy.core.numbers import nan, oo, Float, Integer
|
| 4 |
+
from sympy.core.relational import Lt
|
| 5 |
+
from sympy.core.symbol import symbols, Symbol
|
| 6 |
+
from sympy.functions.elementary.trigonometric import sin
|
| 7 |
+
from sympy.matrices.dense import Matrix
|
| 8 |
+
from sympy.matrices.expressions.matexpr import MatrixSymbol
|
| 9 |
+
from sympy.sets.fancysets import Range
|
| 10 |
+
from sympy.tensor.indexed import Idx, IndexedBase
|
| 11 |
+
from sympy.testing.pytest import raises
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
from sympy.codegen.ast import (
|
| 15 |
+
Assignment, Attribute, aug_assign, CodeBlock, For, Type, Variable, Pointer, Declaration,
|
| 16 |
+
AddAugmentedAssignment, SubAugmentedAssignment, MulAugmentedAssignment,
|
| 17 |
+
DivAugmentedAssignment, ModAugmentedAssignment, value_const, pointer_const,
|
| 18 |
+
integer, real, complex_, int8, uint8, float16 as f16, float32 as f32,
|
| 19 |
+
float64 as f64, float80 as f80, float128 as f128, complex64 as c64, complex128 as c128,
|
| 20 |
+
While, Scope, String, Print, QuotedString, FunctionPrototype, FunctionDefinition, Return,
|
| 21 |
+
FunctionCall, untyped, IntBaseType, intc, Node, none, NoneToken, Token, Comment
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
x, y, z, t, x0, x1, x2, a, b = symbols("x, y, z, t, x0, x1, x2, a, b")
|
| 25 |
+
n = symbols("n", integer=True)
|
| 26 |
+
A = MatrixSymbol('A', 3, 1)
|
| 27 |
+
mat = Matrix([1, 2, 3])
|
| 28 |
+
B = IndexedBase('B')
|
| 29 |
+
i = Idx("i", n)
|
| 30 |
+
A22 = MatrixSymbol('A22',2,2)
|
| 31 |
+
B22 = MatrixSymbol('B22',2,2)
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def test_Assignment():
|
| 35 |
+
# Here we just do things to show they don't error
|
| 36 |
+
Assignment(x, y)
|
| 37 |
+
Assignment(x, 0)
|
| 38 |
+
Assignment(A, mat)
|
| 39 |
+
Assignment(A[1,0], 0)
|
| 40 |
+
Assignment(A[1,0], x)
|
| 41 |
+
Assignment(B[i], x)
|
| 42 |
+
Assignment(B[i], 0)
|
| 43 |
+
a = Assignment(x, y)
|
| 44 |
+
assert a.func(*a.args) == a
|
| 45 |
+
assert a.op == ':='
|
| 46 |
+
# Here we test things to show that they error
|
| 47 |
+
# Matrix to scalar
|
| 48 |
+
raises(ValueError, lambda: Assignment(B[i], A))
|
| 49 |
+
raises(ValueError, lambda: Assignment(B[i], mat))
|
| 50 |
+
raises(ValueError, lambda: Assignment(x, mat))
|
| 51 |
+
raises(ValueError, lambda: Assignment(x, A))
|
| 52 |
+
raises(ValueError, lambda: Assignment(A[1,0], mat))
|
| 53 |
+
# Scalar to matrix
|
| 54 |
+
raises(ValueError, lambda: Assignment(A, x))
|
| 55 |
+
raises(ValueError, lambda: Assignment(A, 0))
|
| 56 |
+
# Non-atomic lhs
|
| 57 |
+
raises(TypeError, lambda: Assignment(mat, A))
|
| 58 |
+
raises(TypeError, lambda: Assignment(0, x))
|
| 59 |
+
raises(TypeError, lambda: Assignment(x*x, 1))
|
| 60 |
+
raises(TypeError, lambda: Assignment(A + A, mat))
|
| 61 |
+
raises(TypeError, lambda: Assignment(B, 0))
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def test_AugAssign():
|
| 65 |
+
# Here we just do things to show they don't error
|
| 66 |
+
aug_assign(x, '+', y)
|
| 67 |
+
aug_assign(x, '+', 0)
|
| 68 |
+
aug_assign(A, '+', mat)
|
| 69 |
+
aug_assign(A[1, 0], '+', 0)
|
| 70 |
+
aug_assign(A[1, 0], '+', x)
|
| 71 |
+
aug_assign(B[i], '+', x)
|
| 72 |
+
aug_assign(B[i], '+', 0)
|
| 73 |
+
|
| 74 |
+
# Check creation via aug_assign vs constructor
|
| 75 |
+
for binop, cls in [
|
| 76 |
+
('+', AddAugmentedAssignment),
|
| 77 |
+
('-', SubAugmentedAssignment),
|
| 78 |
+
('*', MulAugmentedAssignment),
|
| 79 |
+
('/', DivAugmentedAssignment),
|
| 80 |
+
('%', ModAugmentedAssignment),
|
| 81 |
+
]:
|
| 82 |
+
a = aug_assign(x, binop, y)
|
| 83 |
+
b = cls(x, y)
|
| 84 |
+
assert a.func(*a.args) == a == b
|
| 85 |
+
assert a.binop == binop
|
| 86 |
+
assert a.op == binop + '='
|
| 87 |
+
|
| 88 |
+
# Here we test things to show that they error
|
| 89 |
+
# Matrix to scalar
|
| 90 |
+
raises(ValueError, lambda: aug_assign(B[i], '+', A))
|
| 91 |
+
raises(ValueError, lambda: aug_assign(B[i], '+', mat))
|
| 92 |
+
raises(ValueError, lambda: aug_assign(x, '+', mat))
|
| 93 |
+
raises(ValueError, lambda: aug_assign(x, '+', A))
|
| 94 |
+
raises(ValueError, lambda: aug_assign(A[1, 0], '+', mat))
|
| 95 |
+
# Scalar to matrix
|
| 96 |
+
raises(ValueError, lambda: aug_assign(A, '+', x))
|
| 97 |
+
raises(ValueError, lambda: aug_assign(A, '+', 0))
|
| 98 |
+
# Non-atomic lhs
|
| 99 |
+
raises(TypeError, lambda: aug_assign(mat, '+', A))
|
| 100 |
+
raises(TypeError, lambda: aug_assign(0, '+', x))
|
| 101 |
+
raises(TypeError, lambda: aug_assign(x * x, '+', 1))
|
| 102 |
+
raises(TypeError, lambda: aug_assign(A + A, '+', mat))
|
| 103 |
+
raises(TypeError, lambda: aug_assign(B, '+', 0))
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
def test_Assignment_printing():
|
| 107 |
+
assignment_classes = [
|
| 108 |
+
Assignment,
|
| 109 |
+
AddAugmentedAssignment,
|
| 110 |
+
SubAugmentedAssignment,
|
| 111 |
+
MulAugmentedAssignment,
|
| 112 |
+
DivAugmentedAssignment,
|
| 113 |
+
ModAugmentedAssignment,
|
| 114 |
+
]
|
| 115 |
+
pairs = [
|
| 116 |
+
(x, 2 * y + 2),
|
| 117 |
+
(B[i], x),
|
| 118 |
+
(A22, B22),
|
| 119 |
+
(A[0, 0], x),
|
| 120 |
+
]
|
| 121 |
+
|
| 122 |
+
for cls in assignment_classes:
|
| 123 |
+
for lhs, rhs in pairs:
|
| 124 |
+
a = cls(lhs, rhs)
|
| 125 |
+
assert repr(a) == '%s(%s, %s)' % (cls.__name__, repr(lhs), repr(rhs))
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
def test_CodeBlock():
|
| 129 |
+
c = CodeBlock(Assignment(x, 1), Assignment(y, x + 1))
|
| 130 |
+
assert c.func(*c.args) == c
|
| 131 |
+
|
| 132 |
+
assert c.left_hand_sides == Tuple(x, y)
|
| 133 |
+
assert c.right_hand_sides == Tuple(1, x + 1)
|
| 134 |
+
|
| 135 |
+
def test_CodeBlock_topological_sort():
|
| 136 |
+
assignments = [
|
| 137 |
+
Assignment(x, y + z),
|
| 138 |
+
Assignment(z, 1),
|
| 139 |
+
Assignment(t, x),
|
| 140 |
+
Assignment(y, 2),
|
| 141 |
+
]
|
| 142 |
+
|
| 143 |
+
ordered_assignments = [
|
| 144 |
+
# Note that the unrelated z=1 and y=2 are kept in that order
|
| 145 |
+
Assignment(z, 1),
|
| 146 |
+
Assignment(y, 2),
|
| 147 |
+
Assignment(x, y + z),
|
| 148 |
+
Assignment(t, x),
|
| 149 |
+
]
|
| 150 |
+
c1 = CodeBlock.topological_sort(assignments)
|
| 151 |
+
assert c1 == CodeBlock(*ordered_assignments)
|
| 152 |
+
|
| 153 |
+
# Cycle
|
| 154 |
+
invalid_assignments = [
|
| 155 |
+
Assignment(x, y + z),
|
| 156 |
+
Assignment(z, 1),
|
| 157 |
+
Assignment(y, x),
|
| 158 |
+
Assignment(y, 2),
|
| 159 |
+
]
|
| 160 |
+
|
| 161 |
+
raises(ValueError, lambda: CodeBlock.topological_sort(invalid_assignments))
|
| 162 |
+
|
| 163 |
+
# Free symbols
|
| 164 |
+
free_assignments = [
|
| 165 |
+
Assignment(x, y + z),
|
| 166 |
+
Assignment(z, a * b),
|
| 167 |
+
Assignment(t, x),
|
| 168 |
+
Assignment(y, b + 3),
|
| 169 |
+
]
|
| 170 |
+
|
| 171 |
+
free_assignments_ordered = [
|
| 172 |
+
Assignment(z, a * b),
|
| 173 |
+
Assignment(y, b + 3),
|
| 174 |
+
Assignment(x, y + z),
|
| 175 |
+
Assignment(t, x),
|
| 176 |
+
]
|
| 177 |
+
|
| 178 |
+
c2 = CodeBlock.topological_sort(free_assignments)
|
| 179 |
+
assert c2 == CodeBlock(*free_assignments_ordered)
|
| 180 |
+
|
| 181 |
+
def test_CodeBlock_free_symbols():
|
| 182 |
+
c1 = CodeBlock(
|
| 183 |
+
Assignment(x, y + z),
|
| 184 |
+
Assignment(z, 1),
|
| 185 |
+
Assignment(t, x),
|
| 186 |
+
Assignment(y, 2),
|
| 187 |
+
)
|
| 188 |
+
assert c1.free_symbols == set()
|
| 189 |
+
|
| 190 |
+
c2 = CodeBlock(
|
| 191 |
+
Assignment(x, y + z),
|
| 192 |
+
Assignment(z, a * b),
|
| 193 |
+
Assignment(t, x),
|
| 194 |
+
Assignment(y, b + 3),
|
| 195 |
+
)
|
| 196 |
+
assert c2.free_symbols == {a, b}
|
| 197 |
+
|
| 198 |
+
def test_CodeBlock_cse():
|
| 199 |
+
c1 = CodeBlock(
|
| 200 |
+
Assignment(y, 1),
|
| 201 |
+
Assignment(x, sin(y)),
|
| 202 |
+
Assignment(z, sin(y)),
|
| 203 |
+
Assignment(t, x*z),
|
| 204 |
+
)
|
| 205 |
+
assert c1.cse() == CodeBlock(
|
| 206 |
+
Assignment(y, 1),
|
| 207 |
+
Assignment(x0, sin(y)),
|
| 208 |
+
Assignment(x, x0),
|
| 209 |
+
Assignment(z, x0),
|
| 210 |
+
Assignment(t, x*z),
|
| 211 |
+
)
|
| 212 |
+
|
| 213 |
+
# Multiple assignments to same symbol not supported
|
| 214 |
+
raises(NotImplementedError, lambda: CodeBlock(
|
| 215 |
+
Assignment(x, 1),
|
| 216 |
+
Assignment(y, 1), Assignment(y, 2)
|
| 217 |
+
).cse())
|
| 218 |
+
|
| 219 |
+
# Check auto-generated symbols do not collide with existing ones
|
| 220 |
+
c2 = CodeBlock(
|
| 221 |
+
Assignment(x0, sin(y) + 1),
|
| 222 |
+
Assignment(x1, 2 * sin(y)),
|
| 223 |
+
Assignment(z, x * y),
|
| 224 |
+
)
|
| 225 |
+
assert c2.cse() == CodeBlock(
|
| 226 |
+
Assignment(x2, sin(y)),
|
| 227 |
+
Assignment(x0, x2 + 1),
|
| 228 |
+
Assignment(x1, 2 * x2),
|
| 229 |
+
Assignment(z, x * y),
|
| 230 |
+
)
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
def test_CodeBlock_cse__issue_14118():
|
| 234 |
+
# see https://github.com/sympy/sympy/issues/14118
|
| 235 |
+
c = CodeBlock(
|
| 236 |
+
Assignment(A22, Matrix([[x, sin(y)],[3, 4]])),
|
| 237 |
+
Assignment(B22, Matrix([[sin(y), 2*sin(y)], [sin(y)**2, 7]]))
|
| 238 |
+
)
|
| 239 |
+
assert c.cse() == CodeBlock(
|
| 240 |
+
Assignment(x0, sin(y)),
|
| 241 |
+
Assignment(A22, Matrix([[x, x0],[3, 4]])),
|
| 242 |
+
Assignment(B22, Matrix([[x0, 2*x0], [x0**2, 7]]))
|
| 243 |
+
)
|
| 244 |
+
|
| 245 |
+
def test_For():
|
| 246 |
+
f = For(n, Range(0, 3), (Assignment(A[n, 0], x + n), aug_assign(x, '+', y)))
|
| 247 |
+
f = For(n, (1, 2, 3, 4, 5), (Assignment(A[n, 0], x + n),))
|
| 248 |
+
assert f.func(*f.args) == f
|
| 249 |
+
raises(TypeError, lambda: For(n, x, (x + y,)))
|
| 250 |
+
|
| 251 |
+
|
| 252 |
+
def test_none():
|
| 253 |
+
assert none.is_Atom
|
| 254 |
+
assert none == none
|
| 255 |
+
class Foo(Token):
|
| 256 |
+
pass
|
| 257 |
+
foo = Foo()
|
| 258 |
+
assert foo != none
|
| 259 |
+
assert none == None
|
| 260 |
+
assert none == NoneToken()
|
| 261 |
+
assert none.func(*none.args) == none
|
| 262 |
+
|
| 263 |
+
|
| 264 |
+
def test_String():
|
| 265 |
+
st = String('foobar')
|
| 266 |
+
assert st.is_Atom
|
| 267 |
+
assert st == String('foobar')
|
| 268 |
+
assert st.text == 'foobar'
|
| 269 |
+
assert st.func(**st.kwargs()) == st
|
| 270 |
+
assert st.func(*st.args) == st
|
| 271 |
+
|
| 272 |
+
|
| 273 |
+
class Signifier(String):
|
| 274 |
+
pass
|
| 275 |
+
|
| 276 |
+
si = Signifier('foobar')
|
| 277 |
+
assert si != st
|
| 278 |
+
assert si.text == st.text
|
| 279 |
+
s = String('foo')
|
| 280 |
+
assert str(s) == 'foo'
|
| 281 |
+
assert repr(s) == "String('foo')"
|
| 282 |
+
|
| 283 |
+
def test_Comment():
|
| 284 |
+
c = Comment('foobar')
|
| 285 |
+
assert c.text == 'foobar'
|
| 286 |
+
assert str(c) == 'foobar'
|
| 287 |
+
|
| 288 |
+
def test_Node():
|
| 289 |
+
n = Node()
|
| 290 |
+
assert n == Node()
|
| 291 |
+
assert n.func(*n.args) == n
|
| 292 |
+
|
| 293 |
+
|
| 294 |
+
def test_Type():
|
| 295 |
+
t = Type('MyType')
|
| 296 |
+
assert len(t.args) == 1
|
| 297 |
+
assert t.name == String('MyType')
|
| 298 |
+
assert str(t) == 'MyType'
|
| 299 |
+
assert repr(t) == "Type(String('MyType'))"
|
| 300 |
+
assert Type(t) == t
|
| 301 |
+
assert t.func(*t.args) == t
|
| 302 |
+
t1 = Type('t1')
|
| 303 |
+
t2 = Type('t2')
|
| 304 |
+
assert t1 != t2
|
| 305 |
+
assert t1 == t1 and t2 == t2
|
| 306 |
+
t1b = Type('t1')
|
| 307 |
+
assert t1 == t1b
|
| 308 |
+
assert t2 != t1b
|
| 309 |
+
|
| 310 |
+
|
| 311 |
+
def test_Type__from_expr():
|
| 312 |
+
assert Type.from_expr(i) == integer
|
| 313 |
+
u = symbols('u', real=True)
|
| 314 |
+
assert Type.from_expr(u) == real
|
| 315 |
+
assert Type.from_expr(n) == integer
|
| 316 |
+
assert Type.from_expr(3) == integer
|
| 317 |
+
assert Type.from_expr(3.0) == real
|
| 318 |
+
assert Type.from_expr(3+1j) == complex_
|
| 319 |
+
raises(ValueError, lambda: Type.from_expr(sum))
|
| 320 |
+
|
| 321 |
+
|
| 322 |
+
def test_Type__cast_check__integers():
|
| 323 |
+
# Rounding
|
| 324 |
+
raises(ValueError, lambda: integer.cast_check(3.5))
|
| 325 |
+
assert integer.cast_check('3') == 3
|
| 326 |
+
assert integer.cast_check(Float('3.0000000000000000000')) == 3
|
| 327 |
+
assert integer.cast_check(Float('3.0000000000000000001')) == 3 # unintuitive maybe?
|
| 328 |
+
|
| 329 |
+
# Range
|
| 330 |
+
assert int8.cast_check(127.0) == 127
|
| 331 |
+
raises(ValueError, lambda: int8.cast_check(128))
|
| 332 |
+
assert int8.cast_check(-128) == -128
|
| 333 |
+
raises(ValueError, lambda: int8.cast_check(-129))
|
| 334 |
+
|
| 335 |
+
assert uint8.cast_check(0) == 0
|
| 336 |
+
assert uint8.cast_check(128) == 128
|
| 337 |
+
raises(ValueError, lambda: uint8.cast_check(256.0))
|
| 338 |
+
raises(ValueError, lambda: uint8.cast_check(-1))
|
| 339 |
+
|
| 340 |
+
def test_Attribute():
|
| 341 |
+
noexcept = Attribute('noexcept')
|
| 342 |
+
assert noexcept == Attribute('noexcept')
|
| 343 |
+
alignas16 = Attribute('alignas', [16])
|
| 344 |
+
alignas32 = Attribute('alignas', [32])
|
| 345 |
+
assert alignas16 != alignas32
|
| 346 |
+
assert alignas16.func(*alignas16.args) == alignas16
|
| 347 |
+
|
| 348 |
+
|
| 349 |
+
def test_Variable():
|
| 350 |
+
v = Variable(x, type=real)
|
| 351 |
+
assert v == Variable(v)
|
| 352 |
+
assert v == Variable('x', type=real)
|
| 353 |
+
assert v.symbol == x
|
| 354 |
+
assert v.type == real
|
| 355 |
+
assert value_const not in v.attrs
|
| 356 |
+
assert v.func(*v.args) == v
|
| 357 |
+
assert str(v) == 'Variable(x, type=real)'
|
| 358 |
+
|
| 359 |
+
w = Variable(y, f32, attrs={value_const})
|
| 360 |
+
assert w.symbol == y
|
| 361 |
+
assert w.type == f32
|
| 362 |
+
assert value_const in w.attrs
|
| 363 |
+
assert w.func(*w.args) == w
|
| 364 |
+
|
| 365 |
+
v_n = Variable(n, type=Type.from_expr(n))
|
| 366 |
+
assert v_n.type == integer
|
| 367 |
+
assert v_n.func(*v_n.args) == v_n
|
| 368 |
+
v_i = Variable(i, type=Type.from_expr(n))
|
| 369 |
+
assert v_i.type == integer
|
| 370 |
+
assert v_i != v_n
|
| 371 |
+
|
| 372 |
+
a_i = Variable.deduced(i)
|
| 373 |
+
assert a_i.type == integer
|
| 374 |
+
assert Variable.deduced(Symbol('x', real=True)).type == real
|
| 375 |
+
assert a_i.func(*a_i.args) == a_i
|
| 376 |
+
|
| 377 |
+
v_n2 = Variable.deduced(n, value=3.5, cast_check=False)
|
| 378 |
+
assert v_n2.func(*v_n2.args) == v_n2
|
| 379 |
+
assert abs(v_n2.value - 3.5) < 1e-15
|
| 380 |
+
raises(ValueError, lambda: Variable.deduced(n, value=3.5, cast_check=True))
|
| 381 |
+
|
| 382 |
+
v_n3 = Variable.deduced(n)
|
| 383 |
+
assert v_n3.type == integer
|
| 384 |
+
assert str(v_n3) == 'Variable(n, type=integer)'
|
| 385 |
+
assert Variable.deduced(z, value=3).type == integer
|
| 386 |
+
assert Variable.deduced(z, value=3.0).type == real
|
| 387 |
+
assert Variable.deduced(z, value=3.0+1j).type == complex_
|
| 388 |
+
|
| 389 |
+
|
| 390 |
+
def test_Pointer():
|
| 391 |
+
p = Pointer(x)
|
| 392 |
+
assert p.symbol == x
|
| 393 |
+
assert p.type == untyped
|
| 394 |
+
assert value_const not in p.attrs
|
| 395 |
+
assert pointer_const not in p.attrs
|
| 396 |
+
assert p.func(*p.args) == p
|
| 397 |
+
|
| 398 |
+
u = symbols('u', real=True)
|
| 399 |
+
pu = Pointer(u, type=Type.from_expr(u), attrs={value_const, pointer_const})
|
| 400 |
+
assert pu.symbol is u
|
| 401 |
+
assert pu.type == real
|
| 402 |
+
assert value_const in pu.attrs
|
| 403 |
+
assert pointer_const in pu.attrs
|
| 404 |
+
assert pu.func(*pu.args) == pu
|
| 405 |
+
|
| 406 |
+
i = symbols('i', integer=True)
|
| 407 |
+
deref = pu[i]
|
| 408 |
+
assert deref.indices == (i,)
|
| 409 |
+
|
| 410 |
+
|
| 411 |
+
def test_Declaration():
|
| 412 |
+
u = symbols('u', real=True)
|
| 413 |
+
vu = Variable(u, type=Type.from_expr(u))
|
| 414 |
+
assert Declaration(vu).variable.type == real
|
| 415 |
+
vn = Variable(n, type=Type.from_expr(n))
|
| 416 |
+
assert Declaration(vn).variable.type == integer
|
| 417 |
+
|
| 418 |
+
# PR 19107, does not allow comparison between expressions and Basic
|
| 419 |
+
# lt = StrictLessThan(vu, vn)
|
| 420 |
+
# assert isinstance(lt, StrictLessThan)
|
| 421 |
+
|
| 422 |
+
vuc = Variable(u, Type.from_expr(u), value=3.0, attrs={value_const})
|
| 423 |
+
assert value_const in vuc.attrs
|
| 424 |
+
assert pointer_const not in vuc.attrs
|
| 425 |
+
decl = Declaration(vuc)
|
| 426 |
+
assert decl.variable == vuc
|
| 427 |
+
assert isinstance(decl.variable.value, Float)
|
| 428 |
+
assert decl.variable.value == 3.0
|
| 429 |
+
assert decl.func(*decl.args) == decl
|
| 430 |
+
assert vuc.as_Declaration() == decl
|
| 431 |
+
assert vuc.as_Declaration(value=None, attrs=None) == Declaration(vu)
|
| 432 |
+
|
| 433 |
+
vy = Variable(y, type=integer, value=3)
|
| 434 |
+
decl2 = Declaration(vy)
|
| 435 |
+
assert decl2.variable == vy
|
| 436 |
+
assert decl2.variable.value == Integer(3)
|
| 437 |
+
|
| 438 |
+
vi = Variable(i, type=Type.from_expr(i), value=3.0)
|
| 439 |
+
decl3 = Declaration(vi)
|
| 440 |
+
assert decl3.variable.type == integer
|
| 441 |
+
assert decl3.variable.value == 3.0
|
| 442 |
+
|
| 443 |
+
raises(ValueError, lambda: Declaration(vi, 42))
|
| 444 |
+
|
| 445 |
+
|
| 446 |
+
def test_IntBaseType():
|
| 447 |
+
assert intc.name == String('intc')
|
| 448 |
+
assert intc.args == (intc.name,)
|
| 449 |
+
assert str(IntBaseType('a').name) == 'a'
|
| 450 |
+
|
| 451 |
+
|
| 452 |
+
def test_FloatType():
|
| 453 |
+
assert f16.dig == 3
|
| 454 |
+
assert f32.dig == 6
|
| 455 |
+
assert f64.dig == 15
|
| 456 |
+
assert f80.dig == 18
|
| 457 |
+
assert f128.dig == 33
|
| 458 |
+
|
| 459 |
+
assert f16.decimal_dig == 5
|
| 460 |
+
assert f32.decimal_dig == 9
|
| 461 |
+
assert f64.decimal_dig == 17
|
| 462 |
+
assert f80.decimal_dig == 21
|
| 463 |
+
assert f128.decimal_dig == 36
|
| 464 |
+
|
| 465 |
+
assert f16.max_exponent == 16
|
| 466 |
+
assert f32.max_exponent == 128
|
| 467 |
+
assert f64.max_exponent == 1024
|
| 468 |
+
assert f80.max_exponent == 16384
|
| 469 |
+
assert f128.max_exponent == 16384
|
| 470 |
+
|
| 471 |
+
assert f16.min_exponent == -13
|
| 472 |
+
assert f32.min_exponent == -125
|
| 473 |
+
assert f64.min_exponent == -1021
|
| 474 |
+
assert f80.min_exponent == -16381
|
| 475 |
+
assert f128.min_exponent == -16381
|
| 476 |
+
|
| 477 |
+
assert abs(f16.eps / Float('0.00097656', precision=16) - 1) < 0.1*10**-f16.dig
|
| 478 |
+
assert abs(f32.eps / Float('1.1920929e-07', precision=32) - 1) < 0.1*10**-f32.dig
|
| 479 |
+
assert abs(f64.eps / Float('2.2204460492503131e-16', precision=64) - 1) < 0.1*10**-f64.dig
|
| 480 |
+
assert abs(f80.eps / Float('1.08420217248550443401e-19', precision=80) - 1) < 0.1*10**-f80.dig
|
| 481 |
+
assert abs(f128.eps / Float(' 1.92592994438723585305597794258492732e-34', precision=128) - 1) < 0.1*10**-f128.dig
|
| 482 |
+
|
| 483 |
+
assert abs(f16.max / Float('65504', precision=16) - 1) < .1*10**-f16.dig
|
| 484 |
+
assert abs(f32.max / Float('3.40282347e+38', precision=32) - 1) < 0.1*10**-f32.dig
|
| 485 |
+
assert abs(f64.max / Float('1.79769313486231571e+308', precision=64) - 1) < 0.1*10**-f64.dig # cf. np.finfo(np.float64).max
|
| 486 |
+
assert abs(f80.max / Float('1.18973149535723176502e+4932', precision=80) - 1) < 0.1*10**-f80.dig
|
| 487 |
+
assert abs(f128.max / Float('1.18973149535723176508575932662800702e+4932', precision=128) - 1) < 0.1*10**-f128.dig
|
| 488 |
+
|
| 489 |
+
# cf. np.finfo(np.float32).tiny
|
| 490 |
+
assert abs(f16.tiny / Float('6.1035e-05', precision=16) - 1) < 0.1*10**-f16.dig
|
| 491 |
+
assert abs(f32.tiny / Float('1.17549435e-38', precision=32) - 1) < 0.1*10**-f32.dig
|
| 492 |
+
assert abs(f64.tiny / Float('2.22507385850720138e-308', precision=64) - 1) < 0.1*10**-f64.dig
|
| 493 |
+
assert abs(f80.tiny / Float('3.36210314311209350626e-4932', precision=80) - 1) < 0.1*10**-f80.dig
|
| 494 |
+
assert abs(f128.tiny / Float('3.3621031431120935062626778173217526e-4932', precision=128) - 1) < 0.1*10**-f128.dig
|
| 495 |
+
|
| 496 |
+
assert f64.cast_check(0.5) == Float(0.5, 17)
|
| 497 |
+
assert abs(f64.cast_check(3.7) - 3.7) < 3e-17
|
| 498 |
+
assert isinstance(f64.cast_check(3), (Float, float))
|
| 499 |
+
|
| 500 |
+
assert f64.cast_nocheck(oo) == float('inf')
|
| 501 |
+
assert f64.cast_nocheck(-oo) == float('-inf')
|
| 502 |
+
assert f64.cast_nocheck(float(oo)) == float('inf')
|
| 503 |
+
assert f64.cast_nocheck(float(-oo)) == float('-inf')
|
| 504 |
+
assert math.isnan(f64.cast_nocheck(nan))
|
| 505 |
+
|
| 506 |
+
assert f32 != f64
|
| 507 |
+
assert f64 == f64.func(*f64.args)
|
| 508 |
+
|
| 509 |
+
|
| 510 |
+
def test_Type__cast_check__floating_point():
|
| 511 |
+
raises(ValueError, lambda: f32.cast_check(123.45678949))
|
| 512 |
+
raises(ValueError, lambda: f32.cast_check(12.345678949))
|
| 513 |
+
raises(ValueError, lambda: f32.cast_check(1.2345678949))
|
| 514 |
+
raises(ValueError, lambda: f32.cast_check(.12345678949))
|
| 515 |
+
assert abs(123.456789049 - f32.cast_check(123.456789049) - 4.9e-8) < 1e-8
|
| 516 |
+
assert abs(0.12345678904 - f32.cast_check(0.12345678904) - 4e-11) < 1e-11
|
| 517 |
+
|
| 518 |
+
dcm21 = Float('0.123456789012345670499') # 21 decimals
|
| 519 |
+
assert abs(dcm21 - f64.cast_check(dcm21) - 4.99e-19) < 1e-19
|
| 520 |
+
|
| 521 |
+
f80.cast_check(Float('0.12345678901234567890103', precision=88))
|
| 522 |
+
raises(ValueError, lambda: f80.cast_check(Float('0.12345678901234567890149', precision=88)))
|
| 523 |
+
|
| 524 |
+
v10 = 12345.67894
|
| 525 |
+
raises(ValueError, lambda: f32.cast_check(v10))
|
| 526 |
+
assert abs(Float(str(v10), precision=64+8) - f64.cast_check(v10)) < v10*1e-16
|
| 527 |
+
|
| 528 |
+
assert abs(f32.cast_check(2147483647) - 2147483650) < 1
|
| 529 |
+
|
| 530 |
+
|
| 531 |
+
def test_Type__cast_check__complex_floating_point():
|
| 532 |
+
val9_11 = 123.456789049 + 0.123456789049j
|
| 533 |
+
raises(ValueError, lambda: c64.cast_check(.12345678949 + .12345678949j))
|
| 534 |
+
assert abs(val9_11 - c64.cast_check(val9_11) - 4.9e-8) < 1e-8
|
| 535 |
+
|
| 536 |
+
dcm21 = Float('0.123456789012345670499') + 1e-20j # 21 decimals
|
| 537 |
+
assert abs(dcm21 - c128.cast_check(dcm21) - 4.99e-19) < 1e-19
|
| 538 |
+
v19 = Float('0.1234567890123456749') + 1j*Float('0.1234567890123456749')
|
| 539 |
+
raises(ValueError, lambda: c128.cast_check(v19))
|
| 540 |
+
|
| 541 |
+
|
| 542 |
+
def test_While():
|
| 543 |
+
xpp = AddAugmentedAssignment(x, 1)
|
| 544 |
+
whl1 = While(x < 2, [xpp])
|
| 545 |
+
assert whl1.condition.args[0] == x
|
| 546 |
+
assert whl1.condition.args[1] == 2
|
| 547 |
+
assert whl1.condition == Lt(x, 2, evaluate=False)
|
| 548 |
+
assert whl1.body.args == (xpp,)
|
| 549 |
+
assert whl1.func(*whl1.args) == whl1
|
| 550 |
+
|
| 551 |
+
cblk = CodeBlock(AddAugmentedAssignment(x, 1))
|
| 552 |
+
whl2 = While(x < 2, cblk)
|
| 553 |
+
assert whl1 == whl2
|
| 554 |
+
assert whl1 != While(x < 3, [xpp])
|
| 555 |
+
|
| 556 |
+
|
| 557 |
+
def test_Scope():
|
| 558 |
+
assign = Assignment(x, y)
|
| 559 |
+
incr = AddAugmentedAssignment(x, 1)
|
| 560 |
+
scp = Scope([assign, incr])
|
| 561 |
+
cblk = CodeBlock(assign, incr)
|
| 562 |
+
assert scp.body == cblk
|
| 563 |
+
assert scp == Scope(cblk)
|
| 564 |
+
assert scp != Scope([incr, assign])
|
| 565 |
+
assert scp.func(*scp.args) == scp
|
| 566 |
+
|
| 567 |
+
|
| 568 |
+
def test_Print():
|
| 569 |
+
fmt = "%d %.3f"
|
| 570 |
+
ps = Print([n, x], fmt)
|
| 571 |
+
assert str(ps.format_string) == fmt
|
| 572 |
+
assert ps.print_args == Tuple(n, x)
|
| 573 |
+
assert ps.args == (Tuple(n, x), QuotedString(fmt), none)
|
| 574 |
+
assert ps == Print((n, x), fmt)
|
| 575 |
+
assert ps != Print([x, n], fmt)
|
| 576 |
+
assert ps.func(*ps.args) == ps
|
| 577 |
+
|
| 578 |
+
ps2 = Print([n, x])
|
| 579 |
+
assert ps2 == Print([n, x])
|
| 580 |
+
assert ps2 != ps
|
| 581 |
+
assert ps2.format_string == None
|
| 582 |
+
|
| 583 |
+
|
| 584 |
+
def test_FunctionPrototype_and_FunctionDefinition():
|
| 585 |
+
vx = Variable(x, type=real)
|
| 586 |
+
vn = Variable(n, type=integer)
|
| 587 |
+
fp1 = FunctionPrototype(real, 'power', [vx, vn])
|
| 588 |
+
assert fp1.return_type == real
|
| 589 |
+
assert fp1.name == String('power')
|
| 590 |
+
assert fp1.parameters == Tuple(vx, vn)
|
| 591 |
+
assert fp1 == FunctionPrototype(real, 'power', [vx, vn])
|
| 592 |
+
assert fp1 != FunctionPrototype(real, 'power', [vn, vx])
|
| 593 |
+
assert fp1.func(*fp1.args) == fp1
|
| 594 |
+
|
| 595 |
+
|
| 596 |
+
body = [Assignment(x, x**n), Return(x)]
|
| 597 |
+
fd1 = FunctionDefinition(real, 'power', [vx, vn], body)
|
| 598 |
+
assert fd1.return_type == real
|
| 599 |
+
assert str(fd1.name) == 'power'
|
| 600 |
+
assert fd1.parameters == Tuple(vx, vn)
|
| 601 |
+
assert fd1.body == CodeBlock(*body)
|
| 602 |
+
assert fd1 == FunctionDefinition(real, 'power', [vx, vn], body)
|
| 603 |
+
assert fd1 != FunctionDefinition(real, 'power', [vx, vn], body[::-1])
|
| 604 |
+
assert fd1.func(*fd1.args) == fd1
|
| 605 |
+
|
| 606 |
+
fp2 = FunctionPrototype.from_FunctionDefinition(fd1)
|
| 607 |
+
assert fp2 == fp1
|
| 608 |
+
|
| 609 |
+
fd2 = FunctionDefinition.from_FunctionPrototype(fp1, body)
|
| 610 |
+
assert fd2 == fd1
|
| 611 |
+
|
| 612 |
+
|
| 613 |
+
def test_Return():
|
| 614 |
+
rs = Return(x)
|
| 615 |
+
assert rs.args == (x,)
|
| 616 |
+
assert rs == Return(x)
|
| 617 |
+
assert rs != Return(y)
|
| 618 |
+
assert rs.func(*rs.args) == rs
|
| 619 |
+
|
| 620 |
+
|
| 621 |
+
def test_FunctionCall():
|
| 622 |
+
fc = FunctionCall('power', (x, 3))
|
| 623 |
+
assert fc.function_args[0] == x
|
| 624 |
+
assert fc.function_args[1] == 3
|
| 625 |
+
assert len(fc.function_args) == 2
|
| 626 |
+
assert isinstance(fc.function_args[1], Integer)
|
| 627 |
+
assert fc == FunctionCall('power', (x, 3))
|
| 628 |
+
assert fc != FunctionCall('power', (3, x))
|
| 629 |
+
assert fc != FunctionCall('Power', (x, 3))
|
| 630 |
+
assert fc.func(*fc.args) == fc
|
| 631 |
+
|
| 632 |
+
fc2 = FunctionCall('fma', [2, 3, 4])
|
| 633 |
+
assert len(fc2.function_args) == 3
|
| 634 |
+
assert fc2.function_args[0] == 2
|
| 635 |
+
assert fc2.function_args[1] == 3
|
| 636 |
+
assert fc2.function_args[2] == 4
|
| 637 |
+
assert str(fc2) in ( # not sure if QuotedString is a better default...
|
| 638 |
+
'FunctionCall(fma, function_args=(2, 3, 4))',
|
| 639 |
+
'FunctionCall("fma", function_args=(2, 3, 4))',
|
| 640 |
+
)
|
| 641 |
+
|
| 642 |
+
def test_ast_replace():
|
| 643 |
+
x = Variable('x', real)
|
| 644 |
+
y = Variable('y', real)
|
| 645 |
+
n = Variable('n', integer)
|
| 646 |
+
|
| 647 |
+
pwer = FunctionDefinition(real, 'pwer', [x, n], [pow(x.symbol, n.symbol)])
|
| 648 |
+
pname = pwer.name
|
| 649 |
+
pcall = FunctionCall('pwer', [y, 3])
|
| 650 |
+
|
| 651 |
+
tree1 = CodeBlock(pwer, pcall)
|
| 652 |
+
assert str(tree1.args[0].name) == 'pwer'
|
| 653 |
+
assert str(tree1.args[1].name) == 'pwer'
|
| 654 |
+
for a, b in zip(tree1, [pwer, pcall]):
|
| 655 |
+
assert a == b
|
| 656 |
+
|
| 657 |
+
tree2 = tree1.replace(pname, String('power'))
|
| 658 |
+
assert str(tree1.args[0].name) == 'pwer'
|
| 659 |
+
assert str(tree1.args[1].name) == 'pwer'
|
| 660 |
+
assert str(tree2.args[0].name) == 'power'
|
| 661 |
+
assert str(tree2.args[1].name) == 'power'
|
lib/python3.10/site-packages/sympy/codegen/tests/test_cfunctions.py
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.core.numbers import (Rational, pi)
|
| 2 |
+
from sympy.core.singleton import S
|
| 3 |
+
from sympy.core.symbol import (Symbol, symbols)
|
| 4 |
+
from sympy.functions.elementary.exponential import (exp, log)
|
| 5 |
+
from sympy.codegen.cfunctions import (
|
| 6 |
+
expm1, log1p, exp2, log2, fma, log10, Sqrt, Cbrt, hypot
|
| 7 |
+
)
|
| 8 |
+
from sympy.core.function import expand_log
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def test_expm1():
|
| 12 |
+
# Eval
|
| 13 |
+
assert expm1(0) == 0
|
| 14 |
+
|
| 15 |
+
x = Symbol('x', real=True)
|
| 16 |
+
|
| 17 |
+
# Expand and rewrite
|
| 18 |
+
assert expm1(x).expand(func=True) - exp(x) == -1
|
| 19 |
+
assert expm1(x).rewrite('tractable') - exp(x) == -1
|
| 20 |
+
assert expm1(x).rewrite('exp') - exp(x) == -1
|
| 21 |
+
|
| 22 |
+
# Precision
|
| 23 |
+
assert not ((exp(1e-10).evalf() - 1) - 1e-10 - 5e-21) < 1e-22 # for comparison
|
| 24 |
+
assert abs(expm1(1e-10).evalf() - 1e-10 - 5e-21) < 1e-22
|
| 25 |
+
|
| 26 |
+
# Properties
|
| 27 |
+
assert expm1(x).is_real
|
| 28 |
+
assert expm1(x).is_finite
|
| 29 |
+
|
| 30 |
+
# Diff
|
| 31 |
+
assert expm1(42*x).diff(x) - 42*exp(42*x) == 0
|
| 32 |
+
assert expm1(42*x).diff(x) - expm1(42*x).expand(func=True).diff(x) == 0
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def test_log1p():
|
| 36 |
+
# Eval
|
| 37 |
+
assert log1p(0) == 0
|
| 38 |
+
d = S(10)
|
| 39 |
+
assert expand_log(log1p(d**-1000) - log(d**1000 + 1) + log(d**1000)) == 0
|
| 40 |
+
|
| 41 |
+
x = Symbol('x', real=True)
|
| 42 |
+
|
| 43 |
+
# Expand and rewrite
|
| 44 |
+
assert log1p(x).expand(func=True) - log(x + 1) == 0
|
| 45 |
+
assert log1p(x).rewrite('tractable') - log(x + 1) == 0
|
| 46 |
+
assert log1p(x).rewrite('log') - log(x + 1) == 0
|
| 47 |
+
|
| 48 |
+
# Precision
|
| 49 |
+
assert not abs(log(1e-99 + 1).evalf() - 1e-99) < 1e-100 # for comparison
|
| 50 |
+
assert abs(expand_log(log1p(1e-99)).evalf() - 1e-99) < 1e-100
|
| 51 |
+
|
| 52 |
+
# Properties
|
| 53 |
+
assert log1p(-2**Rational(-1, 2)).is_real
|
| 54 |
+
|
| 55 |
+
assert not log1p(-1).is_finite
|
| 56 |
+
assert log1p(pi).is_finite
|
| 57 |
+
|
| 58 |
+
assert not log1p(x).is_positive
|
| 59 |
+
assert log1p(Symbol('y', positive=True)).is_positive
|
| 60 |
+
|
| 61 |
+
assert not log1p(x).is_zero
|
| 62 |
+
assert log1p(Symbol('z', zero=True)).is_zero
|
| 63 |
+
|
| 64 |
+
assert not log1p(x).is_nonnegative
|
| 65 |
+
assert log1p(Symbol('o', nonnegative=True)).is_nonnegative
|
| 66 |
+
|
| 67 |
+
# Diff
|
| 68 |
+
assert log1p(42*x).diff(x) - 42/(42*x + 1) == 0
|
| 69 |
+
assert log1p(42*x).diff(x) - log1p(42*x).expand(func=True).diff(x) == 0
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def test_exp2():
|
| 73 |
+
# Eval
|
| 74 |
+
assert exp2(2) == 4
|
| 75 |
+
|
| 76 |
+
x = Symbol('x', real=True)
|
| 77 |
+
|
| 78 |
+
# Expand
|
| 79 |
+
assert exp2(x).expand(func=True) - 2**x == 0
|
| 80 |
+
|
| 81 |
+
# Diff
|
| 82 |
+
assert exp2(42*x).diff(x) - 42*exp2(42*x)*log(2) == 0
|
| 83 |
+
assert exp2(42*x).diff(x) - exp2(42*x).diff(x) == 0
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
def test_log2():
|
| 87 |
+
# Eval
|
| 88 |
+
assert log2(8) == 3
|
| 89 |
+
assert log2(pi) != log(pi)/log(2) # log2 should *save* (CPU) instructions
|
| 90 |
+
|
| 91 |
+
x = Symbol('x', real=True)
|
| 92 |
+
assert log2(x) != log(x)/log(2)
|
| 93 |
+
assert log2(2**x) == x
|
| 94 |
+
|
| 95 |
+
# Expand
|
| 96 |
+
assert log2(x).expand(func=True) - log(x)/log(2) == 0
|
| 97 |
+
|
| 98 |
+
# Diff
|
| 99 |
+
assert log2(42*x).diff() - 1/(log(2)*x) == 0
|
| 100 |
+
assert log2(42*x).diff() - log2(42*x).expand(func=True).diff(x) == 0
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
def test_fma():
|
| 104 |
+
x, y, z = symbols('x y z')
|
| 105 |
+
|
| 106 |
+
# Expand
|
| 107 |
+
assert fma(x, y, z).expand(func=True) - x*y - z == 0
|
| 108 |
+
|
| 109 |
+
expr = fma(17*x, 42*y, 101*z)
|
| 110 |
+
|
| 111 |
+
# Diff
|
| 112 |
+
assert expr.diff(x) - expr.expand(func=True).diff(x) == 0
|
| 113 |
+
assert expr.diff(y) - expr.expand(func=True).diff(y) == 0
|
| 114 |
+
assert expr.diff(z) - expr.expand(func=True).diff(z) == 0
|
| 115 |
+
|
| 116 |
+
assert expr.diff(x) - 17*42*y == 0
|
| 117 |
+
assert expr.diff(y) - 17*42*x == 0
|
| 118 |
+
assert expr.diff(z) - 101 == 0
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
def test_log10():
|
| 122 |
+
x = Symbol('x')
|
| 123 |
+
|
| 124 |
+
# Expand
|
| 125 |
+
assert log10(x).expand(func=True) - log(x)/log(10) == 0
|
| 126 |
+
|
| 127 |
+
# Diff
|
| 128 |
+
assert log10(42*x).diff(x) - 1/(log(10)*x) == 0
|
| 129 |
+
assert log10(42*x).diff(x) - log10(42*x).expand(func=True).diff(x) == 0
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
def test_Cbrt():
|
| 133 |
+
x = Symbol('x')
|
| 134 |
+
|
| 135 |
+
# Expand
|
| 136 |
+
assert Cbrt(x).expand(func=True) - x**Rational(1, 3) == 0
|
| 137 |
+
|
| 138 |
+
# Diff
|
| 139 |
+
assert Cbrt(42*x).diff(x) - 42*(42*x)**(Rational(1, 3) - 1)/3 == 0
|
| 140 |
+
assert Cbrt(42*x).diff(x) - Cbrt(42*x).expand(func=True).diff(x) == 0
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
def test_Sqrt():
|
| 144 |
+
x = Symbol('x')
|
| 145 |
+
|
| 146 |
+
# Expand
|
| 147 |
+
assert Sqrt(x).expand(func=True) - x**S.Half == 0
|
| 148 |
+
|
| 149 |
+
# Diff
|
| 150 |
+
assert Sqrt(42*x).diff(x) - 42*(42*x)**(S.Half - 1)/2 == 0
|
| 151 |
+
assert Sqrt(42*x).diff(x) - Sqrt(42*x).expand(func=True).diff(x) == 0
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
def test_hypot():
|
| 155 |
+
x, y = symbols('x y')
|
| 156 |
+
|
| 157 |
+
# Expand
|
| 158 |
+
assert hypot(x, y).expand(func=True) - (x**2 + y**2)**S.Half == 0
|
| 159 |
+
|
| 160 |
+
# Diff
|
| 161 |
+
assert hypot(17*x, 42*y).diff(x).expand(func=True) - hypot(17*x, 42*y).expand(func=True).diff(x) == 0
|
| 162 |
+
assert hypot(17*x, 42*y).diff(y).expand(func=True) - hypot(17*x, 42*y).expand(func=True).diff(y) == 0
|
| 163 |
+
|
| 164 |
+
assert hypot(17*x, 42*y).diff(x).expand(func=True) - 2*17*17*x*((17*x)**2 + (42*y)**2)**Rational(-1, 2)/2 == 0
|
| 165 |
+
assert hypot(17*x, 42*y).diff(y).expand(func=True) - 2*42*42*y*((17*x)**2 + (42*y)**2)**Rational(-1, 2)/2 == 0
|
lib/python3.10/site-packages/sympy/codegen/tests/test_cnodes.py
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.core.symbol import symbols
|
| 2 |
+
from sympy.printing.codeprinter import ccode
|
| 3 |
+
from sympy.codegen.ast import Declaration, Variable, float64, int64, String, CodeBlock
|
| 4 |
+
from sympy.codegen.cnodes import (
|
| 5 |
+
alignof, CommaOperator, goto, Label, PreDecrement, PostDecrement, PreIncrement, PostIncrement,
|
| 6 |
+
sizeof, union, struct
|
| 7 |
+
)
|
| 8 |
+
|
| 9 |
+
x, y = symbols('x y')
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def test_alignof():
|
| 13 |
+
ax = alignof(x)
|
| 14 |
+
assert ccode(ax) == 'alignof(x)'
|
| 15 |
+
assert ax.func(*ax.args) == ax
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def test_CommaOperator():
|
| 19 |
+
expr = CommaOperator(PreIncrement(x), 2*x)
|
| 20 |
+
assert ccode(expr) == '(++(x), 2*x)'
|
| 21 |
+
assert expr.func(*expr.args) == expr
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def test_goto_Label():
|
| 25 |
+
s = 'early_exit'
|
| 26 |
+
g = goto(s)
|
| 27 |
+
assert g.func(*g.args) == g
|
| 28 |
+
assert g != goto('foobar')
|
| 29 |
+
assert ccode(g) == 'goto early_exit'
|
| 30 |
+
|
| 31 |
+
l1 = Label(s)
|
| 32 |
+
assert ccode(l1) == 'early_exit:'
|
| 33 |
+
assert l1 == Label('early_exit')
|
| 34 |
+
assert l1 != Label('foobar')
|
| 35 |
+
|
| 36 |
+
body = [PreIncrement(x)]
|
| 37 |
+
l2 = Label(s, body)
|
| 38 |
+
assert l2.name == String("early_exit")
|
| 39 |
+
assert l2.body == CodeBlock(PreIncrement(x))
|
| 40 |
+
assert ccode(l2) == ("early_exit:\n"
|
| 41 |
+
"++(x);")
|
| 42 |
+
|
| 43 |
+
body = [PreIncrement(x), PreDecrement(y)]
|
| 44 |
+
l2 = Label(s, body)
|
| 45 |
+
assert l2.name == String("early_exit")
|
| 46 |
+
assert l2.body == CodeBlock(PreIncrement(x), PreDecrement(y))
|
| 47 |
+
assert ccode(l2) == ("early_exit:\n"
|
| 48 |
+
"{\n ++(x);\n --(y);\n}")
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def test_PreDecrement():
|
| 52 |
+
p = PreDecrement(x)
|
| 53 |
+
assert p.func(*p.args) == p
|
| 54 |
+
assert ccode(p) == '--(x)'
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def test_PostDecrement():
|
| 58 |
+
p = PostDecrement(x)
|
| 59 |
+
assert p.func(*p.args) == p
|
| 60 |
+
assert ccode(p) == '(x)--'
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def test_PreIncrement():
|
| 64 |
+
p = PreIncrement(x)
|
| 65 |
+
assert p.func(*p.args) == p
|
| 66 |
+
assert ccode(p) == '++(x)'
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def test_PostIncrement():
|
| 70 |
+
p = PostIncrement(x)
|
| 71 |
+
assert p.func(*p.args) == p
|
| 72 |
+
assert ccode(p) == '(x)++'
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def test_sizeof():
|
| 76 |
+
typename = 'unsigned int'
|
| 77 |
+
sz = sizeof(typename)
|
| 78 |
+
assert ccode(sz) == 'sizeof(%s)' % typename
|
| 79 |
+
assert sz.func(*sz.args) == sz
|
| 80 |
+
assert not sz.is_Atom
|
| 81 |
+
assert sz.atoms() == {String('unsigned int'), String('sizeof')}
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
def test_struct():
|
| 85 |
+
vx, vy = Variable(x, type=float64), Variable(y, type=float64)
|
| 86 |
+
s = struct('vec2', [vx, vy])
|
| 87 |
+
assert s.func(*s.args) == s
|
| 88 |
+
assert s == struct('vec2', (vx, vy))
|
| 89 |
+
assert s != struct('vec2', (vy, vx))
|
| 90 |
+
assert str(s.name) == 'vec2'
|
| 91 |
+
assert len(s.declarations) == 2
|
| 92 |
+
assert all(isinstance(arg, Declaration) for arg in s.declarations)
|
| 93 |
+
assert ccode(s) == (
|
| 94 |
+
"struct vec2 {\n"
|
| 95 |
+
" double x;\n"
|
| 96 |
+
" double y;\n"
|
| 97 |
+
"}")
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
def test_union():
|
| 101 |
+
vx, vy = Variable(x, type=float64), Variable(y, type=int64)
|
| 102 |
+
u = union('dualuse', [vx, vy])
|
| 103 |
+
assert u.func(*u.args) == u
|
| 104 |
+
assert u == union('dualuse', (vx, vy))
|
| 105 |
+
assert str(u.name) == 'dualuse'
|
| 106 |
+
assert len(u.declarations) == 2
|
| 107 |
+
assert all(isinstance(arg, Declaration) for arg in u.declarations)
|
| 108 |
+
assert ccode(u) == (
|
| 109 |
+
"union dualuse {\n"
|
| 110 |
+
" double x;\n"
|
| 111 |
+
" int64_t y;\n"
|
| 112 |
+
"}")
|
lib/python3.10/site-packages/sympy/codegen/tests/test_cxxnodes.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.core.symbol import Symbol
|
| 2 |
+
from sympy.codegen.ast import Type
|
| 3 |
+
from sympy.codegen.cxxnodes import using
|
| 4 |
+
from sympy.printing.codeprinter import cxxcode
|
| 5 |
+
|
| 6 |
+
x = Symbol('x')
|
| 7 |
+
|
| 8 |
+
def test_using():
|
| 9 |
+
v = Type('std::vector')
|
| 10 |
+
u1 = using(v)
|
| 11 |
+
assert cxxcode(u1) == 'using std::vector'
|
| 12 |
+
|
| 13 |
+
u2 = using(v, 'vec')
|
| 14 |
+
assert cxxcode(u2) == 'using vec = std::vector'
|
lib/python3.10/site-packages/sympy/codegen/tests/test_fnodes.py
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import tempfile
|
| 3 |
+
from sympy.core.symbol import (Symbol, symbols)
|
| 4 |
+
from sympy.codegen.ast import (
|
| 5 |
+
Assignment, Print, Declaration, FunctionDefinition, Return, real,
|
| 6 |
+
FunctionCall, Variable, Element, integer
|
| 7 |
+
)
|
| 8 |
+
from sympy.codegen.fnodes import (
|
| 9 |
+
allocatable, ArrayConstructor, isign, dsign, cmplx, kind, literal_dp,
|
| 10 |
+
Program, Module, use, Subroutine, dimension, assumed_extent, ImpliedDoLoop,
|
| 11 |
+
intent_out, size, Do, SubroutineCall, sum_, array, bind_C
|
| 12 |
+
)
|
| 13 |
+
from sympy.codegen.futils import render_as_module
|
| 14 |
+
from sympy.core.expr import unchanged
|
| 15 |
+
from sympy.external import import_module
|
| 16 |
+
from sympy.printing.codeprinter import fcode
|
| 17 |
+
from sympy.utilities._compilation import has_fortran, compile_run_strings, compile_link_import_strings
|
| 18 |
+
from sympy.utilities._compilation.util import may_xfail
|
| 19 |
+
from sympy.testing.pytest import skip, XFAIL
|
| 20 |
+
|
| 21 |
+
cython = import_module('cython')
|
| 22 |
+
np = import_module('numpy')
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def test_size():
|
| 26 |
+
x = Symbol('x', real=True)
|
| 27 |
+
sx = size(x)
|
| 28 |
+
assert fcode(sx, source_format='free') == 'size(x)'
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
@may_xfail
|
| 32 |
+
def test_size_assumed_shape():
|
| 33 |
+
if not has_fortran():
|
| 34 |
+
skip("No fortran compiler found.")
|
| 35 |
+
a = Symbol('a', real=True)
|
| 36 |
+
body = [Return((sum_(a**2)/size(a))**.5)]
|
| 37 |
+
arr = array(a, dim=[':'], intent='in')
|
| 38 |
+
fd = FunctionDefinition(real, 'rms', [arr], body)
|
| 39 |
+
render_as_module([fd], 'mod_rms')
|
| 40 |
+
|
| 41 |
+
(stdout, stderr), info = compile_run_strings([
|
| 42 |
+
('rms.f90', render_as_module([fd], 'mod_rms')),
|
| 43 |
+
('main.f90', (
|
| 44 |
+
'program myprog\n'
|
| 45 |
+
'use mod_rms, only: rms\n'
|
| 46 |
+
'real*8, dimension(4), parameter :: x = [4, 2, 2, 2]\n'
|
| 47 |
+
'print *, dsqrt(7d0) - rms(x)\n'
|
| 48 |
+
'end program\n'
|
| 49 |
+
))
|
| 50 |
+
], clean=True)
|
| 51 |
+
assert '0.00000' in stdout
|
| 52 |
+
assert stderr == ''
|
| 53 |
+
assert info['exit_status'] == os.EX_OK
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
@XFAIL # https://github.com/sympy/sympy/issues/20265
|
| 57 |
+
@may_xfail
|
| 58 |
+
def test_ImpliedDoLoop():
|
| 59 |
+
if not has_fortran():
|
| 60 |
+
skip("No fortran compiler found.")
|
| 61 |
+
|
| 62 |
+
a, i = symbols('a i', integer=True)
|
| 63 |
+
idl = ImpliedDoLoop(i**3, i, -3, 3, 2)
|
| 64 |
+
ac = ArrayConstructor([-28, idl, 28])
|
| 65 |
+
a = array(a, dim=[':'], attrs=[allocatable])
|
| 66 |
+
prog = Program('idlprog', [
|
| 67 |
+
a.as_Declaration(),
|
| 68 |
+
Assignment(a, ac),
|
| 69 |
+
Print([a])
|
| 70 |
+
])
|
| 71 |
+
fsrc = fcode(prog, standard=2003, source_format='free')
|
| 72 |
+
(stdout, stderr), info = compile_run_strings([('main.f90', fsrc)], clean=True)
|
| 73 |
+
for numstr in '-28 -27 -1 1 27 28'.split():
|
| 74 |
+
assert numstr in stdout
|
| 75 |
+
assert stderr == ''
|
| 76 |
+
assert info['exit_status'] == os.EX_OK
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
@may_xfail
|
| 80 |
+
def test_Program():
|
| 81 |
+
x = Symbol('x', real=True)
|
| 82 |
+
vx = Variable.deduced(x, 42)
|
| 83 |
+
decl = Declaration(vx)
|
| 84 |
+
prnt = Print([x, x+1])
|
| 85 |
+
prog = Program('foo', [decl, prnt])
|
| 86 |
+
if not has_fortran():
|
| 87 |
+
skip("No fortran compiler found.")
|
| 88 |
+
|
| 89 |
+
(stdout, stderr), info = compile_run_strings([('main.f90', fcode(prog, standard=90))], clean=True)
|
| 90 |
+
assert '42' in stdout
|
| 91 |
+
assert '43' in stdout
|
| 92 |
+
assert stderr == ''
|
| 93 |
+
assert info['exit_status'] == os.EX_OK
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
@may_xfail
|
| 97 |
+
def test_Module():
|
| 98 |
+
x = Symbol('x', real=True)
|
| 99 |
+
v_x = Variable.deduced(x)
|
| 100 |
+
sq = FunctionDefinition(real, 'sqr', [v_x], [Return(x**2)])
|
| 101 |
+
mod_sq = Module('mod_sq', [], [sq])
|
| 102 |
+
sq_call = FunctionCall('sqr', [42.])
|
| 103 |
+
prg_sq = Program('foobar', [
|
| 104 |
+
use('mod_sq', only=['sqr']),
|
| 105 |
+
Print(['"Square of 42 = "', sq_call])
|
| 106 |
+
])
|
| 107 |
+
if not has_fortran():
|
| 108 |
+
skip("No fortran compiler found.")
|
| 109 |
+
(stdout, stderr), info = compile_run_strings([
|
| 110 |
+
('mod_sq.f90', fcode(mod_sq, standard=90)),
|
| 111 |
+
('main.f90', fcode(prg_sq, standard=90))
|
| 112 |
+
], clean=True)
|
| 113 |
+
assert '42' in stdout
|
| 114 |
+
assert str(42**2) in stdout
|
| 115 |
+
assert stderr == ''
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
@XFAIL # https://github.com/sympy/sympy/issues/20265
|
| 119 |
+
@may_xfail
|
| 120 |
+
def test_Subroutine():
|
| 121 |
+
# Code to generate the subroutine in the example from
|
| 122 |
+
# http://www.fortran90.org/src/best-practices.html#arrays
|
| 123 |
+
r = Symbol('r', real=True)
|
| 124 |
+
i = Symbol('i', integer=True)
|
| 125 |
+
v_r = Variable.deduced(r, attrs=(dimension(assumed_extent), intent_out))
|
| 126 |
+
v_i = Variable.deduced(i)
|
| 127 |
+
v_n = Variable('n', integer)
|
| 128 |
+
do_loop = Do([
|
| 129 |
+
Assignment(Element(r, [i]), literal_dp(1)/i**2)
|
| 130 |
+
], i, 1, v_n)
|
| 131 |
+
sub = Subroutine("f", [v_r], [
|
| 132 |
+
Declaration(v_n),
|
| 133 |
+
Declaration(v_i),
|
| 134 |
+
Assignment(v_n, size(r)),
|
| 135 |
+
do_loop
|
| 136 |
+
])
|
| 137 |
+
x = Symbol('x', real=True)
|
| 138 |
+
v_x3 = Variable.deduced(x, attrs=[dimension(3)])
|
| 139 |
+
mod = Module('mymod', definitions=[sub])
|
| 140 |
+
prog = Program('foo', [
|
| 141 |
+
use(mod, only=[sub]),
|
| 142 |
+
Declaration(v_x3),
|
| 143 |
+
SubroutineCall(sub, [v_x3]),
|
| 144 |
+
Print([sum_(v_x3), v_x3])
|
| 145 |
+
])
|
| 146 |
+
|
| 147 |
+
if not has_fortran():
|
| 148 |
+
skip("No fortran compiler found.")
|
| 149 |
+
|
| 150 |
+
(stdout, stderr), info = compile_run_strings([
|
| 151 |
+
('a.f90', fcode(mod, standard=90)),
|
| 152 |
+
('b.f90', fcode(prog, standard=90))
|
| 153 |
+
], clean=True)
|
| 154 |
+
ref = [1.0/i**2 for i in range(1, 4)]
|
| 155 |
+
assert str(sum(ref))[:-3] in stdout
|
| 156 |
+
for _ in ref:
|
| 157 |
+
assert str(_)[:-3] in stdout
|
| 158 |
+
assert stderr == ''
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
def test_isign():
|
| 162 |
+
x = Symbol('x', integer=True)
|
| 163 |
+
assert unchanged(isign, 1, x)
|
| 164 |
+
assert fcode(isign(1, x), standard=95, source_format='free') == 'isign(1, x)'
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
def test_dsign():
|
| 168 |
+
x = Symbol('x')
|
| 169 |
+
assert unchanged(dsign, 1, x)
|
| 170 |
+
assert fcode(dsign(literal_dp(1), x), standard=95, source_format='free') == 'dsign(1d0, x)'
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
def test_cmplx():
|
| 174 |
+
x = Symbol('x')
|
| 175 |
+
assert unchanged(cmplx, 1, x)
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
def test_kind():
|
| 179 |
+
x = Symbol('x')
|
| 180 |
+
assert unchanged(kind, x)
|
| 181 |
+
|
| 182 |
+
|
| 183 |
+
def test_literal_dp():
|
| 184 |
+
assert fcode(literal_dp(0), source_format='free') == '0d0'
|
| 185 |
+
|
| 186 |
+
|
| 187 |
+
@may_xfail
|
| 188 |
+
def test_bind_C():
|
| 189 |
+
if not has_fortran():
|
| 190 |
+
skip("No fortran compiler found.")
|
| 191 |
+
if not cython:
|
| 192 |
+
skip("Cython not found.")
|
| 193 |
+
if not np:
|
| 194 |
+
skip("NumPy not found.")
|
| 195 |
+
|
| 196 |
+
a = Symbol('a', real=True)
|
| 197 |
+
s = Symbol('s', integer=True)
|
| 198 |
+
body = [Return((sum_(a**2)/s)**.5)]
|
| 199 |
+
arr = array(a, dim=[s], intent='in')
|
| 200 |
+
fd = FunctionDefinition(real, 'rms', [arr, s], body, attrs=[bind_C('rms')])
|
| 201 |
+
f_mod = render_as_module([fd], 'mod_rms')
|
| 202 |
+
|
| 203 |
+
with tempfile.TemporaryDirectory() as folder:
|
| 204 |
+
mod, info = compile_link_import_strings([
|
| 205 |
+
('rms.f90', f_mod),
|
| 206 |
+
('_rms.pyx', (
|
| 207 |
+
"#cython: language_level={}\n".format("3") +
|
| 208 |
+
"cdef extern double rms(double*, int*)\n"
|
| 209 |
+
"def py_rms(double[::1] x):\n"
|
| 210 |
+
" cdef int s = x.size\n"
|
| 211 |
+
" return rms(&x[0], &s)\n"))
|
| 212 |
+
], build_dir=folder)
|
| 213 |
+
assert abs(mod.py_rms(np.array([2., 4., 2., 2.])) - 7**0.5) < 1e-14
|
lib/python3.10/site-packages/sympy/codegen/tests/test_matrix_nodes.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.core.symbol import symbols
|
| 2 |
+
from sympy.core.function import Function
|
| 3 |
+
from sympy.matrices.dense import Matrix
|
| 4 |
+
from sympy.matrices.dense import zeros
|
| 5 |
+
from sympy.simplify.simplify import simplify
|
| 6 |
+
from sympy.codegen.matrix_nodes import MatrixSolve
|
| 7 |
+
from sympy.utilities.lambdify import lambdify
|
| 8 |
+
from sympy.printing.numpy import NumPyPrinter
|
| 9 |
+
from sympy.testing.pytest import skip
|
| 10 |
+
from sympy.external import import_module
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def test_matrix_solve_issue_24862():
|
| 14 |
+
A = Matrix(3, 3, symbols('a:9'))
|
| 15 |
+
b = Matrix(3, 1, symbols('b:3'))
|
| 16 |
+
hash(MatrixSolve(A, b))
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def test_matrix_solve_derivative_exact():
|
| 20 |
+
q = symbols('q')
|
| 21 |
+
a11, a12, a21, a22, b1, b2 = (
|
| 22 |
+
f(q) for f in symbols('a11 a12 a21 a22 b1 b2', cls=Function))
|
| 23 |
+
A = Matrix([[a11, a12], [a21, a22]])
|
| 24 |
+
b = Matrix([b1, b2])
|
| 25 |
+
x_lu = A.LUsolve(b)
|
| 26 |
+
dxdq_lu = A.LUsolve(b.diff(q) - A.diff(q) * A.LUsolve(b))
|
| 27 |
+
assert simplify(x_lu.diff(q) - dxdq_lu) == zeros(2, 1)
|
| 28 |
+
# dxdq_ms is the MatrixSolve equivalent of dxdq_lu
|
| 29 |
+
dxdq_ms = MatrixSolve(A, b.diff(q) - A.diff(q) * MatrixSolve(A, b))
|
| 30 |
+
assert MatrixSolve(A, b).diff(q) == dxdq_ms
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def test_matrix_solve_derivative_numpy():
|
| 34 |
+
np = import_module('numpy')
|
| 35 |
+
if not np:
|
| 36 |
+
skip("numpy not installed.")
|
| 37 |
+
q = symbols('q')
|
| 38 |
+
a11, a12, a21, a22, b1, b2 = (
|
| 39 |
+
f(q) for f in symbols('a11 a12 a21 a22 b1 b2', cls=Function))
|
| 40 |
+
A = Matrix([[a11, a12], [a21, a22]])
|
| 41 |
+
b = Matrix([b1, b2])
|
| 42 |
+
dx_lu = A.LUsolve(b).diff(q)
|
| 43 |
+
subs = {a11.diff(q): 0.2, a12.diff(q): 0.3, a21.diff(q): 0.1,
|
| 44 |
+
a22.diff(q): 0.5, b1.diff(q): 0.4, b2.diff(q): 0.9,
|
| 45 |
+
a11: 1.3, a12: 0.5, a21: 1.2, a22: 4, b1: 6.2, b2: 3.5}
|
| 46 |
+
p, p_vals = zip(*subs.items())
|
| 47 |
+
dx_sm = MatrixSolve(A, b).diff(q)
|
| 48 |
+
np.testing.assert_allclose(
|
| 49 |
+
lambdify(p, dx_sm, printer=NumPyPrinter)(*p_vals),
|
| 50 |
+
lambdify(p, dx_lu, printer=NumPyPrinter)(*p_vals))
|
lib/python3.10/site-packages/sympy/codegen/tests/test_numpy_nodes.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from itertools import product
|
| 2 |
+
from sympy.core.singleton import S
|
| 3 |
+
from sympy.core.symbol import symbols
|
| 4 |
+
from sympy.functions.elementary.exponential import (exp, log)
|
| 5 |
+
from sympy.printing.repr import srepr
|
| 6 |
+
from sympy.codegen.numpy_nodes import logaddexp, logaddexp2
|
| 7 |
+
|
| 8 |
+
x, y, z = symbols('x y z')
|
| 9 |
+
|
| 10 |
+
def test_logaddexp():
|
| 11 |
+
lae_xy = logaddexp(x, y)
|
| 12 |
+
ref_xy = log(exp(x) + exp(y))
|
| 13 |
+
for wrt, deriv_order in product([x, y, z], range(3)):
|
| 14 |
+
assert (
|
| 15 |
+
lae_xy.diff(wrt, deriv_order) -
|
| 16 |
+
ref_xy.diff(wrt, deriv_order)
|
| 17 |
+
).rewrite(log).simplify() == 0
|
| 18 |
+
|
| 19 |
+
one_third_e = 1*exp(1)/3
|
| 20 |
+
two_thirds_e = 2*exp(1)/3
|
| 21 |
+
logThirdE = log(one_third_e)
|
| 22 |
+
logTwoThirdsE = log(two_thirds_e)
|
| 23 |
+
lae_sum_to_e = logaddexp(logThirdE, logTwoThirdsE)
|
| 24 |
+
assert lae_sum_to_e.rewrite(log) == 1
|
| 25 |
+
assert lae_sum_to_e.simplify() == 1
|
| 26 |
+
was = logaddexp(2, 3)
|
| 27 |
+
assert srepr(was) == srepr(was.simplify()) # cannot simplify with 2, 3
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def test_logaddexp2():
|
| 31 |
+
lae2_xy = logaddexp2(x, y)
|
| 32 |
+
ref2_xy = log(2**x + 2**y)/log(2)
|
| 33 |
+
for wrt, deriv_order in product([x, y, z], range(3)):
|
| 34 |
+
assert (
|
| 35 |
+
lae2_xy.diff(wrt, deriv_order) -
|
| 36 |
+
ref2_xy.diff(wrt, deriv_order)
|
| 37 |
+
).rewrite(log).cancel() == 0
|
| 38 |
+
|
| 39 |
+
def lb(x):
|
| 40 |
+
return log(x)/log(2)
|
| 41 |
+
|
| 42 |
+
two_thirds = S.One*2/3
|
| 43 |
+
four_thirds = 2*two_thirds
|
| 44 |
+
lbTwoThirds = lb(two_thirds)
|
| 45 |
+
lbFourThirds = lb(four_thirds)
|
| 46 |
+
lae2_sum_to_2 = logaddexp2(lbTwoThirds, lbFourThirds)
|
| 47 |
+
assert lae2_sum_to_2.rewrite(log) == 1
|
| 48 |
+
assert lae2_sum_to_2.simplify() == 1
|
| 49 |
+
was = logaddexp2(x, y)
|
| 50 |
+
assert srepr(was) == srepr(was.simplify()) # cannot simplify with x, y
|