math = {
let math = await require("mathjs@13.0.3")
function timeRange(t0, tf, h){
let t = [t0]
h = h ? h : math.divide(math.subtract(tf, t0), 4)
let n = 0
while(isNotDone(t[n], h, tf)){
h = trimStep(t[n], h, tf)
t.push(math.add(t[n],h))
n ++
}
return t.length > 1 ? t : []
}
function isNotDone(t_n, h, tf){
if(math.isPositive(h)){
return math.smaller(t_n, tf)
}
else if(math.isNegative(h)){
return math.smaller(tf, t_n)
}
}
function trimStep(t_n, h, tf){
const next = math.add(t_n,h)
if(math.isPositive(h)){
if(math.larger(next, tf)){
h = math.subtract(tf, t_n)
}
}
else if(math.isNegative(h)){
if(math.smaller(next, tf)){
h = math.subtract(tf, t_n)
}
}
return h
}
function odeEuler (f, T, y0) {
const t = timeRange(...T)
const N = t.length - 1
let y = [y0]
for (let n = 0; n < N; n++) {
const h = math.subtract(t[n + 1], t[n])
y.push(
math.add(
y[n],
math.dotMultiply(
h,
f(t[n], y[n])
)
)
)
}
return { t, y }
}
math.import({
odeEuler: math.typed('odeEuler', {
'function, Array, Array': odeEuler,
'function, Array, number|Unit': (f, T, y0) => {
const sol = odeEuler(f, T, [y0])
return { t: sol.t, y: sol.y.map(y => y[0]) }
},
'function, Matrix, Matrix': (f, T, y0) => {
const sol = odeEuler(f, T.toArray(), y0.toArray())
return { t: math.matrix(sol.t), y: math.matrix(sol.y) }
}
})
})
return math
}