|
179 | 179 | operators = OperatorEnum(; binary_operators=[+, -, *, /], unary_operators=[sin, cos]) |
180 | 180 | X = [1.0 2.0; 0.5 1.0] # 2 features, 2 samples |
181 | 181 |
|
182 | | - |
183 | 182 | # Test that property access doesn't allocate |
184 | 183 | @check_allocs get_degree(n) = n.degree |
185 | 184 | @check_allocs get_val(n) = n.val |
|
474 | 473 |
|
475 | 474 | println("✅ ArrayNode tree_mapreduce operations match Node!") |
476 | 475 | end |
| 476 | + |
| 477 | +@testitem "ArrayNode copy has no array aliasing" begin |
| 478 | + using DynamicExpressions |
| 479 | + const ArrayNode = DynamicExpressions.ArrayNode |
| 480 | + |
| 481 | + # Create a test tree |
| 482 | + x1 = ArrayNode{Float64,2,Vector}(; feature=1) |
| 483 | + x2 = ArrayNode{Float64,2,Vector}(; feature=2) |
| 484 | + tree = ArrayNode{Float64,2,Vector}(; |
| 485 | + op=1, |
| 486 | + l=ArrayNode{Float64,2,Vector}(; |
| 487 | + op=2, l=x1, r=ArrayNode{Float64,2,Vector}(; val=3.5) |
| 488 | + ), |
| 489 | + r=x2, |
| 490 | + ) |
| 491 | + |
| 492 | + # Test 1: Copy entire tree (root node) |
| 493 | + tree_copy = copy(tree) |
| 494 | + |
| 495 | + # Verify no aliasing - modifying copy shouldn't affect original |
| 496 | + tree_copy.val = 999.0 |
| 497 | + tree_copy.l.val = 888.0 |
| 498 | + |
| 499 | + # Check that original is unchanged |
| 500 | + @test tree.l.r.val == 3.5 # Original value unchanged |
| 501 | + @test tree.l.r.val != 888.0 |
| 502 | + |
| 503 | + # Verify the backing arrays are different |
| 504 | + orig_tree = tree.tree |
| 505 | + copy_tree = tree_copy.tree |
| 506 | + @test orig_tree !== copy_tree # Different tree objects |
| 507 | + @test orig_tree.nodes.val !== copy_tree.nodes.val # Different arrays |
| 508 | + @test orig_tree.nodes.degree !== copy_tree.nodes.degree |
| 509 | + @test orig_tree.nodes.children !== copy_tree.nodes.children |
| 510 | + |
| 511 | + # Test 2: Copy subtree (non-root node) |
| 512 | + subtree = tree.l |
| 513 | + subtree_copy = copy(subtree) |
| 514 | + |
| 515 | + # Modify the copy |
| 516 | + subtree_copy.r.val = 777.0 |
| 517 | + |
| 518 | + # Original should be unchanged |
| 519 | + @test tree.l.r.val == 3.5 |
| 520 | + @test subtree.r.val == 3.5 |
| 521 | + |
| 522 | + # Verify different backing arrays for subtree copy too |
| 523 | + subtree_copy_tree = subtree_copy.tree |
| 524 | + @test orig_tree !== subtree_copy_tree |
| 525 | + @test orig_tree.nodes.val !== subtree_copy_tree.nodes.val |
| 526 | + |
| 527 | + # Test 3: Verify structure is preserved in copy |
| 528 | + @test copy(tree) == tree |
| 529 | + @test copy(subtree) == subtree |
| 530 | +end |
0 commit comments