Skip to content

Commit 7cb8000

Browse files
authored
Merge pull request #2 from s-celles/063-fix-symbolics-power
fix: handle symbolic literal numbers in to_giac for Symbolics v7
2 parents 78cc1a9 + 64b09e2 commit 7cb8000

4 files changed

Lines changed: 112 additions & 4 deletions

File tree

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "Giac"
22
uuid = "e4421f97-9838-4fd0-9fa5-94f11373bf78"
3-
version = "0.11.0"
3+
version = "0.11.1"
44
authors = ["Sébastien Celles <s.celles@gmail.com>"]
55

66
[deps]

docs/src/extensions/symbolics.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,23 @@ poly = x^2 + 2*x + 1
176176
giac_poly = to_giac(poly)
177177
# Result: "1+x^2+2*x"
178178

179+
# Power expressions work correctly
180+
squared = to_giac(x^2)
181+
# Result: "x^2"
182+
183+
cubed = to_giac(x^3)
184+
# Result: "x^3"
185+
186+
sum_of_squares = to_giac(x^2 + y^2)
187+
# Result: "x^2+y^2"
188+
189+
# Compound expressions with powers
190+
compound = to_giac(sin(x)^2)
191+
# Result: "sin(x)^2"
192+
193+
product = to_giac(x^2 * y)
194+
# Result: "x^2*y"
195+
179196
# Mathematical functions are mapped correctly
180197
expr = sin(x) + cos(y)
181198
giac_expr = to_giac(expr)

ext/GiacSymbolicsExt.jl

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ module GiacSymbolicsExt
77
using Giac
88
using Symbolics
99
using CxxWrap: StdVector
10-
import Symbolics.SymbolicUtils: Sym, symtype, issym, iscall, operation, arguments
10+
import Symbolics.SymbolicUtils: Sym, symtype, issym, iscall, operation, arguments, is_literal_number, unwrap_const
1111

1212
# ============================================================================
1313
# GIAC to Julia Name Mapping
@@ -184,6 +184,11 @@ function _convert_to_gen(expr)
184184
return Giac.GiacCxxBindings.make_complex(re_gen, im_gen)
185185
end
186186

187+
# Handle symbolic literal numbers (e.g., integer exponents in Symbolics v7)
188+
if is_literal_number(unwrapped)
189+
return _convert_to_gen(unwrap_const(unwrapped))
190+
end
191+
187192
# Handle symbolic variables (identifiers)
188193
if issym(unwrapped)
189194
name = String(Symbolics.tosymbol(unwrapped))
@@ -207,9 +212,9 @@ function _convert_to_gen(expr)
207212
end
208213

209214
# Handle special constants
210-
if unwrapped === π || unwrapped == Base.MathConstants.pi
215+
if unwrapped === π || unwrapped === Base.MathConstants.pi
211216
return Giac.GiacCxxBindings.make_identifier("pi")
212-
elseif unwrapped ===|| unwrapped == Base.MathConstants.e
217+
elseif unwrapped ===|| unwrapped === Base.MathConstants.e
213218
return Giac.GiacCxxBindings.make_identifier("e")
214219
elseif unwrapped === im
215220
return Giac.GiacCxxBindings.make_identifier("i")

test/test_symbolics_ext.jl

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,4 +341,90 @@ using Symbolics.SymbolicUtils: Term
341341
end
342342
end
343343

344+
# ============================================================================
345+
# Feature 063: Fix TypeError when converting power expressions (issue #1)
346+
# ============================================================================
347+
@testset "Feature 063: to_giac power expressions" begin
348+
@variables a x y
349+
350+
# US1: Basic power expressions
351+
@testset "US1: to_giac(a^2) — issue #1 reproducer" begin
352+
result = to_giac(a^2)
353+
@test result isa GiacExpr
354+
@test occursin("a", string(result))
355+
@test occursin("^", string(result)) || occursin("2", string(result))
356+
end
357+
358+
@testset "US1: to_giac(x^3) — other integer exponents" begin
359+
result = to_giac(x^3)
360+
@test result isa GiacExpr
361+
@test occursin("x", string(result))
362+
end
363+
364+
@testset "US1: to_giac(x^2 + y^2) — sum of squares" begin
365+
result = to_giac(x^2 + y^2)
366+
@test result isa GiacExpr
367+
result_str = string(result)
368+
@test occursin("x", result_str)
369+
@test occursin("y", result_str)
370+
end
371+
372+
# US2: Compound expressions
373+
@testset "US2: to_giac(sin(x)^2) — function with power" begin
374+
result = to_giac(sin(x)^2)
375+
@test result isa GiacExpr
376+
result_str = string(result)
377+
@test occursin("sin", result_str)
378+
end
379+
380+
@testset "US2: to_giac(x^2 * y) — power with multiplication" begin
381+
result = to_giac(x^2 * y)
382+
@test result isa GiacExpr
383+
result_str = string(result)
384+
@test occursin("x", result_str)
385+
@test occursin("y", result_str)
386+
end
387+
388+
@testset "US2: to_giac((x + y)^2) — power of sum" begin
389+
result = to_giac((x + y)^2)
390+
@test result isa GiacExpr
391+
result_str = string(result)
392+
@test occursin("x", result_str)
393+
@test occursin("y", result_str)
394+
end
395+
396+
# US2: Edge cases
397+
@testset "US2: edge cases — a^0, a^(-1), a^b" begin
398+
@variables b
399+
400+
result_zero = to_giac(a^0)
401+
@test result_zero isa GiacExpr
402+
403+
result_neg = to_giac(a^(-1))
404+
@test result_neg isa GiacExpr
405+
406+
result_sym = to_giac(a^b)
407+
@test result_sym isa GiacExpr
408+
result_str = string(result_sym)
409+
@test occursin("a", result_str)
410+
@test occursin("b", result_str)
411+
end
412+
413+
# US3: Roundtrip conversion
414+
@testset "US3: roundtrip to_symbolics(to_giac(a^2))" begin
415+
original = a^2
416+
roundtrip = to_symbolics(to_giac(original))
417+
@test roundtrip isa Num
418+
# Verify mathematical equivalence by substituting a value
419+
@test Symbolics.substitute(roundtrip, Dict(a => 3)) == Symbolics.substitute(original, Dict(a => 3))
420+
end
421+
422+
@testset "US3: roundtrip to_symbolics(to_giac(x^2 + y))" begin
423+
original = x^2 + y
424+
roundtrip = to_symbolics(to_giac(original))
425+
@test roundtrip isa Num
426+
@test Symbolics.substitute(roundtrip, Dict(x => 2, y => 5)) == Symbolics.substitute(original, Dict(x => 2, y => 5))
427+
end
428+
end
429+
344430
end # @testset "Symbolics Extension"

0 commit comments

Comments
 (0)