amor 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/amor.gemspec +27 -0
- data/amor.sublime-project +14 -0
- data/bin/amor +5 -0
- data/lib/amor/constraint.rb +37 -0
- data/lib/amor/expression.rb +92 -0
- data/lib/amor/model.rb +65 -0
- data/lib/amor/numeric_extensions.rb +57 -0
- data/lib/amor/objective.rb +17 -0
- data/lib/amor/variable.rb +47 -0
- data/lib/amor/version.rb +3 -0
- data/lib/amor.rb +3 -0
- data/spec/amor/constraint_spec.rb +35 -0
- data/spec/amor/expression_spec.rb +275 -0
- data/spec/amor/model_spec.rb +120 -0
- data/spec/amor/numeric_extensions_spec.rb +83 -0
- data/spec/amor/objective_spec.rb +14 -0
- data/spec/amor/variable_spec.rb +140 -0
- data/spec/spec_helper.rb +89 -0
- metadata +148 -0
@@ -0,0 +1,275 @@
|
|
1
|
+
require 'amor/expression'
|
2
|
+
|
3
|
+
module Amor
|
4
|
+
describe Expression do
|
5
|
+
before(:each) do
|
6
|
+
@variable = double('Variable')
|
7
|
+
@expression = Expression.new([[2, @variable]])
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '.new' do
|
11
|
+
context 'when used with another Expression' do
|
12
|
+
before(:each) do
|
13
|
+
@other_variable = double('Variable')
|
14
|
+
@other_expression = Expression.new([[3.0, @other_variable]])
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'Copys the Expression' do
|
18
|
+
expect(Expression.new(@other_expression).factors).to eq(@other_expression.factors)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when used with an Array of factors' do
|
23
|
+
before(:each) do
|
24
|
+
@factors = [[3.0, double('Variable')]]
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'Creates an Expression with the given factors' do
|
28
|
+
expect(Expression.new(@factors).factors).to eq(@factors)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when used with a Variable' do
|
33
|
+
before(:each) do
|
34
|
+
@variable = Variable.new(double('Model'),1)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'Creates an Expression with the given variable as factor with scalar 1' do
|
38
|
+
expect(Expression.new(@variable).factors).to eq([[1, @variable]])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
[-3, -3.0].each do |number|
|
43
|
+
context "when used with a #{number.class}" do
|
44
|
+
it 'Creates an Expression with the given number as a constant factor' do
|
45
|
+
expect(Expression.new(number).factors).to eq([[number, :constant]])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#+' do
|
53
|
+
context 'when used with another Expression' do
|
54
|
+
before(:each) do
|
55
|
+
@other_variable = double('Other Variable')
|
56
|
+
@other_expression = Expression.new([[3.0, @other_variable]])
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'returns an Expression' do
|
60
|
+
expect(@expression + @other_expression).to be_a(Expression)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'returns an Expression with the combined factors of both Expressions' do
|
64
|
+
expect((@expression + @other_expression).factors).to eq([[2, @variable], [3.0, @other_variable]])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'when used with a variable' do
|
69
|
+
before(:each) do
|
70
|
+
@other_variable = Variable.new(double('Model'),1)
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'returns an Expression' do
|
74
|
+
expect(@expression + @other_variable).to be_a(Expression)
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'returns an Expression with the factor of the variable set to 1' do
|
78
|
+
expect((@expression + @other_variable).factors).to eq([[2, @variable], [1, @other_variable]])
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
[4, 4.0].each do |number|
|
83
|
+
context "when used with a #{number.class}" do
|
84
|
+
it 'returns an Expression' do
|
85
|
+
expect(@expression + number).to be_a(Expression)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'returns an Expression with the the last factor set to the corresponding constant' do
|
89
|
+
expect((@expression + number).factors).to eq([[2, @variable], [number, :constant]])
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe '#-' do
|
96
|
+
context 'when used with another Expression' do
|
97
|
+
before(:each) do
|
98
|
+
@other_variable = double('Other Variable')
|
99
|
+
@other_expression = Expression.new([[3.0, @other_variable]])
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'returns an Expression' do
|
103
|
+
expect(@expression - @other_expression).to be_a(Expression)
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'returns an Expression with the combined factors of the first Expression and the negative second Expression' do
|
107
|
+
expect((@expression - @other_expression).factors).to eq([[2, @variable], [-3.0, @other_variable]])
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'when used with a variable' do
|
112
|
+
before(:each) do
|
113
|
+
@other_variable = Variable.new(double('Model'),1)
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'returns an Expression' do
|
117
|
+
expect(@expression - @other_variable).to be_a(Expression)
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'returns an Expression with the factor of the variable set to -1' do
|
121
|
+
expect((@expression - @other_variable).factors).to eq([[2, @variable], [-1, @other_variable]])
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
[4, 4.0].each do |number|
|
126
|
+
context "when used with a #{number.class}" do
|
127
|
+
it 'returns an Expression' do
|
128
|
+
expect(@expression - number).to be_a(Expression)
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'returns an Expression with the the last factor set to the corresponding negative constant' do
|
132
|
+
expect((@expression - number).factors).to eq([[2, @variable], [-number, :constant]])
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe '#-@' do
|
139
|
+
it 'returns an Expression' do
|
140
|
+
expect(-@expression).to be_a(Expression)
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'returns an Expression with the negative factors' do
|
144
|
+
expect((-@expression).factors).to eq([[-2, @variable]])
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe '#<=' do
|
149
|
+
context 'when used with another Expression' do
|
150
|
+
before(:each) do
|
151
|
+
@other_expression = Expression.new(5.0)
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'returns a Constraint' do
|
155
|
+
expect(@expression <= @other_expression).to be_a(Constraint)
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'sets the Constraints relation to :lesser_equal' do
|
159
|
+
expect((@expression <= @other_expression).relation).to eq(:lesser_equal)
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'sets the lhs of the Constraint to self' do
|
163
|
+
expect((@expression <= @other_expression).lhs).to eql(@expression)
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'sets the rhs of the Constraint to the other Expression' do
|
167
|
+
expect((@expression <= @other_expression).rhs).to eql(@other_expression)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
describe '#>=' do
|
173
|
+
context 'when used with another Expression' do
|
174
|
+
before(:each) do
|
175
|
+
@other_expression = Expression.new(5.0)
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'returns a Constraint' do
|
179
|
+
expect(@expression >= @other_expression).to be_a(Constraint)
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'sets the Constraints relation to :greater_equal' do
|
183
|
+
expect((@expression >= @other_expression).relation).to eq(:greater_equal)
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'sets the lhs of the Constraint to self' do
|
187
|
+
expect((@expression >= @other_expression).lhs).to eql(@expression)
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'sets the rhs of the Constraint to the other Expression' do
|
191
|
+
expect((@expression >= @other_expression).rhs).to eql(@other_expression)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
describe '#==' do
|
197
|
+
context 'when used with another Expression' do
|
198
|
+
before(:each) do
|
199
|
+
@other_expression = Expression.new(5.0)
|
200
|
+
end
|
201
|
+
|
202
|
+
it 'returns a Constraint' do
|
203
|
+
expect(@expression == @other_expression).to be_a(Constraint)
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'sets the Constraints relation to :greater_equal' do
|
207
|
+
expect((@expression == @other_expression).relation).to eq(:equal)
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'sets the lhs of the Constraint to self' do
|
211
|
+
expect((@expression == @other_expression).lhs).to eql(@expression)
|
212
|
+
end
|
213
|
+
|
214
|
+
it 'sets the rhs of the Constraint to the other Expression' do
|
215
|
+
expect((@expression == @other_expression).rhs).to eql(@other_expression)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
describe '#simplified' do
|
221
|
+
it 'returns an Expression' do
|
222
|
+
expect(Expression.new(1).simplified).to be_a(Expression)
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'returns the Expression with no dupplications in the factors' do
|
226
|
+
v1 = double('Variable')
|
227
|
+
v2 = double('Variable')
|
228
|
+
v3 = double('Variable')
|
229
|
+
factors = Expression.new([[3, v1], [-2.0, v2], [-1, v1], [2, :constant], [2.5, v3], [1, v2], [-2.0, :constant], [3, :constant], [-2.5, v3]]).simplified.factors
|
230
|
+
expect(factors).to include([2, v1])
|
231
|
+
expect(factors).to include([-1.0, v2])
|
232
|
+
expect(factors).to include([3.0, :constant])
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'returns an Expression where no factors with scalar 0 appear' do
|
236
|
+
v1 = double('Variable')
|
237
|
+
v2 = double('Variable')
|
238
|
+
v3 = double('Variable')
|
239
|
+
expect(Expression.new([[3, v1], [-2.0, v2], [-1, v1], [2, :constant], [2.5, v3], [1, v2], [-2.0, :constant], [3, :constant], [-2.5, v3]]).simplified.factors.flatten).not_to include(v3)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
describe '#remove_constants' do
|
244
|
+
it 'returns an Expression containing all but the constant factors' do
|
245
|
+
model = Model.new
|
246
|
+
v1 = model.x(1)
|
247
|
+
v2 = model.x(2)
|
248
|
+
v3 = model.x(3)
|
249
|
+
factors = Expression.new([[3, v1], [-2.0, v2], [-1, v1], [2, :constant], [2.5, v3], [1, v2], [-2.0, :constant], [3, :constant], [-2.5, v3]]).remove_constants.factors
|
250
|
+
expect(factors).to eq([[3, v1], [-2.0, v2], [-1, v1], [2.5, v3], [1, v2], [-2.5, v3]])
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
describe '#constant_factor' do
|
255
|
+
it 'returns the total constant factor' do
|
256
|
+
model = Model.new
|
257
|
+
v1 = model.x(1)
|
258
|
+
v2 = model.x(2)
|
259
|
+
v3 = model.x(3)
|
260
|
+
expect(Expression.new([[3, v1], [-2.0, v2], [-1, v1], [2, :constant], [2.5, v3], [1, v2], [-2.0, :constant], [3, :constant], [-2.5, v3]]).constant_factor).to eq(3.0)
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
describe '#lp_string' do
|
265
|
+
it 'returns a string representation feasible for the LP file format' do
|
266
|
+
model = Model.new
|
267
|
+
v1 = model.x(1)
|
268
|
+
v2 = model.x(2)
|
269
|
+
v3 = model.x(3)
|
270
|
+
expect(Expression.new([[3, v1], [-2.0, v2], [-1, v1], [2, :constant], [2.5, v3], [1, v2], [-2.0, :constant], [3, :constant], [-2.5, v3]]).lp_string).to eq('2 x1 - 1.0 x2 + 3.0')
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|
275
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'amor/model'
|
2
|
+
|
3
|
+
module Amor
|
4
|
+
describe Model do
|
5
|
+
before(:each) do
|
6
|
+
@model = Model.new
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#x' do
|
10
|
+
it 'returns a variable' do
|
11
|
+
expect(@model.x(1)).to be_a(Variable)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'returns the same variable for the same indices' do
|
15
|
+
expect(@model.x(1)).to equal(@model.x(1))
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'returns different variables for different indices' do
|
19
|
+
expect(@model.x(1)).not_to equal(@model.x(2))
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'stores the model in the variable' do
|
23
|
+
expect(@model.x(1).model).to equal(@model)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'stores the index in the variable' do
|
27
|
+
expect(@model.x(1).index).to equal(1)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#min' do
|
32
|
+
before(:each) do
|
33
|
+
@expression = Expression.new([[3, double('Variable')], [-2, double('Variable')]])
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'returns an Objective' do
|
37
|
+
expect(@model.min(@expression)).to be_a(Objective)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'returns an Objective with the direction set to :min' do
|
41
|
+
expect(@model.min(@expression).direction).to eq(:minimize)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'returns an Objective with the expression set to the given Expression' do
|
45
|
+
expect(@model.min(@expression).expression).to eql(@expression)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'stores the objective in the model' do
|
49
|
+
objective = @model.min(@expression)
|
50
|
+
expect(@model.objective).to equal(objective)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#max' do
|
55
|
+
before(:each) do
|
56
|
+
@expression = Expression.new([[3, double('Variable')], [-2, double('Variable')]])
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'returns an Objective' do
|
60
|
+
expect(@model.max(@expression)).to be_a(Objective)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'returns an Objective with the direction set to :max' do
|
64
|
+
expect(@model.max(@expression).direction).to eq(:maximize)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'returns an Objective with the expression set to the given Expression' do
|
68
|
+
expect(@model.max(@expression).expression).to eql(@expression)
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'stores the objective in the model' do
|
72
|
+
objective = @model.max(@expression)
|
73
|
+
expect(@model.objective).to equal(objective)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe '#st' do
|
78
|
+
before(:each) do
|
79
|
+
@constraint = Constraint.new(1, :greater_equal, Variable.new(double('Model'), 1))
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'returns the given Constraint' do
|
83
|
+
expect(@model.st(@constraint)).to equal(@constraint)
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'stores the constraint in the model' do
|
87
|
+
@model.st(@constraint)
|
88
|
+
expect(@model.constraints).to include(@constraint)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
describe '.from_string' do
|
94
|
+
before(:each) do
|
95
|
+
@string = "min x(3) + 3 * x(2) + 4.0\nst x(2) - 2.0 * x(3) <= 5.0"
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'returns a Model' do
|
99
|
+
expect(Model.from_string(@string)).to be_a(Model)
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'returns a Model with the specified objective' do
|
103
|
+
model = Model.from_string(@string)
|
104
|
+
expect(model.objective.expression.factors).to eq([[1, model.x(3)], [3, model.x(2)], [4.0, :constant]])
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'returns a Model with the specified constraint' do
|
108
|
+
model = Model.from_string(@string)
|
109
|
+
expect(model.constraints[0].lhs.factors).to eq([[1, model.x(2)], [-2.0, model.x(3)]])
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe '.lp_string' do
|
114
|
+
it 'returns a LP Format ready string of the model' do
|
115
|
+
model = Model.from_string("min x(3) + 3 * x(2) + 4.0\nst x(2) - 2.0 * x(3) <= 5.0")
|
116
|
+
expect(model.lp_string).to eq("Minimize\n obj: 1 x1 + 3 x2 + 4.0\nSubject To\n c1: 1 x2 - 2.0 x1 <= 5.0\nEnd")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'amor/numeric_extensions'
|
2
|
+
|
3
|
+
module Amor
|
4
|
+
[5, 5.0].each do |number|
|
5
|
+
describe "#{number.class}" do
|
6
|
+
describe '#*' do
|
7
|
+
context 'when used with a variable' do
|
8
|
+
before(:each) do
|
9
|
+
@variable = Variable.new(double('Model'), 1)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'returns an Expression' do
|
13
|
+
expect(number * @variable).to be_a(Expression)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'returns an Expression with the factor of the variable set to the number' do
|
17
|
+
expect((number * @variable).factors).to eq([[number, @variable]])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#+' do
|
23
|
+
context 'when used with an expression' do
|
24
|
+
before(:each) do
|
25
|
+
@variable = double('Variable')
|
26
|
+
@expression = Expression.new([[2.0, @variable]])
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'returns an Expression' do
|
30
|
+
expect(number + @expression).to be_a(Expression)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'returns an Expression with the first factor set to the constant' do
|
34
|
+
expect((number + @expression).factors).to eq([[number, :constant], [2.0, @variable]])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'when used with a variable' do
|
39
|
+
before(:each) do
|
40
|
+
@variable = Variable.new(double('Model'), 1)
|
41
|
+
end
|
42
|
+
it 'returns an Expression' do
|
43
|
+
expect(number + @variable).to be_a(Expression)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'returns an Expression with the first factor set to the constant and the second to the variable with scalar 1' do
|
47
|
+
expect((number + @variable).factors).to eq([[number, :constant], [1, @variable]])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#-' do
|
53
|
+
context 'when used with an expression' do
|
54
|
+
before(:each) do
|
55
|
+
@variable = double('Variable')
|
56
|
+
@expression = Expression.new([[2.0, @variable]])
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'returns an Expression' do
|
60
|
+
expect(number - @expression).to be_a(Expression)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'returns an Expression with the first factor set to the constant and the second to the negative Expression' do
|
64
|
+
expect((number - @expression).factors).to eq([[number, :constant], [-2.0, @variable]])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'when used with a variable' do
|
69
|
+
before(:each) do
|
70
|
+
@variable = Variable.new(double('Model'), 1)
|
71
|
+
end
|
72
|
+
it 'returns an Expression' do
|
73
|
+
expect(number - @variable).to be_a(Expression)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'returns an Expression with the first factor set to the constant and the second to the variable with scalar -1' do
|
77
|
+
expect((number - @variable).factors).to eq([[number, :constant], [-1, @variable]])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'amor/objective'
|
2
|
+
|
3
|
+
module Amor
|
4
|
+
describe Objective do
|
5
|
+
describe '#lp_string' do
|
6
|
+
it 'returns LP format ready version of objective, starting with Maximize if direction is :maximize' do
|
7
|
+
expect(Objective.new(:maximize, Expression.new(2)).lp_string).to eq("Maximize\n obj: 2")
|
8
|
+
end
|
9
|
+
it 'returns LP format ready version of objective, starting with Minimize if direction is :minimize' do
|
10
|
+
expect(Objective.new(:minimize, Expression.new(2)).lp_string).to eq("Minimize\n obj: 2")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'amor/variable'
|
2
|
+
|
3
|
+
module Amor
|
4
|
+
describe Variable do
|
5
|
+
before(:each) do
|
6
|
+
@model = double('Model')
|
7
|
+
@variable = Variable.new(@model, 1)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#*' do
|
11
|
+
# Make sure it works with Integer and Float
|
12
|
+
[5, 5.0].each do |number|
|
13
|
+
context "used with a #{number.class} as scalar" do
|
14
|
+
it "returns an Expression when called with #{number}" do
|
15
|
+
expect(@variable * number).to be_a(Expression)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "returns an Expression with one factor" do
|
19
|
+
expect((@variable * number).factors.size).to eq(1)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "returns an Expression with one factor consisting of given variable and the value it was called with" do
|
23
|
+
expect((@variable * number).factors.first).to eq([number, @variable])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#+' do
|
30
|
+
context 'when used with an expression' do
|
31
|
+
before(:each) do
|
32
|
+
@other_variable = double('Other Variable')
|
33
|
+
@other_expression = Expression.new([[3.0, @other_variable]])
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'returns an Expression' do
|
37
|
+
expect(@variable + @other_expression).to be_a(Expression)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'returns an Expression with the factor of the variable set to 1' do
|
41
|
+
expect((@variable + @other_expression).factors).to eq([[1, @variable], [3.0, @other_variable]])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when used with a variable' do
|
46
|
+
before(:each) do
|
47
|
+
@other_variable = Variable.new(@model,2)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'returns an Expression' do
|
51
|
+
expect(@variable + @other_variable).to be_a(Expression)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'returns an Expression with the factor of the variables set to 1' do
|
55
|
+
expect((@variable + @other_variable).factors).to eq([[1, @variable], [1, @other_variable]])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
[6, 6.0].each do |number|
|
60
|
+
context "when used with a #{number.class}" do
|
61
|
+
it 'returns an Expression' do
|
62
|
+
expect(@variable + number).to be_a(Expression)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'returns an Expression with the first factor set to the variable and the second factor set to the constant' do
|
66
|
+
expect((@variable + number).factors).to eq([[1, @variable], [number, :constant]])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#-' do
|
73
|
+
context 'when used with an expression' do
|
74
|
+
before(:each) do
|
75
|
+
@other_variable = double('Other Variable')
|
76
|
+
@other_expression = Expression.new([[3.0, @other_variable]])
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'returns an Expression' do
|
80
|
+
expect(@variable - @other_expression).to be_a(Expression)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'returns an Expression with the factor of the variable set to 1 and the negative expression' do
|
84
|
+
expect((@variable - @other_expression).factors).to eq([[1, @variable], [-3.0, @other_variable]])
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'when used with a variable' do
|
89
|
+
before(:each) do
|
90
|
+
@other_variable = Variable.new(@model,2)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'returns an Expression' do
|
94
|
+
expect(@variable - @other_variable).to be_a(Expression)
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'returns an Expression with the factor of the first variable set to 1 and the second to -1' do
|
98
|
+
expect((@variable - @other_variable).factors).to eq([[1, @variable], [-1, @other_variable]])
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
[6, 6.0].each do |number|
|
103
|
+
context "when used with a #{number.class}" do
|
104
|
+
it 'returns an Expression' do
|
105
|
+
expect(@variable - number).to be_a(Expression)
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'returns an Expression with the first factor set to the variable and the second factor set to the negative constant' do
|
109
|
+
expect((@variable - number).factors).to eq([[1, @variable], [-number, :constant]])
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe '#-@' do
|
116
|
+
it 'returns an Expression' do
|
117
|
+
expect(-@variable).to be_a(Expression)
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'returns an Expression with the variables factor set to -1' do
|
121
|
+
expect((-@variable).factors).to eq([[-1, @variable]])
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe '#internal_index' do
|
126
|
+
before(:each) do
|
127
|
+
@model = Model.new
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'returns 0 for the first variable' do
|
131
|
+
expect(@model.x(1).internal_index).to eq(0)
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'returns 1 for the second variable' do
|
135
|
+
@model.x(1)
|
136
|
+
expect(@model.x(2).internal_index).to eq(1)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|