User Guide
diffeq_helper.hpp
Go to the documentation of this file.
1
/*
2
* Copyright 2023 Blue Brain Project, EPFL.
3
* See the top-level LICENSE file for details.
4
*
5
* SPDX-License-Identifier: Apache-2.0
6
*/
7
8
#pragma once
9
10
#include "
parser/diffeq_context.hpp
"
11
12
namespace
nmodl
{
13
namespace
parser {
14
15
/**
16
* \brief Helper functions for solving differential equations
17
*
18
* Differential euqation parser (diffeq.yy) needs to solve derivative
19
* of various binary expressions and those are provided below. This
20
* implementation is based on original neuron implementation.
21
*
22
* \todo The implementations here are verbose and has duplicate code.
23
* Need to revisit this, may be using better library like symengine
24
* altogether.
25
*/
26
namespace
diffeq {
27
28
/// operators beign supported as part of binary expressions
29
enum class
MathOp
{
add
= 1,
sub
,
mul
,
div
};
30
31
template
<MathOp Op>
32
inline
Term
eval_derivative
(
const
Term& first,
33
const
Term& second,
34
bool
& deriv_invalid,
35
bool
& eqn_invalid);
36
37
38
/// implement (f(x) + g(x))' = f'(x) + g'(x)
39
template
<>
40
inline
Term
eval_derivative<MathOp::add>(
const
Term
& first,
41
const
Term
& second,
42
bool
& deriv_invalid,
43
bool
& eqn_invalid) {
44
Term
solution;
45
solution.
expr
= first.
expr
+
"+"
+ second.
expr
;
46
47
if
(first.
deriv_nonzero
() && second.
deriv_nonzero
()) {
48
solution.
deriv
= first.
deriv
+
"+"
+ second.
deriv
;
49
}
else
if
(first.
deriv_nonzero
()) {
50
solution.
deriv
= first.
deriv
;
51
}
else
if
(second.
deriv_nonzero
()) {
52
solution.
deriv
= second.
deriv
;
53
}
54
55
if
(first.
a_nonzero
() && second.
a_nonzero
()) {
56
solution.
a
= first.
a
+
"+"
+ second.
a
;
57
}
else
if
(first.
a_nonzero
()) {
58
solution.
a
= first.
a
;
59
}
else
if
(second.
a_nonzero
()) {
60
solution.
a
= second.
a
;
61
}
62
63
if
(first.
b_nonzero
() && second.
b_nonzero
()) {
64
solution.
b
= first.
b
+
"+"
+ second.
b
;
65
}
else
if
(first.
b_nonzero
()) {
66
solution.
b
= first.
b
;
67
}
else
if
(second.
b_nonzero
()) {
68
solution.
b
= second.
b
;
69
}
70
71
return
solution;
72
}
73
74
75
/// implement (f(x) - g(x))' = f'(x) - g'(x)
76
template
<>
77
inline
Term
eval_derivative<MathOp::sub>(
const
Term
& first,
78
const
Term
& second,
79
bool
& deriv_invalid,
80
bool
& eqn_invalid) {
81
Term
solution;
82
solution.
expr
= first.
expr
+
"-"
+ second.
expr
;
83
84
if
(first.
deriv_nonzero
() && second.
deriv_nonzero
()) {
85
solution.
deriv
= first.
deriv
+
"-"
+ second.
deriv
;
86
}
else
if
(first.
deriv_nonzero
()) {
87
solution.
deriv
= first.
deriv
;
88
}
else
if
(second.
deriv_nonzero
()) {
89
solution.
deriv
=
"(-"
+ second.
deriv
+
")"
;
90
}
91
92
if
(first.
a_nonzero
() && second.
a_nonzero
()) {
93
solution.
a
= first.
a
+
"-"
+ second.
a
;
94
}
else
if
(first.
a_nonzero
()) {
95
solution.
a
= first.
a
;
96
}
else
if
(second.
a_nonzero
()) {
97
solution.
a
=
"(-"
+ second.
a
+
")"
;
98
}
99
100
if
(first.
b_nonzero
() && second.
b_nonzero
()) {
101
solution.
b
= first.
b
+
"-"
+ second.
b
;
102
}
else
if
(first.
b_nonzero
()) {
103
solution.
b
= first.
b
;
104
}
else
if
(second.
b_nonzero
()) {
105
solution.
b
=
"(-"
+ second.
b
+
")"
;
106
}
107
108
return
solution;
109
}
110
111
112
/// implement (f(x) * g(x))' = f'(x)g(x) + f(x)g'(x)
113
template
<>
114
inline
Term
eval_derivative<MathOp::mul>(
const
Term
& first,
115
const
Term
& second,
116
bool
& deriv_invalid,
117
bool
& eqn_invalid) {
118
Term
solution;
119
solution.
expr
= first.
expr
+
"*"
+ second.
expr
;
120
121
if
(first.
deriv_nonzero
() && second.
deriv_nonzero
()) {
122
solution.
deriv
=
"(("
+ first.
deriv
+
")*("
+ second.
expr
+
")"
;
123
solution.
deriv
+=
"+("
+ first.
expr
+
")*("
+ second.
deriv
+
"))"
;
124
}
else
if
(first.
deriv_nonzero
()) {
125
solution.
deriv
=
"("
+ first.
deriv
+
")*("
+ second.
expr
+
")"
;
126
}
else
if
(second.
deriv_nonzero
()) {
127
solution.
deriv
=
"("
+ first.
expr
+
")*("
+ second.
deriv
+
")"
;
128
}
129
130
if
(first.
a_nonzero
() && second.
a_nonzero
()) {
131
eqn_invalid =
true
;
132
}
else
if
(first.
a_nonzero
() && second.
b_nonzero
()) {
133
solution.
a
=
"("
+ first.
a
+
")*("
+ second.
b
+
")"
;
134
}
else
if
(second.
a_nonzero
() && first.
b_nonzero
()) {
135
solution.
a
=
"("
+ first.
b
+
")*("
+ second.
a
+
")"
;
136
}
137
138
if
(first.
b_nonzero
() && second.
b_nonzero
()) {
139
solution.
b
=
"("
+ first.
b
+
")*("
+ second.
b
+
")"
;
140
}
141
142
return
solution;
143
}
144
145
146
/**
147
* Implement (f(x) / g(x))' = (f'(x)g(x) - f(x)g'(x))/g^2(x)
148
* Note that the implementation is very limited for the g(x)
149
* and this needs to be discussed with Michael.
150
*/
151
template
<>
152
inline
Term
eval_derivative<MathOp::div>(
const
Term
& first,
153
const
Term
& second,
154
bool
& deriv_invalid,
155
bool
& eqn_invalid) {
156
Term
solution;
157
solution.
expr
= first.
expr
+
"/"
+ second.
expr
;
158
159
if
(second.
deriv_nonzero
()) {
160
deriv_invalid =
true
;
161
}
else
if
(first.
deriv_nonzero
()) {
162
solution.
deriv
=
"("
+ first.
deriv
+
")/"
+ second.
expr
;
163
}
164
165
if
(second.
a_nonzero
()) {
166
eqn_invalid =
true
;
167
}
else
if
(first.
a_nonzero
()) {
168
solution.
a
=
"("
+ first.
a
+
")/"
+ second.
expr
;
169
}
170
171
if
(first.
b_nonzero
()) {
172
solution.
b
=
"("
+ first.
b
+
")/"
+ second.
expr
;
173
}
174
175
return
solution;
176
}
177
178
}
// namespace diffeq
179
}
// namespace parser
180
}
// namespace nmodl
nmodl::parser::diffeq::Term::deriv_nonzero
bool deriv_nonzero() const
helper routines used in parser
Definition:
diffeq_context.hpp:49
nmodl::parser::diffeq::MathOp::div
@ div
nmodl::parser::diffeq::Term::expr
std::string expr
expression being solved
Definition:
diffeq_context.hpp:28
nmodl
encapsulates code generation backend implementations
Definition:
ast_common.hpp:26
diffeq_context.hpp
nmodl::parser::diffeq::MathOp::add
@ add
nmodl::parser::diffeq::MathOp::sub
@ sub
nmodl::parser::diffeq::Term::deriv
std::string deriv
derivative of the expression
Definition:
diffeq_context.hpp:31
nmodl::parser::diffeq::Term
Represent a term in differential equation and it's "current" solution.
Definition:
diffeq_context.hpp:26
nmodl::parser::diffeq::MathOp::mul
@ mul
nmodl::parser::diffeq::Term::b
std::string b
Definition:
diffeq_context.hpp:35
nmodl::parser::diffeq::Term::a
std::string a
Definition:
diffeq_context.hpp:34
nmodl::parser::diffeq::Term::b_nonzero
bool b_nonzero() const
Definition:
diffeq_context.hpp:57
nmodl::parser::diffeq::Term::a_nonzero
bool a_nonzero() const
Definition:
diffeq_context.hpp:53
nmodl::parser::diffeq::MathOp
MathOp
operators beign supported as part of binary expressions
Definition:
diffeq_helper.hpp:29
nmodl::parser::diffeq::eval_derivative
Term eval_derivative(const Term &first, const Term &second, bool &deriv_invalid, bool &eqn_invalid)
src
parser
diffeq_helper.hpp