@@ -77,16 +77,19 @@ function simplify!(f::MOI.ScalarAffineFunction{T}) where {T}
77
77
if isempty (f. terms)
78
78
return f. constant
79
79
end
80
+ if iszero (f. constant) && length (f. terms) == 1
81
+ term = only (f. terms)
82
+ if isone (term. coefficient)
83
+ return term. variable
84
+ end
85
+ end
80
86
return f
81
87
end
82
88
83
89
function simplify! (f:: MOI.ScalarQuadraticFunction{T} ) where {T}
84
90
f = MOI. Utilities. canonicalize! (f)
85
91
if isempty (f. quadratic_terms)
86
- if isempty (f. affine_terms)
87
- return f. constant
88
- end
89
- return MOI. ScalarAffineFunction (f. affine_terms, f. constant)
92
+ return simplify! (MOI. ScalarAffineFunction (f. affine_terms, f. constant))
90
93
end
91
94
return f
92
95
end
@@ -117,7 +120,7 @@ function simplify!(f::MOI.ScalarNonlinearFunction)
117
120
push! (result_stack, arg)
118
121
end
119
122
end
120
- return _simplify_if_affine ! (only (result_stack))
123
+ return _simplify_if_quadratic ! (only (result_stack))
121
124
end
122
125
123
126
function simplify! (f:: MOI.VectorAffineFunction{T} ) where {T}
@@ -140,10 +143,12 @@ function simplify!(f::MOI.VectorQuadraticFunction{T}) where {T}
140
143
end
141
144
142
145
function simplify! (f:: MOI.VectorNonlinearFunction )
143
- for (i, row) in enumerate (f. rows)
144
- f. rows[i] = simplify! (row)
146
+ rows = simplify! .(f. rows)
147
+ Y = reduce (promote_type, typeof .(rows))
148
+ if isconcretetype (Y)
149
+ return MOI. Utilities. vectorize (convert (Vector{Y}, rows))
145
150
end
146
- return f
151
+ return MOI . VectorNonlinearFunction (rows)
147
152
end
148
153
149
154
# If a ScalarNonlinearFunction has only constant arguments, we should return
@@ -1507,100 +1512,207 @@ function MOI.eval_hessian_lagrangian(model::Evaluator, H, x, σ, μ)
1507
1512
end
1508
1513
1509
1514
# A default fallback for all types
1510
- _add_to_affine! (:: Any , :: Any , :: T ) where {T} = nothing
1515
+ _add_to_quadratic! (:: Any , :: Real , :: Any ) = nothing
1516
+ _add_to_quadratic! (:: Any , :: Real , :: Any , :: Any ) = nothing
1511
1517
1512
- # The creation of `ret::MOI.ScalarAffineFunction` has been delayed until now.
1513
- function _add_to_affine! (
1514
- :: Nothing ,
1515
- f:: Union{Real,MOI.VariableIndex,MOI.ScalarAffineFunction} ,
1518
+ # The creation of `ret::MOI.ScalarQuadraticFunction` has been delayed until now.
1519
+ function _add_to_quadratic! (
1520
+ :: Missing ,
1516
1521
scale:: T ,
1517
- ) where {T}
1518
- return _add_to_affine! (zero (MOI. ScalarAffineFunction{T}), f, scale)
1522
+ f:: Union {
1523
+ Real,
1524
+ MOI. VariableIndex,
1525
+ MOI. ScalarAffineFunction,
1526
+ MOI. ScalarQuadraticFunction,
1527
+ }. .. ,
1528
+ ) where {T<: Real }
1529
+ return _add_to_quadratic! (zero (MOI. ScalarQuadraticFunction{T}), scale, f... )
1530
+ end
1531
+
1532
+ function _add_to_quadratic! (
1533
+ ret:: MOI.ScalarQuadraticFunction{T} ,
1534
+ scale:: T ,
1535
+ x:: S ,
1536
+ ) where {T<: Real ,S<: Real }
1537
+ if promote_type (T, S) != T
1538
+ return # We can't store `S` in `T`.
1539
+ end
1540
+ ret. constant += scale * convert (T, x)
1541
+ return ret
1519
1542
end
1520
1543
1521
- function _add_to_affine! (
1522
- ret:: MOI.ScalarAffineFunction{T} ,
1523
- x:: S ,
1544
+ function _add_to_quadratic! (
1545
+ ret:: MOI.ScalarQuadraticFunction{T} ,
1524
1546
scale:: T ,
1525
- ) where {T,S<: Real }
1547
+ f:: MOI.ScalarAffineTerm{S} ,
1548
+ ) where {T<: Real ,S}
1526
1549
if promote_type (T, S) != T
1527
1550
return # We can't store `S` in `T`.
1528
1551
end
1529
- ret. constant += scale * convert (T, x)
1552
+ push! (
1553
+ ret. affine_terms,
1554
+ MOI. ScalarAffineTerm {T} (scale * f. coefficient, f. variable),
1555
+ )
1530
1556
return ret
1531
1557
end
1532
1558
1533
- function _add_to_affine! (
1534
- ret:: MOI.ScalarAffineFunction{T} ,
1535
- x:: MOI.VariableIndex ,
1559
+ function _add_to_quadratic! (
1560
+ ret:: MOI.ScalarQuadraticFunction{T} ,
1536
1561
scale:: T ,
1537
- ) where {T}
1538
- push! (ret. terms, MOI. ScalarAffineTerm (scale, x))
1562
+ f:: MOI.ScalarQuadraticTerm{S} ,
1563
+ ) where {T<: Real ,S}
1564
+ if promote_type (T, S) != T
1565
+ return # We can't store `S` in `T`.
1566
+ end
1567
+ push! (
1568
+ ret. quadratic_terms,
1569
+ MOI. ScalarQuadraticTerm {T} (
1570
+ scale * f. coefficient,
1571
+ f. variable_1,
1572
+ f. variable_2,
1573
+ ),
1574
+ )
1539
1575
return ret
1540
1576
end
1541
1577
1542
- function _add_to_affine! (
1543
- ret:: MOI.ScalarAffineFunction{T} ,
1544
- f:: MOI.ScalarAffineFunction{S} ,
1578
+ function _add_to_quadratic! (
1579
+ ret:: MOI.ScalarQuadraticFunction{T} ,
1545
1580
scale:: T ,
1546
- ) where {T,S}
1581
+ x:: MOI.VariableIndex ,
1582
+ ) where {T<: Real }
1583
+ return _add_to_quadratic! (ret, scale, MOI. ScalarAffineTerm (one (T), x))
1584
+ end
1585
+
1586
+ function _add_to_quadratic! (
1587
+ ret:: MOI.ScalarQuadraticFunction{T} ,
1588
+ scale:: T ,
1589
+ f:: MOI.ScalarAffineFunction{S} ,
1590
+ ) where {T<: Real ,S}
1547
1591
if promote_type (T, S) != T
1548
1592
return # We can't store `S` in `T`.
1549
1593
end
1550
- ret = _add_to_affine ! (ret, f. constant, scale )
1594
+ ret = _add_to_quadratic ! (ret, scale, f. constant)
1551
1595
for term in f. terms
1552
- ret = _add_to_affine ! (ret, term . variable, scale * term. coefficient )
1596
+ ret = _add_to_quadratic ! (ret, scale, term)
1553
1597
end
1554
1598
return ret
1555
1599
end
1556
1600
1557
- function _add_to_affine! (
1558
- ret:: Union{Nothing,MOI.ScalarAffineFunction{T}} ,
1559
- f:: MOI.ScalarNonlinearFunction ,
1601
+ function _add_to_quadratic! (
1602
+ ret:: MOI.ScalarQuadraticFunction{T} ,
1560
1603
scale:: T ,
1561
- ) where {T}
1604
+ f:: MOI.ScalarQuadraticFunction{S} ,
1605
+ ) where {T<: Real ,S}
1606
+ if promote_type (T, S) != T
1607
+ return # We can't store `S` in `T`.
1608
+ end
1609
+ ret = _add_to_quadratic! (ret, scale, f. constant)
1610
+ for term in f. affine_terms
1611
+ ret = _add_to_quadratic! (ret, scale, term)
1612
+ end
1613
+ for q_term in f. quadratic_terms
1614
+ ret = _add_to_quadratic! (ret, scale, q_term)
1615
+ end
1616
+ return ret
1617
+ end
1618
+
1619
+ function _add_to_quadratic! (
1620
+ ret:: MOI.ScalarQuadraticFunction{T} ,
1621
+ scale:: T ,
1622
+ f:: MOI.VariableIndex ,
1623
+ g:: MOI.VariableIndex ,
1624
+ ) where {T<: Real }
1625
+ return _add_to_quadratic! (ret, scale, one (T) * f * g)
1626
+ end
1627
+
1628
+ function _add_to_quadratic! (
1629
+ ret:: MOI.ScalarQuadraticFunction{T} ,
1630
+ scale:: T ,
1631
+ f:: MOI.ScalarAffineFunction{F} ,
1632
+ g:: MOI.ScalarAffineFunction{G} ,
1633
+ ) where {T<: Real ,F,G}
1634
+ H = MOI. ScalarAffineFunction{promote_type (F, G)}
1635
+ return _add_to_quadratic! (ret, scale, convert (H, f) * convert (H, g))
1636
+ end
1637
+
1638
+ function _add_to_quadratic! (
1639
+ ret:: MOI.ScalarQuadraticFunction{T} ,
1640
+ scale:: T ,
1641
+ f:: MOI.VariableIndex ,
1642
+ g:: MOI.ScalarAffineFunction ,
1643
+ ) where {T<: Real }
1644
+ return _add_to_quadratic! (ret, scale, f * g)
1645
+ end
1646
+
1647
+ function _add_to_quadratic! (
1648
+ ret:: MOI.ScalarQuadraticFunction{T} ,
1649
+ scale:: T ,
1650
+ f:: MOI.ScalarAffineFunction ,
1651
+ g:: MOI.VariableIndex ,
1652
+ ) where {T<: Real }
1653
+ return _add_to_quadratic! (ret, scale, g, f)
1654
+ end
1655
+
1656
+ function _add_to_quadratic! (
1657
+ ret:: Union{Missing,MOI.ScalarQuadraticFunction{T}} ,
1658
+ scale:: T ,
1659
+ f:: MOI.ScalarNonlinearFunction ,
1660
+ ) where {T<: Real }
1562
1661
if f. head == :+
1563
1662
for arg in f. args
1564
- ret = _add_to_affine ! (ret, arg, scale )
1663
+ ret = _add_to_quadratic ! (ret, scale, arg )
1565
1664
if ret === nothing
1566
1665
return
1567
1666
end
1568
1667
end
1569
1668
return ret
1570
1669
elseif f. head == :-
1571
1670
if length (f. args) == 1
1572
- return _add_to_affine ! (ret, only (f. args), - scale )
1671
+ return _add_to_quadratic ! (ret, - scale, only (f. args))
1573
1672
end
1574
1673
@assert length (f. args) == 2
1575
- ret = _add_to_affine ! (ret, f. args[1 ], scale )
1674
+ ret = _add_to_quadratic ! (ret, scale, f. args[1 ])
1576
1675
if ret === nothing
1577
1676
return
1578
1677
end
1579
- return _add_to_affine ! (ret, f. args[2 ], - scale )
1678
+ return _add_to_quadratic ! (ret, - scale, f. args[2 ])
1580
1679
elseif f. head == :*
1581
- y = nothing
1680
+ y1, y2 = nothing , nothing
1582
1681
for arg in f. args
1583
1682
if arg isa Real
1584
1683
scale *= arg
1585
- elseif y === nothing
1586
- y = arg
1684
+ elseif y1 === nothing
1685
+ y1 = arg
1686
+ elseif y2 === nothing
1687
+ y2 = arg
1587
1688
else
1588
1689
return # We already have a `y`. Can't multiple factors.
1589
1690
end
1590
1691
end
1591
- return _add_to_affine! (ret, something (y, one (T)), convert (T, scale))
1692
+ if y1 === nothing
1693
+ @assert y2 === nothing
1694
+ return _add_to_quadratic! (ret, one (T), scale)
1695
+ elseif y2 === nothing
1696
+ return _add_to_quadratic! (ret, scale, y1)
1697
+ else
1698
+ return _add_to_quadratic! (ret, scale, y1, y2)
1699
+ end
1700
+ elseif f. head == :^ && f. args[2 ] isa Real && f. args[2 ] == 2
1701
+ return _add_to_quadratic! (ret, scale, f. args[1 ], f. args[1 ])
1702
+ elseif f. head == :/ && f. args[2 ] isa Real
1703
+ return _add_to_quadratic! (ret, convert (T, scale / f. args[2 ]), f. args[1 ])
1592
1704
end
1593
1705
return # An unsupported f.head
1594
1706
end
1595
1707
1596
- function _simplify_if_affine ! (f:: MOI.ScalarNonlinearFunction )
1597
- ret = _add_to_affine! ( nothing , f, 1.0 )
1708
+ function _simplify_if_quadratic ! (f:: MOI.ScalarNonlinearFunction )
1709
+ ret = _add_to_quadratic! ( missing , 1.0 , f )
1598
1710
if ret === nothing
1599
1711
return f
1600
1712
end
1601
- return simplify! (ret:: MOI.ScalarAffineFunction {Float64} )
1713
+ return simplify! (ret:: MOI.ScalarQuadraticFunction {Float64} )
1602
1714
end
1603
1715
1604
- _simplify_if_affine ! (f:: Any ) = f
1716
+ _simplify_if_quadratic ! (f:: Any ) = f
1605
1717
1606
1718
end # module
0 commit comments