diff --git a/pkg/JuliaInterface/gap/convert.gd b/pkg/JuliaInterface/gap/convert.gd index 65e0e3df..aab9d196 100644 --- a/pkg/JuliaInterface/gap/convert.gd +++ b/pkg/JuliaInterface/gap/convert.gd @@ -205,24 +205,24 @@ #! UInt64, #! UInt128, #! BigInt, -#! Rational{T} where T <: Integer, +#! or Rational{T} where T <: Integer, #! #! #! GapObj and IsInt to #! BigInt (default), -#! Rational{T} where T <: Integer, +#! or Rational{T} where T <: Integer, #! #! #! GapObj and IsRat to #! Rational{BigInt} (default), -#! Rational{T} where T <: Integer, +#! or Rational{T} where T <: Integer, #! #! #! IsFloat to #! Float16, #! Float32, #! Float64 (default), -#! BigFloat, +#! or BigFloat, #! #! #! IsChar to @@ -254,12 +254,12 @@ #! Vector{Union{Any,Nothing}} (default), #! Vector{T}, #! Matrix{T}, -#! T <: Tuple, +#! or T <: Tuple, #! #! #! IsRecord to -#! Dict{Symbol,Any} (default), -#! Dict{Symbol,T}. +#! Dict{Symbol,Any} (default) +#! or Dict{Symbol,T}. #! #! #! @@ -271,16 +271,33 @@ #! #! Conversion from &Julia; to &GAP; #! -#! The function -#! is a &GAP; constructor taking two arguments, -#! a &GAP; filter and an object to be converted. +#! There are two alternatives for this direction, +#! the Julia constructor +#! and the &GAP; constructor +#! . +#! +#! is a &Julia; function +#! that takes one or two arguments, +#! the object to be converted and optionally the value true +#! indicating recursive conversion of nested objects. +#! The chosen method depends on the &Julia; type of the first argument. +#! +#! The function . +#! takes two or three arguments, +#! a &GAP; filter and an object to be converted, +#! and optionally the value true indicating recursive conversion +#! of nested objects. #! Various methods for this constructor then take care of input validation #! and the actual conversion, either by delegating to the &Julia; function #! julia_to_gap -#! (which takes just one argument and chooses the &GAP; filters of its -#! result depending on the &Julia; type), +#! (which takes just one or two arguments and chooses the &GAP; filters of +#! its result depending on the &Julia; type), #! or by automatic conversion. -#! The supported &Julia; types are as follows. +#! +#! The supported &Julia; types of the second argument of +#! +#! are as follows; +#! more &Julia; types may be supported for . #! #! #! @@ -350,6 +367,46 @@ #! @Section Conversion functions #! @SectionLabel Conversion_functions +#! +#! +#! +#! +#! a &GAP; object +#! +#! The &Julia; constructor takes an object +#! juliaobj and chooses a method depending on its &Julia; type +#! for computing a &GAP; object corresponding to juliaobj. +#! If recursive is true then nested objects are converted +#! recursively. +#!

+#! +#! +#!gap> Julia.GAP.Obj( 42 ); +#!42 +#!gap> m:= GAPToJulia( [ [ 1, 2 ], [ 3, 4 ] ] ); +#!<Julia: Any[Any[1, 2], Any[3, 4]]> +#!gap> Julia.GAP.Obj( m ); +#![ <Julia: Any[1, 2]>, <Julia: Any[3, 4]> ] +#!gap> Julia.GAP.Obj( m, true ); +#![ [ 1, 2 ], [ 3, 4 ] ] +#! +#!

+#! One advantage of compared to the &GAP; +#! constructor is +#! that it is easy to extend the scope of +#! on the &Julia; side, whereas extending +#! +#! would require changing its methods. +#! For example, the Oscar system provides &Julia; types +#! of matrices for which conversions to &GAP; matrices are installed, +#! via suitable methods for . +#!

