Module: CompSci::Simplex::Parse

Defined in:
lib/compsci/simplex/parse.rb

Defined Under Namespace

Classes: Error, InvalidExpression, InvalidInequality, InvalidTerm

Constant Summary collapse

TERM_RGX =

coefficient concatenated with a single letter variable, e.g. “-1.23x”

%r{
  \A                  # starts with
    (-)?              # possible negative sign
    (\d+(?:\.\d*)?)?  # possible float (optional)
    ([a-zA-Z])        # single letter variable
  \z                  # end str
}x
CONSTANT_RGX =

a float or integer, possibly negative

%r{
  \A           # starts with
    -?         # possible negative sign
    \d+        # integer portion
    (?:\.\d*)? # possible decimal portion
  \z           # end str
}x

Class Method Summary collapse

Class Method Details

.expression(str) ⇒ Object

rules: variables are a single letter

may have a coefficient (default: 1.0)
only sum and difference operations allowed
normalize to all sums with possibly negative coefficients

valid inputs:

'x + y'          => [1.0, 1.0],         [:x, :y]
'2x - 5y'        => [2.0, -5.0],        [:x, :y]
'-2x - 3y + -4z' => [-2.0, -3.0, -4.0], [:x, :y, :z]

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/compsci/simplex/parse.rb', line 54

def self.expression(str)
  terms = self.tokenize(str)
  negative = false
  coefficients = {}
  while !terms.empty?
    # consume plus and minus operations
    term = terms.shift
    if term == '-'
      negative = true
      term = terms.shift
    elsif term == '+'
      negative = false
      term = terms.shift
    end

    coefficient, variable = self.term(term)
    raise("double variable: #{str}") if coefficients.key?(variable)
    coefficients[variable] = negative ? coefficient * -1 : coefficient
  end
  coefficients
end

.inequality(str) ⇒ Object

Raises:


28
29
30
31
32
33
34
35
36
37
38
# File 'lib/compsci/simplex/parse.rb', line 28

def self.inequality(str)
  lhs, rhs = str.split('<=')
  if lhs.nil? or lhs.empty? or rhs.nil? or rhs.empty?
    raise(InvalidInequality, "#{str}")
  end
  rht = self.tokenize(rhs)
  raise(InvalidInequality, "#{str}; bad rhs: #{rhs}") unless rht.size == 1
  c = rht.first
  raise(InvalidInequality, "bad rhs: #{rhs}") if !c.match CONSTANT_RGX
  return self.expression(lhs), c.to_f
end

.term(str) ⇒ Object

Raises:


76
77
78
79
80
81
82
# File 'lib/compsci/simplex/parse.rb', line 76

def self.term(str)
  matches = str.match TERM_RGX
  raise(InvalidTerm, str) unless matches
  flt = (matches[2] || 1).to_f * (matches[1] ? -1 : 1)
  sym = matches[3].to_sym # consider matches[3].downcase.to_sym
  return flt, sym
end

.tokenize(str) ⇒ Object

ignore leading and trailing spaces ignore multiple spaces


42
43
44
# File 'lib/compsci/simplex/parse.rb', line 42

def self.tokenize(str)
  str.strip.split(/\s+/)
end