compsci 0.1.1.1 → 0.2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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