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
Quicopt has no "not equal to" constraint, and Ruby would otherwise derive
!=from==and silently answerfalsefor every row. -
#*(other) ⇒ Expression
self * other. -
#**(exponent) ⇒ Expression
Integer powers 0, 1 and 2 only — a Quicopt model is linear or quadratic.
-
#+(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 a Quicopt model is a polynomial.
-
#<=(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
Quicopt has no "not equal to" constraint, and Ruby would otherwise derive
!= from == and silently answer false for every row.
148 149 150 151 152 153 154 |
# File 'lib/quicopt/model.rb', line 148 def !=(other) return !equal?(other) unless Expression.castable?(other) raise UnsupportedExpression, "!= is not a constraint Quicopt can express; model it with a binary " \ "variable and two big-M rows" end |
#*(other) ⇒ Expression
Returns self * other.
75 76 77 |
# File 'lib/quicopt/model.rb', line 75 def *(other) to_expr.times(Expression.cast(other)) end |
#**(exponent) ⇒ Expression
Integer powers 0, 1 and 2 only — a Quicopt model is linear or quadratic.
98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/quicopt/model.rb', line 98 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 not supported: a Quicopt model is " \ "linear or quadratic, so the exponent must be 0, 1 or 2" end end |
#+(other) ⇒ Expression
Returns +self + other+.
64 65 66 |
# File 'lib/quicopt/model.rb', line 64 def +(other) to_expr.plus(Expression.cast(other)) end |
#+@ ⇒ Expression
Returns self, unchanged.
116 117 118 |
# File 'lib/quicopt/model.rb', line 116 def +@ to_expr end |
#-(other) ⇒ Expression
Returns self - other.
69 70 71 |
# File 'lib/quicopt/model.rb', line 69 def -(other) to_expr.plus(Expression.cast(other).scale(-1.0)) end |
#-@ ⇒ Expression
Returns the negation of self.
111 112 113 |
# File 'lib/quicopt/model.rb', line 111 def -@ to_expr.scale(-1.0) end |
#/(divisor) ⇒ Expression
Division by a numeric constant only — dividing by an expression is not a polynomial, and a Quicopt model is a polynomial.
84 85 86 87 88 89 90 91 92 |
# File 'lib/quicopt/model.rb', line 84 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.
121 122 123 |
# File 'lib/quicopt/model.rb', line 121 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.
138 139 140 141 142 |
# File 'lib/quicopt/model.rb', line 138 def ==(other) return equal?(other) unless Expression.castable?(other) Constraint.build(self, other, :eq) end |
#>=(other) ⇒ Constraint
Returns the row self >= other.
126 127 128 |
# File 'lib/quicopt/model.rb', line 126 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+.
161 162 163 |
# File 'lib/quicopt/model.rb', line 161 def coerce(other) [Expression.cast(other), to_expr] end |