amor 0.0.2
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.
- 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
|