+#! If one is sure that the result of the conversion to &GAP; is not an +#! immediate &GAP; object then one can call +#! instead of . +#! +#! #! @Arguments filt, juliaobj[, recursive] #! @Returns a &GAP; object in the filter filt @@ -361,6 +418,17 @@ #! Then #! returns this &GAP; object. #! +#! @BeginExampleSession +#! gap> s:= GAPToJulia( "abc" ); +#! +#! gap> JuliaToGAP( IsString, s ); +#! "abc" +#! gap> l:= GAPToJulia( [ 1, 2, 4 ] ); +#! +#! gap> JuliaToGAP( IsList, l ); +#! [ 1, 2, 4 ] +#! @EndExampleSession +#! #! For recursive structures (&GAP; lists and records), #! only the outermost level is converted except if the optional argument #! recursive is given and has the value true, @@ -375,14 +443,12 @@ #! something useful on the &GAP; side. #! #! @BeginExampleSession -#! gap> s:= GAPToJulia( "abc" ); -#! -#! gap> JuliaToGAP( IsString, s ); -#! "abc" -#! gap> l:= GAPToJulia( [ 1, 2, 4 ] ); -#! -#! gap> JuliaToGAP( IsList, l ); -#! [ 1, 2, 4 ] +#! gap> m:= GAPToJulia( [ [ 1, 2 ], [ 3, 4 ] ] ); +#! +#! gap> JuliaToGAP( IsList, m ); +#! [ , ] +#! gap> JuliaToGAP( IsList, m, true ); +#! [ [ 1, 2 ], [ 3, 4 ] ] #! @EndExampleSession #! #! The following values for filt are supported. diff --git a/pkg/JuliaInterface/tst/convert.tst b/pkg/JuliaInterface/tst/convert.tst index 2400cc73..0d5b9a00 100644 --- a/pkg/JuliaInterface/tst/convert.tst +++ b/pkg/JuliaInterface/tst/convert.tst @@ -14,6 +14,8 @@ gap> typeof(x); gap> JuliaToGAP(IsInt, x); 123 +gap> Julia.GAP.Obj(x); +123 # gap> x := JuliaEvalString("Int64(123)");; @@ -21,6 +23,8 @@ gap> typeof(x); gap> JuliaToGAP(IsInt, x); 123 +gap> Julia.GAP.Obj(x); +123 # gap> x := JuliaEvalString("Int32(123)");; @@ -28,6 +32,8 @@ gap> typeof(x); gap> JuliaToGAP(IsInt, x); 123 +gap> Julia.GAP.Obj(x); +123 # gap> x := JuliaEvalString("Int16(123)");; @@ -35,6 +41,8 @@ gap> typeof(x); gap> JuliaToGAP(IsInt, x); 123 +gap> Julia.GAP.Obj(x); +123 # gap> x := JuliaEvalString("Int8(123)");; @@ -42,6 +50,8 @@ gap> typeof(x); gap> JuliaToGAP(IsInt, x); 123 +gap> Julia.GAP.Obj(x); +123 # gap> x := JuliaEvalString("UInt128(123)");; @@ -49,6 +59,8 @@ gap> typeof(x); gap> JuliaToGAP(IsInt, x); 123 +gap> Julia.GAP.Obj(x); +123 # gap> x := JuliaEvalString("UInt64(123)");; @@ -56,6 +68,8 @@ gap> typeof(x); gap> JuliaToGAP(IsInt, x); 123 +gap> Julia.GAP.Obj(x); +123 # gap> x := JuliaEvalString("UInt32(123)");; @@ -63,6 +77,8 @@ gap> typeof(x); gap> JuliaToGAP(IsInt, x); 123 +gap> Julia.GAP.Obj(x); +123 # gap> x := JuliaEvalString("UInt16(123)");; @@ -70,6 +86,8 @@ gap> typeof(x); gap> JuliaToGAP(IsInt, x); 123 +gap> Julia.GAP.Obj(x); +123 # gap> x := JuliaEvalString("UInt8(123)");; @@ -77,12 +95,16 @@ gap> typeof(x); gap> JuliaToGAP(IsInt, x); 123 +gap> Julia.GAP.Obj(x); +123 # gap> int := GAPToJulia( Julia.Base.Int64, 11 ); 11 gap> JuliaToGAP(IsInt, int ); 11 +gap> Julia.GAP.Obj( int ); +11 # gap> x := JuliaEvalString("BigInt(123)");; @@ -90,6 +112,8 @@ gap> typeof(x); gap> JuliaToGAP(IsInt, x); 123 +gap> Julia.GAP.Obj(x); +123 ### ### Floats @@ -101,6 +125,8 @@ gap> typeof(x); gap> JuliaToGAP(IsFloat, x); 1. +gap> Julia.GAP.Obj(x); +1. # gap> x := JuliaEvalString("Float32(1.0)");; @@ -108,6 +134,8 @@ gap> typeof(x); gap> JuliaToGAP(IsFloat, x); 1. +gap> Julia.GAP.Obj(x); +1. # gap> x := JuliaEvalString("Float16(1.0)");; @@ -115,6 +143,8 @@ gap> typeof(x); gap> JuliaToGAP(IsFloat, x); 1. +gap> Julia.GAP.Obj(x); +1. ### ### @@ -127,16 +157,24 @@ gap> Zero(big2); gap> JuliaToGAP( IsInt, Zero(big2) ); 0 +gap> Julia.GAP.Obj( Zero(big2) ); +0 gap> ForAll([0..64], n -> JuliaToGAP( IsInt, big2^n) = 2^n); true +gap> ForAll([0..64], n -> Julia.GAP.Obj( big2^n ) = 2^n); +true gap> ForAll([0..64], n -> JuliaToGAP( IsInt, -big2^n) = -2^n); true +gap> ForAll([0..64], n -> Julia.GAP.Obj( -big2^n ) = -2^n); +true # gap> string := GAPToJulia( Julia.Base.AbstractString, "bla" ); gap> JuliaToGAP( IsString, string ); "bla" +gap> Julia.GAP.Obj( string ); +"bla" gap> GAPToJulia( true ); true gap> GAPToJulia( false ); @@ -147,6 +185,8 @@ gap> list:= GAPToJulia( [ 1, 2, 3 ] ); gap> JuliaToGAP( IsList, list ); [ 1, 2, 3 ] +gap> Julia.GAP.Obj( list ); +[ 1, 2, 3 ] ## ranges gap> Julia.GAP.julia_to_gap( JuliaEvalString( "1:3" ) ); @@ -155,6 +195,12 @@ gap> Julia.GAP.julia_to_gap( JuliaEvalString( "1:2:5" ) ); [ 1, 3 .. 5 ] gap> Julia.GAP.julia_to_gap( JuliaEvalString( "3:2" ) ); [ ] +gap> Julia.GAP.Obj( JuliaEvalString( "1:3" ) ); +[ 1 .. 3 ] +gap> Julia.GAP.Obj( JuliaEvalString( "1:2:5" ) ); +[ 1, 3 .. 5 ] +gap> Julia.GAP.Obj( JuliaEvalString( "3:2" ) ); +[ ] gap> JuliaToGAP( IsList, JuliaEvalString( "1:3" ) ); [ 1 .. 3 ] gap> JuliaToGAP( IsList, JuliaEvalString( "1:2:5" ) ); @@ -179,8 +225,12 @@ gap> emptystring:= GAPToJulia( Julia.Base.AbstractString, "" ); gap> JuliaToGAP( IsList, emptylist ); [ ] +gap> Julia.GAP.Obj( emptylist ); +[ ] gap> JuliaToGAP( IsString, emptystring ); "" +gap> Julia.GAP.Obj( emptystring ); +"" ## 'GAPToJulia' for Julia functions (inside arrays) gap> parse:= JuliaFunction( "parse", "Base" ); @@ -189,11 +239,15 @@ gap> list:= GAPToJulia( JuliaEvalString( "Vector{Any}"), [ 1, parse, 3 ] ); gap> list2:= JuliaToGAP( IsList, list ); [ 1, , 3 ] +gap> Julia.GAP.Obj( list ); +[ 1, , 3 ] ## gap> xx := JuliaEvalString("GAP.Globals.PROD(2^59,2^59)");; gap> JuliaToGAP( IsInt, xx ); 332306998946228968225951765070086144 +gap> Julia.GAP.Obj( xx ); +332306998946228968225951765070086144 ### ### Records/Dictionaries @@ -204,6 +258,8 @@ gap> dict:= GAPToJulia( rec() ); gap> JuliaToGAP( IsRecord, dict ); rec( ) +gap> Julia.GAP.Obj( dict ); +rec( ) ## nested record: non-recursive vs. recursive gap> dict:= GAPToJulia( rec( bool:= true, @@ -212,8 +268,12 @@ gap> dict:= GAPToJulia( rec( bool:= true, > ) );; gap> JuliaToGAP( IsRecord, dict ); rec( bool := true, list := , string := ) +gap> Julia.GAP.Obj( dict ); +rec( bool := true, list := , string := ) gap> JuliaToGAP( IsRecord, dict, true ); rec( bool := true, list := [ 1, 2, 3 ], string := "abc" ) +gap> Julia.GAP.Obj( dict, true ); +rec( bool := true, list := [ 1, 2, 3 ], string := "abc" ) ## something where recursive conversion would run into a Julia error gap> dict:= GAPToJulia( rec( juliafunc:= Julia.Base.map, @@ -221,6 +281,8 @@ gap> dict:= GAPToJulia( rec( juliafunc:= Julia.Base.map, map)> gap> JuliaToGAP( IsRecord, dict ); rec( juliafunc := ) +gap> Julia.GAP.Obj( dict ); +rec( juliafunc := ) # iterating over dict gives key-value pairs gap> dict:= GAPToJulia( rec( a := 1, b := 2 ) ); @@ -230,4 +292,4 @@ Pair{Symbol, Any}(:a, 1) Pair{Symbol, Any}(:b, 2) ## -gap> STOP_TEST( "convert.tst", 1 ); +gap> STOP_TEST( "convert.tst" ); diff --git a/src/types.jl b/src/types.jl index 0213aa22..6a06d37b 100644 --- a/src/types.jl +++ b/src/types.jl @@ -91,8 +91,9 @@ However, this is restricted to outputs that actually are of type `GapObj`. To also deal with GAP integers, finite field elements and booleans, use [`GAP.Obj`](@ref) instead. -The keyword argument `recursive` with value `true` can be used to force -recursive conversion of nested Julia objects (arrays, tuples, dictionaries). +Recursive conversion of nested Julia objects (arrays, tuples, dictionaries) +can be forced either by a second agument `true` +or by the keyword argument `recursive` with value `true`. # Examples ```jldoctest @@ -105,6 +106,9 @@ GAP: [ [ 1, 2 ], [ 3, 4 ] ] julia> GapObj([[1, 2], [3, 4]]) GAP: [ , ] +julia> GapObj([[1, 2], [3, 4]], true) +GAP: [ [ 1, 2 ], [ 3, 4 ] ] + julia> GapObj([[1, 2], [3, 4]], recursive=true) GAP: [ [ 1, 2 ], [ 3, 4 ] ] @@ -124,8 +128,9 @@ Moreover, it can be used as a constructor, in order to convert Julia objects to GAP objects, whenever a suitable conversion has been defined. -The keyword argument `recursive` with value `true` can be used to force -recursive conversion of nested Julia objects (arrays, tuples, dictionaries). +Recursive conversion of nested Julia objects (arrays, tuples, dictionaries) +can be forced either by a second agument `true` +or by the keyword argument `recursive` with value `true`. # Examples ```jldoctest @@ -138,12 +143,14 @@ GAP: [ [ 1, 2 ], [ 3, 4 ] ] julia> GAP.Obj([[1, 2], [3, 4]]) GAP: [ , ] +julia> GAP.Obj([[1, 2], [3, 4]], true) +GAP: [ [ 1, 2 ], [ 3, 4 ] ] + julia> GAP.Obj([[1, 2], [3, 4]], recursive=true) GAP: [ [ 1, 2 ], [ 3, 4 ] ] julia> GAP.Obj(42) 42 - ``` """ const Obj = Union{GapObj,FFE,Int64,Bool} diff --git a/test/constructors.jl b/test/constructors.jl index ff376c3f..c442d19e 100644 --- a/test/constructors.jl +++ b/test/constructors.jl @@ -1,6 +1,6 @@ @testset "conversion from GAP using constructors" begin - ## Analogous tests for conversion using convert are in convert.jl. + ## Analogous tests for conversion using convert are in conversion.jl. @testset "Conversion to GAP.Obj and GAP.GapObj" begin x = GAP.evalstr("2^100") @@ -9,6 +9,19 @@ x = GAP.evalstr("Z(3)") @test GAP.Obj(x) == x @test GAP.Obj(0) == 0 + + # recursive conversion of nested objects + m = [[1, 2], [3, 4]] + c = GAP.Obj(m) + @test c[1] isa Vector + @test c == GAP.Obj(m, false) + c = GAP.Obj(m, true) + @test c[1] isa GAP.Obj + c = GAP.GapObj(m) + @test c[1] isa Vector + @test c == GAP.GapObj(m, false) + c = GAP.GapObj(m, true) + @test c[1] isa GAP.GapObj end @testset "Border cases" begin