Class: RubyChem::Equation

Inherits:
Object
  • Object
show all
Defined in:
lib/rubychem/equation.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(equation) ⇒ Equation

Checks if two formulas are balanced. Takes user input.. such as x + y + z = a + b yields @left[Chemical1, Chemical2, Chemical3], @right



10
11
12
13
14
15
16
# File 'lib/rubychem/equation.rb', line 10

def initialize(equation)
	@left = Array.new
	@right = Array.new
  
  left_and_right = equation.split(/\=/)
  process_equation_string(left_and_right)
end

Instance Attribute Details

#arrayObject

Returns the value of attribute array.



4
5
6
# File 'lib/rubychem/equation.rb', line 4

def array
  @array
end

#balancedObject

Returns the value of attribute balanced.



4
5
6
# File 'lib/rubychem/equation.rb', line 4

def balanced
  @balanced
end

#leftObject

Returns the value of attribute left.



4
5
6
# File 'lib/rubychem/equation.rb', line 4

def left
  @left
end

#left_system_of_equationsObject

Returns the value of attribute left_system_of_equations.



4
5
6
# File 'lib/rubychem/equation.rb', line 4

def left_system_of_equations
  @left_system_of_equations
end

#left_totalObject

Returns the value of attribute left_total.



4
5
6
# File 'lib/rubychem/equation.rb', line 4

def left_total
  @left_total
end

#rightObject

Returns the value of attribute right.



4
5
6
# File 'lib/rubychem/equation.rb', line 4

def right
  @right
end

#right_system_of_equationsObject

Returns the value of attribute right_system_of_equations.



4
5
6
# File 'lib/rubychem/equation.rb', line 4

def right_system_of_equations
  @right_system_of_equations
end

#right_totalObject

Returns the value of attribute right_total.



4
5
6
# File 'lib/rubychem/equation.rb', line 4

def right_total
  @right_total
end

#search_orderObject

Returns the value of attribute search_order.



4
5
6
# File 'lib/rubychem/equation.rb', line 4

def search_order
  @search_order
end

Instance Method Details

#apply_solved_equivalent_fractions_to_fractionObject

Now that we have the whole number from solve_equivalent_fractions we must apply that to each of the fractions to solve for the balanced equation



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/rubychem/equation.rb', line 172

def apply_solved_equivalent_fractions_to_fraction
  int = self.solve_equivalent_fractions
  answer = []
  @reduced_row_echelon_form.each do |row|
    answer << row.last * int
  end
  answer << int
  count = 0
  @balanced = Hash.new
  @left_system_of_equations.each do |x,v|
    answer[count]
    @left_system_of_equations[x] = answer[count].to_i.abs unless answer[count].nil?
    count += 1
  end
  @right_system_of_equations.each do |x,v|
    answer[count]
    @right_system_of_equations[x] = answer[count].to_i.abs unless answer[count].nil?
    count += 1
  end
  answer
  @balanced = {left:@left_system_of_equations,right:@right_system_of_equations}
  self.balanced_string
end

#assign_coeficients_to_part_system_of_equations(part, atom_to_search) ⇒ Object



108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/rubychem/equation.rb', line 108

def assign_coeficients_to_part_system_of_equations(part,atom_to_search)
    chemicals =  part.keys
    chemicals.each do |chemical|
      @search_order << chemical
      # look at the Chemical
      chemical.chem_species.each do |atom|
      # Does the chemical have the atom we are looking for?
      if atom_to_search == atom[0] 
        part[chemical] = atom[1]
      end
    end
  end
end

#assign_coeficients_to_system_of_equationsObject

  1. determnie instances on left and right of each atom, and assign those to coeficients

C12H26 + O2 = CO2 + H2O O = + 1dā€ O = ā€œ2b=2c+1dā€



94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/rubychem/equation.rb', line 94

def assign_coeficients_to_system_of_equations
  self.list_atoms
  atom_list = self.left_total.merge(self.right_total)
  # Get the Chemical list
  atom_list.keys.each do |atom|

    self.set_up_system_of_equations
    assign_coeficients_to_part_system_of_equations(@right_system_of_equations,atom)
    assign_coeficients_to_part_system_of_equations(@left_system_of_equations,atom)
    subtract_right_side
    write_matrix
  end
end

#balanceObject



145
146
147
148
149
150
151
152
# File 'lib/rubychem/equation.rb', line 145

def balance
  @search_order = Array.new
  @array = Array.new
  @reduced_row_echelon_form = Array.new
  self.assign_coeficients_to_system_of_equations
  @reduced_row_echelon_form = self.reduced_row_echelon_form(@array)
  self.apply_solved_equivalent_fractions_to_fraction
end

#balanced_stringObject



196
197
198
199
200
201
202
203
204
# File 'lib/rubychem/equation.rb', line 196

def balanced_string
  array_of_strings = Array.new
  @balanced[:left].each{|x,y|array_of_strings << (x.chem_species.unshift(y).join);x.chem_species.shift}
  left = array_of_strings.join(" + ")
  array_of_strings = []
  @balanced[:right].each{|x,y|array_of_strings << (x.chem_species.unshift(y).join);x.chem_species.shift}
  right = array_of_strings.join(" + ")
  left + " = " + right
end

#convert_to(ary, type) ⇒ Object

type should be one of :to_s, :to_i, :to_f, :to_r



250
251
252
253
254
255
256
# File 'lib/rubychem/equation.rb', line 250

