@@ -1446,6 +1446,94 @@ function test_intercept_ForwardDiff_MethodError()
1446
1446
return
1447
1447
end
1448
1448
1449
+ function test_extract_subexpression ()
1450
+ model = Nonlinear. Model ()
1451
+ x = MOI. VariableIndex (1 )
1452
+ sub = MOI. ScalarNonlinearFunction (:^ , Any[x, 3 ])
1453
+ f = MOI. ScalarNonlinearFunction (:+ , Any[sub, sub])
1454
+ expr = Nonlinear. parse_expression (model, f)
1455
+ display (expr. nodes)
1456
+ @test expr == Nonlinear. Expression (
1457
+ [
1458
+ Nonlinear. Node (Nonlinear. NODE_CALL_MULTIVARIATE, 1 , - 1 ),
1459
+ Nonlinear. Node (Nonlinear. NODE_SUBEXPRESSION, 1 , 1 ),
1460
+ Nonlinear. Node (Nonlinear. NODE_SUBEXPRESSION, 1 , 1 ),
1461
+ ],
1462
+ Float64[],
1463
+ )
1464
+ expected_sub = Nonlinear. Expression (
1465
+ [
1466
+ Nonlinear. Node (Nonlinear. NODE_CALL_MULTIVARIATE, 4 , - 1 )
1467
+ Nonlinear. Node (Nonlinear. NODE_MOI_VARIABLE, 1 , 1 )
1468
+ Nonlinear. Node (Nonlinear. NODE_VALUE, 1 , 1 )
1469
+ ],
1470
+ [3.0 ],
1471
+ )
1472
+ @test model. expressions == [expected_sub]
1473
+ @test model. cache[sub] == Nonlinear. ExpressionIndex (1 )
1474
+
1475
+ h = MOI. ScalarNonlinearFunction (:* , Any[2 , sub, 1 ])
1476
+ g = MOI. ScalarNonlinearFunction (:+ , Any[sub, h])
1477
+ expr = MOI. Nonlinear. parse_expression (model, g)
1478
+ expected_g = Nonlinear. Expression (
1479
+ [
1480
+ Nonlinear. Node (Nonlinear. NODE_CALL_MULTIVARIATE, 1 , - 1 )
1481
+ Nonlinear. Node (Nonlinear. NODE_SUBEXPRESSION, 1 , 1 )
1482
+ Nonlinear. Node (Nonlinear. NODE_CALL_MULTIVARIATE, 3 , 1 )
1483
+ Nonlinear. Node (Nonlinear. NODE_VALUE, 1 , 3 )
1484
+ Nonlinear. Node (Nonlinear. NODE_SUBEXPRESSION, 1 , 3 )
1485
+ Nonlinear. Node (Nonlinear. NODE_VALUE, 2 , 3 )
1486
+ ],
1487
+ [2.0 , 1.0 ],
1488
+ )
1489
+ @test expr == expected_g
1490
+ # It should have detected the sub-expressions that was the same as `f`
1491
+ @test model. expressions == [expected_sub]
1492
+ # This means that it didn't get to extract from `g`, let's also test
1493
+ # with extraction by starting with an empty model
1494
+
1495
+ model = Nonlinear. Model ()
1496
+ MOI. Nonlinear. set_objective (model, g)
1497
+ @test model. objective == expected_g
1498
+ @test model. expressions == [expected_sub]
1499
+ # Test that the objective function gets rewritten as we reuse `h`
1500
+ # Also test that we don't change the parents in the stack of `h`
1501
+ # by creating a long stack
1502
+ prod = MOI. ScalarNonlinearFunction (:* , [h, x])
1503
+ sum = MOI. ScalarNonlinearFunction (:* , [x, x, x, x, prod])
1504
+ expr = Nonlinear. parse_expression (model, sum)
1505
+ @test isempty (model. objective. values)
1506
+ @test model. objective. nodes == [
1507
+ Nonlinear. Node (Nonlinear. NODE_CALL_MULTIVARIATE, 1 , - 1 ),
1508
+ Nonlinear. Node (Nonlinear. NODE_SUBEXPRESSION, 1 , 1 ),
1509
+ Nonlinear. Node (Nonlinear. NODE_SUBEXPRESSION, 2 , 1 ),
1510
+ ]
1511
+ @test model. expressions == [
1512
+ expected_sub,
1513
+ Nonlinear. Expression (
1514
+ [
1515
+ Nonlinear. Node (Nonlinear. NODE_CALL_MULTIVARIATE, 3 , - 1 ),
1516
+ Nonlinear. Node (Nonlinear. NODE_VALUE, 1 , 1 ),
1517
+ Nonlinear. Node (Nonlinear. NODE_SUBEXPRESSION, 1 , 1 ),
1518
+ Nonlinear. Node (Nonlinear. NODE_VALUE, 2 , 1 ),
1519
+ ],
1520
+ [2.0 , 1.0 ],
1521
+ ),
1522
+ ]
1523
+ @test isempty (expr. values)
1524
+ @test expr. nodes == [
1525
+ Nonlinear. Node (Nonlinear. NODE_CALL_MULTIVARIATE, 3 , - 1 ),
1526
+ Nonlinear. Node (Nonlinear. NODE_MOI_VARIABLE, 1 , 1 ),
1527
+ Nonlinear. Node (Nonlinear. NODE_MOI_VARIABLE, 1 , 1 ),
1528
+ Nonlinear. Node (Nonlinear. NODE_MOI_VARIABLE, 1 , 1 ),
1529
+ Nonlinear. Node (Nonlinear. NODE_MOI_VARIABLE, 1 , 1 ),
1530
+ Nonlinear. Node (Nonlinear. NODE_CALL_MULTIVARIATE, 3 , 1 ),
1531
+ Nonlinear. Node (Nonlinear. NODE_SUBEXPRESSION, 2 , 6 ),
1532
+ Nonlinear. Node (Nonlinear. NODE_MOI_VARIABLE, 1 , 6 ),
1533
+ ]
1534
+ return
1535
+ end
1536
+
1449
1537
end # TestNonlinear
1450
1538
1451
1539
TestNonlinear. runtests ()
0 commit comments