|
595 | 595 | @test dummy.op == src.op |
596 | 596 | @test get_children(dummy) == get_children(src) |
597 | 597 | end |
| 598 | + |
| 599 | +@testitem "GraphNode compatibility" begin |
| 600 | + using DynamicExpressions |
| 601 | + using Test |
| 602 | + |
| 603 | + my_ternary_op(x, y, z) = x + y * z |
| 604 | + operators = OperatorEnum(1 => (sin,), 2 => (+, *), 3 => (my_ternary_op,)) |
| 605 | + |
| 606 | + x1, x2, x3 = GraphNode{Float64,3}(; feature=1), |
| 607 | + GraphNode{Float64,3}(; feature=2), |
| 608 | + GraphNode{Float64,3}(; feature=3) |
| 609 | + c1 = GraphNode{Float64,3}(; val=2.5) |
| 610 | + |
| 611 | + # Test 1: Basic 3-degree node construction |
| 612 | + ternary_node = GraphNode{Float64,3}(; op=1, children=(x1, x2, x3)) |
| 613 | + @test ternary_node.degree == 3 |
| 614 | + @test ternary_node.op == 1 |
| 615 | + @test length(ternary_node.children) == 3 |
| 616 | + @test all(ternary_node.children .=== (x1, x2, x3)) |
| 617 | + |
| 618 | + # Test 2: Sharing functionality |
| 619 | + shared_subexpr = GraphNode{Float64,3}(; op=1, children=(x1, x2, c1)) |
| 620 | + tree_with_sharing = GraphNode{Float64,3}(; |
| 621 | + op=1, children=(shared_subexpr, x3, shared_subexpr) |
| 622 | + ) |
| 623 | + |
| 624 | + # # Verify reference equality (sharing) |
| 625 | + @test get_child(tree_with_sharing, 1) === get_child(tree_with_sharing, 3) |
| 626 | + @test get_child(tree_with_sharing, 1) === shared_subexpr |
| 627 | + |
| 628 | + # Also should last through copy: |
| 629 | + tree_with_sharing_copy = copy(tree_with_sharing) |
| 630 | + @test get_child(tree_with_sharing_copy, 1) === get_child(tree_with_sharing_copy, 3) |
| 631 | + |
| 632 | + # Test 3: String representation shows sharing with {} |
| 633 | + sharing_string = string_tree(tree_with_sharing, operators) |
| 634 | + @test count("my_ternary_op(x1, x2, 2.5)", sharing_string) == 2 |
| 635 | + @test count("{my_ternary_op(x1, x2, 2.5)}", sharing_string) == 1 # With sharing notation |
| 636 | + |
| 637 | + # Test 4: Copy operations |
| 638 | + # Breaking sharing creates separate instances |
| 639 | + tree_no_sharing = copy_node(tree_with_sharing; break_sharing=Val(true)) |
| 640 | + @test get_child(tree_no_sharing, 1) !== get_child(tree_no_sharing, 3) # No longer shared |
| 641 | + no_sharing_string = string_tree(tree_no_sharing, operators) |
| 642 | + @test !occursin("{", no_sharing_string) # No more shared nodes |
| 643 | + @test count("my_ternary_op(x1, x2, 2.5)", no_sharing_string) == 2 # Appears twice |
| 644 | + |
| 645 | + # Test 5: Modification propagation through shared nodes |
| 646 | + original_string = string_tree(tree_with_sharing, operators) |
| 647 | + set_children!(shared_subexpr, (x3, x1, x2)) # Modify shared node |
| 648 | + modified_string = string_tree(tree_with_sharing, operators) |
| 649 | + @test original_string != modified_string |
| 650 | + @test get_child(tree_with_sharing, 1) === get_child(tree_with_sharing, 3) # Still shared |
| 651 | + @test occursin("my_ternary_op(x3, x1, x2)", modified_string) |
| 652 | + |
| 653 | + # Test 6: Evaluation with 3-degree nodes |
| 654 | + X = [1.0 2.0; 0.5 1.5; 0.8 0.3] # 3 features, 2 samples |
| 655 | + simple_ternary = GraphNode{Float64,3}(; op=1, children=(x1, x2, x3)) |
| 656 | + expected = [my_ternary_op(1.0, 0.5, 0.8), my_ternary_op(2.0, 1.5, 0.3)] |
| 657 | + result, flag = eval_tree_array(simple_ternary, X, operators) |
| 658 | + @test flag |
| 659 | + @test result ≈ expected |
| 660 | +end |
0 commit comments