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.
- myokit/__init__.py +5 -3
- myokit/__main__.py +9 -159
- myokit/_config.py +2 -2
- myokit/_expressions.py +6 -6
- myokit/_model_api.py +11 -7
- myokit/_myokit_version.py +1 -1
- myokit/_protocol.py +4 -0
- myokit/_sim/__init__.py +1 -0
- myokit/_sim/cvodessim.c +321 -177
- myokit/_sim/cvodessim.py +107 -43
- myokit/_sim/mcl.h +54 -0
- myokit/formats/__init__.py +63 -12
- myokit/formats/ansic/__init__.py +2 -1
- myokit/formats/ansic/_ewriter.py +159 -40
- myokit/formats/cpp/_ewriter.py +12 -1
- myokit/formats/cuda/_ewriter.py +15 -51
- myokit/formats/easyml/_ewriter.py +26 -54
- myokit/formats/heka/_patchmaster.py +15 -3
- myokit/formats/latex/_ewriter.py +103 -88
- myokit/formats/latex/_exporter.py +1 -1
- myokit/formats/mathml/_ewriter.py +2 -2
- myokit/formats/matlab/_ewriter.py +50 -28
- myokit/formats/opencl/_ewriter.py +61 -78
- myokit/formats/python/_ewriter.py +81 -50
- myokit/formats/stan/_ewriter.py +29 -37
- myokit/gui/source.py +1 -1
- myokit/lib/hh.py +3 -0
- myokit/lib/markov.py +6 -0
- myokit/tests/__init__.py +70 -0
- myokit/tests/data/decker.model +59 -59
- myokit/tests/test_formats.py +115 -7
- myokit/tests/test_formats_ansic.py +344 -0
- myokit/tests/test_formats_axon.py +17 -0
- myokit/tests/test_formats_cpp.py +97 -0
- myokit/tests/test_formats_cuda.py +226 -0
- myokit/tests/test_formats_easyml.py +169 -152
- myokit/tests/{test_formats_exporters.py → test_formats_exporters_run.py} +1 -69
- myokit/tests/test_formats_html.py +1 -3
- myokit/tests/test_formats_latex.py +211 -0
- myokit/tests/test_formats_mathml_content.py +13 -0
- myokit/tests/test_formats_mathml_presentation.py +54 -42
- myokit/tests/test_formats_matlab.py +218 -0
- myokit/tests/test_formats_opencl.py +206 -380
- myokit/tests/test_formats_python.py +557 -0
- myokit/tests/test_formats_stan.py +175 -0
- myokit/tests/test_formats_sympy.py +9 -2
- myokit/tests/test_lib_hh.py +36 -0
- myokit/tests/test_lib_plots.py +0 -16
- myokit/tests/test_model.py +21 -1
- myokit/tests/test_simulation_cvodes.py +137 -56
- myokit/tools.py +3 -2
- {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/LICENSE.txt +1 -1
- {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/METADATA +19 -8
- {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/RECORD +57 -52
- {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/WHEEL +1 -1
- myokit/tests/test_formats_expression_writers.py +0 -1281
- myokit/tests/test_formats_importers.py +0 -53
- {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/entry_points.txt +0 -0
- {myokit-1.35.4.dist-info → myokit-1.36.1.dist-info}/top_level.txt +0 -0
myokit/formats/latex/_ewriter.py
CHANGED
|
@@ -20,19 +20,29 @@ class LatexExpressionWriter(myokit.formats.ExpressionWriter):
|
|
|
20
20
|
self.set_time_variable_name()
|
|
21
21
|
|
|
22
22
|
# Default lhs function
|
|
23
|
-
def
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
def flhs(lhs):
|
|
24
|
+
v = r'\text{' + self._prepare_name(lhs.var().uname()) + '}'
|
|
25
|
+
if isinstance(lhs, myokit.Name):
|
|
26
|
+
return v
|
|
27
|
+
elif isinstance(lhs, myokit.Derivative):
|
|
28
|
+
return r'\frac{d' + v + r'}{d\text{' + self._time + '}}'
|
|
29
|
+
elif isinstance(lhs, myokit.PartialDerivative):
|
|
30
|
+
v2 = self._prepare_name(
|
|
31
|
+
lhs.independent_expression().var().uname())
|
|
32
|
+
return r'\frac{\partial' + v + r'}{\partial\text{' + v2 + '}}'
|
|
33
|
+
elif isinstance(lhs, myokit.InitialValue):
|
|
34
|
+
return v + r'(\text{' + self._time + '} = 0)'
|
|
35
|
+
else: # pragma: no cover
|
|
36
|
+
raise ValueError(f'Unsupported LHS type {type(lhs)}')
|
|
37
|
+
|
|
29
38
|
self._flhs = None
|
|
30
|
-
self.set_lhs_function(
|
|
39
|
+
self.set_lhs_function(flhs)
|
|
31
40
|
|
|
32
41
|
def set_lhs_function(self, f):
|
|
33
42
|
"""
|
|
34
43
|
Sets a naming function, will be called to get the variable name from a
|
|
35
|
-
|
|
44
|
+
:class:`myokit.LhsExpression`. This function is also responsible for
|
|
45
|
+
converting it to a suitable Latex form (e.g. adding `\\text{}`).
|
|
36
46
|
|
|
37
47
|
The argument ``f`` should be a function that takes an ``LhsExpression``
|
|
38
48
|
as input and returns a string.
|
|
@@ -40,31 +50,22 @@ class LatexExpressionWriter(myokit.formats.ExpressionWriter):
|
|
|
40
50
|
self._flhs = f
|
|
41
51
|
|
|
42
52
|
def set_time_variable_name(self, name='t'):
|
|
43
|
-
"""
|
|
44
|
-
Sets a name to use for the time variable in derivatives
|
|
45
|
-
"""
|
|
53
|
+
""" Sets a name to use for the time variable in derivatives. """
|
|
46
54
|
self._time = self._prepare_name(name)
|
|
47
55
|
|
|
48
56
|
def eq(self, eq):
|
|
49
|
-
"""
|
|
50
|
-
Converts an equation to a string.
|
|
51
|
-
"""
|
|
57
|
+
""" See :meth:`myokit.formats.ExpressionWriter.eq()`. """
|
|
52
58
|
return self.ex(eq.lhs) + ' = ' + self.ex(eq.rhs)
|
|
53
59
|
|
|
54
60
|
def ex(self, e):
|
|
55
|
-
"""
|
|
56
|
-
Converts an expression to a string.
|
|
57
|
-
"""
|
|
61
|
+
""" See :meth:`myokit.formats.ExpressionWriter.ex()`. """
|
|
58
62
|
b = []
|
|
59
63
|
self._ex(e, b)
|
|
60
64
|
return ''.join(b)
|
|
61
65
|
|
|
62
66
|
def _prepare_name(self, text):
|
|
63
|
-
"""
|
|
64
|
-
|
|
65
|
-
"""
|
|
66
|
-
text = str(text)
|
|
67
|
-
return text.replace('_', '\_')
|
|
67
|
+
""" Sanitises a name for use in latex. """
|
|
68
|
+
return str(text).replace('_', r'\_')
|
|
68
69
|
|
|
69
70
|
def _ex(self, e, b):
|
|
70
71
|
try:
|
|
@@ -73,40 +74,43 @@ class LatexExpressionWriter(myokit.formats.ExpressionWriter):
|
|
|
73
74
|
raise ValueError('Unknown expression type: ' + str(type(e)))
|
|
74
75
|
action(e, b)
|
|
75
76
|
|
|
77
|
+
def _ex_prefix(self, e, b, op):
|
|
78
|
+
""" Handles _ex() for prefix operators. """
|
|
79
|
+
b.append(op)
|
|
80
|
+
if e.bracket(e[0]):
|
|
81
|
+
b.append(r'\left(')
|
|
82
|
+
self._ex(e[0], b)
|
|
83
|
+
if e.bracket(e[0]):
|
|
84
|
+
b.append(r'\right)')
|
|
85
|
+
|
|
76
86
|
def _ex_infix(self, e, b, op):
|
|
77
|
-
"""
|
|
78
|
-
Handles _ex() for infix operators
|
|
79
|
-
"""
|
|
87
|
+
""" Handles _ex() for infix operators. """
|
|
80
88
|
if e.bracket(e[0]):
|
|
81
|
-
b.append('
|
|
89
|
+
b.append(r'\left(')
|
|
82
90
|
self._ex(e[0], b)
|
|
83
91
|
if e.bracket(e[0]):
|
|
84
|
-
b.append('
|
|
92
|
+
b.append(r'\right)')
|
|
85
93
|
b.append(op)
|
|
86
94
|
if e.bracket(e[1]):
|
|
87
|
-
b.append('
|
|
95
|
+
b.append(r'\left(')
|
|
88
96
|
self._ex(e[1], b)
|
|
89
97
|
if e.bracket(e[1]):
|
|
90
|
-
b.append('
|
|
98
|
+
b.append(r'\right)')
|
|
91
99
|
|
|
92
100
|
def _ex_function(self, e, b, func):
|
|
93
|
-
"""
|
|
94
|
-
Handles _ex() for function operators
|
|
95
|
-
"""
|
|
101
|
+
""" Handles _ex() for function operators. """
|
|
96
102
|
b.append(func)
|
|
97
|
-
b.append('
|
|
103
|
+
b.append(r'\left(')
|
|
98
104
|
b.append(','.join([self.ex(x) for x in e]))
|
|
99
|
-
b.append('
|
|
105
|
+
b.append(r'\right)')
|
|
100
106
|
|
|
101
107
|
def _ex_infix_condition(self, e, b, op):
|
|
102
|
-
"""
|
|
103
|
-
|
|
104
|
-
"""
|
|
105
|
-
b.append('\\left(')
|
|
108
|
+
""" Handles _ex() for infix condition operators. """
|
|
109
|
+
b.append(r'\left(')
|
|
106
110
|
self._ex(e[0], b)
|
|
107
111
|
b.append(op)
|
|
108
112
|
self._ex(e[1], b)
|
|
109
|
-
b.append('
|
|
113
|
+
b.append(r'\right)')
|
|
110
114
|
|
|
111
115
|
def _ex_name(self, e, b):
|
|
112
116
|
b.append(self._flhs(e))
|
|
@@ -114,21 +118,24 @@ class LatexExpressionWriter(myokit.formats.ExpressionWriter):
|
|
|
114
118
|
def _ex_derivative(self, e, b):
|
|
115
119
|
b.append(self._flhs(e))
|
|
116
120
|
|
|
121
|
+
def _ex_partial_derivative(self, e, b):
|
|
122
|
+
b.append(self._flhs(e))
|
|
123
|
+
|
|
124
|
+
def _ex_initial_value(self, e, b):
|
|
125
|
+
b.append(self._flhs(e))
|
|
126
|
+
|
|
117
127
|
def _ex_number(self, e, b):
|
|
118
|
-
b.append(myokit.float.str(e))
|
|
128
|
+
b.append(myokit.float.str(e).strip())
|
|
129
|
+
u = e.unit()
|
|
130
|
+
if u is not None and u is not myokit.units.dimensionless:
|
|
131
|
+
u = str(u)[1:-1]
|
|
132
|
+
b.append(r' \text{' + u + '}')
|
|
119
133
|
|
|
120
134
|
def _ex_prefix_plus(self, e, b):
|
|
121
|
-
self.
|
|
135
|
+
self._ex_prefix(e, b, '+')
|
|
122
136
|
|
|
123
137
|
def _ex_prefix_minus(self, e, b):
|
|
124
|
-
|
|
125
|
-
b.append('-')
|
|
126
|
-
if e.bracket(e[0]):
|
|
127
|
-
b.append('\\left(')
|
|
128
|
-
self._ex(e[0], b)
|
|
129
|
-
if e.bracket(e[0]):
|
|
130
|
-
b.append('\\right)')
|
|
131
|
-
b.append('\\right)')
|
|
138
|
+
self._ex_prefix(e, b, '-')
|
|
132
139
|
|
|
133
140
|
def _ex_plus(self, e, b):
|
|
134
141
|
self._ex_infix(e, b, '+')
|
|
@@ -137,10 +144,10 @@ class LatexExpressionWriter(myokit.formats.ExpressionWriter):
|
|
|
137
144
|
self._ex_infix(e, b, '-')
|
|
138
145
|
|
|
139
146
|
def _ex_multiply(self, e, b):
|
|
140
|
-
self._ex_infix(e, b, '
|
|
147
|
+
self._ex_infix(e, b, r'\cdot')
|
|
141
148
|
|
|
142
149
|
def _ex_divide(self, e, b):
|
|
143
|
-
b.append('
|
|
150
|
+
b.append(r'\frac{')
|
|
144
151
|
self._ex(e[0], b)
|
|
145
152
|
b.append('}{')
|
|
146
153
|
self._ex(e[1], b)
|
|
@@ -149,85 +156,88 @@ class LatexExpressionWriter(myokit.formats.ExpressionWriter):
|
|
|
149
156
|
def _ex_quotient(self, e, b):
|
|
150
157
|
# Note: Quotient in myokit uses round-to-zero (like Python does!)
|
|
151
158
|
# See: myokit.Quotient
|
|
152
|
-
b.append('
|
|
159
|
+
b.append(r'\left\lfloor')
|
|
153
160
|
self._ex_divide(e, b)
|
|
154
|
-
b.append('
|
|
161
|
+
b.append(r'\right\rfloor')
|
|
155
162
|
|
|
156
163
|
def _ex_remainder(self, e, b):
|
|
157
|
-
self.
|
|
164
|
+
self._ex_infix(e, b, r'\bmod')
|
|
158
165
|
|
|
159
166
|
def _ex_power(self, e, b):
|
|
160
|
-
if e.bracket(e[0]):
|
|
161
|
-
b.append('
|
|
167
|
+
if e.bracket(e[0]) or isinstance(e[0], myokit.Power):
|
|
168
|
+
b.append(r'\left(')
|
|
162
169
|
self._ex(e[0], b)
|
|
163
|
-
if e.bracket(e[0]):
|
|
164
|
-
b.append('
|
|
165
|
-
b.append('^
|
|
170
|
+
if e.bracket(e[0]) or isinstance(e[0], myokit.Power):
|
|
171
|
+
b.append(r'\right)')
|
|
172
|
+
b.append('^')
|
|
173
|
+
if e.bracket(e[1]) or isinstance(e[1], myokit.Power):
|
|
174
|
+
b.append('{')
|
|
166
175
|
self._ex(e[1], b)
|
|
167
|
-
|
|
176
|
+
if e.bracket(e[1]) or isinstance(e[1], myokit.Power):
|
|
177
|
+
b.append('}')
|
|
168
178
|
|
|
169
179
|
def _ex_sqrt(self, e, b):
|
|
170
|
-
b.append('
|
|
180
|
+
b.append(r'\sqrt{')
|
|
171
181
|
self._ex(e[0], b)
|
|
172
182
|
b.append('}')
|
|
173
183
|
|
|
174
184
|
def _ex_sin(self, e, b):
|
|
175
|
-
self._ex_function(e, b, '
|
|
185
|
+
self._ex_function(e, b, r'\sin')
|
|
176
186
|
|
|
177
187
|
def _ex_cos(self, e, b):
|
|
178
|
-
self._ex_function(e, b, '
|
|
188
|
+
self._ex_function(e, b, r'\cos')
|
|
179
189
|
|
|
180
190
|
def _ex_tan(self, e, b):
|
|
181
|
-
self._ex_function(e, b, '
|
|
191
|
+
self._ex_function(e, b, r'\tan')
|
|
182
192
|
|
|
183
193
|
def _ex_asin(self, e, b):
|
|
184
|
-
self._ex_function(e, b, '
|
|
194
|
+
self._ex_function(e, b, r'\arcsin')
|
|
185
195
|
|
|
186
196
|
def _ex_acos(self, e, b):
|
|
187
|
-
self._ex_function(e, b, '
|
|
197
|
+
self._ex_function(e, b, r'\arccos')
|
|
188
198
|
|
|
189
199
|
def _ex_atan(self, e, b):
|
|
190
|
-
self._ex_function(e, b, '
|
|
200
|
+
self._ex_function(e, b, r'\arctan')
|
|
191
201
|
|
|
192
202
|
def _ex_exp(self, e, b):
|
|
193
|
-
self._ex_function(e, b, '
|
|
203
|
+
self._ex_function(e, b, r'\exp')
|
|
194
204
|
|
|
195
205
|
def _ex_log(self, e, b):
|
|
196
|
-
b.append('
|
|
206
|
+
b.append(r'\log')
|
|
197
207
|
if len(e) > 1:
|
|
198
208
|
b.append('_{')
|
|
199
209
|
self._ex(e[1], b)
|
|
200
210
|
b.append('}')
|
|
201
|
-
b.append('
|
|
211
|
+
b.append(r'\left(')
|
|
202
212
|
self._ex(e[0], b)
|
|
203
|
-
b.append('
|
|
213
|
+
b.append(r'\right)')
|
|
204
214
|
|
|
205
215
|
def _ex_log10(self, e, b):
|
|
206
|
-
|
|
216
|
+
b.append(r'\log_{10}')
|
|
217
|
+
b.append(r'\left(')
|
|
218
|
+
self._ex(e[0], b)
|
|
219
|
+
b.append(r'\right)')
|
|
207
220
|
|
|
208
221
|
def _ex_floor(self, e, b):
|
|
209
|
-
b.append('
|
|
222
|
+
b.append(r'\left\lfloor{')
|
|
210
223
|
self._ex(e[0], b)
|
|
211
|
-
b.append('}
|
|
224
|
+
b.append(r'}\right\rfloor')
|
|
212
225
|
|
|
213
226
|
def _ex_ceil(self, e, b):
|
|
214
|
-
b.append('
|
|
227
|
+
b.append(r'\left\lceil{')
|
|
215
228
|
self._ex(e[0], b)
|
|
216
|
-
b.append('}
|
|
229
|
+
b.append(r'}\right\rceil')
|
|
217
230
|
|
|
218
231
|
def _ex_abs(self, e, b):
|
|
219
|
-
b.append('
|
|
232
|
+
b.append(r'\lvert{')
|
|
220
233
|
self._ex(e[0], b)
|
|
221
|
-
b.append('}
|
|
222
|
-
|
|
223
|
-
def _ex_not(self, e, b):
|
|
224
|
-
self._ex_function(e, b, '\\not')
|
|
234
|
+
b.append(r'}\rvert')
|
|
225
235
|
|
|
226
236
|
def _ex_equal(self, e, b):
|
|
227
237
|
self._ex_infix_condition(e, b, '=')
|
|
228
238
|
|
|
229
239
|
def _ex_not_equal(self, e, b):
|
|
230
|
-
self._ex_infix_condition(e, b, '
|
|
240
|
+
self._ex_infix_condition(e, b, r'\neq')
|
|
231
241
|
|
|
232
242
|
def _ex_more(self, e, b):
|
|
233
243
|
self._ex_infix_condition(e, b, '>')
|
|
@@ -236,21 +246,26 @@ class LatexExpressionWriter(myokit.formats.ExpressionWriter):
|
|
|
236
246
|
self._ex_infix_condition(e, b, '<')
|
|
237
247
|
|
|
238
248
|
def _ex_more_equal(self, e, b):
|
|
239
|
-
self._ex_infix_condition(e, b, '
|
|
249
|
+
self._ex_infix_condition(e, b, r'\geq')
|
|
240
250
|
|
|
241
251
|
def _ex_less_equal(self, e, b):
|
|
242
|
-
self._ex_infix_condition(e, b, '
|
|
252
|
+
self._ex_infix_condition(e, b, r'\leq')
|
|
253
|
+
|
|
254
|
+
def _ex_not(self, e, b):
|
|
255
|
+
b.append(r'\left(\not')
|
|
256
|
+
self._ex(e[0], b)
|
|
257
|
+
b.append(r'\right)')
|
|
243
258
|
|
|
244
259
|
def _ex_and(self, e, b):
|
|
245
|
-
self._ex_infix_condition(e, b, '
|
|
260
|
+
self._ex_infix_condition(e, b, r'\and')
|
|
246
261
|
|
|
247
262
|
def _ex_or(self, e, b):
|
|
248
|
-
self._ex_infix_condition(e, b, '
|
|
263
|
+
self._ex_infix_condition(e, b, r'\or')
|
|
249
264
|
|
|
250
265
|
def _ex_if(self, e, b):
|
|
251
266
|
# Not suported
|
|
252
|
-
self._ex_function(e, b, 'if')
|
|
267
|
+
self._ex_function(e, b, r'\text{if}')
|
|
253
268
|
|
|
254
269
|
def _ex_piecewise(self, e, b):
|
|
255
270
|
# Not suported
|
|
256
|
-
self._ex_function(e, b, 'piecewise')
|
|
271
|
+
self._ex_function(e, b, r'\text{piecewise}')
|
|
@@ -130,11 +130,11 @@ class MathMLExpressionWriter(myokit.formats.ExpressionWriter):
|
|
|
130
130
|
bra = e.bracket(e[0])
|
|
131
131
|
if self._pres:
|
|
132
132
|
row = etree.SubElement(t, 'mrow')
|
|
133
|
+
x = etree.SubElement(row, 'mo')
|
|
134
|
+
x.text = e.operator_rep()
|
|
133
135
|
if bra:
|
|
134
136
|
x = etree.SubElement(row, 'mo')
|
|
135
137
|
x.text = '('
|
|
136
|
-
x = etree.SubElement(row, 'mo')
|
|
137
|
-
x.text = e.operator_rep()
|
|
138
138
|
self._ex(e[0], row)
|
|
139
139
|
if bra:
|
|
140
140
|
x = etree.SubElement(row, 'mo')
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
# This file is part of Myokit.
|
|
5
5
|
# See http://myokit.org for copyright, sharing, and licensing details.
|
|
6
6
|
#
|
|
7
|
+
import myokit
|
|
8
|
+
|
|
7
9
|
from myokit.formats.python import PythonExpressionWriter
|
|
8
10
|
|
|
9
11
|
|
|
@@ -17,15 +19,32 @@ class MatlabExpressionWriter(PythonExpressionWriter):
|
|
|
17
19
|
self._function_prefix = ''
|
|
18
20
|
self._fcond = 'ifthenelse'
|
|
19
21
|
|
|
20
|
-
def set_condition_function(self, func
|
|
22
|
+
def set_condition_function(self, func):
|
|
21
23
|
"""
|
|
22
|
-
Sets a function name to
|
|
24
|
+
Sets a function name to output to handle :class:`myokit.If`.
|
|
25
|
+
|
|
26
|
+
The function must take arguments ``(condition, value_if_true,
|
|
27
|
+
value_if_false)`` and will be used to handle both :class:`myokit.If`
|
|
28
|
+
and :class:`myokit.Piecewise`.
|
|
29
|
+
|
|
30
|
+
By default, `ifthenelse` is used, which the user is expected to define
|
|
31
|
+
if ``If`` or ``Piecewise`` will be used. For example::
|
|
32
|
+
|
|
33
|
+
function y = ifthenelse(condition, value_if_true, value_if_false)
|
|
34
|
+
if (condition)
|
|
35
|
+
y = value_if_true;
|
|
36
|
+
else
|
|
37
|
+
y = value_if_false;
|
|
38
|
+
end
|
|
39
|
+
end
|
|
23
40
|
|
|
24
|
-
By setting func to None you can revert back to the default behavior
|
|
25
|
-
(the ternary operator). Any other value will be interpreted as the
|
|
26
|
-
name of a function taking arguments (condition, value_if_true,
|
|
27
|
-
value_if_false).
|
|
28
41
|
"""
|
|
42
|
+
if func is not None:
|
|
43
|
+
func = str(func).strip()
|
|
44
|
+
if func is None or func == '':
|
|
45
|
+
raise ValueError(
|
|
46
|
+
'The MatlabExpressionWriter needs a condition function to be'
|
|
47
|
+
' set.')
|
|
29
48
|
self._fcond = func
|
|
30
49
|
|
|
31
50
|
#def _ex_name(self, e):
|
|
@@ -40,14 +59,17 @@ class MatlabExpressionWriter(PythonExpressionWriter):
|
|
|
40
59
|
|
|
41
60
|
def _ex_quotient(self, e):
|
|
42
61
|
# Round towards minus infinity
|
|
43
|
-
return
|
|
62
|
+
return self.ex(myokit.Floor(myokit.Divide(e[0], e[1])))
|
|
44
63
|
|
|
45
64
|
def _ex_remainder(self, e):
|
|
46
65
|
# Uses the round-towards-minus-infinity convention!
|
|
47
|
-
return 'mod(
|
|
66
|
+
return f'mod({self.ex(e[0])}, {self.ex(e[1])})'
|
|
48
67
|
|
|
49
68
|
def _ex_power(self, e):
|
|
50
|
-
|
|
69
|
+
# Same associativity as Myokit, not Python! So override
|
|
70
|
+
e1 = f'({self.ex(e[0])})' if e.bracket(e[0]) else f'{self.ex(e[0])}'
|
|
71
|
+
e2 = f'({self.ex(e[1])})' if e.bracket(e[1]) else f'{self.ex(e[1])}'
|
|
72
|
+
return f'{e1}^{e2}'
|
|
51
73
|
|
|
52
74
|
#def _ex_sqrt(self, e):
|
|
53
75
|
# Ignore imaginary part
|
|
@@ -63,8 +85,9 @@ class MatlabExpressionWriter(PythonExpressionWriter):
|
|
|
63
85
|
def _ex_log(self, e):
|
|
64
86
|
if len(e) == 1:
|
|
65
87
|
return self._ex_function(e, 'log')
|
|
66
|
-
|
|
67
|
-
|
|
88
|
+
# Always add brackets: Parent was expecting a function so will never
|
|
89
|
+
# have added them.
|
|
90
|
+
return f'(log({self.ex(e[0])}) / log({self.ex(e[1])}))'
|
|
68
91
|
|
|
69
92
|
#def _ex_log10(self, e):
|
|
70
93
|
#def _ex_floor(self, e):
|
|
@@ -73,9 +96,6 @@ class MatlabExpressionWriter(PythonExpressionWriter):
|
|
|
73
96
|
def _ex_abs(self, e):
|
|
74
97
|
return self._ex_function(e, 'abs')
|
|
75
98
|
|
|
76
|
-
def _ex_not(self, e):
|
|
77
|
-
return '!(' + self.ex(e[0]) + ')'
|
|
78
|
-
|
|
79
99
|
#def _ex_equal(self, e):
|
|
80
100
|
#def _ex_not_equal(self, e):
|
|
81
101
|
#def _ex_more(self, e):
|
|
@@ -84,26 +104,28 @@ class MatlabExpressionWriter(PythonExpressionWriter):
|
|
|
84
104
|
#def _ex_less_equal(self, e):
|
|
85
105
|
|
|
86
106
|
def _ex_and(self, e):
|
|
87
|
-
return self.
|
|
107
|
+
return self._ex_infix_logical(e, '&&')
|
|
88
108
|
|
|
89
109
|
def _ex_or(self, e):
|
|
90
|
-
return self.
|
|
110
|
+
return self._ex_infix_logical(e, '||')
|
|
111
|
+
|
|
112
|
+
def _ex_not(self, e):
|
|
113
|
+
return f'(!{self.ex(e[0])})'
|
|
91
114
|
|
|
92
115
|
def _ex_if(self, e):
|
|
93
|
-
|
|
94
|
-
|
|
116
|
+
_if, _then, _else = self.ex(e._i), self.ex(e._t), self.ex(e._e)
|
|
117
|
+
return f'{self._fcond}({_if}, {_then}, {_else})'
|
|
95
118
|
|
|
96
119
|
def _ex_piecewise(self, e):
|
|
120
|
+
# Render ifs; add extra bracket if not a condition (see _ex_if)
|
|
121
|
+
_ifs = [self.ex(x) for x in e._i]
|
|
122
|
+
_thens = [self.ex(x) for x in e._e]
|
|
123
|
+
|
|
97
124
|
s = []
|
|
98
|
-
n = len(
|
|
99
|
-
for
|
|
100
|
-
s.append(self._fcond)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
s.append(', ')
|
|
104
|
-
s.append(self.ex(e._e[i]))
|
|
105
|
-
s.append(', ')
|
|
106
|
-
s.append(self.ex(e._e[n]))
|
|
107
|
-
s.append(')' * n)
|
|
125
|
+
n = len(_ifs)
|
|
126
|
+
for _if, _then in zip(_ifs, _thens):
|
|
127
|
+
s.append(f'{self._fcond}({_if}, {_then}, ')
|
|
128
|
+
s.append(_thens[-1])
|
|
129
|
+
s.append(')' * len(_ifs))
|
|
108
130
|
return ''.join(s)
|
|
109
131
|
|