Skip to content

Commit c2ad58c

Browse files
committed
HarmonicVariable
1 parent 0a64208 commit c2ad58c

File tree

6 files changed

+106
-38
lines changed

6 files changed

+106
-38
lines changed

src/DifferentialEquation.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,9 @@ function rearrange!(eom::DifferentialEquation, new_lhs::Vector{Num})
190190
eom.equations = OrderedDict(zip(get_variables_nums(new_lhs), new_lhs .~ soln))
191191
return nothing
192192
end
193+
function get_variables_nums(vars::Vector{Num})
194+
unique(flatten([Num.(get_variables(x)) for x in vars]))
195+
end # TODO: remove this function or at least better names
193196

194197
"""
195198
$(TYPEDSIGNATURES)

src/HarmonicVariable.jl

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -97,46 +97,8 @@ function QuestBase.substitute_all(vars::Vector{HarmonicVariable}, rules)
9797
end
9898

9999
"Returns the symbols of a `HarmonicVariable`."
100-
function get_variables_nums(vars::Vector{Num})
101-
unique(flatten([Num.(get_variables(x)) for x in vars]))
102-
end
103-
104100
Symbolics.get_variables(var::HarmonicVariable)::Num = Num(first(get_variables(var.symbol)))
105101

106102
Base.isequal(v1::HarmonicVariable, v2::HarmonicVariable)::Bool = isequal(
107103
v1.symbol, v2.symbol
108104
)
109-
110-
"The derivative of f w.r.t. x of degree deg"
111-
function d(f::Num, x::Num, deg=1)::Num
112-
return isequal(deg, 0) ? f : (Differential(x)^deg)(f)
113-
end
114-
d(funcs::Vector{Num}, x::Num, deg=1) = Num[d(f, x, deg) for f in funcs]
115-
116-
"Declare a variable in the the currently active Module namespace"
117-
function declare_variable(name::String)
118-
var_sym = Symbol(name)
119-
@eval($(var_sym) = first(Symbolics.@variables $var_sym))
120-
return eval(var_sym)
121-
end
122-
123-
declare_variable(x::Num) = declare_variable(string(x))
124-
125-
"Declare a variable that is a function of another variable in the Module namespace"
126-
function declare_variable(name::String, independent_variable::Num)
127-
# independent_variable = declare_variable(independent_variable) convert string into Num
128-
var_sym = Symbol(name)
129-
new_var = Symbolics.@variables $var_sym(independent_variable)
130-
@eval($(var_sym) = first($new_var)) # store the variable under "name" in this namespace
131-
return eval(var_sym)
132-
end
133-
134-
"Return the name of a variable (excluding independent variables)"
135-
function var_name(x::Num)::String
136-
var = Symbolics._toexpr(x)
137-
var = var isa Expr ? String(var.args[1]) : String(var)
138-
return String(replace(var, r"\\mathtt\{([^}]*)\}" => s"\1"))
139-
# ^ remove "\\mathtt{}" from the variable name coming from Symbolics
140-
# since Symbolics v6.14.1 (Symbolics#1305)
141-
end
142-
var_name(x::SymbolicUtils.Sym) = String(x.name)

src/QuestBase.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ include("Symbolics/exponentials.jl")
4141
include("Symbolics/fourier.jl")
4242
include("Symbolics/drop_powers.jl")
4343
include("DifferentialEquation.jl")
44+
include("Variables.jl")
4445
include("HarmonicVariable.jl")
4546
include("HarmonicEquation.jl")
4647
include("abstracttypes.jl")

src/Variables.jl

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"The derivative of f w.r.t. x of degree deg"
2+
function d(f::Num, x::Num, deg=1)::Num
3+
return isequal(deg, 0) ? f : (Differential(x)^deg)(f)
4+
end
5+
d(funcs::Vector{Num}, x::Num, deg=1) = Num[d(f, x, deg) for f in funcs]
6+
7+
"Declare a variable in the the currently active Module namespace"
8+
function declare_variable(name::String)
9+
var_sym = Symbol(name)
10+
@eval($(var_sym) = first(Symbolics.@variables $var_sym))
11+
return eval(var_sym)
12+
end
13+
14+
declare_variable(x::Num) = declare_variable(string(x))
15+
16+
"Declare a variable that is a function of another variable in the Module namespace"
17+
function declare_variable(name::String, independent_variable::Num)
18+
# independent_variable = declare_variable(independent_variable) convert string into Num
19+
var_sym = Symbol(name)
20+
new_var = Symbolics.@variables $var_sym(independent_variable)
21+
@eval($(var_sym) = first($new_var)) # store the variable under "name" in this namespace
22+
return eval(var_sym)
23+
end
24+
25+
"Return the name of a variable (excluding independent variables)"
26+
function var_name(x::Num)::String
27+
var = Symbolics._toexpr(x)
28+
var = var isa Expr ? String(var.args[1]) : String(var)
29+
return String(replace(var, r"\\mathtt\{([^}]*)\}" => s"\1"))
30+
# ^ remove "\\mathtt{}" from the variable name coming from Symbolics
31+
# since Symbolics v6.14.1 (Symbolics#1305)
32+
end
33+
var_name(x::SymbolicUtils.Sym) = String(x.name)

test/HarmonicVariable.jl

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# test/test_HarmonicVariable.jl
2+
using Test
3+
using Symbolics
4+
using QuestBase: declare_variable, declare_variables, substitute_all, var_name, HarmonicVariable, _show_ansatz, _coordinate_transform, @eqtest, _create_harmonic_variable, get_variables_nums
5+
6+
# Setup
7+
@variables t T
8+
nat_var = declare_variable("x", t)
9+
rot_var = declare_variable("u", T)
10+
ω = declare_variable("ω")
11+
12+
@testset "Constructor" begin
13+
hv = HarmonicVariable(rot_var, "test_name", "u", ω, nat_var)
14+
@eqtest hv.symbol == rot_var
15+
@test hv.name == "test_name"
16+
@test hv.type == "u"
17+
@eqtest hv.ω == ω
18+
@eqtest hv.natural_variable == nat_var
19+
end
20+
21+
@testset "Show and Display" begin
22+
hv = HarmonicVariable(rot_var, "test_name", "u", ω, nat_var)
23+
# Test show output
24+
io = IOBuffer()
25+
show(io, hv)
26+
@test String(take!(io)) == "Harmonic variable u(T) for harmonic ω of x(t)\n"
27+
28+
# Test _show_ansatz
29+
@test contains(_show_ansatz(hv), "cos(ωt)")
30+
end
31+
32+
@testset "Coordinate Transforms" begin
33+
new_var = declare_variable("y")
34+
# Test u-type transform
35+
@eqtest _coordinate_transform(new_var, ω, t, "u") == new_var * cos(ω * t)
36+
# Test v-type transform
37+
@eqtest _coordinate_transform(new_var, ω, t, "v") == new_var * sin(ω * t)
38+
# Test a-type transform
39+
@eqtest _coordinate_transform(new_var, ω, t, "a") == new_var
40+
end
41+
42+
@testset "Create Harmonic Variable" begin
43+
rule, hvar = _create_harmonic_variable(nat_var, ω, t, "u"; new_symbol="a")
44+
a = declare_variable("a", t)
45+
@eqtest rule == a * cos(ω * t)
46+
@test hvar isa HarmonicVariable
47+
@test rule isa Num
48+
@test hvar.type == "u"
49+
@eqtest hvar.ω == ω
50+
end
51+
52+
@testset "Substitution" begin
53+
hv = HarmonicVariable(nat_var, "test_name", "u", ω, nat_var)
54+
new_var = declare_variable("z")
55+
rules = Dict(hv => new_var)
56+
57+
# Test equation substitution
58+
eq = nat_var^2 + ω
59+
result = substitute_all(eq, rules)
60+
@eqtest result == new_var^2 + ω
61+
62+
# Test variable substitution
63+
new_hv = substitute_all(hv, Dict(ω => 2))
64+
@test new_hv.ω == 2
65+
end

test/runtests.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ end
1717
include("DifferentialEquations.jl")
1818
end
1919

20+
@testset "HarmonicVariable" begin
21+
include("HarmonicVariable.jl")
22+
end
23+
2024
@testset "HarmonicEquation" begin
2125
include("HarmonicEquation.jl")
2226
end

0 commit comments

Comments
 (0)