Module: Quicopt::Operators
- Included in:
- Expression, Variable
- Defined in:
- lib/quicopt/model.rb
Overview
The operator surface shared by Variable and Expression.
Every operator is written against to_expr, so a variable and an expression
behave identically. coerce makes a numeric on the left work too, which is
what lets 3 * x parse: Ruby hands the multiplication back to us rather than
failing in Integer#*.
Instance Method Summary collapse
-
#!=(other) ⇒ Object
A disequality is not representable on the wire, and Ruby would otherwise derive it from
==and silently answerfalsefor every row. -
#*(other) ⇒ Expression
self * other. -
#**(exponent) ⇒ Expression
Integer powers 0, 1 and 2 only — the degree the subset admits.
-
#+(other) ⇒ Expression
+self + other+.
-
#+@ ⇒ Expression
self, unchanged. -
#-(other) ⇒ Expression
self - other. -
#-@ ⇒ Expression
The negation of
self. -
#/(divisor) ⇒ Expression
Division by a numeric constant only — dividing by an expression is not a polynomial and has no wire form.
-
#<=(other) ⇒ Constraint
The row
self <= other. -
#==(other) ⇒ Constraint, Boolean
Builds an equality row, not a boolean —
x == 5is a constraint. -
#>=(other) ⇒ Constraint
The row
self >= other. -
#coerce(other) ⇒ Array(Expression, Expression)
Lets Ruby fold a numeric on the left into an expression, so
3 * xand10 - xdispatch here instead of failing inside +Integer+/+Float+.
Instance Method Details
#!=(other) ⇒ Object
A disequality is not representable on the wire, and Ruby would otherwise
derive it from == and silently answer false for every row.
146 147 148 149 150 151 |
# File 'lib/quicopt/model.rb', line 146 def !=(other) return !equal?(other) unless Expression.castable?(other) raise UnsupportedExpression, "!= is not a constraint the wire schema can carry; model it with a binary and a big-M row" end |
#*(other) ⇒ Expression
Returns self * other.
74 75 76 |
# File 'lib/quicopt/model.rb', line 74 def *(other) to_expr.times(Expression.cast(other)) end |
#**(exponent) ⇒ Expression
Integer powers 0, 1 and 2 only — the degree the subset admits.
97 98 99 100 101 102 103 104 105 106 |
# File 'lib/quicopt/model.rb', line 97 def **(exponent) case exponent when 0 then Expression.new(constant: 1.0) when 1 then to_expr when 2 then to_expr.times(to_expr) else raise UnsupportedExpression, "exponent #{exponent.inspect} is outside the linear/quadratic subset (0, 1 or 2)" end end |
#+(other) ⇒ Expression
Returns +self + other+.
63 64 65 |
# File 'lib/quicopt/model.rb', line 63 def +(other) to_expr.plus(Expression.cast(other)) end |
#+@ ⇒ Expression
Returns self, unchanged.
114 115 116 |
# File 'lib/quicopt/model.rb', line 114 def +@ to_expr end |
#-(other) ⇒ Expression
Returns self - other.
68 69 70 |
# File 'lib/quicopt/model.rb', line 68 def -(other) to_expr.plus(Expression.cast(other).scale(-1.0)) end |
#-@ ⇒ Expression
Returns the negation of self.
109 110 111 |
# File 'lib/quicopt/model.rb', line 109 def -@ to_expr.scale(-1.0) end |
#/(divisor) ⇒ Expression
Division by a numeric constant only — dividing by an expression is not a polynomial and has no wire form.
83 84 85 86 87 88 89 90 91 |
# File 'lib/quicopt/model.rb', line 83 def /(divisor) unless divisor.is_a?(Numeric) raise UnsupportedExpression, "cannot divide by #{divisor.class}: only division by a numeric constant is supported" end raise ZeroDivisionError, "divided by 0" if divisor.zero? to_expr.scale(1.0 / divisor) end |
#<=(other) ⇒ Constraint
Returns the row self <= other.
119 120 121 |
# File 'lib/quicopt/model.rb', line 119 def <=(other) Constraint.build(self, other, :le) end |
#==(other) ⇒ Constraint, Boolean
Builds an equality row, not a boolean — x == 5 is a constraint.
A non-numeric, non-expression operand falls back to identity, so an
incidental comparison (+x == nil+, x == "x") still answers false instead
of raising. Hash and Set membership are unaffected either way: they key off
+hash+/+eql?+, which Variable defines separately.
136 137 138 139 140 |
# File 'lib/quicopt/model.rb', line 136 def ==(other) return equal?(other) unless Expression.castable?(other) Constraint.build(self, other, :eq) end |
#>=(other) ⇒ Constraint
Returns the row self >= other.
124 125 126 |
# File 'lib/quicopt/model.rb', line 124 def >=(other) Constraint.build(self, other, :ge) end |
#coerce(other) ⇒ Array(Expression, Expression)
Lets Ruby fold a numeric on the left into an expression, so 3 * x and
10 - x dispatch here instead of failing inside +Integer+/+Float+.
158 159 160 |
# File 'lib/quicopt/model.rb', line 158 def coerce(other) [Expression.cast(other), to_expr] end |