Skip to content

Commit c63df32

Browse files
committed
rule based trigo rules
1 parent 6c2a2cb commit c63df32

1 file changed

Lines changed: 29 additions & 54 deletions

File tree

src/Symbolics/fourier.jl

Lines changed: 29 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -37,63 +37,38 @@ function _is_sin_cos(ex::BasicSymbolic)
3737
return isterm(ex) && (operation(ex) === sin || operation(ex) === cos)
3838
end
3939

40-
function _trig_mul_to_sum(a::BasicSymbolic, b::BasicSymbolic)
41-
op1, op2 = operation(a), operation(b)
42-
x = first(arguments(a))
43-
y = first(arguments(b))
44-
if op1 === cos && op2 === cos
45-
return (cos(x - y) + cos(x + y)) / 2
46-
elseif op1 === sin && op2 === sin
47-
return (cos(x - y) - cos(x + y)) / 2
48-
elseif op1 === sin && op2 === cos
49-
return (sin(x + y) + sin(x - y)) / 2
50-
elseif op1 === cos && op2 === sin
51-
return (sin(x + y) - sin(x - y)) / 2
52-
end
53-
return nothing
54-
end
40+
const _rw_trig_mul_to_sum = SymbolicUtils.Rewriters.Chain([
41+
SymbolicUtils.@rule(cos(~x) * cos(~y) => (cos(~x - ~y) + cos(~x + ~y)) / 2),
42+
SymbolicUtils.@rule(sin(~x) * sin(~y) => (cos(~x - ~y) - cos(~x + ~y)) / 2),
43+
SymbolicUtils.@rule(sin(~x) * cos(~y) => (sin(~x + ~y) + sin(~x - ~y)) / 2),
44+
SymbolicUtils.@rule(cos(~x) * sin(~y) => (sin(~x + ~y) - sin(~x - ~y)) / 2),
45+
])
46+
47+
const _rw_trig_expand = SymbolicUtils.Rewriters.Fixpoint(
48+
SymbolicUtils.Rewriters.Postwalk(
49+
SymbolicUtils.Rewriters.Chain([
50+
SymbolicUtils.@rule((cos(~x))^2 => (1 + cos(2 * ~x)) / 2),
51+
SymbolicUtils.@rule((sin(~x))^2 => (1 - cos(2 * ~x)) / 2),
52+
_rw_trig_mul_to_sum,
53+
]),
54+
),
55+
)
5556

5657
function _trig_expand_products(x::BasicSymbolic)
5758
# Expand trig products/powers into sums so `get_independent` can isolate constants.
58-
y = Postwalk(
59-
ex -> begin
60-
if ispow(ex)
61-
base, exponent = arguments(ex)
62-
exp_val = SymbolicUtils.unwrap_const(exponent)
63-
if exp_val isa Integer && exp_val == 2 && _is_sin_cos(base)
64-
arg = first(arguments(base))
65-
if operation(base) === cos
66-
return (1 + cos(2 * arg)) / 2
67-
else
68-
return (1 - cos(2 * arg)) / 2
69-
end
70-
end
71-
elseif ismul(ex)
72-
# In SymbolicUtils v4, `arguments(ismul(...))` includes the numeric coefficient
73-
# even though `ex.coeff` also stores it. Avoid double-counting it.
74-
factors = BasicSymbolic[
75-
f for f in arguments(ex) if !(SymbolicUtils.unwrap_const(f) isa Number)
76-
]
77-
trig_idx = findall(_is_sin_cos, factors)
78-
if length(trig_idx) >= 2
79-
i, j = trig_idx[1], trig_idx[2]
80-
repl = _trig_mul_to_sum(factors[i], factors[j])
81-
if repl !== nothing
82-
others = BasicSymbolic[]
83-
for (k, f) in pairs(factors)
84-
(k == i || k == j) && continue
85-
push!(others, f)
86-
end
87-
coeff = ex.coeff
88-
return coeff * prod(others; init=1) * repl
89-
end
90-
end
91-
end
92-
return ex
93-
end,
94-
)(
95-
x
96-
)
59+
y = Postwalk(ex -> begin
60+
if ismul(ex)
61+
# In SymbolicUtils v4, `arguments(ismul(...))` includes the numeric coefficient
62+
# even though `ex.coeff` also stores it. Avoid double-counting it.
63+
coeff = ex.coeff
64+
factors = BasicSymbolic[
65+
f for f in arguments(ex) if !(SymbolicUtils.unwrap_const(f) isa Number)
66+
]
67+
rest = isempty(factors) ? 1 : prod(factors; init=1)
68+
return coeff * _rw_trig_expand(rest)
69+
end
70+
return _rw_trig_expand(ex)
71+
end)(x)
9772
return SymbolicUtils.expand(y)
9873
end
9974
_trig_expand_products(x::Num) = wrap(_trig_expand_products(unwrap(x)))

0 commit comments

Comments
 (0)