compsci 0.1.1.1 → 0.2.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,291 @@
1
+ require 'minitest/autorun'
2
+ require 'compsci/simplex'
3
+
4
+ include CompSci
5
+
6
+ class SimplexTest < Minitest::Test
7
+ def test_2x2
8
+ result = Simplex.new(
9
+ [1, 1],
10
+ [
11
+ [ 2, 1],
12
+ [ 1, 2],
13
+ ],
14
+ [4, 3]
15
+ ).solution
16
+ assert_equal [Rational(5, 3), Rational(2, 3)], result
17
+ end
18
+
19
+ def test_2x2_b
20
+ result = Simplex.new(
21
+ [3, 4],
22
+ [
23
+ [ 1, 1],
24
+ [ 2, 1],
25
+ ],
26
+ [4, 5]
27
+ ).solution
28
+ assert_equal [0, 4], result
29
+ end
30
+
31
+ def test_2x2_c
32
+ result = Simplex.new(
33
+ [2, -1],
34
+ [
35
+ [ 1, 2],
36
+ [ 3, 2],
37
+ ],
38
+ [6, 12]
39
+ ).solution
40
+ assert_equal [4, 0], result
41
+ end
42
+
43
+ def test_3x3_a
44
+ result = Simplex.new(
45
+ [60, 90, 300],
46
+ [
47
+ [1, 1, 1],
48
+ [1, 3, 0],
49
+ [2, 0, 1]
50
+ ],
51
+ [600, 600, 900]
52
+ ).solution
53
+ assert_equal [0, 0, 600], result
54
+ end
55
+
56
+ def test_3x3_b
57
+ result = Simplex.new(
58
+ [70, 210, 140],
59
+ [
60
+ [ 1, 1, 1],
61
+ [ 5, 4, 4],
62
+ [40, 20, 30]
63
+ ],
64
+ [100, 480, 3200]
65
+ ).solution
66
+ assert_equal [0, 100, 0], result
67
+ end
68
+
69
+ def test_3x3_c
70
+ result = Simplex.new(
71
+ [2, -1, 2],
72
+ [
73
+ [ 2, 1, 0],
74
+ [ 1, 2, -2],
75
+ [ 0, 1, 2]
76
+ ],
77
+ [10, 20, 5]
78
+ ).solution
79
+ assert_equal [5, 0, Rational(5, 2)], result
80
+ end
81
+
82
+ def test_3x3_d
83
+ result = Simplex.new(
84
+ [11, 16, 15],
85
+ [
86
+ [ 1, 2, Rational(3, 2)],
87
+ [Rational(2, 3), Rational(2, 3), 1],
88
+ [Rational(1, 2), Rational(1, 3), Rational(1, 2)]
89
+ ],
90
+ [12_000, 4_600, 2_400]
91
+ ).solution
92
+ assert_equal [600, 5_100, 800], result
93
+ end
94
+
95
+ def test_3x3_e
96
+ simplex = Simplex.new(
97
+ [5, 4, 3],
98
+ [
99
+ [2, 3, 1],
100
+ [4, 1, 2],
101
+ [3, 4, 2]
102
+ ],
103
+ [5, 11, 8]
104
+ )
105
+ assert_equal [2, 0, 1], simplex.solution
106
+ end
107
+
108
+ def test_3x3_f
109
+ simplex = Simplex.new(
110
+ [3, 2, -4],
111
+ [
112
+ [1, 4, 0],
113
+ [2, 4,-2],
114
+ [1, 1,-2]
115
+ ],
116
+ [5, 6, 2]
117
+ )
118
+ assert_equal [4, 0, 1], simplex.solution
119
+ end
120
+
121
+ def test_3x3_g
122
+ simplex = Simplex.new(
123
+ [2, -1, 8],
124
+ [
125
+ [2, -4, 6],
126
+ [-1, 3, 4],
127
+ [0, 0, 2]
128
+ ],
129
+ [3, 2, 1]
130
+ )
131
+ assert_equal [Rational(17, 2), Rational(7,2), 0], simplex.solution
132
+ end
133
+
134
+ def test_3x4
135
+ result = Simplex.new(
136
+ [100_000, 40_000, 18_000],
137
+ [
138
+ [20, 6, 3],
139
+ [ 0, 1, 0],
140
+ [-1,-1, 1],
141
+ [-9, 1, 1]
142
+ ],
143
+ [182, 10, 0, 0]
144
+ ).solution
145
+ assert_equal [4, 10, 14], result
146
+ end
147
+
148
+ def test_4x4
149
+ result = Simplex.new(
150
+ [1, 2, 1, 2],
151
+ [
152
+ [1, 0, 1, 0],
153
+ [0, 1, 0, 1],
154
+ [1, 1, 0, 0],
155
+ [0, 0, 1, 1]
156
+ ],
157
+ [1, 4, 2, 2]
158
+ ).solution
159
+ assert_equal [0, 2, 0, 2], result
160
+ end
161
+
162
+ def test_cycle
163
+ result = Simplex.new(
164
+ [10, -57, -9, -24],
165
+ [
166
+ [0.5, -5.5, -2.5, 9],
167
+ [0.5, -1.5, -0.5, 1],
168
+ [ 1, 0, 0, 0]
169
+ ],
170
+ [0, 0, 1]
171
+ ).solution
172
+ assert_equal [1, 0, 1, 0], result
173
+ end
174
+
175
+ def test_cycle2
176
+ simplex = Simplex.new(
177
+ [2, 3, -1, -12],
178
+ [
179
+ [-2, -9, 1, 9],
180
+ [Rational(1, 3), 1, Rational(-1, 3), -2],
181
+ ],
182
+ [0, 0]
183
+ )
184
+ assert_raises Simplex::UnboundedProblem do
185
+ simplex.solution
186
+ end
187
+ end
188
+
189
+ def test_error_mismatched_dimensions
190
+ assert_raises ArgumentError do
191
+ Simplex.new(
192
+ [10, -57, -9],
193
+ [
194
+ [0.5, -5.5, -2.5, 9],
195
+ [0.5, -1.5, -0.5, 1],
196
+ [ 1, 0, 0, 0]
197
+ ],
198
+ [0, 0, 1]
199
+ )
200
+ end
201
+
202
+ assert_raises ArgumentError do
203
+ Simplex.new(
204
+ [10, -57, -9, 2],
205
+ [
206
+ [0.5, -5.5, 9, 4],
207
+ [0.5, -1.5, 1],
208
+ [ 1, 0, 0]
209
+ ],
210
+ [0, 0, 1]
211
+ )
212
+ end
213
+
214
+ assert_raises ArgumentError do
215
+ Simplex.new(
216
+ [10, -57, -9, 2],
217
+ [
218
+ [0.5, -5.5, 9, 4],
219
+ [0.5, -1.5, 1, 5],
220
+ [ 1, 0, 0, 5]
221
+ ],
222
+ [0, 1]
223
+ )
224
+ end
225
+ end
226
+
227
+ def test_manual_iteration
228
+ simplex = Simplex.new(
229
+ [10, -57, -9, -24],
230
+ [
231
+ [0.5, -5.5, -2.5, 9],
232
+ [0.5, -1.5, -0.5, 1],
233
+ [ 1, 0, 0, 0]
234
+ ],
235
+ [0, 0, 1]
236
+ )
237
+ while simplex.can_improve?
238
+ assert simplex.formatted_tableau.is_a?(String)
239
+ simplex.pivot
240
+ end
241
+ result = simplex.solution
242
+ assert_equal [1, 0, 1, 0], result
243
+ end
244
+
245
+ def test_cup_factory
246
+ result = Simplex.new(
247
+ [25, 20],
248
+ [
249
+ [20, 12],
250
+ [1, 1]
251
+ ],
252
+ [1800, 8*15]
253
+ )
254
+ assert_equal [45, 75], result.solution
255
+ end
256
+
257
+ #def test_infeasible1
258
+ # simplex = Simplex.new(
259
+ # [2, -1],
260
+ # [
261
+ # [1, -1],
262
+ # [-1, 1]
263
+ # ],
264
+ # [1, -2]
265
+ # )
266
+ # while simplex.can_improve?
267
+ # puts
268
+ # puts simplex.formatted_tableau
269
+ # simplex.pivot
270
+ # end
271
+ # p :done
272
+ # puts
273
+ # puts simplex.formatted_tableau
274
+
275
+ #end
276
+
277
+ def test_unbounded
278
+ simplex = Simplex.new(
279
+ [1, 1, 1],
280
+ [
281
+ [3, 1, -2],
282
+ [4, 3, 0]
283
+ ],
284
+ [5, 7]
285
+ )
286
+ assert_raises Simplex::UnboundedProblem do
287
+ simplex.solution
288
+ end
289
+ end
290
+
291
+ end
@@ -0,0 +1,94 @@
1
+ require 'compsci/simplex/parse'
2
+ require 'minitest/autorun'
3
+
4
+ include CompSci
5
+
6
+ describe Simplex::Parse do
7
+ P = Simplex::Parse
8
+
9
+ describe "Parse.term" do
10
+ it "must parse valid terms" do
11
+ { "-1.2A" => [-1.2, :A],
12
+ "99x" => [99.0, :x],
13
+ "z" => [ 1.0, :z],
14
+ "-b" => [-1.0, :b] }.each { |valid, expected|
15
+ P.term(valid).must_equal expected
16
+ }
17
+ end
18
+
19
+ it "must reject invalid terms" do
20
+ ["3xy", "24/7x", "x17", "2*x"].each { |invalid|
21
+ proc { P.term(invalid) }.must_raise RuntimeError
22
+ }
23
+ end
24
+ end
25
+
26
+ describe "Parse.expression" do
27
+ it "must parse valid expressions" do
28
+ { "x + y" => { x: 1.0, y: 1.0 },
29
+ "2x - 5y" => { x: 2.0, y: -5.0 },
30
+ "-2x - 3y + -42.7z" => { x: -2.0, y: -3.0, z: -42.7 },
31
+ " -5y + -x " => { y: -5.0, x: -1.0 },
32
+ "a - -b" => { a: 1.0, b: 1.0 },
33
+ "a A b" => { a: 1.0, :A => 1.0, b: 1.0 },
34
+ }.each { |valid, expected|
35
+ P.expression(valid).must_equal expected
36
+ }
37
+ end
38
+
39
+ it "must reject invalid expressions" do
40
+ ["a2 + b2 = c2",
41
+ "x + xy",
42
+ "x * 2"].each { |invalid|
43
+ proc { P.expression(invalid) }.must_raise P::Error
44
+ }
45
+ end
46
+ end
47
+
48
+ describe "Parse.tokenize" do
49
+ it "ignores leading or trailing whitespace" do
50
+ P.tokenize(" 5x + 2.9y ").must_equal ["5x", "+", "2.9y"]
51
+ end
52
+
53
+ it "ignores multiple spaces" do
54
+ P.tokenize("5x + 2.9y").must_equal ["5x", "+", "2.9y"]
55
+ end
56
+ end
57
+
58
+ describe "Parse.inequality" do
59
+ it "must parse valid inequalities" do
60
+ { "x + y <= 4" => [{ x: 1.0, y: 1.0 }, 4.0],
61
+ "0.94a - 22.1b <= -14.67" => [{ a: 0.94, b: -22.1 }, -14.67],
62
+ "x <= 0" => [{ x: 1.0 }, 0],
63
+ }.each { |valid, expected|
64
+ P.inequality(valid).must_equal expected
65
+ }
66
+ end
67
+
68
+ it "must reject invalid inequalities" do
69
+ ["x + y >= 4",
70
+ "0.94a - 22.1b <= -14.67c",
71
+ "x < 0",
72
+ ].each { |invalid|
73
+ proc { P.inequality(invalid) }.must_raise P::Error
74
+ }
75
+ end
76
+ end
77
+ end
78
+
79
+ describe "Simplex.maximize" do
80
+ it "must problem stuff" do
81
+ prob = Simplex.problem(maximize: 'x + y',
82
+ constraints: ['2x + y <= 4',
83
+ 'x + 2y <= 3'])
84
+ sol = prob.solution
85
+ sol.must_equal [Rational(5, 3), Rational(2, 3)]
86
+ end
87
+
88
+ it "must maximize stuff" do
89
+ Simplex.maximize('x + y',
90
+ '2x + y <= 4',
91
+ 'x + 2y <= 3').must_equal [Rational(5, 3),
92
+ Rational(2, 3)]
93
+ end
94
+ end
@@ -1,3 +1,4 @@
1
+ require 'compsci/node'
1
2
  require 'compsci/tree'
