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
@@ -0,0 +1,344 @@
1
+ #!/usr/bin/env python3
2
+ #
3
+ # Tests writing of AnsiC expressions, as used by the Simulation.
4
+ # C++ tests are lumped in as well.
5
+ #
6
+ # This file is part of Myokit.
7
+ # See http://myokit.org for copyright, sharing, and licensing details.
8
+ #
9
+ import math
10
+ import unittest
11
+
12
+ import myokit
13
+ import myokit.formats.ansic
14
+ import myokit.formats.cpp
15
+
16
+ from myokit import (
17
+ Number, PrefixPlus, PrefixMinus, Plus, Minus,
18
+ Multiply, Divide, Quotient, Remainder, Power, Sqrt,
19
+ Exp, Log, Log10, Sin, Cos, Tan, ASin, ACos, ATan, Floor, Ceil, Abs,
20
+ Not, And, Or, Equal, NotEqual, More, Less, MoreEqual, LessEqual,
21
+ If, Piecewise,
22
+ )
23
+
24
+ import myokit.tests
25
+
26
+
27
+ class AnsiCExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
28
+ """
29
+ Test conversion to Ansi C, as used by the Simulation.
30
+ Numerical tests are provided by composing and evaluating a single RHS.
31
+ """
32
+ _name = 'ansic'
33
+ _target = myokit.formats.ansic.AnsiCExpressionWriter
34
+
35
+ def test_number(self):
36
+ self.eq(Number(1), '1.0')
37
+ self.eq(Number(-2), '-2.0')
38
+ self.eq(Number(13, 'mV'), '13.0')
39
+
40
+ def test_name(self):
41
+ self.eq(self.a, 'a')
42
+ w = self._target()
43
+ w.set_lhs_function(lambda v: v.var().qname().upper())
44
+ self.assertEqual(w.ex(self.a), 'COMP.A')
45
+
46
+ def test_derivative(self):
47
+ self.eq(myokit.Derivative(self.a), 'dot(a)')
48
+
49
+ def test_partial_derivative(self):
50
+ self.eq(myokit.PartialDerivative(self.a, self.b), 'partial(a, b)')
51
+
52
+ def test_initial_value(self):
53
+ self.eq(myokit.InitialValue(self.a), 'initial(a)')
54
+
55
+ def test_prefix_plus(self):
56
+ # Test with numbers
57
+ p = Number(11, 'kV')
58
+ self.eq(PrefixPlus(p), '+11.0')
59
+ self.eq(PrefixPlus(PrefixPlus(p)), '+(+11.0)')
60
+ self.eq(PrefixPlus(PrefixPlus(PrefixPlus(p))), '+(+(+11.0))')
61
+ self.eq(PrefixPlus(Number('+1')), '+1.0')
62
+
63
+ # Test with operators of precedence SUM, PRODUCT
64
+ a, b, c = self.abc
65
+ self.eq(PrefixPlus(Plus(a, b)), '+(a + b)')
66
+ self.eq(Divide(PrefixPlus(Plus(a, b)), c), '+(a + b) / c')
67
+ self.eq(PrefixPlus(Divide(b, a)), '+(b / a)')
68
+
69
+ def test_prefix_minus(self):
70
+ # Test with numbers
71
+ p = Number(11, 'kV')
72
+ self.eq(PrefixMinus(p), '-11.0')
73
+ self.eq(PrefixMinus(PrefixMinus(p)), '-(-11.0)')
74
+ self.eq(PrefixMinus(Number(-1)), '-(-1.0)')
75
+ self.eq(PrefixMinus(PrefixMinus(Number(-2))), '-(-(-2.0))')
76
+
77
+ # Test with operators of precedence SUM, PRODUCT
78
+ a, b, c = self.abc
79
+ self.eq(PrefixMinus(Minus(a, b)), '-(a - b)')
80
+ self.eq(Multiply(PrefixMinus(Plus(b, a)), c), '-(b + a) * c')
81
+ self.eq(PrefixMinus(Divide(b, a)), '-(b / a)')
82
+
83
+ def test_plus_minus(self):
84
+ a, b, c = self.abc
85
+ self.eq(Plus(a, b), 'a + b')
86
+ self.eq(Plus(Plus(a, b), c), 'a + b + c')
87
+ self.eq(Plus(a, Plus(b, c)), 'a + (b + c)')
88
+
89
+ self.eq(Minus(a, b), 'a - b')
90
+ self.eq(Minus(Minus(a, b), c), 'a - b - c')
91
+ self.eq(Minus(a, Minus(b, c)), 'a - (b - c)')
92
+
93
+ self.eq(Minus(a, b), 'a - b')
94
+ self.eq(Plus(Minus(a, b), c), 'a - b + c')
95
+ self.eq(Minus(a, Plus(b, c)), 'a - (b + c)')
96
+ self.eq(Minus(Plus(a, b), c), 'a + b - c')
97
+ self.eq(Minus(a, Plus(b, c)), 'a - (b + c)')
98
+
99
+ def test_multiply_divide(self):
100
+ a, b, c = self.abc
101
+ self.eq(Multiply(a, b), 'a * b')
102
+ self.eq(Multiply(Multiply(a, b), c), 'a * b * c')
103
+ self.eq(Multiply(a, Multiply(b, c)), 'a * (b * c)')
104
+
105
+ self.eq(Divide(a, b), 'a / b')
106
+ self.eq(Divide(Divide(a, b), c), 'a / b / c')
107
+ self.eq(Divide(a, Divide(b, c)), 'a / (b / c)')
108
+
109
+ self.eq(Divide(Multiply(a, b), c), 'a * b / c')
110
+ self.eq(Multiply(Divide(a, b), c), 'a / b * c')
111
+ self.eq(Divide(a, Multiply(b, c)), 'a / (b * c)')
112
+ self.eq(Multiply(a, Divide(b, c)), 'a * (b / c)')
113
+
114
+ self.eq(Multiply(Minus(a, b), c), '(a - b) * c')
115
+ self.eq(Multiply(a, Plus(b, c)), 'a * (b + c)')
116
+ self.eq(Minus(Multiply(a, b), c), 'a * b - c')
117
+ self.eq(Plus(a, Multiply(b, c)), 'a + b * c')
118
+ self.eq(Divide(Plus(a, b), c), '(a + b) / c')
119
+ self.eq(Divide(a, Minus(b, c)), 'a / (b - c)')
120
+ self.eq(Plus(Divide(a, b), c), 'a / b + c')
121
+ self.eq(Minus(a, Divide(b, c)), 'a - b / c')
122
+ self.eq(Divide(a, Divide(b, c)), 'a / (b / c)')
123
+ self.eq(Divide(Divide(a, b), c), 'a / b / c')
124
+
125
+ def test_quotient(self):
126
+ a, b, c = self.abc
127
+ self.eq(Quotient(a, b), 'floor(a / b)')
128
+ self.eq(Quotient(Plus(a, c), b), 'floor((a + c) / b)')
129
+ self.eq(Quotient(Divide(a, c), b), 'floor(a / c / b)')
130
+ self.eq(Quotient(a, Divide(b, c)), 'floor(a / (b / c))')
131
+ self.eq(Multiply(Quotient(a, b), c), 'floor(a / b) * c')
132
+ # Bracket() method expects a PRODUCT level operation, so will add
133
+ # unnecessary brackets here
134
+ self.eq(Multiply(c, Quotient(a, b)), 'c * (floor(a / b))')
135
+
136
+ def test_remainder(self):
137
+ a, b, c = self.abc
138
+ self.eq(Remainder(a, b), '(a - b * floor(a / b))')
139
+ self.eq(Remainder(Plus(a, c), b), '(a + c - b * floor((a + c) / b))')
140
+ self.eq(Multiply(Remainder(a, b), c), '(a - b * floor(a / b)) * c')
141
+ # Bracket() method expects a PRODUCT level operation, so will add
142
+ # unnecessary brackets here
143
+ self.eq(Divide(c, Remainder(b, a)), 'c / ((b - a * floor(b / a)))')
144
+
145
+ def test_power(self):
146
+ a, b, c = self.abc
147
+ self.eq(Power(a, b), 'pow(a, b)')
148
+ self.eq(Power(Power(a, b), c), 'pow(pow(a, b), c)')
149
+ self.eq(Power(a, Power(b, c)), 'pow(a, pow(b, c))')
150
+
151
+ self.eq(Power(Plus(a, b), c), 'pow(a + b, c)')
152
+ self.eq(Power(a, Minus(b, c)), 'pow(a, b - c)')
153
+ self.eq(Power(Multiply(a, b), c), 'pow(a * b, c)')
154
+ self.eq(Power(a, Divide(b, c)), 'pow(a, b / c)')
155
+
156
+ def test_log(self):
157
+ a, b = self.ab
158
+ self.eq(Log(a), 'log(a)')
159
+ self.eq(Log10(a), 'log10(a)')
160
+ self.eq(Log(a, b), '(log(a) / log(b))')
161
+
162
+ def test_functions(self):
163
+ a, b = self.ab
164
+
165
+ self.eq(Sqrt(a), 'sqrt(a)')
166
+ self.eq(Exp(a), 'exp(a)')
167
+ self.eq(Sin(a), 'sin(a)')
168
+ self.eq(Cos(a), 'cos(a)')
169
+ self.eq(Tan(a), 'tan(a)')
170
+ self.eq(ASin(a), 'asin(a)')
171
+ self.eq(ACos(a), 'acos(a)')
172
+ self.eq(ATan(a), 'atan(a)')
173
+ self.eq(Floor(a), 'floor(a)')
174
+ self.eq(Ceil(a), 'ceil(a)')
175
+ self.eq(Abs(a), 'fabs(a)')
176
+
177
+ def test_conditions(self):
178
+ a, b, c, d = self.abcd
179
+
180
+ self.eq(And(a, b), '(a && b)')
181
+ self.eq(Or(d, c), '(d || c)')
182
+ self.eq(Not(And(a, b)), '(!(a && b))')
183
+ self.eq(Not(c), '(!(c))')
184
+
185
+ self.eq(Equal(a, b), '(a == b)')
186
+ self.eq(NotEqual(a, b), '(a != b)')
187
+ self.eq(More(b, a), '(b > a)')
188
+ self.eq(Less(d, c), '(d < c)')
189
+ self.eq(MoreEqual(c, a), '(c >= a)')
190
+ self.eq(LessEqual(b, d), '(b <= d)')
191
+
192
+ self.eq(And(Equal(a, b), NotEqual(c, d)), '((a == b) && (c != d))')
193
+ self.eq(Or(More(d, c), Less(b, a)), '((d > c) || (b < a))')
194
+ self.eq(Not(Or(Number(1), Number(2))), '(!(1.0 || 2.0))')
195
+ self.eq(Not(Less(Number(1), Number(2))), '(!(1.0 < 2.0))')
196
+ self.eq(Not(Plus(Number(1), Number(2))), '(!(1.0 + 2.0))')
197
+
198
+ self.eq(Equal(Equal(Number(0), Number(0)), Number(0)),
199
+ '((0.0 == 0.0) == 0.0)')
200
+
201
+ def test_conditionals(self):
202
+
203
+ a, b, c, d = self.abcd
204
+ self.eq(If(Equal(a, b), d, c), '((a == b) ? d : c)')
205
+ self.eq(Piecewise(NotEqual(d, c), b, a), '((d != c) ? b : a)')
206
+ self.eq(Piecewise(Equal(a, b), c, Equal(a, d), Number(3), Number(4)),
207
+ '((a == b) ? c : ((a == d) ? 3.0 : 4.0))')
208
+
209
+ # Extra parentheses if condition is not a condition
210
+ self.eq(If(a, d, c), '((a) ? d : c)')
211
+ self.eq(Piecewise(a, b, c, d, Number(4)),
212
+ '((a) ? b : ((c) ? d : 4.0))')
213
+
214
+ # Using if-then-else function
215
+ w = self._target()
216
+ w.set_lhs_function(lambda v: v.var().name())
217
+ w.set_condition_function('ite')
218
+
219
+ self.assertEqual(w.ex(If(More(b, a), c, d)), 'ite((b > a), c, d)')
220
+ self.assertEqual(w.ex(Piecewise(Less(d, c), b, a)),
221
+ 'ite((d < c), b, a)')
222
+ self.assertEqual(w.ex(
223
+ Piecewise(Equal(a, b), c, Equal(a, d), Number(3), Number(4))),
224
+ 'ite((a == b), c, ite((a == d), 3.0, 4.0))')
225
+
226
+ def test_in_c(self):
227
+ """ Compile and test the values evaluated in C. """
228
+
229
+ class CTester():
230
+ def __init__(self, parent):
231
+ self._parent = parent
232
+ self._m = myokit.Model()
233
+ self._c = self._m.add_component('c')
234
+ t = self._c.add_variable('time', rhs=0, binding='time')
235
+ self._expected = []
236
+
237
+ def add(self, expression, expected):
238
+ v = self._c.add_variable(
239
+ f'v{len(self._expected)}', rhs=expression, initial_value=0)
240
+ self._expected.append(float(expected))
241
+
242
+ def run(self):
243
+ s = myokit.Simulation(self._m)
244
+ x = s.evaluate_derivatives()
245
+ self._parent.assertEqual(len(x), len(self._expected))
246
+ for a, b in zip(x, self._expected):
247
+ self._parent.assertEqual(a, b)
248
+
249
+ c = CTester(self,)
250
+
251
+ c.add(Number(12, 'pF'), 12)
252
+
253
+ c.add(PrefixPlus(Number(3)), 3)
254
+ c.add(PrefixPlus(PrefixPlus(PrefixPlus(Number(4)))), 4)
255
+ c.add(PrefixMinus(Number(6)), -6)
256
+ c.add(PrefixMinus(PrefixMinus(Number(2))), 2)
257
+ c.add(PrefixMinus(PrefixMinus(PrefixMinus(Number(5)))), -5)
258
+ c.add(PrefixMinus(PrefixMinus(PrefixMinus(Number(-5)))), 5)
259
+
260
+ c.add(Plus(Number(4), Number(2)), 6)
261
+ c.add(Minus(Number(5), Number(1.5)), 3.5)
262
+
263
+ c.add(Multiply(Number(7), Number(9)), 63)
264
+ c.add(Divide(Number(5), Number(2)), 2.5)
265
+ c.add(Divide(Divide(Number(12), Number(2)), Number(2)), 3)
266
+ c.add(Divide(Number(1), Divide(Number(2), Number(3))), 1.5)
267
+
268
+ c.add(Remainder(Number(10), Number(4)), 2)
269
+ c.add(Remainder(Number(10), Number(6)), 4)
270
+ c.add(Remainder(Number(5), Number(3)), 2)
271
+ c.add(Remainder(Number(-5), Number(3)), 1)
272
+ c.add(Remainder(Number(5), Number(-3)), -1)
273
+ c.add(Remainder(Number(-5), Number(-3)), -2)
274
+
275
+ c.add(Quotient(Number(10), Number(4)), 2)
276
+ c.add(Quotient(Number(10), Number(6)), 1)
277
+ c.add(Quotient(Number(5), Number(3)), 1)
278
+ c.add(Quotient(Number(-5), Number(3)), -2)
279
+ c.add(Quotient(Number(5), Number(-3)), -2)
280
+ c.add(Quotient(Number(-5), Number(-3)), 1)
281
+
282
+ c.add(Power(Number(4), Power(Number(2), Number(3))), 65536)
283
+ c.add(Power(Power(Number(2), Number(3)), Number(4)), 4096)
284
+
285
+ c.add(Log(Number(3)), math.log(3))
286
+ c.add(Log10(Number(1000)), 3)
287
+ c.add(Log10(Number(0.01)), -2)
288
+ c.add(Log(Number(27), Number(3)), 3)
289
+ c.add(Divide(Number(12), Log(Number(256), Number(4))), 3)
290
+ c.add(Divide(Log(Number(256), Number(4)), Number(4)), 1)
291
+
292
+ c.add(Sqrt(Number(9)), 3)
293
+ c.add(Exp(Number(3)), math.exp(3))
294
+ c.add(Sin(Number(1)), math.sin(1))
295
+ c.add(Cos(Number(1)), math.cos(1))
296
+ c.add(Tan(Number(4)), math.tan(4))
297
+ c.add(ASin(Number(0.4)), math.asin(0.4))
298
+ c.add(ACos(Number(0.4)), math.acos(0.4))
299
+ c.add(ATan(Number(0.4)), math.atan(0.4))
300
+
301
+ c.add(Floor(Number(3.9)), 3)
302
+ c.add(Floor(Number(-3.9)), -4)
303
+ c.add(Ceil(Number(4.01)), 5)
304
+ c.add(Ceil(Number(-4.01)), -4)
305
+ c.add(Abs(PrefixMinus(Number(12))), 12)
306
+ c.add(Abs(Number(-13)), 13)
307
+
308
+ true = Equal(Number(2), Number(2))
309
+ false = Equal(Number(3), Number(-1))
310
+ a, b = Number(10), Number(20)
311
+ c.add(If(true, a, b), 10)
312
+ c.add(If(false, a, b), 20)
313
+
314
+ c.add(If(More(Number(5), Number(3)), a, b), 10)
315
+ c.add(If(More(Number(3), Number(3)), a, b), 20)
316
+ c.add(If(MoreEqual(Number(3), Number(3)), a, b), 10)
317
+ c.add(If(Less(Number(3), Number(5)), a, b), 10)
318
+ c.add(If(More(Number(3), Number(3)), a, b), 20)
319
+ c.add(If(LessEqual(Number(3), Number(3)), a, b), 10)
320
+
321
+ c.add(If(And(false, false), a, b), 20)
322
+ c.add(If(And(false, true), a, b), 20)
323
+ c.add(If(And(true, false), a, b), 20)
324
+ c.add(If(And(true, true), a, b), 10)
325
+ c.add(If(Or(false, false), a, b), 20)
326
+ c.add(If(Or(false, true), a, b), 10)
327
+ c.add(If(Or(true, false), a, b), 10)
328
+ c.add(If(Or(true, true), a, b), 10)
329
+ c.add(If(Not(true), a, b), 20)
330
+ c.add(If(Not(false), a, b), 10)
331
+
332
+ c.add(If(Equal(Equal(Number(0), Number(0)), Number(0)), a, b), 20)
333
+ c.add(If(Equal(Equal(Number(0), Number(0)), Number(1)), a, b), 10)
334
+
335
+ c.add(Piecewise(true, Number(10), false, Number(20), Number(30)), 10)
336
+ c.add(Piecewise(true, Number(10), true, Number(20), Number(30)), 10)
337
+ c.add(Piecewise(false, Number(10), true, Number(20), Number(30)), 20)
338
+ c.add(Piecewise(false, Number(10), false, Number(20), Number(30)), 30)
339
+
340
+ c.run()
341
+
342
+
343
+ if __name__ == '__main__':
344
+ unittest.main()
@@ -11,6 +11,7 @@ import unittest
11
11
  import numpy as np
