25
25
"""
26
26
parse_cn(node)
27
27
28
- parse a <cn> node
28
+ parse a <cn> node
29
29
"""
30
30
function parse_cn (node)
31
31
# elements(node) != EzXML.Node[] && error("node cant have elements rn, check if </sep> is in the node")
32
32
# this isnt great might want to check that `sep` actually shows up
33
33
if haskey (node, " type" ) && elements (node) != EzXML. Node[]
34
34
parse_cn_w_sep (node)
35
- else
35
+ else
36
36
Meta. parse (node. content)
37
37
end
38
38
end
39
39
40
40
"""
41
41
parse_cn_w_sep(node)
42
42
43
- parse a <cn type=".."> node
43
+ parse a <cn type=".."> node
44
44
45
45
where type ∈ ["e-notation", "rational", "complex-cartesian", "complex-polar"]
46
46
"""
47
47
function parse_cn_w_sep (node)
48
48
# node = clean_attributes(node)
49
- txts = findall (" // text()" , node)
49
+ txts = findall (" text()" , node)
50
50
length (txts) != 2 && error (" stop, collaborate, and listen!, problem with <cn>" )
51
51
x1, x2 = map (x -> Meta. parse (x. content), txts)
52
52
t = node[" type" ]
@@ -58,14 +58,14 @@ function parse_cn_w_sep(node)
58
58
Complex (x1, x2)
59
59
elseif t == " complex-polar"
60
60
x1 * exp (x2 * im)
61
- else
61
+ else
62
62
error (" $t in parse_cn_w_sep, somethings wrong" )
63
63
end
64
64
end
65
65
66
66
# """
67
67
# remove all attributes neq to `type`
68
- # this is an issue for undefined namespaces
68
+ # this is an issue for undefined namespaces
69
69
# https://github.com/JuliaIO/EzXML.jl/issues/156
70
70
# """
71
71
# function clean_attributes(node)
84
84
"""
85
85
parse_ci(node)
86
86
87
- parse a <ci> node
87
+ parse a <ci> node
88
88
"""
89
89
function parse_ci (node)
90
90
c = Meta. parse (strip (node. content))
91
91
Num (Variable (c))
92
92
end
93
93
94
+ # ######### Parse piecewise ###################################################
95
+
96
+ function parse_piecewise (node)
97
+ return process_pieces (elements (node))
98
+ end
99
+
100
+ function process_pieces (pieces)
101
+ if length (pieces) == 1
102
+ return process_piece (pieces[1 ])
103
+ else
104
+ return process_piece (pieces[1 ], process_pieces (pieces[2 : end ]))
105
+ end
106
+ end
107
+
108
+ function process_piece (node)
109
+ if nodename (node) != " otherwise"
110
+ error (" expect an otherwise" )
111
+ else
112
+ return parse_node (firstelement (node))
113
+ end
114
+ end
115
+
116
+ function process_piece (node, otherwise)
117
+ if nodename (node) == " otherwise"
118
+ return parse_node (firstelement (node))
119
+ elseif nodename (node) == " piece"
120
+ c = parse_node .(elements (node))
121
+ return Symbolics. IfElse. ifelse (c[2 ] > 0.5 , c[1 ], otherwise)
122
+ end
123
+ end
124
+
94
125
# """
95
126
# parse_piecewise(node)
96
127
97
- # parse a <piecewise> node
128
+ # parse a <piecewise> node
98
129
# want to recursively call ifelse on the pieces
99
130
# """
100
131
# function parse_piecewise(node)
101
132
# es = elements(node)
102
- # IfElse.ifelse(a, b,
103
- # IfElse.ifelse(c, d,
133
+ # IfElse.ifelse(a, b,
134
+ # IfElse.ifelse(c, d,
104
135
# IfElse.ifelse(e, f, otherwise)))
105
136
# end
106
137
107
138
# """
108
139
# parse_piece(node)
109
140
110
- # parse a <piece> node
141
+ # parse a <piece> node
111
142
# Each <piece> element contains exactly two children.
112
143
# The conditional is the second child and the return is the first.
113
144
# """
133
164
"""
134
165
parse_bvar(node)
135
166
136
- parse a <bvar> node
167
+ parse a <bvar> node
137
168
"""
138
169
function parse_bvar (node)
139
170
es = elements (node)
@@ -156,20 +187,20 @@ end
156
187
tagmap = Dict {String,Function} (
157
188
" cn" => parse_cn,
158
189
" ci" => parse_ci,
159
-
190
+
160
191
" degree" => x -> parse_node (x. firstelement), # won't work for all cases
161
192
" bvar" => parse_bvar, # won't work for all cases
162
- # "diff" => parse_diff, #inputs are
193
+ # "diff" => parse_diff, #inputs are
163
194
164
- # "piecewise" => parse_piecewise,
165
- # "piece" => parse_piece,
166
- # "otherwise" => x-> parse_node(x.firstelement),
195
+ " piecewise" => parse_piecewise,
196
+ # "piece" => parse_piece,
197
+ # "otherwise" => x-> parse_node(x.firstelement),
167
198
168
199
" apply" => parse_apply,
169
200
" math" => x -> map (parse_node, elements (x)),
170
201
" vector" => x -> map (parse_node, elements (x)),
171
202
)
172
-
203
+
173
204
function custom_root (x)
174
205
length (x) == 1 ? sqrt (x... ) : Base.:^ (x[2 ], x[1 ])
175
206
end
@@ -180,45 +211,72 @@ function check_ivs(node)
180
211
all (y -> y. content == x[1 ]. content, x)
181
212
end
182
213
183
- # need to check the arities
214
+ H (x) = Symbolics. IfElse. ifelse (x > 0 , one (x), zero (x))
215
+ const ϵ = eps (Float64)
216
+ frac (x) = 0.5 - atan (cot (π * x)) / π
217
+ heaviside_or (x) = length (x) == 1 ? x[1 ] : x[1 ] + heaviside_or (x[2 : end ]) - x[1 ] * heaviside_or (x[2 : end ])
218
+
219
+ # need to check the arities
184
220
# units handling??
185
221
applymap = Dict {String,Function} (
186
222
# eq sometimes needs to be ~ and sometimes needs to be =, not sure what the soln is
187
- " eq" => x -> Symbolics.:~ (x... ), # arity 2,
223
+ " eq" => x -> Symbolics.:~ (x... ), # arity 2,
188
224
" times" => Base. prod, # arity 2, but prod fine
189
- # "prod" => Base.prod,
225
+ # "prod" => Base.prod,
190
226
" divide" => x -> Base.:/ (x... ),
191
227
" power" => x -> Base.:^ (x... ),
192
- " root" => custom_root,
228
+ " root" => custom_root,
193
229
" plus" => x -> Base.:+ (x... ),
194
230
" minus" => x -> Base.:- (x... ),
195
- " lt" => x -> Base. foldl (Base.:< , x),
196
- " leq" => x -> Base. foldl (Base.:≤ , x),
197
- " geq" => x -> Base. foldl (Base.:≥ , x),
198
- " gt" => x -> Base. foldl (Base.:> , x),
231
+
232
+ # comparison functions implemented using the Heaviside function
233
+ " lt" => x -> H (x[2 ] - x[1 ] - ϵ),
234
+ " leq" => x -> H (x[2 ] - x[1 ]),
235
+ " geq" => x -> H (x[1 ] - x[2 ]),
236
+ " gt" => x -> H (x[1 ] - x[2 ] - ϵ),
237
+
238
+ # "lt" => x -> Base.foldl(Base.:<, x),
239
+ # "leq" => x -> Base.foldl(Base.:≤, x),
240
+ # "geq" => x -> Base.foldl(Base.:≥, x),
241
+ # "gt" => x -> Base.foldl(Base.:>, x),
242
+
199
243
# "quotient" => x->Base.:div(x...), # broken, RoundingMode
200
244
" factorial" => x -> Base. factorial (x... ),
201
245
" max" => x -> Base. max (x... ),
202
246
" min" => x -> Base. min (x... ),
203
247
" rem" => x -> Base.:rem (x... ),
204
248
" gcd" => x -> Base.:gcd (x... ),
205
- " and" => Base.:& ,
206
- " or" => Base.:| ,
207
- " xor" => Base.:⊻ ,
208
- " not" => Base.:! ,
249
+
250
+ " and" => x -> Base.:* (x... ),
251
+ " or" => heaviside_or,
252
+ " xor" => x -> x[1 ]* (one (x[2 ])- x[2 ]) + (one (x[1 ])- x[1 ])* x[2 ],
253
+ " not" => x -> one (x[1 ]) - x[1 ],
254
+
255
+ # "and" => x -> Base.:&(x...),
256
+ # "or" => Base.:|,
257
+ # "xor" => Base.:⊻,
258
+ # "not" => Base.:!,
259
+
209
260
" abs" => x -> Base. abs (x... ),
210
261
" conjugate" => Base. conj,
211
262
" arg" => Base. angle,
212
263
" real" => Base. real,
213
264
" imaginary" => Base. imag,
214
265
" lcm" => x -> Base. lcm (x... ),
215
- " floor" => x -> Base. floor (x... ),
216
- " ceiling" => x -> Base. ceil (x... ),
266
+
267
+ " floor" => x -> x[1 ] - frac (x[1 ]),
268
+ " ceiling" => x -> x[1 ] - frac (x[1 ]) + one (x[1 ]),
269
+ " round" => x -> x[1 ] + 0.5 - frac (x[1 ] + 0.5 ),
270
+
271
+ # "floor" => x -> Base.floor(x...),
272
+ # "ceiling" => x -> Base.ceil(x...),
273
+ # "round" => x -> Base.round(x...),
274
+
217
275
" inverse" => Base. inv,
218
276
" compose" => x -> Base.:∘ (x... ),
219
277
" ident" => Base. identity,
220
278
" approx" => x -> Base.:≈ (x... ),
221
-
279
+
222
280
" sin" => x -> Base. sin (x... ),
223
281
" cos" => x -> Base. cos (x... ),
224
282
" tan" => x -> Base. tan (x... ),
@@ -245,7 +303,7 @@ applymap = Dict{String,Function}(
245
303
" arccoth" => x -> Base. acoth (x... ),
246
304
247
305
" exp" => x -> Base. exp (x... ),
248
- " log" => x -> Base. log10 (x... ), # todo handle <logbase>
306
+ " log" => x -> Base. log10 (x... ), # todo handle <logbase>
249
307
" ln" => x -> Base. log (x... ),
250
308
251
309
" mean" => Statistics. mean,
0 commit comments