myokit 1.35.4__py3-none-any.whl → 1.36.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. myokit/__init__.py +5 -3
  2. myokit/__main__.py +9 -159
  3. myokit/_config.py +2 -2
  4. myokit/_expressions.py +6 -6
  5. myokit/_model_api.py +11 -7
  6. myokit/_myokit_version.py +1 -1
  7. myokit/_protocol.py +4 -0
  8. myokit/_sim/__init__.py +1 -0
  9. myokit/_sim/cvodessim.c +321 -177
  10. myokit/_sim/cvodessim.py +107 -43
  11. myokit/_sim/mcl.h +54 -0
  12. myokit/formats/__init__.py +63 -12
  13. myokit/formats/ansic/__init__.py +2 -1
  14. myokit/formats/ansic/_ewriter.py +159 -40
  15. myokit/formats/cpp/_ewriter.py +12 -1
  16. myokit/formats/cuda/_ewriter.py +15 -51
  17. myokit/formats/easyml/_ewriter.py +26 -54
  18. myokit/formats/heka/_patchmaster.py +15 -3
  19. myokit/formats/latex/_ewriter.py +103 -88
  20. myokit/formats/latex/_exporter.py +1 -1
  21. myokit/formats/mathml/_ewriter.py +2 -2
  22. myokit/formats/matlab/_ewriter.py +50 -28
  23. myokit/formats/opencl/_ewriter.py +61 -78
  24. myokit/formats/python/_ewriter.py +81 -50
  25. myokit/formats/stan/_ewriter.py +29 -37
  26. myokit/gui/source.py +1 -1
  27. myokit/lib/hh.py +3 -0
  28. myokit/lib/markov.py +6 -0
  29. myokit/tests/__init__.py +70 -0
  30. myokit/tests/data/decker.model +59 -59
  31. myokit/tests/test_formats.py +115 -7
  32. myokit/tests/test_formats_ansic.py +344 -0
  33. myokit/tests/test_formats_axon.py +17 -0
  34. myokit/tests/test_formats_cpp.py +97 -0
  35. myokit/tests/test_formats_cuda.py +226 -0
  36. myokit/tests/test_formats_easyml.py +169 -152
  37. myokit/tests/{test_formats_exporters.py → test_formats_exporters_run.py} +1 -69
  38. myokit/tests/test_formats_html.py +1 -3
  39. myokit/tests/test_formats_latex.py +211 -0
  40. myokit/tests/test_formats_mathml_content.py +13 -0
  41. myokit/tests/test_formats_mathml_presentation.py +54 -42
  42. myokit/tests/test_formats_matlab.py +218 -0
  43. myokit/tests/test_formats_opencl.py +206 -380
  44. myokit/tests/test_formats_python.py +557 -0
  45. myokit/tests/test_formats_stan.py +175 -0
  46. myokit/tests/test_formats_sympy.py +9 -2
  47. myokit/tests/test_lib_hh.py +36 -0
  48. myokit/tests/test_lib_plots.py +0 -16
  49. myokit/tests/test_model.py +21 -1
  50. myokit/tests/test_simulation_cvodes.py +137 -56
  51. myokit/tools.py +3 -2
  52. {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/LICENSE.txt +1 -1
  53. {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/METADATA +19 -8
  54. {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/RECORD +57 -52
  55. {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/WHEEL +1 -1
  56. myokit/tests/test_formats_expression_writers.py +0 -1281
  57. myokit/tests/test_formats_importers.py +0 -53
  58. {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/entry_points.txt +0 -0
  59. {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/top_level.txt +0 -0
@@ -8,392 +8,218 @@
8
8
  import unittest
9
9
 
10
10
  import myokit
11
- import myokit.formats
12
11
  import myokit.formats.opencl
13
12
 
13
+ from myokit import (
14
+ Number, PrefixPlus, PrefixMinus, Plus, Minus,
15
+ Multiply, Divide, Quotient, Remainder, Power, Sqrt,
16
+ Exp, Log, Log10, Sin, Cos, Tan, ASin, ACos, ATan, Floor, Ceil, Abs,
17
+ Not, And, Or, Equal, NotEqual, More, Less, MoreEqual, LessEqual,
18
+ If, Piecewise,
19
+ )
20
+
21
+ import myokit.tests
22
+
23
+
24
+ class OpenCLExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
25
+ """
26
+ Test conversion to Ansi C, as used by the Simulation.
27
+ Numerical tests are provided by composing and evaluating a single RHS.
28
+ """
29
+ _name = 'opencl'
30
+ _target = myokit.formats.opencl.OpenCLExpressionWriter
31
+
32
+ def test_number(self):
33
+ self.eq(Number(1), '1.0f')
34
+ self.eq(Number(-2), '-2.0f')
35
+ self.eq(Number(13, 'mV'), '13.0f')
36
+
37
+ def test_number_double(self):
38
+ w = self._target(precision=myokit.DOUBLE_PRECISION)
39
+ self.assertEqual(w.ex(Number(1)), '1.0')
40
+ self.assertEqual(w.ex(Number(-2)), '-2.0')
41
+ self.assertEqual(w.ex(Number(13, 'mV')), '13.0')
42
+
43
+ def test_name(self):
44
+ self.eq(self.a, 'a')
45
+ w = self._target()
46
+ w.set_lhs_function(lambda v: v.var().qname().upper())
47
+ self.assertEqual(w.ex(self.a), 'COMP.A')
48
+
49
+ def test_derivative(self):
50
+ self.eq(myokit.Derivative(self.a), 'dot(a)')
51
+
52
+ def test_partial_derivative(self):
53
+ self.assertRaisesRegex(
54
+ NotImplementedError, 'Partial',
55
+ self.w.ex, myokit.PartialDerivative(self.a, self.b))
14
56
 
15
- class OpenCLExpressionWriterTest(unittest.TestCase):
16
- """ Test the OpenCL ewriter class. """
17
-
18
- def test_basic(self):
19
-
20
- # Single and double precision and native maths
21
- ws = myokit.formats.opencl.OpenCLExpressionWriter()
22
- wd = myokit.formats.opencl.OpenCLExpressionWriter(
23
- myokit.DOUBLE_PRECISION)
24
- wn = myokit.formats.opencl.OpenCLExpressionWriter(native_math=False)
25
-
26
- a = myokit.Name(myokit.Model().add_component('c').add_variable('a'))
27
- b = myokit.Number('12', 'pF')
28
-
29
- # Name
30
- self.assertEqual(ws.ex(a), 'c.a')
31
- self.assertEqual(wd.ex(a), 'c.a')
32
- self.assertEqual(wn.ex(a), 'c.a')
33
-
34
- # Number with unit
35
- self.assertEqual(ws.ex(b), '12.0f')
36
- self.assertEqual(wd.ex(b), '12.0')
37
- self.assertEqual(wn.ex(b), '12.0f')
38
-
39
- # Prefix plus
40
- x = myokit.PrefixPlus(b)
41
- self.assertEqual(ws.ex(x), '12.0f')
42
- self.assertEqual(wd.ex(x), '12.0')
43
- self.assertEqual(wn.ex(x), '12.0f')
44
- # Prefix minus
45
- x = myokit.PrefixMinus(b)
46
- self.assertEqual(ws.ex(x), '(-12.0f)')
47
- self.assertEqual(wd.ex(x), '(-12.0)')
48
- self.assertEqual(wn.ex(x), '(-12.0f)')
49
-
50
- # Plus
51
- x = myokit.Plus(a, b)
52
- self.assertEqual(ws.ex(x), 'c.a + 12.0f')
53
- self.assertEqual(wd.ex(x), 'c.a + 12.0')
54
- self.assertEqual(wn.ex(x), 'c.a + 12.0f')
55
- # Minus
56
- x = myokit.Minus(a, b)
57
- self.assertEqual(ws.ex(x), 'c.a - 12.0f')
58
- self.assertEqual(wd.ex(x), 'c.a - 12.0')
59
- self.assertEqual(wn.ex(x), 'c.a - 12.0f')
60
- # Multiply
61
- x = myokit.Multiply(a, b)
62
- self.assertEqual(ws.ex(x), 'c.a * 12.0f')
63
- self.assertEqual(wd.ex(x), 'c.a * 12.0')
64
- self.assertEqual(wn.ex(x), 'c.a * 12.0f')
65
- # Divide
66
- x = myokit.Divide(a, b)
67
- self.assertEqual(ws.ex(x), 'c.a / 12.0f')
68
- self.assertEqual(wd.ex(x), 'c.a / 12.0')
69
- self.assertEqual(wn.ex(x), 'c.a / 12.0f')
70
-
71
- # Quotient
72
- x = myokit.Quotient(a, b)
73
- self.assertEqual(ws.ex(x), 'floor(c.a / 12.0f)')
74
- self.assertEqual(wd.ex(x), 'floor(c.a / 12.0)')
75
- self.assertEqual(wn.ex(x), 'floor(c.a / 12.0f)')
76
- # Remainder
77
- x = myokit.Remainder(a, b)
78
- self.assertEqual(ws.ex(x), 'c.a - 12.0f * (floor(c.a / 12.0f))')
79
- self.assertEqual(wd.ex(x), 'c.a - 12.0 * (floor(c.a / 12.0))')
80
- self.assertEqual(wn.ex(x), 'c.a - 12.0f * (floor(c.a / 12.0f))')
81
-
82
- def test_functions(self):
83
-
84
- # Single and double precision and native maths
85
- ws = myokit.formats.opencl.OpenCLExpressionWriter()
86
- wd = myokit.formats.opencl.OpenCLExpressionWriter(
87
- myokit.DOUBLE_PRECISION)
88
- wn = myokit.formats.opencl.OpenCLExpressionWriter(native_math=False)
89
-
90
- a = myokit.Name(myokit.Model().add_component('c').add_variable('a'))
91
- b = myokit.Number('12', 'pF')
92
-
93
- # Power
94
- x = myokit.Power(a, b)
95
- self.assertEqual(ws.ex(x), 'pow(c.a, 12.0f)')
96
- self.assertEqual(wd.ex(x), 'pow(c.a, 12.0)')
97
- self.assertEqual(wn.ex(x), 'pow(c.a, 12.0f)')
98
- # Square
99
- x = myokit.Power(a, myokit.Number(2))
100
- self.assertEqual(ws.ex(x), '(c.a * c.a)')
101
- self.assertEqual(wd.ex(x), '(c.a * c.a)')
102
- self.assertEqual(wn.ex(x), '(c.a * c.a)')
103
- # Square with brackets
104
- x = myokit.Power(myokit.Plus(a, b), myokit.Number(2))
105
- self.assertEqual(ws.ex(x), '((c.a + 12.0f) * (c.a + 12.0f))')
106
- self.assertEqual(wd.ex(x), '((c.a + 12.0) * (c.a + 12.0))')
107
- self.assertEqual(wn.ex(x), '((c.a + 12.0f) * (c.a + 12.0f))')
108
- # Sqrt
109
- x = myokit.Sqrt(b)
110
- self.assertEqual(ws.ex(x), 'native_sqrt(12.0f)')
111
- self.assertEqual(wd.ex(x), 'native_sqrt(12.0)')
112
- self.assertEqual(wn.ex(x), 'sqrt(12.0f)')
113
- # Exp
114
- x = myokit.Exp(a)
115
- self.assertEqual(ws.ex(x), 'native_exp(c.a)')
116
- self.assertEqual(wd.ex(x), 'native_exp(c.a)')
117
- self.assertEqual(wn.ex(x), 'exp(c.a)')
118
- # Log(a)
119
- x = myokit.Log(b)
120
- self.assertEqual(ws.ex(x), 'native_log(12.0f)')
121
- self.assertEqual(wd.ex(x), 'native_log(12.0)')
122
- self.assertEqual(wn.ex(x), 'log(12.0f)')
123
- # Log(a, b)
124
- x = myokit.Log(a, b)
125
- self.assertEqual(ws.ex(x), '(native_log(c.a) / native_log(12.0f))')
126
- self.assertEqual(wd.ex(x), '(native_log(c.a) / native_log(12.0))')
127
- self.assertEqual(wn.ex(x), '(log(c.a) / log(12.0f))')
128
- # Log10
129
- x = myokit.Log10(b)
130
- self.assertEqual(ws.ex(x), 'native_log10(12.0f)')
131
- self.assertEqual(wd.ex(x), 'native_log10(12.0)')
132
- self.assertEqual(wn.ex(x), 'log10(12.0f)')
133
-
134
- # Sin
135
- x = myokit.Sin(b)
136
- self.assertEqual(ws.ex(x), 'native_sin(12.0f)')
137
- self.assertEqual(wd.ex(x), 'native_sin(12.0)')
138
- self.assertEqual(wn.ex(x), 'sin(12.0f)')
139
- # Cos
140
- x = myokit.Cos(b)
141
- self.assertEqual(ws.ex(x), 'native_cos(12.0f)')
142
- self.assertEqual(wd.ex(x), 'native_cos(12.0)')
143
- self.assertEqual(wn.ex(x), 'cos(12.0f)')
144
- # Tan
145
- x = myokit.Tan(b)
146
- self.assertEqual(ws.ex(x), 'native_tan(12.0f)')
147
- self.assertEqual(wd.ex(x), 'native_tan(12.0)')
148
- self.assertEqual(wn.ex(x), 'tan(12.0f)')
149
- # ASin
150
- x = myokit.ASin(b)
151
- self.assertEqual(ws.ex(x), 'asin(12.0f)')
152
- self.assertEqual(wd.ex(x), 'asin(12.0)')
153
- self.assertEqual(wn.ex(x), 'asin(12.0f)')
154
- # ACos
155
- x = myokit.ACos(b)
156
- self.assertEqual(ws.ex(x), 'acos(12.0f)')
157
- self.assertEqual(wd.ex(x), 'acos(12.0)')
158
- self.assertEqual(wn.ex(x), 'acos(12.0f)')
159
- # ATan
160
- x = myokit.ATan(b)
161
- self.assertEqual(ws.ex(x), 'atan(12.0f)')
162
- self.assertEqual(wd.ex(x), 'atan(12.0)')
163
- self.assertEqual(wn.ex(x), 'atan(12.0f)')
164
-
165
- # Floor
166
- x = myokit.Floor(b)
167
- self.assertEqual(ws.ex(x), 'floor(12.0f)')
168
- self.assertEqual(wd.ex(x), 'floor(12.0)')
169
- self.assertEqual(wn.ex(x), 'floor(12.0f)')
170
- # Ceil
171
- x = myokit.Ceil(b)
172
- self.assertEqual(ws.ex(x), 'ceil(12.0f)')
173
- self.assertEqual(wd.ex(x), 'ceil(12.0)')
174
- self.assertEqual(wn.ex(x), 'ceil(12.0f)')
175
- # Abs
176
- x = myokit.Abs(b)
177
- self.assertEqual(ws.ex(x), 'fabs(12.0f)')
178
- self.assertEqual(wd.ex(x), 'fabs(12.0)')
179
- self.assertEqual(wn.ex(x), 'fabs(12.0f)')
180
-
181
- def test_conditional(self):
182
-
183
- # Single and double precision and native maths
184
- ws = myokit.formats.opencl.OpenCLExpressionWriter()
185
- wd = myokit.formats.opencl.OpenCLExpressionWriter(
186
- myokit.DOUBLE_PRECISION)
187
- wn = myokit.formats.opencl.OpenCLExpressionWriter(native_math=False)
188
-
189
- a = myokit.Name(myokit.Model().add_component('c').add_variable('a'))
190
- b = myokit.Number('12', 'pF')
191
- cond1 = myokit.parse_expression('5 > 3')
192
- cond2 = myokit.parse_expression('2 < 1')
193
-
194
- # Equal
195
- x = myokit.Equal(a, b)
196
- self.assertEqual(ws.ex(x), '(c.a == 12.0f)')
197
- self.assertEqual(wd.ex(x), '(c.a == 12.0)')
198
- self.assertEqual(wn.ex(x), '(c.a == 12.0f)')
199
- x = myokit.Equal(cond1, cond2)
200
- self.assertEqual(ws.ex(x), '((5.0f > 3.0f) == (2.0f < 1.0f))')
201
- self.assertEqual(wd.ex(x), '((5.0 > 3.0) == (2.0 < 1.0))')
202
- self.assertEqual(wn.ex(x), '((5.0f > 3.0f) == (2.0f < 1.0f))')
203
- x = myokit.Equal(cond1, b)
204
- self.assertEqual(ws.ex(x), '((5.0f > 3.0f) == (12.0f != 0.0f))')
205
- self.assertEqual(wd.ex(x), '((5.0 > 3.0) == (12.0 != 0.0))')
206
- self.assertEqual(wn.ex(x), '((5.0f > 3.0f) == (12.0f != 0.0f))')
207
- x = myokit.Equal(a, cond2)
208
- self.assertEqual(ws.ex(x), '((c.a != 0.0f) == (2.0f < 1.0f))')
209
- self.assertEqual(wd.ex(x), '((c.a != 0.0) == (2.0 < 1.0))')
210
- self.assertEqual(wn.ex(x), '((c.a != 0.0f) == (2.0f < 1.0f))')
211
-
212
- # NotEqual
213
- x = myokit.NotEqual(a, b)
214
- self.assertEqual(ws.ex(x), '(c.a != 12.0f)')
215
- self.assertEqual(wd.ex(x), '(c.a != 12.0)')
216
- self.assertEqual(wn.ex(x), '(c.a != 12.0f)')
217
- x = myokit.NotEqual(cond1, cond2)
218
- self.assertEqual(ws.ex(x), '((5.0f > 3.0f) != (2.0f < 1.0f))')
219
- self.assertEqual(wd.ex(x), '((5.0 > 3.0) != (2.0 < 1.0))')
220
- self.assertEqual(wn.ex(x), '((5.0f > 3.0f) != (2.0f < 1.0f))')
221
- x = myokit.NotEqual(cond1, b)
222
- self.assertEqual(ws.ex(x), '((5.0f > 3.0f) != (12.0f != 0.0f))')
223
- self.assertEqual(wd.ex(x), '((5.0 > 3.0) != (12.0 != 0.0))')
224
- self.assertEqual(wn.ex(x), '((5.0f > 3.0f) != (12.0f != 0.0f))')
225
- x = myokit.NotEqual(a, cond2)
226
- self.assertEqual(ws.ex(x), '((c.a != 0.0f) != (2.0f < 1.0f))')
227
- self.assertEqual(wd.ex(x), '((c.a != 0.0) != (2.0 < 1.0))')
228
- self.assertEqual(wn.ex(x), '((c.a != 0.0f) != (2.0f < 1.0f))')
229
-
230
- # More
231
- x = myokit.More(a, b)
232
- self.assertEqual(ws.ex(x), '(c.a > 12.0f)')
233
- self.assertEqual(wd.ex(x), '(c.a > 12.0)')
234
- self.assertEqual(wn.ex(x), '(c.a > 12.0f)')
235
- x = myokit.More(cond1, cond2)
236
- self.assertEqual(ws.ex(x), '((5.0f > 3.0f) > (2.0f < 1.0f))')
237
- self.assertEqual(wd.ex(x), '((5.0 > 3.0) > (2.0 < 1.0))')
238
- self.assertEqual(wn.ex(x), '((5.0f > 3.0f) > (2.0f < 1.0f))')
239
- x = myokit.More(cond1, b)
240
- self.assertEqual(ws.ex(x), '((5.0f > 3.0f) > (12.0f != 0.0f))')
241
- self.assertEqual(wd.ex(x), '((5.0 > 3.0) > (12.0 != 0.0))')
242
- self.assertEqual(wn.ex(x), '((5.0f > 3.0f) > (12.0f != 0.0f))')
243
- x = myokit.More(a, cond2)
244
- self.assertEqual(ws.ex(x), '((c.a != 0.0f) > (2.0f < 1.0f))')
245
- self.assertEqual(wd.ex(x), '((c.a != 0.0) > (2.0 < 1.0))')
246
- self.assertEqual(wn.ex(x), '((c.a != 0.0f) > (2.0f < 1.0f))')
247
-
248
- # Less
249
- x = myokit.Less(a, b)
250
- self.assertEqual(ws.ex(x), '(c.a < 12.0f)')
251
- self.assertEqual(wd.ex(x), '(c.a < 12.0)')
252
- self.assertEqual(wn.ex(x), '(c.a < 12.0f)')
253
- x = myokit.Less(cond1, cond2)
254
- self.assertEqual(ws.ex(x), '((5.0f > 3.0f) < (2.0f < 1.0f))')
255
- self.assertEqual(wd.ex(x), '((5.0 > 3.0) < (2.0 < 1.0))')
256
- self.assertEqual(wn.ex(x), '((5.0f > 3.0f) < (2.0f < 1.0f))')
257
- x = myokit.Less(cond1, b)
258
- self.assertEqual(ws.ex(x), '((5.0f > 3.0f) < (12.0f != 0.0f))')
259
- self.assertEqual(wd.ex(x), '((5.0 > 3.0) < (12.0 != 0.0))')
260
- self.assertEqual(wn.ex(x), '((5.0f > 3.0f) < (12.0f != 0.0f))')
261
- x = myokit.Less(a, cond2)
262
- self.assertEqual(ws.ex(x), '((c.a != 0.0f) < (2.0f < 1.0f))')
263
- self.assertEqual(wd.ex(x), '((c.a != 0.0) < (2.0 < 1.0))')
264
- self.assertEqual(wn.ex(x), '((c.a != 0.0f) < (2.0f < 1.0f))')
265
-
266
- # MoreEqual
267
- x = myokit.MoreEqual(a, b)
268
- self.assertEqual(ws.ex(x), '(c.a >= 12.0f)')
269
- self.assertEqual(wd.ex(x), '(c.a >= 12.0)')
270
- self.assertEqual(wn.ex(x), '(c.a >= 12.0f)')
271
- x = myokit.MoreEqual(cond1, cond2)
272
- self.assertEqual(ws.ex(x), '((5.0f > 3.0f) >= (2.0f < 1.0f))')
273
- self.assertEqual(wd.ex(x), '((5.0 > 3.0) >= (2.0 < 1.0))')
274
- self.assertEqual(wn.ex(x), '((5.0f > 3.0f) >= (2.0f < 1.0f))')
275
- x = myokit.MoreEqual(cond1, b)
276
- self.assertEqual(ws.ex(x), '((5.0f > 3.0f) >= (12.0f != 0.0f))')
277
- self.assertEqual(wd.ex(x), '((5.0 > 3.0) >= (12.0 != 0.0))')
278
- self.assertEqual(wn.ex(x), '((5.0f > 3.0f) >= (12.0f != 0.0f))')
279
- x = myokit.MoreEqual(a, cond2)
280
- self.assertEqual(ws.ex(x), '((c.a != 0.0f) >= (2.0f < 1.0f))')
281
- self.assertEqual(wd.ex(x), '((c.a != 0.0) >= (2.0 < 1.0))')
282
- self.assertEqual(wn.ex(x), '((c.a != 0.0f) >= (2.0f < 1.0f))')
283
-
284
- # LessEqual
285
- x = myokit.LessEqual(a, b)
286
- self.assertEqual(ws.ex(x), '(c.a <= 12.0f)')
287
- self.assertEqual(wd.ex(x), '(c.a <= 12.0)')
288
- self.assertEqual(wn.ex(x), '(c.a <= 12.0f)')
289
- x = myokit.LessEqual(cond1, cond2)
290
- self.assertEqual(ws.ex(x), '((5.0f > 3.0f) <= (2.0f < 1.0f))')
291
- self.assertEqual(wd.ex(x), '((5.0 > 3.0) <= (2.0 < 1.0))')
292
- self.assertEqual(wn.ex(x), '((5.0f > 3.0f) <= (2.0f < 1.0f))')
293
- x = myokit.LessEqual(cond1, b)
294
- self.assertEqual(ws.ex(x), '((5.0f > 3.0f) <= (12.0f != 0.0f))')
295
- self.assertEqual(wd.ex(x), '((5.0 > 3.0) <= (12.0 != 0.0))')
296
- self.assertEqual(wn.ex(x), '((5.0f > 3.0f) <= (12.0f != 0.0f))')
297
- x = myokit.LessEqual(a, cond2)
298
- self.assertEqual(ws.ex(x), '((c.a != 0.0f) <= (2.0f < 1.0f))')
299
- self.assertEqual(wd.ex(x), '((c.a != 0.0) <= (2.0 < 1.0))')
300
- self.assertEqual(wn.ex(x), '((c.a != 0.0f) <= (2.0f < 1.0f))')
301
-
302
- def test_logical(self):
303
-
304
- # Single and double precision and native maths
305
- ws = myokit.formats.opencl.OpenCLExpressionWriter()
306
- wd = myokit.formats.opencl.OpenCLExpressionWriter(
307
- myokit.DOUBLE_PRECISION)
308
- wn = myokit.formats.opencl.OpenCLExpressionWriter(native_math=False)
309
-
310
- a = myokit.Name(myokit.Model().add_component('c').add_variable('a'))
311
- b = myokit.Number('12', 'pF')
312
- cond1 = myokit.parse_expression('5 > 3')
313
- cond2 = myokit.parse_expression('2 < 1')
314
- condx = myokit.Number(1.2)
315
-
316
- # Not
317
- x = myokit.Not(cond1)
318
- self.assertEqual(ws.ex(x), '!((5.0f > 3.0f))')
319
- self.assertEqual(wd.ex(x), '!((5.0 > 3.0))')
320
- self.assertEqual(wn.ex(x), '!((5.0f > 3.0f))')
321
- x = myokit.Not(condx)
322
- self.assertEqual(ws.ex(x), '!((1.2f != 0.0f))')
323
- self.assertEqual(wd.ex(x), '!((1.2 != 0.0))')
324
- self.assertEqual(wn.ex(x), '!((1.2f != 0.0f))')
325
-
326
- # And
327
- x = myokit.And(cond1, cond2)
328
- self.assertEqual(ws.ex(x), '((5.0f > 3.0f) && (2.0f < 1.0f))')
329
- self.assertEqual(wd.ex(x), '((5.0 > 3.0) && (2.0 < 1.0))')
330
- self.assertEqual(wn.ex(x), '((5.0f > 3.0f) && (2.0f < 1.0f))')
331
- x = myokit.And(condx, cond2)
332
- self.assertEqual(ws.ex(x), '((1.2f != 0.0f) && (2.0f < 1.0f))')
333
- self.assertEqual(wd.ex(x), '((1.2 != 0.0) && (2.0 < 1.0))')
334
- self.assertEqual(wn.ex(x), '((1.2f != 0.0f) && (2.0f < 1.0f))')
335
- x = myokit.And(cond1, condx)
336
- self.assertEqual(ws.ex(x), '((5.0f > 3.0f) && (1.2f != 0.0f))')
337
- self.assertEqual(wd.ex(x), '((5.0 > 3.0) && (1.2 != 0.0))')
338
- self.assertEqual(wn.ex(x), '((5.0f > 3.0f) && (1.2f != 0.0f))')
339
-
340
- # Or
341
- x = myokit.Or(cond1, cond2)
342
- self.assertEqual(ws.ex(x), '((5.0f > 3.0f) || (2.0f < 1.0f))')
343
- self.assertEqual(wd.ex(x), '((5.0 > 3.0) || (2.0 < 1.0))')
344
- self.assertEqual(wn.ex(x), '((5.0f > 3.0f) || (2.0f < 1.0f))')
345
- x = myokit.Or(condx, cond2)
346
- self.assertEqual(ws.ex(x), '((1.2f != 0.0f) || (2.0f < 1.0f))')
347
- self.assertEqual(wd.ex(x), '((1.2 != 0.0) || (2.0 < 1.0))')
348
- self.assertEqual(wn.ex(x), '((1.2f != 0.0f) || (2.0f < 1.0f))')
349
- x = myokit.Or(cond1, condx)
350
- self.assertEqual(ws.ex(x), '((5.0f > 3.0f) || (1.2f != 0.0f))')
351
- self.assertEqual(wd.ex(x), '((5.0 > 3.0) || (1.2 != 0.0))')
352
- self.assertEqual(wn.ex(x), '((5.0f > 3.0f) || (1.2f != 0.0f))')
353
-
354
- # If
355
- x = myokit.If(cond1, a, b)
356
- self.assertEqual(ws.ex(x), '((5.0f > 3.0f) ? c.a : 12.0f)')
357
- self.assertEqual(wd.ex(x), '((5.0 > 3.0) ? c.a : 12.0)')
358
- self.assertEqual(wn.ex(x), '((5.0f > 3.0f) ? c.a : 12.0f)')
359
- x = myokit.If(condx, a, b)
360
- self.assertEqual(ws.ex(x), '((1.2f != 0.0f) ? c.a : 12.0f)')
361
- self.assertEqual(wd.ex(x), '((1.2 != 0.0) ? c.a : 12.0)')
362
- self.assertEqual(wn.ex(x), '((1.2f != 0.0f) ? c.a : 12.0f)')
363
-
364
- # Piecewise
365
- c = myokit.Number(1)
366
- x = myokit.Piecewise(cond1, a, cond2, b, c)
367
- self.assertEqual(
368
- ws.ex(x),
369
- '((5.0f > 3.0f) ? c.a : ((2.0f < 1.0f) ? 12.0f : 1.0f))')
370
- self.assertEqual(
371
- wd.ex(x),
372
- '((5.0 > 3.0) ? c.a : ((2.0 < 1.0) ? 12.0 : 1.0))')
373
- self.assertEqual(
374
- wn.ex(x),
375
- '((5.0f > 3.0f) ? c.a : ((2.0f < 1.0f) ? 12.0f : 1.0f))')
376
- x = myokit.Piecewise(condx, a, condx, b, c)
377
- self.assertEqual(
378
- ws.ex(x),
379
- '((1.2f != 0.0f) ? c.a : ((1.2f != 0.0f) ? 12.0f : 1.0f))')
57
+ def test_initial_value(self):
58
+ self.assertRaisesRegex(
59
+ NotImplementedError, 'Initial',
60
+ self.w.ex, myokit.InitialValue(self.a))
61
+
62
+ def test_prefix_plus_minus(self):
63
+ # Inherited from c-based
64
+
65
+ p = Number(11, 'kV')
66
+ self.eq(PrefixPlus(p), '+11.0f')
67
+ self.eq(PrefixPlus(PrefixPlus(p)), '+(+11.0f)')
68
+ self.eq(PrefixPlus(PrefixPlus(PrefixPlus(p))), '+(+(+11.0f))')
69
+ self.eq(PrefixPlus(Number('+1')), '+1.0f')
70
+ self.eq(PrefixMinus(p), '-11.0f')
71
+ self.eq(PrefixMinus(PrefixMinus(p)), '-(-11.0f)')
72
+ self.eq(PrefixMinus(Number(-1)), '-(-1.0f)')
73
+ self.eq(PrefixMinus(PrefixMinus(Number(-2))), '-(-(-2.0f))')
74
+
75
+ # Test with operators of precedence SUM, PRODUCT
76
+ a, b, c = self.abc
77
+ self.eq(PrefixPlus(Plus(a, b)), '+(a + b)')
78
+ self.eq(Divide(PrefixPlus(Plus(a, b)), c), '+(a + b) / c')
79
+ self.eq(PrefixPlus(Divide(b, a)), '+(b / a)')
80
+ self.eq(PrefixMinus(Minus(a, b)), '-(a - b)')
81
+ self.eq(Multiply(PrefixMinus(Plus(b, a)), c), '-(b + a) * c')
82
+ self.eq(PrefixMinus(Divide(b, a)), '-(b / a)')
83
+
84
+ def test_prefix_plus_minus_double(self):
85
+
86
+ w = self._target(precision=myokit.DOUBLE_PRECISION)
87
+ p = Number(3, 'mA')
88
+ self.assertEqual(w.ex(PrefixPlus(p)), '+3.0')
89
+ self.assertEqual(w.ex(PrefixPlus(PrefixPlus(p))), '+(+3.0)')
380
90
  self.assertEqual(
381
- wd.ex(x),
382
- '((1.2 != 0.0) ? c.a : ((1.2 != 0.0) ? 12.0 : 1.0))')
91
+ w.ex(PrefixPlus(PrefixPlus(PrefixPlus(p)))), '+(+(+3.0))')
92
+ self.assertEqual(w.ex(PrefixPlus(Number('+1'))), '+1.0')
93
+ self.assertEqual(w.ex(PrefixMinus(p)), '-3.0')
94
+ self.assertEqual(w.ex(PrefixMinus(PrefixMinus(p))), '-(-3.0)')
95
+ self.assertEqual(w.ex(PrefixMinus(Number(-1))), '-(-1.0)')
383
96
  self.assertEqual(
384
- wn.ex(x),
385
- '((1.2f != 0.0f) ? c.a : ((1.2f != 0.0f) ? 12.0f : 1.0f))')
97
+ w.ex(PrefixMinus(PrefixMinus(Number(-2)))), '-(-(-2.0))')
98
+
99
+ def test_arithmetic(self):
100
+ # Inherited from c-based
101
+
102
+ a, b, c = self.abc
103
+ self.eq(Minus(Plus(a, b), c), 'a + b - c')
104
+ self.eq(Minus(a, Plus(b, c)), 'a - (b + c)')
105
+ self.eq(Multiply(Minus(a, b), c), '(a - b) * c')
106
+ self.eq(Multiply(a, Plus(b, c)), 'a * (b + c)')
107
+ self.eq(Minus(Multiply(a, b), c), 'a * b - c')
108
+ self.eq(Divide(a, Minus(b, c)), 'a / (b - c)')
109
+ self.eq(Plus(Divide(a, b), c), 'a / b + c')
110
+ self.eq(Divide(Divide(a, b), c), 'a / b / c')
111
+
112
+ def test_quotient_remainder(self):
113
+ # Inherited from c-based
114
+
115
+ a, b, c = self.abc
116
+ self.eq(Quotient(a, Divide(b, c)), 'floor(a / (b / c))')
117
+ self.eq(Remainder(Plus(a, c), b), '(a + c - b * floor((a + c) / b))')
118
+ self.eq(Divide(c, Remainder(b, a)), 'c / ((b - a * floor(b / a)))')
119
+
120
+ def test_power(self):
121
+ a, b, c = self.abc
122
+ self.eq(Power(a, b), 'pow(a, b)')
123
+ self.eq(Power(Power(a, b), c), 'pow(pow(a, b), c)')
124
+ self.eq(Power(a, Power(b, c)), 'pow(a, pow(b, c))')
125
+
126
+ self.eq(Power(Plus(a, b), c), 'pow(a + b, c)')
127
+ self.eq(Power(a, Minus(b, c)), 'pow(a, b - c)')
128
+ self.eq(Power(Multiply(a, b), c), 'pow(a * b, c)')
129
+ self.eq(Power(a, Divide(b, c)), 'pow(a, b / c)')
130
+
131
+ def test_log(self):
132
+ a, b = self.ab
133
+ self.eq(Log(a), 'native_log(a)')
134
+ self.eq(Log10(a), 'native_log10(a)')
135
+ self.eq(Log(a, b), '(native_log(a) / native_log(b))')
136
+
137
+ def test_log_no_native(self):
138
+ w = self._target(native_math=False)
139
+ a, b = self.ab
140
+ self.assertEqual(w.ex(Log(a)), 'log(comp.a)')
141
+ self.assertEqual(w.ex(Log10(b)), 'log10(comp.b)')
142
+ self.assertEqual(w.ex(Log(b, a)), '(log(comp.b) / log(comp.a))')
386
143
 
387
- def test_fetching(self):
388
- # Test fetching using ewriter method
389
- w = myokit.formats.ewriter('opencl')
390
- self.assertIsInstance(w, myokit.formats.opencl.OpenCLExpressionWriter)
391
-
392
- def test_bad_operand(self):
393
- # Test without a Myokit expression
394
- w = myokit.formats.opencl.OpenCLExpressionWriter()
395
- self.assertRaisesRegex(
396
- ValueError, 'Unknown expression type', w.ex, 7)
144
+ def test_functions(self):
145
+ a = self.a
146
+ self.eq(Sqrt(self.a), 'native_sqrt(a)')
147
+ self.eq(Exp(self.a), 'native_exp(a)')
148
+ self.eq(Sin(self.a), 'native_sin(a)')
149
+ self.eq(Cos(self.a), 'native_cos(a)')
150
+ self.eq(Tan(self.a), 'native_tan(a)')
151
+ self.eq(ASin(self.a), 'asin(a)')
152
+ self.eq(ACos(self.a), 'acos(a)')
153
+ self.eq(ATan(self.a), 'atan(a)')
154
+ self.eq(Floor(self.a), 'floor(a)')
155
+ self.eq(Ceil(self.a), 'ceil(a)')
156
+ self.eq(Abs(self.a), 'fabs(a)')
157
+
158
+ def test_functions_no_native(self):
159
+ w = self._target(native_math=False)
160
+ self.assertEqual(w.ex(Sqrt(self.a)), 'sqrt(comp.a)')
161
+ self.assertEqual(w.ex(Exp(self.a)), 'exp(comp.a)')
162
+ self.assertEqual(w.ex(Sin(self.a)), 'sin(comp.a)')
163
+ self.assertEqual(w.ex(Cos(self.a)), 'cos(comp.a)')
164
+ self.assertEqual(w.ex(Tan(self.a)), 'tan(comp.a)')
165
+ self.assertEqual(w.ex(ASin(self.a)), 'asin(comp.a)')
166
+ self.assertEqual(w.ex(ACos(self.a)), 'acos(comp.a)')
167
+ self.assertEqual(w.ex(ATan(self.a)), 'atan(comp.a)')
168
+ self.assertEqual(w.ex(Floor(self.a)), 'floor(comp.a)')
169
+ self.assertEqual(w.ex(Ceil(self.a)), 'ceil(comp.a)')
170
+ self.assertEqual(w.ex(Abs(self.a)), 'fabs(comp.a)')
171
+
172
+ def test_conditions(self):
173
+ # Can be greatly simplified after
174
+ # https://github.com/myokit/myokit/issues/1056
175
+
176
+ a, b, c, d = self.abcd
177
+
178
+ self.eq(And(a, b), '((a != 0.0f) && (b != 0.0f))')
179
+ self.eq(Or(d, c), '((d != 0.0f) || (c != 0.0f))')
180
+ self.eq(Not(And(a, b)), '(!((a != 0.0f) && (b != 0.0f)))')
181
+ self.eq(Not(c), '(!(c != 0.0f))')
182
+
183
+ self.eq(Equal(a, b), '(a == b)')
184
+ self.eq(NotEqual(a, b), '(a != b)')
185
+ self.eq(More(b, a), '(b > a)')
186
+ self.eq(Less(d, c), '(d < c)')
187
+ self.eq(MoreEqual(c, a), '(c >= a)')
188
+ self.eq(LessEqual(b, d), '(b <= d)')
189
+
190
+ self.eq(And(Equal(a, b), NotEqual(c, d)), '((a == b) && (c != d))')
191
+ self.eq(Or(More(d, c), Less(b, a)), '((d > c) || (b < a))')
192
+ self.eq(Not(Or(Number(1), Number(2))),
193
+ '(!((1.0f != 0.0f) || (2.0f != 0.0f)))')
194
+ self.eq(Not(Less(Number(1), Number(2))), '(!(1.0f < 2.0f))')
195
+ self.eq(Not(Plus(Number(1), Number(2))), '(!(1.0f + 2.0f != 0.0f))')
196
+
197
+ self.eq(Equal(Equal(Number(0), Number(0)), Number(0)),
198
+ '((0.0f == 0.0f) == (0.0f != 0.0f))')
199
+
200
+ def test_boolean_comparisons(self):
201
+ # Can be removed after https://github.com/myokit/myokit/issues/1056
202
+
203
+ a, b = self.ab
204
+ c1, c2 = More(Number(5), Number(3)), Less(Number(2), Number(1))
205
+ self.eq(Equal(c1, c2), '((5.0f > 3.0f) == (2.0f < 1.0f))')
206
+ self.eq(NotEqual(c1, a), '((5.0f > 3.0f) != (a != 0.0f))')
207
+ self.eq(More(b, c2), '((b != 0.0f) > (2.0f < 1.0f))')
208
+ self.eq(LessEqual(a, b), '(a <= b)')
209
+
210
+ def test_conditionals(self):
211
+ # Inherited from c-based
212
+
213
+ a, b, c, d = self.abcd
214
+ self.eq(If(Equal(a, b), d, c), '((a == b) ? d : c)')
215
+ self.eq(Piecewise(NotEqual(d, c), b, a), '((d != c) ? b : a)')
216
+ self.eq(Piecewise(Equal(a, b), c, Equal(a, d), Number(3), Number(4)),
217
+ '((a == b) ? c : ((a == d) ? 3.0f : 4.0f))')
218
+
219
+ # If condition is not a condition
220
+ self.eq(If(a, d, c), '((a != 0.0f) ? d : c)')
221
+ self.eq(Piecewise(a, b, c, d, Number(4)),
222
+ '((a != 0.0f) ? b : ((c != 0.0f) ? d : 4.0f))')
397
223
 
398
224
 
399
225
  if __name__ == '__main__':