From bb927ef271b88858a106de503d05b949a4b52880 Mon Sep 17 00:00:00 2001 From: MilesCranmer Date: Sat, 8 Feb 2025 19:45:18 +0000 Subject: [PATCH 1/2] feat: rename `@template` to `@template_spec` --- docs/src/examples.md | 4 +- docs/src/types.md | 4 +- examples/template_expression.jl | 2 +- examples/template_expression_complex.jl | 2 +- src/SymbolicRegression.jl | 4 +- src/TemplateExpressionMacro.jl | 8 +-- test/test_parametric_template_expressions.jl | 4 +- test/test_template_expression.jl | 2 +- test/test_template_macro.jl | 52 ++++++++++---------- 9 files changed, 42 insertions(+), 40 deletions(-) diff --git a/docs/src/examples.md b/docs/src/examples.md index 298426649..79f41ba53 100644 --- a/docs/src/examples.md +++ b/docs/src/examples.md @@ -285,7 +285,7 @@ using MLJBase: machine, fit!, report The key part is defining our template structure. This determines how different parts of the expression combine: ```julia -expression_spec = @template(expressions=(f, g)) do x1, x2, x3 +expression_spec = @template_spec(expressions=(f, g)) do x1, x2, x3 f(x1, x2) + g(x2) - g(x3) end ``` @@ -432,7 +432,7 @@ Now, define the template for the derivative operator: ```julia using SymbolicRegression: D -expression_spec = @template(expressions=(f,)) do x +expression_spec = @template_spec(expressions=(f,)) do x D(f, 1)(x) end ``` diff --git a/docs/src/types.md b/docs/src/types.md index d70051754..6088790ab 100644 --- a/docs/src/types.md +++ b/docs/src/types.md @@ -64,10 +64,10 @@ TemplateStructure TemplateExpressionSpec ``` -You can use the `@template` macro as an easy way to create a `TemplateExpressionSpec`: +You can use the `@template_spec` macro as an easy way to create a `TemplateExpressionSpec`: ```@docs -@template +@template_spec ``` Composable expressions are used internally by `TemplateExpression` and allow you to combine multiple expressions together. diff --git a/examples/template_expression.jl b/examples/template_expression.jl index 9bfc57c5f..511cfc61e 100644 --- a/examples/template_expression.jl +++ b/examples/template_expression.jl @@ -3,7 +3,7 @@ using Random: rand using MLJBase: machine, fit!, report, predict using Test: @test -expression_spec = @template(expressions = (f, g1, g2)) do x1, x2, x3 +expression_spec = @template_spec(expressions = (f, g1, g2)) do x1, x2, x3 _f = f(x1, x2) _g1 = g1(x3) _g2 = g2(x3) diff --git a/examples/template_expression_complex.jl b/examples/template_expression_complex.jl index 070f10e92..372ac1c3a 100644 --- a/examples/template_expression_complex.jl +++ b/examples/template_expression_complex.jl @@ -226,7 +226,7 @@ subexpression symbols we wish to learn: structure = TemplateStructure{(:B_x, :B_y, :B_z, :F_d_scale)}(compute_force) #= -Note that we could have also used the `@template` macro which is +Note that we could have also used the `@template_spec` macro which is more convenient. First, let's look at an example of how this would be used diff --git a/src/SymbolicRegression.jl b/src/SymbolicRegression.jl index 58239a93f..d50c9c7a7 100644 --- a/src/SymbolicRegression.jl +++ b/src/SymbolicRegression.jl @@ -18,7 +18,7 @@ export Population, TemplateExpression, TemplateStructure, TemplateExpressionSpec, - @template, + @template_spec, ValidVector, ComposableExpression, NodeSampler, @@ -339,7 +339,7 @@ using .TemplateExpressionModule: ValidVector using .ComposableExpressionModule: ComposableExpression using .ExpressionBuilderModule: embed_metadata, strip_metadata using .ParametricExpressionModule: ParametricExpressionSpec -using .TemplateExpressionMacroModule: @template +using .TemplateExpressionMacroModule: @template_spec @stable default_mode = "disable" begin include("deprecates.jl") diff --git a/src/TemplateExpressionMacro.jl b/src/TemplateExpressionMacro.jl index 888489e1d..b8b195ae2 100644 --- a/src/TemplateExpressionMacro.jl +++ b/src/TemplateExpressionMacro.jl @@ -1,7 +1,7 @@ module TemplateExpressionMacroModule """ - @template( + @template_spec( parameters=(p1=10, p2=10, p3=1), expressions=(f, g), ) do x1, x2, class @@ -12,11 +12,11 @@ module TemplateExpressionMacroModule The parameters are used to define constants that can be indexed, and the expressions define the function keys for the template structure. """ -macro template(f, args...) - return esc(template(f, args...)) +macro template_spec(f, args...) + return esc(template_spec(f, args...)) end -function template(func, args...) +function template_spec(func, args...) # Extract the parameters and expressions from the arguments parameters = nothing expressions = nothing diff --git a/test/test_parametric_template_expressions.jl b/test/test_parametric_template_expressions.jl index 545450c34..dd90f94de 100644 --- a/test/test_parametric_template_expressions.jl +++ b/test/test_parametric_template_expressions.jl @@ -271,12 +271,12 @@ end #= ## Defining the Template - Now we'll use the `@template` macro to encode this structure, which will create + Now we'll use the `@template_spec` macro to encode this structure, which will create a `TemplateExpressionSpec` object. =# ## Define the template structure with sub-expressions f and g - template = @template( + template = @template_spec( expressions=(f, g), parameters=(p1=2, p2=2) ) do x1, x2, class diff --git a/test/test_template_expression.jl b/test/test_template_expression.jl index b881580ae..034010fbe 100644 --- a/test/test_template_expression.jl +++ b/test/test_template_expression.jl @@ -523,7 +523,7 @@ end @test eval_loss(ex, d, options; idx=idx) < 1e-10 # Test with template expressions - template = @template(expressions = (f,), parameters = (p=2,)) do x + template = @template_spec(expressions = (f,), parameters = (p=2,)) do x f(x) + sum(p) end diff --git a/test/test_template_macro.jl b/test/test_template_macro.jl index 719f18171..5d70c16d8 100644 --- a/test/test_template_macro.jl +++ b/test/test_template_macro.jl @@ -1,12 +1,13 @@ -@testitem "Basic @template macro functionality" tags = [:part1, :template_macro] begin +@testitem "Basic @template_spec macro functionality" tags = [:part1, :template_macro] begin using SymbolicRegression using DynamicExpressions: OperatorEnum, Node # Test basic parameter/expression handling - expr_spec = - @template(parameters = (p1=10, p2=10, p3=1), expressions = (f, g)) do x1, x2, class - return p1[class] * x1^2 + f(x1, x2, p2[class]) - g(p3[1] * x1) - end + expr_spec = @template_spec( + parameters = (p1=10, p2=10, p3=1), expressions = (f, g) + ) do x1, x2, class + return p1[class] * x1^2 + f(x1, x2, p2[class]) - g(p3[1] * x1) + end # Verify spec structure @test expr_spec.structure isa TemplateStructure{(:f, :g),(:p1, :p2, :p3)} @@ -37,52 +38,52 @@ end @testitem "Template macro error handling" tags = [:part1, :template_macro] begin using SymbolicRegression - using SymbolicRegression.TemplateExpressionMacroModule: template + using SymbolicRegression.TemplateExpressionMacroModule: template_spec # Test missing expressions @test_throws( ArgumentError("expressions must be specified"), - template(:((x,) -> f(x)), :(parameters = (p1=1,))) + template_spec(:((x,) -> f(x)), :(parameters = (p1=1,))) ) # Test invalid parameters format @test_throws( "parameters must be a tuple of parameter name-size pairs like `(p1=10, p2=10, p3=1)`", - template(:((x,) -> f(x)), :(parameters = 1), :(expressions = (f,))) + template_spec(:((x,) -> f(x)), :(parameters = 1), :(expressions = (f,))) ) @test_throws( "parameters must be a tuple of parameter name-size pairs like `(p1=10, p2=10, p3=1)`", - template(:((x,) -> f(x)), :(parameters = (1, 2)), :(expressions = (f,))) + template_spec(:((x,) -> f(x)), :(parameters = (1, 2)), :(expressions = (f,))) ) # Test invalid expressions format @test_throws( "expressions must be a tuple of the form `(f, g, ...)`", - template(:((x,) -> f(x)), :(parameters = (p1=1,)), :(expressions = f)) + template_spec(:((x,) -> f(x)), :(parameters = (p1=1,)), :(expressions = f)) ) # Test invalid function format @test_throws( ArgumentError("Expected a do block"), - template(:(f(x)), :(parameters = (p1=1,)), :(expressions = (f,))) + template_spec(:(f(x)), :(parameters = (p1=1,)), :(expressions = (f,))) ) @test_throws( ArgumentError("Expected a tuple of arguments for the function arguments"), - template(:(x -> f(x)), :(parameters = (p1=1,)), :(expressions = (f,))) + template_spec(:(x -> f(x)), :(parameters = (p1=1,)), :(expressions = (f,))) ) # Test missing expressions (but having parameters) @test_throws( ArgumentError("expressions must be specified"), - template(:((x,) -> f(x)), :(parameters = (p1=1,))) + template_spec(:((x,) -> f(x)), :(parameters = (p1=1,))) ) # Test invalid expressions format without parameters @test_throws( "expressions must be a tuple of the form `(f, g, ...)`", - template(:((x,) -> f(x)), :(expressions = f)) + template_spec(:((x,) -> f(x)), :(expressions = f)) ) end @@ -92,12 +93,13 @@ end using Test # Multi-output template with parameter reuse - template = - @template(parameters = (coeff=5,), expressions = (base, modifier)) do x, y, class - base_val = base(x, coeff[class]) - modified = modifier(y, coeff[class]) - return coeff[class] * x * base_val + modified - end + template = @template_spec( + parameters = (coeff=5,), expressions = (base, modifier) + ) do x, y, class + base_val = base(x, coeff[class]) + modified = modifier(y, coeff[class]) + return coeff[class] * x * base_val + modified + end # Verify structure @test template.structure isa TemplateStructure{(:base, :modifier),(:coeff,)} @@ -126,7 +128,7 @@ end using DynamicExpressions: OperatorEnum, Node # Test template without parameters - expr_spec = @template(expressions = (f, g)) do x1, x2 + expr_spec = @template_spec(expressions = (f, g)) do x1, x2 return x1^2 + f(x1, x2) - g(x1) end @@ -160,7 +162,7 @@ end # Test setting parameters keyword twice @test_throws( "cannot set `parameters` keyword twice", - template( + template_spec( :((x,) -> f(x)), :(parameters = (p1=1,)), :(parameters = (p2=1,)), @@ -171,18 +173,18 @@ end # Test setting expressions keyword twice @test_throws( "cannot set `expressions` keyword twice", - template(:((x,) -> f(x)), :(expressions = (f,)), :(expressions = (g,))) + template_spec(:((x,) -> f(x)), :(expressions = (f,)), :(expressions = (g,))) ) # Test unrecognized keyword @test_throws( "unrecognized keyword invalid_keyword", - template(:((x,) -> f(x)), :(invalid_keyword = 1), :(expressions = (f,))) + template_spec(:((x,) -> f(x)), :(invalid_keyword = 1), :(expressions = (f,))) ) # Test positional args after first @test_throws( "no positional args accepted after the first", - template(:((x,) -> f(x)), :(expressions = (f,)), :extra_arg) + template_spec(:((x,) -> f(x)), :(expressions = (f,)), :extra_arg) ) end From 8eeb51fe3583c4fc5391d93035af6ec6af318015 Mon Sep 17 00:00:00 2001 From: MilesCranmer Date: Sat, 8 Feb 2025 20:05:19 +0000 Subject: [PATCH 2/2] test: fix error handling template test --- test/test_template_macro.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_template_macro.jl b/test/test_template_macro.jl index 5d70c16d8..5281bec75 100644 --- a/test/test_template_macro.jl +++ b/test/test_template_macro.jl @@ -157,7 +157,7 @@ end @testitem "Template macro additional error handling" tags = [:part1, :template_macro] begin using SymbolicRegression - using SymbolicRegression.TemplateExpressionMacroModule: template + using SymbolicRegression.TemplateExpressionMacroModule: template_spec # Test setting parameters keyword twice @test_throws(