2
3
  require 'minitest/autorun'
3
4
 
@@ -5,7 +6,7 @@ include CompSci
5
6
 
6
7
  describe Tree do
7
8
  before do
8
- @tree = Tree.new(Node, 42)
9
+ @tree = Tree.new(FlexNode, 42)
9
10
  @vals = Array.new(99) { rand 99 }
10
11
  end
11
12
 
@@ -16,7 +17,7 @@ describe Tree do
16
17
 
17
18
  it "does depth_first search" do
18
19
  vals = (0..30).to_a
19
- tree = Tree.new(Node, vals.shift)
20
+ tree = Tree.new(FlexNode, vals.shift)
20
21
  tree.root.new_child vals.shift
21
22
  tree.root.new_child vals.shift
22
23
  tree.root.children.each { |c|
@@ -40,7 +41,7 @@ describe Tree do
40
41
 
41
42
  it "does breadth_first search" do
42
43
  vals = (0..30).to_a
43
- tree = Tree.new(Node, vals.shift)
44
+ tree = Tree.new(FlexNode, vals.shift)
44
45
  tree.root.new_child vals.shift
45
46
  tree.root.new_child vals.shift
46
47
  tree.root.children.each { |c|
@@ -64,9 +65,32 @@ describe Tree do
64
65
  end
65
66
 
66
67
  describe NaryTree do
67
- describe "with Node" do
68
+ it "must power_of?" do
69
+ powers = {}
70
+ basemax = 12
71
+ expmax = 10
72
+ 2.upto(basemax) { |base|
73
+ 0.upto(expmax) { |exp|
74
+ powers[base] ||= []
75
+ powers[base] << base**exp
76
+ }
77
+ }
78
+
79
+ # 12k assertions below!
80
+ 2.upto(basemax) { |base|
81
+ 1.upto(2**expmax) { |num|
82
+ if powers[base].include?(num)
83
+ NaryTree.power_of?(num, base).must_equal true
84
+ else
85
+ NaryTree.power_of?(num, base).must_equal false
86
+ end
87
+ }
88
+ }
89
+ end
90
+
91
+ describe "with FlexNode" do
68
92
  before do
69
- @tree = NaryTree.new(Node, 42, child_slots: 3)
93
+ @tree = NaryTree.new(FlexNode, 42, child_slots: 3)
70
94
  end
71
95
 
72
96
  it "must have an open parent" do
@@ -82,9 +106,9 @@ describe NaryTree do
82
106
  end
83
107
  end
84
108
 
85
- describe "with ChildNode" do
109
+ describe "with ChildFlexNode" do
86
110
  before do
87
- @tree = NaryTree.new(ChildNode, 42, child_slots: 4)
111
+ @tree = NaryTree.new(ChildFlexNode, 42, child_slots: 4)
88
112
  end
89
113
 
90
114
  it "must have an open parent" do
@@ -103,7 +127,7 @@ end
103
127
 
104
128
  describe "BinaryTree" do
105
129
  before do
106
- @tree = BinaryTree.new(Node, 42)
130
+ @tree = BinaryTree.new(FlexNode, 42)
107
131
  end
108
132
 
109
133
  it "must have 2 child_slots" do
@@ -121,7 +145,7 @@ describe "BinaryTree" do
121
145
 
122
146
  describe "searching" do
123
147
  before do
124
- @tree = NaryTree.new(Node, 42, child_slots: 2)
148
+ @tree = NaryTree.new(FlexNode, 42, child_slots: 2)
125
149
  99.times { |i| @tree.push i }
126
150
  end
127
151