From 84080a99191534b506edd312892c53e8be8e5fd8 Mon Sep 17 00:00:00 2001 From: Martin Bies Date: Fri, 20 Sep 2024 23:32:46 +0200 Subject: [PATCH 1/2] Add daily tests (cf. https://github.com/oscar-system/Oscar.jl/issues/4072) (#1048) --- .github/workflows/CI.yml | 3 +++ .github/workflows/oscar.yml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index cd329ed91..76a2ec148 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -7,6 +7,9 @@ on: - 'release-*' tags: '*' pull_request: + schedule: + # Every day at 3:08 AM UTC + - cron: '8 3 * * *' concurrency: # group by workflow and ref; the last slightly strange component ensures that for pull diff --git a/.github/workflows/oscar.yml b/.github/workflows/oscar.yml index f21b45dba..f7c867149 100644 --- a/.github/workflows/oscar.yml +++ b/.github/workflows/oscar.yml @@ -7,6 +7,9 @@ on: push: branches: - master + schedule: + # Every day at 3:08 AM UTC (Tutorial tests initiated at 2:00AM) + - cron: '8 3 * * *' workflow_dispatch: concurrency: From e60382dfc1236648125bdfcd7f73d4948ca32872 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 20 Sep 2024 23:43:47 +0200 Subject: [PATCH 2/2] Remove JuliaFunction and a bunch of C code (#1047) --- .../ipynb/GAPJulia_Singular_car.ipynb | 2 +- pkg/JuliaExperimental/tst/singular_blog.tst | 2 +- .../example/function_perform.gi | 23 ++---- .../example/function_perform.jl | 22 +----- pkg/JuliaInterface/example/orbits.gi | 4 +- pkg/JuliaInterface/gap/JuliaInterface.gd | 46 +----------- pkg/JuliaInterface/gap/JuliaInterface.gi | 36 ++++------ pkg/JuliaInterface/src/JuliaInterface.c | 72 ++----------------- pkg/JuliaInterface/tst/calls.tst | 52 +++----------- pkg/JuliaInterface/tst/convert.tst | 2 +- pkg/JuliaInterface/tst/utils.tst | 8 --- 11 files changed, 39 insertions(+), 230 deletions(-) diff --git a/pkg/JuliaExperimental/ipynb/GAPJulia_Singular_car.ipynb b/pkg/JuliaExperimental/ipynb/GAPJulia_Singular_car.ipynb index 1690e9f13..d7a0bce79 100644 --- a/pkg/JuliaExperimental/ipynb/GAPJulia_Singular_car.ipynb +++ b/pkg/JuliaExperimental/ipynb/GAPJulia_Singular_car.ipynb @@ -192,7 +192,7 @@ } ], "source": [ - "i:= JuliaFunction( \"Matrix\", \"Singular\" )( I );" + "i:= Julia.Singular.Matrix( I );" ] }, { diff --git a/pkg/JuliaExperimental/tst/singular_blog.tst b/pkg/JuliaExperimental/tst/singular_blog.tst index c82c4533f..e209905ff 100644 --- a/pkg/JuliaExperimental/tst/singular_blog.tst +++ b/pkg/JuliaExperimental/tst/singular_blog.tst @@ -73,7 +73,7 @@ gap> M:= Julia.Singular.syz( I ); x*gen(3)-2*x*gen(2)+y*gen(3)-y*gen(2)-z*gen(2) y^2*gen(3)-y^2*gen(2)-y*z*gen(2)-y*gen(1)+z*gen(1)-gen(3)+2*gen(2) x*y*gen(2)-x*gen(1)-y*gen(1)+gen(2)> -gap> JuliaFunction( "Matrix", "Singular" )( M ); +gap> Julia.Singular.Matrix( M ); diff --git a/pkg/JuliaInterface/example/function_perform.gi b/pkg/JuliaInterface/example/function_perform.gi index 3f31903e7..99d91684e 100644 --- a/pkg/JuliaInterface/example/function_perform.gi +++ b/pkg/JuliaInterface/example/function_perform.gi @@ -4,32 +4,17 @@ dirs:= DirectoriesPackageLibrary( "JuliaInterface", "example" ); JuliaIncludeFile( Filename( dirs, "function_perform.jl" ) ); -typed_func := JuliaFunction("typed_func", "GapFunctionPerform"); -typed_funcNoConv := _JuliaFunctionByModule("typed_func", "GapFunctionPerform"); - -untyped_func := JuliaFunction("untyped_func"); -untyped_funcNoConv := _JuliaFunction("untyped_func"); +return_first := Julia.GapFunctionPerform.return_first; GASMAN("collect"); ListX([1..10^5], [1..10], {i,j} -> i);; time; GASMAN("collect"); ListX([1..10^5], [1..10], ReturnFirst);; time; -GASMAN("collect"); ListX([1..10^5], [1..10], typed_func);; time; -GASMAN("collect"); ListX([1..10^5], [1..10], untyped_func);; time; -GASMAN("collect"); ListX([1..10^5], [1..10], typed_funcNoConv);; time; -GASMAN("collect"); ListX([1..10^5], [1..10], untyped_funcNoConv);; time; - +GASMAN("collect"); ListX([1..10^5], [1..10], return_first);; time; GASMAN("collect"); ListX("0123456789", [1..10^5], {i,j} -> i);; time; GASMAN("collect"); ListX("0123456789", [1..10^5], ReturnFirst);; time; -GASMAN("collect"); ListX("0123456789", [1..10^5], typed_func);; time; -GASMAN("collect"); ListX("0123456789", [1..10^5], untyped_func);; time; -GASMAN("collect"); ListX("0123456789", [1..10^5], typed_funcNoConv);; time; -GASMAN("collect"); ListX("0123456789", [1..10^5], untyped_funcNoConv);; time; - +GASMAN("collect"); ListX("0123456789", [1..10^5], return_first);; time; input:=ListWithIdenticalEntries(10^5,fail);; GASMAN("collect"); ListX("0123456789", input, {i,j} -> i);; time; GASMAN("collect"); ListX("0123456789", input, ReturnFirst);; time; -GASMAN("collect"); ListX("0123456789", input, typed_func);; time; -GASMAN("collect"); ListX("0123456789", input, untyped_func);; time; -GASMAN("collect"); ListX("0123456789", input, typed_funcNoConv);; time; -GASMAN("collect"); ListX("0123456789", input, untyped_funcNoConv);; time; \ No newline at end of file +GASMAN("collect"); ListX("0123456789", input, return_first);; time; diff --git a/pkg/JuliaInterface/example/function_perform.jl b/pkg/JuliaInterface/example/function_perform.jl index 1077c54e5..6a7357caf 100644 --- a/pkg/JuliaInterface/example/function_perform.jl +++ b/pkg/JuliaInterface/example/function_perform.jl @@ -1,25 +1,7 @@ module GapFunctionPerform -import GAP: GapObj - -function typed_func(a::GapObj, b::GapObj) - return a -end - -function typed_func(a::GapObj, b::Int64) - return a -end - -function typed_func(a::Int64, b::GapObj) +function return_first(a, b) return a end -function typed_func(a::Int64, b::Int64) - return a -end - -end - -function untyped_func(a, b) - return a -end +end \ No newline at end of file diff --git a/pkg/JuliaInterface/example/orbits.gi b/pkg/JuliaInterface/example/orbits.gi index a18941788..035a6e200 100644 --- a/pkg/JuliaInterface/example/orbits.gi +++ b/pkg/JuliaInterface/example/orbits.gi @@ -20,10 +20,8 @@ end; example_dirs := DirectoriesPackageLibrary( "JuliaInterface", "example" ); JuliaIncludeFile( Filename( example_dirs, "orbits.jl" ) ); -bahn_jl := JuliaFunction( "bahn" ); - grp := SymmetricGroup( 10000 ); gens := GeneratorsOfGroup( grp );; bahn(1, gens, OnPoints);;time; -bahn_jl(1, gens, OnPoints);;time; +Julia.bahn(1, gens, OnPoints);;time; diff --git a/pkg/JuliaInterface/gap/JuliaInterface.gd b/pkg/JuliaInterface/gap/JuliaInterface.gd index c6f3c8c5f..517bfa206 100644 --- a/pkg/JuliaInterface/gap/JuliaInterface.gd +++ b/pkg/JuliaInterface/gap/JuliaInterface.gd @@ -180,8 +180,6 @@ DeclareAttribute( "JuliaPointer", IsJuliaWrapper ); #! true #! gap> Julia.GAP.julia_to_gap; #! -#! gap> JuliaFunction( "julia_to_gap", "GAP" ); # the same function -#! #! @EndExampleSession DeclareCategory( "IsJuliaModule", IsJuliaWrapper and IsRecord ); @@ -246,47 +244,6 @@ DeclareGlobalFunction( "JuliaImportPackage" ); #! @Section Access to &Julia; objects -#! @Arguments function_name[, module_name] -#! @Returns a function -#! @Description -#! Returns a &GAP; function that wraps the &Julia; function with identifier -#! function_name from the module module_name. -#! Both arguments must be strings. -#! If module_name is not given, -#! the function is taken from &Julia;'s Main module. -#! -#! @BeginExampleSession -#! gap> fun:= JuliaFunction( "sqrt" ); -#! -#! gap> Print( fun ); -#! function ( arg... ) -#! <> from Julia:sqrt -#! end -#! gap> IsFunction( fun ); -#! true -#! gap> IsJuliaObject( fun ); -#! false -#! @EndExampleSession -#! -#! Alternatively, one can access &Julia; functions also via the global object -#! , as follows. -#! -#! @BeginExampleSession -#! gap> Julia.sqrt; -#! -#! @EndExampleSession -#! -#! Note that each call to and each component -#! access to create a new &GAP; object. -#! -#! @BeginExampleSession -#! gap> IsIdenticalObj( JuliaFunction( "sqrt" ), JuliaFunction( "sqrt" ) ); -#! false -#! gap> IsIdenticalObj( Julia.sqrt, Julia.sqrt ); -#! false -#! @EndExampleSession -DeclareGlobalFunction( "JuliaFunction" ); - #! @Description #! This global variable represents the &Julia; module Main, #! see . @@ -411,8 +368,7 @@ DeclareGlobalFunction( "CallJuliaFunctionWithKeywordArguments" ); #! #! @EndExampleSession #! In fact, there are slightly different kinds of function calls. -#! A &Julia; function such as Julia.sqrt -#! (or equivalently JuliaFunction( "sqrt" )) is represented by +#! A &Julia; function such as Julia.sqrt is represented by #! a &GAP; function object, #! and calls to it are executed on the C level, #! using &Julia;'s jl_call. diff --git a/pkg/JuliaInterface/gap/JuliaInterface.gi b/pkg/JuliaInterface/gap/JuliaInterface.gi index f1315ec3e..d28a5f3c2 100644 --- a/pkg/JuliaInterface/gap/JuliaInterface.gi +++ b/pkg/JuliaInterface/gap/JuliaInterface.gi @@ -4,19 +4,9 @@ # Implementations # -InstallGlobalFunction( JuliaFunction, - function( arglist... ) - if Length( arglist ) = 1 and IsString( arglist[ 1 ] ) then - return _JuliaFunction( arglist[ 1 ] ); - elif Length( arglist ) = 2 and ForAll( arglist, IsString ) then - return _JuliaFunctionByModule( arglist[1], arglist[2] ); - fi; - Error( "arguments must be strings function_name[,module_name]" ); -end ); - -BindGlobal( "_JULIA_MODULE_TYPE", _JuliaGetGlobalVariable( "Module" ) ); -BindGlobal( "_JULIA_FUNCTION_TYPE", _JuliaGetGlobalVariable( "Function" ) ); -BindGlobal( "_JULIA_ISA", JuliaFunction( "isa" ) ); +BindGlobal( "_JULIA_MODULE_TYPE", _JuliaGetGlobalVariableByModule( "Module", "Core" ) ); +BindGlobal( "_JULIA_FUNCTION_TYPE", _JuliaGetGlobalVariableByModule( "Function", "Core" ) ); +BindGlobal( "_JULIA_ISA", _WrapJuliaFunction( _JuliaGetGlobalVariableByModule( "isa", "Core" ) ) ); BindGlobal( "_WrapJuliaModule", function( name, julia_pointer ) @@ -44,7 +34,7 @@ InstallMethod( ViewString, InstallMethod( \., [ "IsJuliaModule", "IsPosInt" ], function( module, rnum ) - local rnam, global_variable; + local rnam, var; if IsBound\.( module!.storage, rnum ) then return \.(module!.storage, rnum ); @@ -52,19 +42,19 @@ InstallMethod( \., rnam := NameRNam( rnum ); - global_variable := _JuliaGetGlobalVariableByModule( rnam, JuliaPointer( module ) ); - if global_variable = fail then + var := _JuliaGetGlobalVariableByModule( rnam, JuliaPointer( module ) ); + if var = fail then Error( rnam, " is not bound in Julia" ); fi; - if _JULIA_ISA( global_variable, _JULIA_FUNCTION_TYPE ) then - global_variable := _JuliaFunction( global_variable ); - elif _JULIA_ISA( global_variable, _JULIA_MODULE_TYPE ) then - global_variable := _WrapJuliaModule( rnam, global_variable ); - \.\:\=( module!.storage, rnum, global_variable ); + if _JULIA_ISA( var, _JULIA_FUNCTION_TYPE ) then + var := _WrapJuliaFunction( var ); + elif _JULIA_ISA( var, _JULIA_MODULE_TYPE ) then + var := _WrapJuliaModule( rnam, var ); + \.\:\=( module!.storage, rnum, var ); fi; - return global_variable; + return var; end ); InstallMethod( \.\:\=, @@ -93,7 +83,7 @@ function( obj ) return JuliaToGAP( IsList, Julia.GAP.get_symbols_in_module( JuliaPointer( obj ) ), true ); end); -InstallValue( Julia, _WrapJuliaModule( "Main", _JuliaGetGlobalVariable( "Main" ) ) ); +InstallValue( Julia, _WrapJuliaModule( "Main", _JuliaGetGlobalVariableByModule( "Main", "Main" ) ) ); InstallGlobalFunction( "JuliaIncludeFile", function( filename, module_name... ) diff --git a/pkg/JuliaInterface/src/JuliaInterface.c b/pkg/JuliaInterface/src/JuliaInterface.c index 26976c49a..a39223c6c 100644 --- a/pkg/JuliaInterface/src/JuliaInterface.c +++ b/pkg/JuliaInterface/src/JuliaInterface.c @@ -129,28 +129,6 @@ Obj NewJuliaObj(jl_value_t * v) } -jl_function_t * get_function_from_obj_or_string(Obj func) -{ - jl_function_t * f = NULL; - BEGIN_GAP_SYNC(); - if (IS_JULIA_OBJ(func)) { - f = (jl_function_t *)GET_JULIA_OBJ(func); - } - else if (IsStringConv(func)) { - // jl_get_function is a thin wrapper for jl_get_global and never - // throws an exception - f = jl_get_function(jl_main_module, CONST_CSTR_STRING(func)); - if (f == 0) { - ErrorMayQuit("Function is not defined in julia", 0, 0); - } - } - else - ErrorMayQuit("argument is not a julia object or string", 0, 0); - END_GAP_SYNC(); - return f; -} - - void ResetUserHasQUIT(void) { STATE(UserHasQUIT) = 0; @@ -158,34 +136,14 @@ void ResetUserHasQUIT(void) /* - * Returns the function from the Object - * or the function with name from - * the Julia main module. + * Wrap Julia object into a GAP function. */ -static Obj Func_JuliaFunction(Obj self, Obj func) +static Obj Func_WrapJuliaFunction(Obj self, Obj func) { - jl_function_t * f = get_function_from_obj_or_string(func); - return WrapJuliaFunc(f); -} + if (!IS_JULIA_OBJ(func)) + ErrorMayQuit("argument is not a julia object", 0, 0); -/* - * Returns the function with name from the Julia module with - * name . - */ -static Obj Func_JuliaFunctionByModule(Obj self, Obj funcName, Obj moduleName) -{ - BEGIN_GAP_SYNC(); - RequireStringRep("_JuliaFunctionByModule", funcName); - RequireStringRep("_JuliaFunctionByModule", moduleName); - - jl_module_t * m = get_module(CONST_CSTR_STRING(moduleName)); - // jl_get_function is a thin wrapper for jl_get_global and never throws - // an exception - jl_function_t * f = jl_get_function(m, CONST_CSTR_STRING(funcName)); - if (f == 0) - ErrorMayQuit("Function %g.%g is not defined in julia", - (Int)moduleName, (Int)funcName); - END_GAP_SYNC(); + jl_function_t * f = (jl_function_t *)GET_JULIA_OBJ(func); return WrapJuliaFunc(f); } @@ -233,22 +191,6 @@ static int gap_jl_boundp(jl_module_t * m, jl_sym_t * var) #endif } -// Returns the julia object GAP object that holds a pointer to the value -// currently bound to the julia identifier . -static Obj Func_JuliaGetGlobalVariable(Obj self, Obj name) -{ - BEGIN_GAP_SYNC(); - RequireStringRep("_JuliaGetGlobalVariable", name); - - jl_sym_t * symbol = jl_symbol(CONST_CSTR_STRING(name)); - END_GAP_SYNC(); - if (!gap_jl_boundp(jl_main_module, symbol)) { - return Fail; - } - jl_value_t * value = jl_get_global(jl_main_module, symbol); - return gap_julia(value); -} - // Returns the julia object GAP object that holds a pointer to the value // currently bound to the julia identifier .. static Obj Func_JuliaGetGlobalVariableByModule(Obj self, Obj name, Obj module) @@ -309,11 +251,9 @@ static void MarkJuliaObject(Bag bag) // Table of functions to export static StructGVarFunc GVarFuncs[] = { - GVAR_FUNC(_JuliaFunction, 1, "string"), - GVAR_FUNC(_JuliaFunctionByModule, 2, "funcName, moduleName"), + GVAR_FUNC(_WrapJuliaFunction, 1, "juliafunc"), GVAR_FUNC(IS_JULIA_FUNC, 1, "obj"), GVAR_FUNC(JuliaEvalString, 1, "string"), - GVAR_FUNC(_JuliaGetGlobalVariable, 1, "name"), GVAR_FUNC(_JuliaGetGlobalVariableByModule, 2, "name, module"), GVAR_FUNC(JuliaSymbol, 1, "name"), GVAR_FUNC(_JuliaGetGapModule, 0, ""), diff --git a/pkg/JuliaInterface/tst/calls.tst b/pkg/JuliaInterface/tst/calls.tst index d68ec83b3..78bc55a49 100644 --- a/pkg/JuliaInterface/tst/calls.tst +++ b/pkg/JuliaInterface/tst/calls.tst @@ -87,7 +87,7 @@ gap> f7(true,2,3,4,5,6,7); # # variadic function -gap> fw := JuliaFunction("f");; +gap> fw := Julia.f;; # gap> fw(); @@ -122,14 +122,14 @@ gap> fw(true,2,3,4,5,6,7); # non-variadic functions -gap> f0w := JuliaFunction("f0");; -gap> f1w := JuliaFunction("f1");; -gap> f2w := JuliaFunction("f2");; -gap> f3w := JuliaFunction("f3");; -gap> f4w := JuliaFunction("f4");; -gap> f5w := JuliaFunction("f5");; -gap> f6w := JuliaFunction("f6");; -gap> f7w := JuliaFunction("f7");; +gap> f0w := Julia.f0;; +gap> f1w := Julia.f1;; +gap> f2w := Julia.f2;; +gap> f3w := Julia.f3;; +gap> f4w := Julia.f4;; +gap> f5w := Julia.f5;; +gap> f6w := Julia.f6;; +gap> f7w := Julia.f7;; # gap> f0w(); @@ -202,39 +202,5 @@ gap> h4 := JuliaEvalString("function h4(a,b,c,d) end");; gap> h5 := JuliaEvalString("function h5(a,b,c,d,e) end");; gap> h6 := JuliaEvalString("function h6(a,b,c,d,e,f) end");; -# -# handling invalid inputs -# - -# -gap> JuliaFunction(); -Error, arguments must be strings function_name[,module_name] -gap> JuliaFunction(fail); -Error, arguments must be strings function_name[,module_name] -gap> JuliaFunction("foo_bar_quux_not_defined"); -Error, Function is not defined in julia - -# -gap> _JuliaFunction(fail); -Error, argument is not a julia object or string -gap> _JuliaFunction("foo_bar_quux_not_defined"); -Error, Function is not defined in julia - -# -gap> _JuliaFunctionByModule(fail, fail); -Error, _JuliaFunctionByModule: must be a string (not the value 'fai\ -l') -gap> _JuliaFunctionByModule("foo", fail); -Error, _JuliaFunctionByModule: must be a string (not the value 'f\ -ail') -gap> _JuliaFunctionByModule("foo", "bar"); -Error, bar not defined -gap> _JuliaFunctionByModule("foo", "Int"); -Error, Int is not a module -gap> _JuliaFunctionByModule("foo", "Base"); -Error, Function Base.foo is not defined in julia -gap> _JuliaFunctionByModule("parse", "Base"); - - # gap> STOP_TEST( "calls.tst" ); diff --git a/pkg/JuliaInterface/tst/convert.tst b/pkg/JuliaInterface/tst/convert.tst index 6deea470a..bd02e25d5 100644 --- a/pkg/JuliaInterface/tst/convert.tst +++ b/pkg/JuliaInterface/tst/convert.tst @@ -233,7 +233,7 @@ gap> Julia.GAP.Obj( emptystring ); "" ## 'GAPToJulia' for Julia functions (inside arrays) -gap> parse:= JuliaFunction( "parse", "Base" ); +gap> parse:= Julia.parse; gap> list:= GAPToJulia( JuliaEvalString( "Vector{Any}"), [ 1, parse, 3 ] ); diff --git a/pkg/JuliaInterface/tst/utils.tst b/pkg/JuliaInterface/tst/utils.tst index 5a82fe4ab..3df6c57e1 100644 --- a/pkg/JuliaInterface/tst/utils.tst +++ b/pkg/JuliaInterface/tst/utils.tst @@ -42,14 +42,6 @@ gap> JuliaSymbol(""); gap> JuliaSymbol(1); Error, JuliaSymbol: must be a string (not the integer 1) -## -gap> _JuliaGetGlobalVariable(0); -Error, _JuliaGetGlobalVariable: must be a string (not the integer 0) -gap> _JuliaGetGlobalVariable("not-a-global-variable"); -fail -gap> _JuliaGetGlobalVariable("sqrt"); - - ## gap> _JuliaGetGlobalVariableByModule(0, 0); Error, _JuliaGetGlobalVariableByModule: must be a string (not the integ\