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) ⇒ Constraint, Boolean
A "not equal to" comparison, for
Quicopt.holdsonly:Model#addrefuses it as a 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
A strict comparison, for
Quicopt.holdsonly: no constraint row can be strict, soModel#addrefuses it. -
#<=(other) ⇒ Constraint
The row
self <= other. -
#==(other) ⇒ Constraint, Boolean
Builds an equality row, not a boolean —
x == 5is a constraint. -
#>(other) ⇒ Constraint
A strict comparison, for
Quicopt.holdsonly (see<). -
#>=(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) ⇒ Constraint, Boolean
A "not equal to" comparison, for Quicopt.holds only: Model#add refuses
it as a row. Defined so that Ruby does not derive != from == and
silently answer false.
168 169 170 171 172 |
# File 'lib/quicopt/model.rb', line 168 def !=(other) return !equal?(other) unless Expression.castable?(other) Constraint.build(self, other, :ne) end |
#*(other) ⇒ Expression
Returns self * other.
78 79 80 |
# File 'lib/quicopt/model.rb', line 78 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.
101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/quicopt/model.rb', line 101 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.
67 68 69 |
# File 'lib/quicopt/model.rb', line 67 def +(other) to_expr.plus(Expression.cast(other)) end |
#+@ ⇒ Expression
Returns self, unchanged.
119 120 121 |
# File 'lib/quicopt/model.rb', line 119 def +@ to_expr end |
#-(other) ⇒ Expression
Returns self - other.
72 73 74 |
# File 'lib/quicopt/model.rb', line 72 def -(other) to_expr.plus(Expression.cast(other).scale(-1.0)) end |
#-@ ⇒ Expression
Returns the negation of self.
114 115 116 |
# File 'lib/quicopt/model.rb', line 114 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.
87 88 89 90 91 92 93 94 95 |
# File 'lib/quicopt/model.rb', line 87 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
A strict comparison, for Quicopt.holds only: no constraint row can be
strict, so Model#add refuses it.
137 138 139 |
# File 'lib/quicopt/model.rb', line 137 def <(other) Constraint.build(self, other, :lt) end |
#<=(other) ⇒ Constraint
Returns the row self <= other.
124 125 126 |
# File 'lib/quicopt/model.rb', line 124 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.
157 158 159 160 161 |
# File 'lib/quicopt/model.rb', line 157 def ==(other) return equal?(other) unless Expression.castable?(other) Constraint.build(self, other, :eq) end |
#>(other) ⇒ Constraint
A strict comparison, for Quicopt.holds only (see <).
144 145 146 |
# File 'lib/quicopt/model.rb', line 144 def >(other) Constraint.build(self, other, :gt) end |
#>=(other) ⇒ Constraint
Returns the row self >= other.
129 130 131 |
# File 'lib/quicopt/model.rb', line 129 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.
180 181 182 |
# File 'lib/quicopt/model.rb', line 180 def coerce(other) [Expression.cast(other), to_expr] end |