12
12
 
13
13
  import myokit
14
+ import myokit.formats
14
15
  import myokit.formats.axon as axon
15
16
 
16
17
  from myokit.tests import TemporaryDirectory, DIR_FORMATS, WarningCollector
@@ -853,5 +854,21 @@ class AtfTest(unittest.TestCase):
853
854
  self.assertEqual(atf.version(), '1.0')
854
855
 
855
856
 
857
+ class AbfImporterInterfaceTest(unittest.TestCase):
858
+ """ Tests ABF importer interface. """
859
+
860
+ def test_capability_reporting(self):
861
+ # Test if the right capabilities are reported.
862
+ i = myokit.formats.importer('abf')
863
+ self.assertFalse(i.supports_component())
864
+ self.assertFalse(i.supports_model())
865
+ self.assertTrue(i.supports_protocol())
866
+
867
+ def test_protocol(self):
868
+ i = myokit.formats.importer('abf')
869
+ self.assertTrue(i.supports_protocol())
870
+ i.protocol(os.path.join(DIR_FORMATS, 'abf-v1.abf'))
871
+
872
+
856
873
  if __name__ == '__main__':
857
874
  unittest.main()
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env python3
2
+ #
3
+ # Tests the expression writer for C++.
4
+ #
5
+ # This file is part of Myokit.
6
+ # See http://myokit.org for copyright, sharing, and licensing details.
7
+ #
8
+ import unittest
9
+
10
+ import myokit
11
+ import myokit.formats.cpp
12
+
13
+ import myokit.tests
14
+
15
+
16
+ class CppExpressionWriterTest(myokit.tests.ExpressionWriterTestCase):
17
+ """
18
+ Test the C++ expression writer.
19
+ This inherits from Ansi C, only dropping support for initial values and
20
+ partial derivatives.
21
+ """
22
+ _name = 'cpp'
23
+ _target = myokit.formats.cpp.CppExpressionWriter
24
+
25
+ def test_basics(self):
26
+ # Test a few arbitrary expressions, just to check the inheritcance has
27
+ # worked.
28
+ a, b, c, d = self.abcd
29
+ self.eq(myokit.Number(1), '1.0')
30
+ self.eq(myokit.Number(13, 'mV'), '13.0')
31
+ self.eq(myokit.Divide(myokit.PrefixPlus(myokit.Plus(a, b)), c),
32
+ '+(a + b) / c')
33
+ self.eq(myokit.Multiply(myokit.PrefixMinus(myokit.Plus(b, a)), c),
34
+ '-(b + a) * c')
35
+ self.eq(myokit.Multiply(myokit.Divide(a, b), c), 'a / b * c')
36
+ self.eq(myokit.Divide(a, myokit.Multiply(b, c)), 'a / (b * c)')
37
+ self.eq(myokit.Quotient(myokit.Divide(a, c), b), 'floor(a / c / b)')
38
+ self.eq(myokit.ASin(a), 'asin(a)')
39
+ self.eq(myokit.Power(myokit.PrefixMinus(a), b), 'pow(-a, b)')
40
+ self.eq(myokit.Power(a, myokit.Minus(b, c)), 'pow(a, b - c)')
41
+ self.eq(myokit.Power(myokit.Multiply(a, b), c), 'pow(a * b, c)')
42
+ self.eq(myokit.Log(a, b), '(log(a) / log(b))')
43
+ self.eq(myokit.Sin(a), 'sin(a)')
44
+ self.eq(myokit.And(myokit.Equal(a, b), myokit.NotEqual(c, d)),
45
+ '((a == b) && (c != d))')
46
+ self.eq(myokit.Not(myokit.Less(myokit.Number(1), myokit.Number(2))),
47
+ '(!(1.0 < 2.0))')
48
+ self.eq(myokit.If(myokit.Equal(a, b), d, c), '((a == b) ? d : c)')
49
+
50
+ def test_derivative(self):
51
+ self.eq(myokit.Derivative(self.a), 'dot(a)')
52
+
53
+ def test_partial_derivative(self):
54
+ self.assertRaisesRegex(
55
+ NotImplementedError, 'Partial',
56
+ self.w.ex, myokit.PartialDerivative(self.a, self.b))
57
+
58
+ def test_initial_value(self):
59
+ self.assertRaisesRegex(
60
+ NotImplementedError, 'Initial',
61
+ self.w.ex, myokit.InitialValue(self.a))
62
+
63
+ def test_conditionals(self):
64
+ # Inherited from AnsiCExpressionWriter
65
+
66
+ a, b, c, d = self.abcd
67
+ self.eq(myokit.If(myokit.Equal(a, b), d, c), '((a == b) ? d : c)')
68
+ self.eq(myokit.Piecewise(myokit.NotEqual(d, c), b, a),
69
+ '((d != c) ? b : a)')
70
+ self.eq(myokit.Piecewise(myokit.Equal(a, b), c,
71
+ myokit.Equal(a, d), myokit.Number(3),
72
+ myokit.Number(4)),
73
+ '((a == b) ? c : ((a == d) ? 3.0 : 4.0))')
74
+
75
+ # Extra parentheses if condition is not a condition
76
+ self.eq(myokit.If(a, d, c), '((a) ? d : c)')
77
+ self.eq(myokit.Piecewise(a, b, c, d, myokit.Number(4)),
78
+ '((a) ? b : ((c) ? d : 4.0))')
79
+
80
+ # Using if-then-else function
81
+ w = self._target()
82
+ w.set_lhs_function(lambda v: v.var().name())
83
+ w.set_condition_function('ite')
84
+
85
+ self.assertEqual(w.ex(myokit.If(myokit.More(b, a), c, d)),
86
+ 'ite((b > a), c, d)')
87
+ self.assertEqual(w.ex(myokit.Piecewise(myokit.Less(d, c), b, a)),
88
+ 'ite((d < c), b, a)')
89
+ self.assertEqual(
90
+ w.ex(myokit.Piecewise(myokit.Equal(a, b), c,
91
+ myokit.Equal(a, d), myokit.Number(3),
92
+ myokit.Number(4))),
93
+ 'ite((a == b), c, ite((a == d), 3.0, 4.0))')
94
+
95
+
96
+ if __name__ == '__main__':
97
+ unittest.main()