@@ -249,3 +249,118 @@ end
249249 tree = get_tree (ex)
250250 @test_throws ArgumentError get_operators (tree, nothing )
251251end
252+
253+ @testitem " Expression Literate examples" begin
254+ # literate_begin file="src/examples/expression.md"
255+ #=
256+ # `Expression` example
257+
258+ `Expression` is a fundamental type in DynamicExpressions that represents
259+ a mathematical expression as a tree structure. It combines an
260+ `AbstractExpressionNode` (typically a `Node`) with metadata like operators
261+ and variable names.
262+
263+ Let's explore how to create and work with `Expression` objects:
264+ =#
265+ using DynamicExpressions, Random
266+
267+ # First, let's define our operators and variable names:
268+
269+ operators = OperatorEnum (;
270+ binary_operators= [+ , - , * , / ], unary_operators= [sin, cos, exp]
271+ )
272+ variable_names = [" x" , " y" ]
273+
274+ # Now, let's create a simple Expression manually:
275+ x = Node {Float64} (; feature= 1 )
276+ x_expr = Expression (x; operators, variable_names)
277+
278+ # We can build up more complex expressions using these basic building blocks:
279+ y = Node {Float64} (; feature= 2 )
280+ c = Node {Float64} (; val= 2.0 )
281+ complex_node = Node (; op= 3 , l= x, r= Node (; op= 1 , l= y, r= c))
282+ # where the `3` indicates `*` and `1` indicates `+`.
283+ complex_expr = Expression (complex_node; operators, variable_names)
284+
285+ #=
286+ This expression includes its own metadata: the operators and variable names,
287+ and so there are no scope issues as with raw `AbstractExpressionNode` types
288+ which depend on the last-used metadata for convenience functions like printing.
289+ In other words, you can print this expression, or evaluate it, directly:
290+ =#
291+ rng = Random. MersenneTwister (0 )
292+ complex_expr (randn (rng, 2 , 5 ))
293+
294+ #=
295+ While creating expressions manually is possible, it can be cumbersome for more
296+ complex expressions. DynamicExpressions provides a more convenient way to create
297+ expressions using the `parse_expression` function:
298+ =#
299+ parsed_expr = parse_expression (
300+ :(sin (2.0 * x + exp (y + 5.0 ))); operators= operators, variable_names= variable_names
301+ )
302+
303+ # We can convert an expression into the primitive `AbstractExpressionNode` type
304+ # with [`get_tree`](@ref):
305+ tree = get_tree (parsed_expr)
306+ @test tree isa AbstractExpressionNode # src
307+
308+ # Some `AbstractExpression` types may choose to store their expression in
309+ # a different way than simply saving it as one of the fields. For any expression,
310+ # you can get the raw contents with [`get_contents`](@ref):
311+ get_contents (parsed_expr)
312+
313+ #=
314+ Similarly, you can get the metadata for an expression with [`get_metadata`](@ref):
315+ =#
316+ get_metadata (parsed_expr)
317+
318+ #=
319+ These can be used with [`with_contents`](@ref) and [`with_metadata`](@ref) to
320+ create new expressions based on the original:
321+ =#
322+ with_contents (parsed_expr, Node (; op= 2 , l= get_contents (parsed_expr)))
323+
324+ #=
325+ One of the key features of `Expression` is that it can be evaluated
326+ on data. Let's create some random input data and evaluate our expression:
327+ =#
328+ rng = Random. MersenneTwister (0 )
329+ X = rand (rng, 2 , 5 ) # 2 variables, 5 data points
330+
331+ result = parsed_expr (X)
332+ @test size (result) == (1 , 5 ) # src
333+
334+ # We can verify this result against a direct calculation:
335+ expected = @. sin (2.0 * X[1 , :] + exp (X[2 , :] + 5.0 ))
336+ @test result ≈ expected # src
337+
338+ #=
339+ `Expression` objects also support various tree operations.
340+ For example, we can count the number of nodes:
341+ =#
342+ node_count = count_nodes (parsed_expr)
343+ println (" Number of nodes: $node_count " )
344+
345+ # Or find the depth of the expression tree:
346+ depth = count_depth (parsed_expr)
347+ println (" Tree depth: $depth " )
348+
349+ #=
350+ We can also perform more complex operations, like simplification:
351+ =#
352+ complex_expr = parse_expression (
353+ :((2.0 + x) + 3.0 ); operators= operators, variable_names= [" x" ]
354+ )
355+ simplified_expr = combine_operators (complex_expr)
356+ println (" Original: " , complex_expr)
357+ println (" Simplified: " , simplified_expr)
358+
359+ #=
360+ These examples demonstrate some of the key features of `Expression` objects.
361+ They provide a powerful way to represent, evaluate, and manipulate
362+ mathematical expressions in DynamicExpressions.
363+ =#
364+
365+ # literate_end
366+ end
0 commit comments