def convert_to(ary, type)
  new = []
  ary.each_index do |row|
    new << ary[row].collect {|elem| elem.send(type)}
  end
  new
end

#convert_to_rational(ary) ⇒ Object



241
242
243
244
245
246
247
# File 'lib/rubychem/equation.rb', line 241

def convert_to_rational(ary)
  new = []
  ary.each_index do |row|
    new << ary[row].collect {|elem| Rational(elem)}
  end
  new
end

#instantiate_chemical_object_from_string(equation, side) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
# File 'lib/rubychem/equation.rb', line 23

def instantiate_chemical_object_from_string(equation, side)	
 if side == "left"
   equation.split(/\+/).each do |chemical|
     @left << RubyChem::Chemical.new(chemical.strip)     
    end
  else
  	equation.split(/\+/).each do |chemical|
     @right << RubyChem::Chemical.new(chemical.strip)     
    end
  end  
end

#is_balanced?Boolean

Returns:

  • (Boolean)


58
59
60
61
62
63
# File 'lib/rubychem/equation.rb', line 58

def is_balanced?
   @right_total.each_key do |key|
    @balanced = @right_total[key] == @left_total[key]
   end
   @balanced
end

#list_atomsObject

add up all atoms, on each side left = Na:1,Cl:2 right = Na:2,Cl:4



39
40
41
42
43
44
# File 'lib/rubychem/equation.rb', line 39

def list_atoms
  @left_total = Hash.new
  @right_total = Hash.new
  list_part(@left, @left_total)
  list_part(@right, @right_total)
end

#list_part(part, total) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
# File 'lib/rubychem/equation.rb', line 46

def list_part(part, total)
  part.each do |chemical|
    chemical.chem_species.each do |atom|
      if total[atom[0]].nil?
        total[atom[0]] = atom[1]
      else
        total[atom[0]] += atom[1]
      end
    end
  end
end

#part_set_up_system_of_equations(part, total) ⇒ Object



83
84
85
86
87
# File 'lib/rubychem/equation.rb', line 83

def part_set_up_system_of_equations(part,total)
  part.each do |key|
    total[key] = 0
  end
end


258
259
260
261
262
# File 'lib/rubychem/equation.rb', line 258

def print_matrix(m)
  max = m[0].collect {-1}
  m.each {|row| row.each_index {|i| max[i] = [max[i], row[i].to_s.length].max}}
  m.each {|row| row.each_index {|i| print "%#{max[i]}s " % row[i].to_s}; puts ""}
end

#process_equation_string(left_and_right) ⇒ Object



18
19
20
21
# File 'lib/rubychem/equation.rb', line 18

def process_equation_string(left_and_right)
  instantiate_chemical_object_from_string(left_and_right[0], "left")
  instantiate_chemical_object_from_string(left_and_right[1], "right")
end

#reduced_row_echelon_form(ary) ⇒ Object

returns an 2-D array where each element is a Rational



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/rubychem/equation.rb', line 207

def reduced_row_echelon_form(ary)
  lead = 0
  rows = ary.size
  cols = ary[0].size
  rary = convert_to_rational(ary)  # use rational arithmetic
  catch :done  do
    rows.times do |r|
    throw :done  if cols <= lead
      i = r
      while rary[i][lead] == 0
        i += 1
        if rows == i
          i = r
          lead += 1
          throw :done  if cols == lead
        end
      end
      # swap rows i and r 
      rary[i], rary[r] = rary[r], rary[i]
      # normalize row r
      v = rary[r][lead]
      rary[r].collect! {|x| x /= v}
      # reduce other rows
      rows.times do |i|
        next if i == r
        v = rary[i][lead]
        rary[i].each_index {|j| rary[i][j] -= v * rary[r][j]}
      end
      lead += 1
    end
  end
  rary
end

#set_up_system_of_equationsObject

System of Equations setup

  1. Assign unknown coeficients

C12H26 + O2 = CO2 + H2O aC12H26 + bO2 = cCO2 + dH2O



76
77
78
79
80
81
# File 'lib/rubychem/equation.rb', line 76

def set_up_system_of_equations
  @right_system_of_equations = Hash.new
  @left_system_of_equations = Hash.new
  part_set_up_system_of_equations(@right,@right_system_of_equations)
  part_set_up_system_of_equations(@left,@left_system_of_equations)
end

#solve_equivalent_fractionsObject

from the reduced row echelon form we are left with a set of equivalent fractions to transform into a whole number we do this by using the gcdlcm method



158
159
160
161
162
163
164
165
166
# File 'lib/rubychem/equation.rb', line 158

def solve_equivalent_fractions
  last = 0
  array = Array.new
  @reduced_row_echelon_form.each do |x|
     array = last.gcdlcm(x.last.denominator)
     last = x.last.denominator
  end
  array.max
end

#subtract_right_sideObject



122
123
124
125
126
# File 'lib/rubychem/equation.rb', line 122

def subtract_right_side
  self.right_system_of_equations.each do |k,v|
    self.right_system_of_equations[k] = v *= -1
  end
end

#write_matrixObject

  1. Rearrange the system of equations and write it in a matrix

a   b   c  d

O 0 2 -2 -1

[0,2,-2,-1]


133
134
135
136
137
138
139
140
141
142
# File 'lib/rubychem/equation.rb', line 133

def write_matrix
  array = Array.new
  @left_system_of_equations.keys.each do |key|
    array << @left_system_of_equations[key]
  end
  @right_system_of_equations.keys.each do |key|
    array  <<  @right_system_of_equations[key]
  end
   @array << array
end