mll 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -1
  3. data/lib/mll.rb +77 -29
  4. data/mll.gemspec +1 -1
  5. data/spec/_spec.rb +372 -70
  6. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0b28b0ef583cd90f87454f37cebdc8a3088ba42a
4
- data.tar.gz: 05757c078b5eade518f1895e71c9bf3e0af97f5f
3
+ metadata.gz: 1826ae5ecd9c663432d75b8d35387762e7d3ce85
4
+ data.tar.gz: 1387511b30a66d4331ab6fe978682dfc0e4607af
5
5
  SHA512:
6
- metadata.gz: cf8caa79c3a7cc275b234c1dcb1d1bc6a0bc9a772f585bddc171cc8d4bd2dacff587cc37c963df7fbab53880c48ca62579ba5c63e109235836288611b6011f8a
7
- data.tar.gz: 8c3053016c69c2ead9e8fd965a661167332e45b00841e15fbdd570325888e5c74e03c5ee89b339bcd665ae75d24bf37574e201686ae0bf3a3b9f3127a1ea9331
6
+ metadata.gz: 3e791cfab9e6f9e979b3c68a6364a2e8fd362696ae7592083f934165a543a525828f9b7504d137a32984988490c22b9e2bc891df7542f94bbcc1c3241b9c3e94
7
+ data.tar.gz: 71d9d47ec39472b8666db934b34fb33042a18b64e5543f0e8c19c1a39982e035335bf1075521069732014529b49ae59f298cb88f6ed10daea28c3f1dd13b255a
data/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  ## Why
8
8
 
9
- 1. Важной является реализация https://reference.wolfram.com/language/ref/Listable.html: автоматическое применение функции ко всем элементам аргумента, если тот является List-ом (Array-ем в среде Ruby).
9
+ 1. Важной является реализация https://reference.wolfram.com/language/ref/Listable.html: автоматическое применение функции ко всем элементам аргумента, если тот является List-ом (Array-ем в среде Ruby).
10
10
  2. `::range`, в отличие от рубишного, может иметь отрицательный step.
11
11
  3. `::table`, в отличие от рубишного `.map`, может создавать многомерные массивы одним вызовом, а не только вложенными.
12
12
 
@@ -24,6 +24,18 @@
24
24
  # => [[[111, 112, 113, 114], [121, 122, 123, 124], [131, 132, 133, 134]],
25
25
  [[211, 212, 213, 214], [221, 222, 223, 224], [231, 232, 233, 234]]]
26
26
 
27
+ MLL::table MLL.method(:times), 9, 9
28
+ # => [[1, 2, 3, 4, 5, 6, 7, 8, 9],
29
+ [2, 4, 6, 8, 10, 12, 14, 16, 18],
30
+ [3, 6, 9, 12, 15, 18, 21, 24, 27],
31
+ [4, 8, 12, 16, 20, 24, 28, 32, 36],
32
+ [5, 10, 15, 20, 25, 30, 35, 40, 45],
33
+ [6, 12, 18, 24, 30, 36, 42, 48, 54],
34
+ [7, 14, 21, 28, 35, 42, 49, 56, 63],
35
+ [8, 16, 24, 32, 40, 48, 56, 64, 72],
36
+ [9, 18, 27, 36, 45, 54, 63, 72, 81]]
37
+
38
+
27
39
  ## Installation
28
40
 
29
41
  $ gem install mll
data/lib/mll.rb CHANGED
@@ -1,14 +1,67 @@
1
1
  module MLL
2
2
 
3
- # https://reference.wolfram.com/language/ref/Listable.html
3
+ def self.nest_list f, expr, n
4
+ Enumerator.new do |e|
5
+ e << expr
6
+ n.times do
7
+ e << expr = f.call(expr)
8
+ end
9
+ end
10
+ end
11
+ # def self.nest *args
12
+ # nest_list(*args).last
13
+ # end
14
+ def self.nest f, expr, n
15
+ n.times{ expr = f.call expr }
16
+ expr
17
+ end
18
+
19
+ def self.fold_list f, x, list = nil
20
+ # TODO teach it to accept Range ?
21
+ x, *list = x unless list
22
+ # use Ruby#inject ?
23
+ Enumerator.new do |e|
24
+ e << x
25
+ list.each do |i|
26
+ e << x = f.call(x, i)
27
+ end
28
+ end
29
+ end
30
+
31
+ def self.table f, *args
32
+ [].tap do |result|
33
+ [[result, args.map{ |r| # add lazy?
34
+ r.respond_to?(:map) && r.first.respond_to?(:map) ?
35
+ r.first : range(*r)
36
+ }]].tap do |stack|
37
+ stack.each do |ai, ri|
38
+ # TODO try to make #table lazy (Enumerator instead of Array)
39
+ # "no implicit conversion of Enumerator::Lazy into Array"
40
+ # "undefined method `replace' for #<Enumerator::Lazy: []>"
41
+ ai.replace ri.first.map{ |i|
42
+ if ri.size == 1
43
+ f.call(*ai, i)
44
+ else
45
+ [*ai.dup, i].tap{ |t| stack << [t, ri.drop(1)] }
46
+ end
47
+ }#.to_a # WTF
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ # http://reference.wolfram.com/language/ref/Listable.html
4
54
  def self.define_listable_function name, &block
5
55
  (class << self; self end).class_eval do # http://stackoverflow.com/a/12792313/322020
6
56
  define_method name do |*args|
7
- # p [name, args]
8
- next block.call *args unless args[0].respond_to? :map
9
- next args[0].lazy.map{ |i| send name, i, *args.drop(1) } unless args[1].respond_to? :map
10
- # raise "idk how to list this function" if args.size > 2
11
- next args[0].lazy.zip(args[1]).map{ |i,j| send name, i, j, *args.drop(2) }
57
+ case args.map{ |i| i.respond_to? :map }
58
+ when [true] ; args.first.lazy.map &method(name)
59
+ when [true, true] ; args.first.lazy.zip(args.last).map{ |i, j| send name, i, j }
60
+ when [true, false] ; args.first.lazy.map{ |i| send name, i, args.last }
61
+ when [false, true] ; args.last.lazy.map{ |i| send name, args.first, i }
62
+ else
63
+ block.call *args
64
+ end
12
65
  end
13
66
  end
14
67
  end
@@ -36,37 +89,32 @@ module MLL
36
89
  end
37
90
  end
38
91
 
39
- def self.table f, *args
40
- [].tap do |result|
41
- [[result, args.map{ |r| # add lazy?
42
- r.respond_to?(:map) && r.first.respond_to?(:map) ?
43
- r.first : range(*r)
44
- }]].tap do |stack|
45
- stack.each do |ai, ri|
46
- # TODO try to make #table lazy (Enumerator instead of Array)
47
- # "no implicit conversion of Enumerator::Lazy into Array"
48
- # "undefined method `replace' for #<Enumerator::Lazy: []>"
49
- ai.replace ri.first.map{ |i|
50
- if ri.size == 1
51
- f.call(*ai, i)
52
- else
53
- [*ai.dup, i].tap{ |t| stack << [t, ri.drop(1)] }
54
- end
55
- }#.to_a # WTF
92
+ define_listable_function (:subtract) { |a, b| a - b }
93
+ define_listable_function (:divide) { |a, b| a / b }
94
+ define_listable_function (:_plus) { |a, b| a + b }
95
+ define_listable_function (:_times) { |a, b| a * b }
96
+
97
+ # http://reference.wolfram.com/language/ref/Orderless.html
98
+ def self.define_orderless_function name, &block
99
+ (class << self; self end).class_eval do # http://stackoverflow.com/a/12792313/322020
100
+ define_method name do |*args|
101
+ args.inject do |memo, obj|
102
+ block.call memo, obj
56
103
  end
57
104
  end
58
105
  end
59
106
  end
60
107
 
61
- define_listable_function :divide do |a, b|
62
- a / b
63
- end
108
+ define_orderless_function (:plus) { |a, b| _plus a, b }
109
+ define_orderless_function (:times) { |a, b| _times a, b }
64
110
 
65
111
  def self.subdivide *args
66
112
  case args.size
67
- when 1 ; subdivide 1, args[0]
68
- when 2 ; subdivide 0, args[0], args[1]
69
- when 3 ; range(args[0], args[1], (args[1] - args[0]) * 1.0 / args[2])
113
+ when 1 ; subdivide 1, args[0]
114
+ when 2 ; subdivide 0, args[0], args[1]
115
+ when 3 ; range(args[0], args[1], (args[1] - args[0]) * 1.0 / args[2])
116
+ ## using only pure Ruby methods makes unittests more reliable
117
+ # when 3 ; plus args[0], divide(times(1.0, args[1] - args[0], range(0, args[2])), args[2])
70
118
  else
71
119
  raise ArgumentError.new("wrong number of arguments (#{args.size} for 1..3)")
72
120
  end
data/mll.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "mll"
3
- spec.version = "0.3.0"
3
+ spec.version = "0.4.0"
4
4
  spec.authors = ["Victor Maslov"]
5
5
  spec.email = ["nakilon@gmail.com"]
6
6
  spec.summary = "Mathematica Language Library in Ruby"
data/spec/_spec.rb CHANGED
@@ -1,9 +1,26 @@
1
1
  require_relative File.join "..", "lib", "mll"
2
2
 
3
3
 
4
- # PERMANENT TODO test all implemented exceptions
5
- # PERMANENT TODO test all types returned
6
-
4
+ # PERMATODO test all implemented exceptions
5
+ # PERMATODO test all types returned (not actually all but about lazyness)
6
+ # PERMATODO check for "Details" paragraphs to make more trivial examples
7
+ # PERMATODO leave here only useful tests, not demostrations -- move them to README.rb
8
+ # PERMATODO single element Arrays tests
9
+ # PERMATODO move Properties & Relations to some separate contexts maybe
10
+
11
+ # TODO test all implemented exceptions
12
+ # TODO test all types returned (not actually all but about lazyness)
13
+ # TODO check for "Details" paragraphs to make more trivial examples
14
+ # TODO leave here only useful tests, not demostrations -- move them to README.rb
15
+ # TODO single element Arrays tests
16
+ # TODO move Properties & Relations to some separate contexts maybe
17
+
18
+ # TODO @fraggedICE wishes using Rational -- would also allow implementing more examples
19
+ # TODO rake task for appending TODOs and pendings to README.rb
20
+ # TODO rename examples according to their description not content
21
+ # TODO elegantly get rid of repetitive type checks
22
+ # TODO implement #power for use in unittests
23
+ # TODO let(:fake_lambda){ ->(*args){fail} } ?
7
24
 
8
25
  # http://reference.wolfram.com/language/guide/LanguageOverview.html
9
26
  describe MLL do
@@ -14,13 +31,35 @@ describe MLL do
14
31
  # NO URL
15
32
  describe "Mathematics & Operators" do
16
33
 
34
+ # http://reference.wolfram.com/language/ref/Subtract.html
35
+ describe "#subtract" do
36
+
37
+ describe "Basic Examples" do
38
+
39
+ example "subtract(n1, n2)" do
40
+ expect(MLL::subtract(10,3)).to eq 7
41
+ end
42
+
43
+ end
44
+
45
+ describe "Scope" do
46
+
47
+ example "subtract(list, n)" do
48
+ expect(MLL::subtract([1,2,3,4],0.5)).to be_a Enumerator
49
+ expect(MLL::subtract([1,2,3,4],0.5).to_a).to eq [0.5,1.5,2.5,3.5]
50
+ end
51
+
52
+ end
53
+
54
+ end
55
+
17
56
  # http://reference.wolfram.com/language/ref/Divide.html
18
57
  describe "#divide" do
19
58
 
20
59
  describe "Basic Examples" do
21
60
 
22
- example "n1 / n2" do
23
- expect(MLL::divide(77,11)).to be_a Fixnum
61
+ example "divide(n1, n2)" do
62
+ # expect(MLL::divide(77,11)).to be_a Fixnum
24
63
  expect(MLL::divide(77,11)).to eq 7
25
64
  end
26
65
 
@@ -28,11 +67,11 @@ describe MLL do
28
67
 
29
68
  describe "Scope" do
30
69
 
31
- example "list / n" do
70
+ example "divide(list, n)" do
32
71
  expect(MLL::divide([2,3,4,5],2.0)).to be_a Enumerator
33
72
  expect(MLL::divide([2,3,4,5],2.0).to_a).to eq [1,1.5,2,2.5]
34
73
  end
35
- example "list / list" do
74
+ example "divide(list, list)" do
36
75
  expect(MLL::divide([2,3,4],[2,1,4])).to be_a Enumerator
37
76
  expect(MLL::divide([2,3,4],[2,1,4]).to_a).to eq [1,3,1]
38
77
  end
@@ -41,11 +80,6 @@ describe MLL do
41
80
 
42
81
  describe "Applications" do
43
82
 
44
- example "foldlist(divide, 1, range(10))" do
45
- pending "#foldlist is yet to be implemented"
46
- fail
47
- end
48
-
49
83
  # TODO: "Successive ratios in a list:"
50
84
 
51
85
  end
@@ -56,7 +90,7 @@ describe MLL do
56
90
  pending "#nestlist is yet to be implemented"
57
91
  fail
58
92
  end
59
- example "table(divide, n1, n2)" do
93
+ example "table(function, n1, n2)" do
60
94
  expect(MLL::table(MLL.method(:divide), [[3,6]], 4.0)).to be_a Array
61
95
  expect(MLL::table(MLL.method(:divide), [[6]], 4.0)).to eq [[6.0,3.0,2.0,1.5]]
62
96
  end
@@ -65,6 +99,73 @@ describe MLL do
65
99
 
66
100
  end
67
101
 
102
+ # TODO common tests for threading functions like times, plus, etc.
103
+
104
+ # http://reference.wolfram.com/language/ref/Plus.html
105
+ describe "#plus" do
106
+
107
+ describe "Basic Examples" do
108
+
109
+ example "plus(n1, n2, n3)" do
110
+ expect(MLL::plus(2,3,4)).to eq 9
111
+ end
112
+ example "plus([n1, n2, n3], n)" do
113
+ expect(MLL::plus([3,4,5],2)).to be_a Enumerator
114
+ expect(MLL::plus([3,4,5],2).to_a).to eq [5,6,7]
115
+ end
116
+ example "plus(n1, n2, [n3, n4])" do
117
+ expect(MLL::plus(2,3,[4,5])).to be_a Enumerator
118
+ expect(MLL::plus(2,3,[4,5]).to_a).to eq [9,10]
119
+ end
120
+ example "plus(list, list)" do
121
+ expect(MLL::plus([10,20,30],[1,2,3])).to be_a Enumerator
122
+ expect(MLL::plus([10,20,30],[1,2,3]).to_a).to eq [11,22,33]
123
+ end
124
+ example "plus(list_of_lists, n)" do
125
+ expect(MLL::plus([[1,2],[3,4]],5)).to be_a Enumerator
126
+ expect(MLL::plus([[1,2],[3,4]],5).to_a.map(&:to_a)).to eq [[6,7],[8,9]]
127
+ end
128
+ example "plus(list_of_lists, list_of_lists)" do
129
+ expect(MLL::plus([[1,2],[3,4]],[[5,6],[7,8]])).to be_a Enumerator
130
+ expect(MLL::plus([[1,2],[3,4]],[[5,6],[7,8]]).to_a.map(&:to_a)).to eq [[6,8],[10,12]]
131
+ end
132
+ example "plus([[n1, n2], [n3, n4]], [n5, n6])" do
133
+ expect(MLL::plus([[1,2],[3,4]],[5,6])).to be_a Enumerator
134
+ expect(MLL::plus([[1,2],[3,4]],[5,6]).to_a.map(&:to_a)).to eq [[6,7],[9,10]]
135
+ end
136
+
137
+ end
138
+
139
+ # TODO "Accumulate makes a cumulative sum:"
140
+
141
+ end
142
+
143
+ # http://reference.wolfram.com/language/ref/Times.html
144
+ describe "#times" do
145
+
146
+ describe "Basic Examples" do
147
+
148
+ example "times(n1, n2, n3)" do
149
+ # expect(MLL::times(2,3,4)).to be_a Fixnum
150
+ expect(MLL::times(2,3,4)).to eq 24
151
+ end
152
+ example "times(n, [n1, n2, n3])" do
153
+ expect(MLL::times(2,[3,4,5])).to be_a Enumerator
154
+ expect(MLL::times(2,[3,4,5]).to_a).to eq [6,8,10]
155
+ end
156
+ example "times(n1, n2, [n3, n4])" do
157
+ expect(MLL::times(2,3,[4,5])).to be_a Enumerator
158
+ expect(MLL::times(2,3,[4,5]).to_a).to eq [24,30]
159
+ end
160
+ example "times([[n1, n2], [n3, n4]], [n5, n6])" do
161
+ expect(MLL::times([[1,2],[3,4]],[5,6])).to be_a Enumerator
162
+ expect(MLL::times([[1,2],[3,4]],[5,6]).to_a.map(&:to_a)).to eq [[5,10],[18,24]]
163
+ end
164
+
165
+ end
166
+
167
+ end
168
+
68
169
  end
69
170
 
70
171
  end
@@ -75,6 +176,66 @@ describe MLL do
75
176
  # http://reference.wolfram.com/language/guide/ConstructingLists.html
76
177
  describe "Constructing Lists" do
77
178
 
179
+ # http://reference.wolfram.com/language/ref/Table.html
180
+ describe "#table" do
181
+
182
+ describe "Basic Examples" do
183
+
184
+ example "table(lambda, n)" do
185
+ expect(MLL::table(->(i){ i**2 }, 10)).to be_a Array
186
+ expect(MLL::table(->(i){ i**2 }, 10)).to eq [1,4,9,16,25,36,49,64,81,100]
187
+ end
188
+ example "table(lambda, [min, max, step])" do
189
+ expect(MLL::table(->(i){ i+2 }, [0, 20, 2])).to be_a Array
190
+ expect(MLL::table(->(i){ i+2 }, [0, 20, 2])).to eq [2,4,6,8,10,12,14,16,18,20,22]
191
+ end
192
+ example "table(lambda, n1, n2)" do
193
+ # TODO example to README.rb about multiplication table
194
+ expect(MLL::table(->(i,j){ 10*i + j }, 4, 3)).to be_a Array
195
+ expect(MLL::table(->(i,j){ 10*i + j }, 4, 3)).to eq [[11,12,13],[21,22,23],[31,32,33],[41,42,43]]
196
+ end
197
+ example "table(lambda, n1, min..max, [max, min, -step])" do
198
+ expect(MLL::table(->(i,j,k){ [i,j,k] }, 3, 2..3, [5, 1, -2])).to be_a Array
199
+ expect(MLL::table(->(i,j,k){ [i,j,k] }, 3, 2..3, [5, 1, -2])).to eq \
200
+ [
201
+ [[[1, 2, 5], [1, 2, 3], [1, 2, 1]], [[1, 3, 5], [1, 3, 3], [1, 3, 1]]],
202
+ [[[2, 2, 5], [2, 2, 3], [2, 2, 1]], [[2, 3, 5], [2, 3, 3], [2, 3, 1]]],
203
+ [[[3, 2, 5], [3, 2, 3], [3, 2, 1]], [[3, 3, 5], [3, 3, 3], [3, 3, 1]]]
204
+ ]
205
+ end
206
+
207
+ example "matrix_form table(lambda, n1, n2)" do
208
+ pending "#matrix_form is yet to be implemented"
209
+ expect(MLL::matrix_form MLL::table(->(i,j){ 10*i + j }, 4, 3)).to eq "
210
+ "
211
+ end
212
+
213
+ end
214
+
215
+ describe "Scope" do
216
+
217
+ # TODO: "Make a triangular array:"
218
+
219
+ example "table(lambda, [list1], [list2])" do
220
+ expect(MLL::table(->(base, power){ base ** power }, [[1,2,4]], [[1,3,4]])).to be_a Array
221
+ expect(MLL::table(->(base, power){ base ** power }, [[1,2,4]], [[1,3,4]])).to eq [[1,1,1],[2,8,16],[4,64,256]]
222
+ expect(MLL::table(MLL::method(:plus), [[1]], [[2]])).to be_a Array
223
+ expect(MLL::table(MLL::method(:plus), [[1]], [[2]])).to eq [[3]]
224
+ end
225
+
226
+ end
227
+
228
+ describe "Applications" do
229
+
230
+ example "column table(binomial, )" do
231
+ pending "#binomial and #column are yet to be implemented"
232
+ fail
233
+ end
234
+
235
+ end
236
+
237
+ end
238
+
78
239
  # http://reference.wolfram.com/language/ref/Range.html
79
240
  describe "#range" do
80
241
 
@@ -160,60 +321,163 @@ describe MLL do
160
321
 
161
322
  end
162
323
 
163
- # http://reference.wolfram.com/language/ref/Table.html
164
- describe "#table" do
165
- # TODO type checks
324
+ # http://reference.wolfram.com/language/ref/Subdivide.html
325
+ describe "#subdivide" do
326
+
327
+ example "subdivide(n)" do
328
+ expect(MLL::subdivide(4)).to be_a Enumerator
329
+ expect(MLL::subdivide(4).to_a).to eq [0,0.25,0.5,0.75,1]
330
+ end
331
+ example "subdivide(max, n)" do
332
+ expect(MLL::subdivide(10,5)).to be_a Enumerator
333
+ expect(MLL::subdivide(10,5).to_a).to eq [0,2,4,6,8,10]
334
+ end
335
+ example "subdivide(min, max, n)" do
336
+ expect(MLL::subdivide(-1,1,8)).to be_a Enumerator
337
+ expect(MLL::subdivide(-1,1,8).to_a).to eq [-1,-0.75,-0.5,-0.25,0,0.25,0.5,0.75,1]
338
+ end
339
+ example "subdivide(max, min, n)" do
340
+ expect(MLL::subdivide(1,-1,8)).to be_a Enumerator
341
+ expect(MLL::subdivide(1,-1,8).to_a).to eq [1,0.75,0.5,0.25,0,-0.25,-0.5,-0.75,-1]
342
+ end
343
+
344
+ end
345
+
346
+ # http://reference.wolfram.com/language/ref/NestList.html
347
+ describe "#nest_list" do
348
+
349
+ example "#nest_list gives a list of length n+1" do
350
+ expect(MLL::nest_list(->{}, 0, 5)).to be_a Enumerator
351
+ expect(MLL::nest_list(->(*args){}, 0, 5).to_a.size).to eq 6
352
+ end
166
353
 
167
354
  describe "Basic Examples" do
168
355
 
169
- example "table(lambda, n)" do
170
- expect(MLL::table(->(i){ i**2 }, 10)).to be_a Array
171
- expect(MLL::table(->(i){ i**2 }, 10)).to eq [1,4,9,16,25,36,49,64,81,100]
356
+ example "'nest_list with #cos starting with 1.0)'" do
357
+ pending "#cos is yet to be implemented"
358
+ fail
172
359
  end
173
- example "table(lambda, [min, max, step])" do
174
- expect(MLL::table(->(i){ i+2 }, [0, 20, 2])).to be_a Array
175
- expect(MLL::table(->(i){ i+2 }, [0, 20, 2])).to eq [2,4,6,8,10,12,14,16,18,20,22]
360
+
361
+ end
362
+
363
+ describe "Scope" do
364
+
365
+ example "nesting can return a single number" do
366
+ pending "#sqrt is yet to be implemented"
367
+ fail
176
368
  end
177
- example "table(lambda, n1, n2)" do
178
- # TODO example to README.rb about multiplication table
179
- expect(MLL::table(->(i, j){ 10*i + j }, 4, 3)).to be_a Array
180
- expect(MLL::table(->(i, j){ 10*i + j }, 4, 3)).to eq [[11,12,13],[21,22,23],[31,32,33],[41,42,43]]
369
+
370
+ end
371
+
372
+ describe "Applications" do
373
+
374
+ example "powers of 2" do
375
+ expect(MLL::nest_list(->(i){ 2*i }, 1, 10)).to be_a Enumerator
376
+ expect(MLL::nest_list(->(i){ 2*i }, 1, 10).to_a).to eq [1,2,4,8,16,32,64,128,256,512,1024]
181
377
  end
182
- example "table(lambda, n1, min..max, [max, min, -step])" do
183
- expect(MLL::table(->(i,j,k){ [i,j,k] }, 3, 2..3, [5, 1, -2])).to be_a Array
184
- expect(MLL::table(->(i,j,k){ [i,j,k] }, 3, 2..3, [5, 1, -2])).to eq \
185
- [
186
- [[[1, 2, 5], [1, 2, 3], [1, 2, 1]], [[1, 3, 5], [1, 3, 3], [1, 3, 1]]],
187
- [[[2, 2, 5], [2, 2, 3], [2, 2, 1]], [[2, 3, 5], [2, 3, 3], [2, 3, 1]]],
188
- [[[3, 2, 5], [3, 2, 3], [3, 2, 1]], [[3, 3, 5], [3, 3, 3], [3, 3, 1]]]
189
- ]
378
+ example "iterates in the problem" do
379
+ expect(MLL::nest_list(->(i){ i.even? ? i/2 : (i*3+1)/2 }, 100, 20)).to be_a Enumerator
380
+ expect(MLL::nest_list(->(i){ i.even? ? i/2 : (i*3+1)/2 }, 100, 20).to_a).to eq [100,50,25,38,19,29,44,22,11,17,26,13,20,10,5,8,4,2,1,2,1]
381
+ end
382
+ example "linear congruential pseudorandom generator" do
383
+ expect(MLL::nest_list(->(i){ (i*59)%101 }, 1, 15)).to be_a Enumerator
384
+ expect(MLL::nest_list(->(i){ (i*59)%101 }, 1, 15).to_a).to eq [1,59,47,46,88,41,96,8,68,73,65,98,25,61,64,39]
385
+ end
386
+ example "random walk" do
387
+ expect(( r = Random.new(0); MLL::nest_list(->(i){ i+[-1,1][r.rand(2)] }, 0, 20) )).to be_a Enumerator
388
+ expect(( r = Random.new(0); MLL::nest_list(->(i){ i+[-1,1][r.rand(2)] }, 0, 20).to_a )).to eq [0,-1,0,1,0,1,2,3,4,5,6,7,6,5,6,5,4,3,2,1,2]
389
+ end
390
+ example "successively rotate a list" do
391
+ expect(MLL::nest_list(->(i){ i.rotate 1 }, [1,2,3,4], 4)).to be_a Enumerator
392
+ expect(MLL::nest_list(->(i){ i.rotate 1 }, [1,2,3,4], 4).to_a).to eq [[1,2,3,4],[2,3,4,1],[3,4,1,2],[4,1,2,3],[1,2,3,4]]
190
393
  end
191
394
 
192
- example "matrix_form table(lambda, n1, n2)" do
193
- pending "#matrix_form is yet to be implemented"
194
- expect(MLL::matrix_form MLL::table(->(i, j){ 10*i + j }, 4, 3)).to eq "
195
- "
395
+ end
396
+
397
+ describe "Properties & Relations" do
398
+
399
+ # TODO "Nest gives the last element of NestList:"
400
+
401
+ example "nesting zero times simply returns to the original argument" do
402
+ expect(MLL::nest_list(->{fail}, 5, 0)).to be_a Enumerator
403
+ expect(MLL::nest_list(->(*args){fail}, 5, 0).to_a).to eq [5]
404
+ end
405
+ example "#fold_list automatically inserts second arguments from a list" do
406
+ expect(MLL::nest_list(->(i ){ i*2 }, 3, 4).to_a).to eq \
407
+ MLL::fold_list(->(i,j){ i*j }, 3, [2]*4).to_a
196
408
  end
197
409
 
198
410
  end
199
411
 
200
- describe "Scope" do
412
+ end
201
413
 
202
- # TODO: "Make a triangular array:"
414
+ end
203
415
 
204
- example "table(lambda, [list1], [list2])" do
205
- expect(MLL::table(->(base, power){ base ** power }, [[1,2,4]], [[1,3,4]])).to be_a Array
206
- expect(MLL::table(->(base, power){ base ** power }, [[1,2,4]], [[1,3,4]])).to eq [[1,1,1],[2,8,16],[4,64,256]]
207
- expect(MLL::table(->(i,j){ i+j }, [[1]], [[2]])).to be_a Array
208
- expect(MLL::table(->(i,j){ i+j }, [[1]], [[2]])).to eq [[3]]
416
+ # http://reference.wolfram.com/language/guide/ApplyingFunctionsToLists.html
417
+ describe "Applying Functions to Lists" do
418
+
419
+ describe "#fold_list" do
420
+
421
+ describe "Basic Examples" do
422
+
423
+ example "fold_list(function, list)" do
424
+ expect(MLL::fold_list(MLL.method(:plus),[1,2,3,4])).to be_a Enumerator
425
+ expect(MLL::fold_list(MLL.method(:plus),[1,2,3,4]).to_a).to eq [1,3,6,10]
426
+ end
427
+ example "fold_list(function, n, list)" do
428
+ expect(MLL::fold_list(MLL.method(:plus),5,[1,2,3,4])).to be_a Enumerator
429
+ expect(MLL::fold_list(MLL.method(:plus),5,[1,2,3,4]).to_a).to eq [5,6,8,11,15]
430
+ end
431
+ example "fold_list(lambda, n, list)" do
432
+ expect(MLL::fold_list(->(base, power){ base ** power },2,[3,2,1])).to be_a Enumerator
433
+ expect(MLL::fold_list(->(base, power){ base ** power },2,[3,2,1]).to_a).to eq [2,8,64,64]
209
434
  end
210
435
 
211
436
  end
212
437
 
213
438
  describe "Applications" do
214
439
 
215
- example "column table(binomial, )" do
216
- pending "#binomial and #column are yet to be implemented"
440
+ example "fold_list(function, n, list)" do
441
+ expect(MLL::fold_list(MLL.method(:times), [*1..10])).to be_a Enumerator
442
+ expect(MLL::fold_list(MLL.method(:times), [*1..10]).to_a).to eq [1,2,6,24,120,720,5040,40320,362880,3628800]
443
+ end
444
+ example "fold_list(lambda, n, list)" do
445
+ expect(MLL::fold_list(->(a,b){ 10*a + b }, 0, [4,5,1,6,7,8])).to be_a Enumerator
446
+ expect(MLL::fold_list(->(a,b){ 10*a + b }, 0, [4,5,1,6,7,8]).to_a).to eq [0,4,45,451,4516,45167,451678]
447
+ end
448
+ example "fold_list(lambda, n, list)" do
449
+ expect(( r = Random.new(0); MLL::fold_list(MLL.method(:plus), 0, Array.new(20){ [-1,1][r.rand(2)] }) )).to be_a Enumerator
450
+ expect(( r = Random.new(0); MLL::fold_list(MLL.method(:plus), 0, Array.new(20){ [-1,1][r.rand(2)] }).to_a )).to eq [0,-1,0,1,0,1,2,3,4,5,6,7,6,5,6,5,4,3,2,1,2]
451
+ end
452
+
453
+ # TODO "Find successively deeper parts in an expression:"
454
+
455
+ end
456
+
457
+ describe "Properties & Relations" do
458
+
459
+ example "#fold_list makes a list of length n+1" do
460
+ expect(MLL::fold_list(->{}, 0, [*1..10])).to be_a Enumerator
461
+ expect(MLL::fold_list(->(*args){}, 0, [*1..10]).to_a.size).to eq 11
462
+ end
463
+ example "folding with an empty list does not apply the function at all" do
464
+ expect(MLL::fold_list(->{}, 0, [])).to be_a Enumerator
465
+ expect(MLL::fold_list(->(*args){}, 0, []).to_a).to eq [0]
466
+ end
467
+ example "Ruby#inject gives the last element of #fold_list" do
468
+ f = ->(i,j){ i+j }
469
+ expect(MLL::fold_list(f, [1,2,3])).to be_a Enumerator
470
+ expect(MLL::fold_list(f, [1,2,3]).to_a.last).to eq [1,2,3].inject(&f)
471
+ end
472
+ # TODO "Functions that ignore their second argument give the same result as in NestList:"
473
+ # TODO "Accumulate is equivalent to FoldList with Plus:"
474
+
475
+ end
476
+
477
+ describe "Neat Examples" do
478
+
479
+ example "compute the minimum number of coins of different value needed to make up an amount" do
480
+ pending "at least #mod is yet to be implemented"
217
481
  fail
218
482
  end
219
483
 
@@ -221,40 +485,78 @@ describe MLL do
221
485
 
222
486
  end
223
487
 
224
- # http://reference.wolfram.com/language/ref/Subdivide.html
225
- describe "#subdivide" do
488
+ end
489
+
490
+ # TODO http://reference.wolfram.com/language/guide/ElementsOfLists.html
491
+ # TODO http://reference.wolfram.com/language/guide/RearrangingAndRestructuringLists.html
492
+ # TODO http://reference.wolfram.com/language/guide/MathematicalAndCountingOperationsOnLists.html
493
+
494
+ end
495
+
496
+ # http://reference.wolfram.com/language/guide/FunctionalProgramming.html
497
+ describe "Functional Programming" do
498
+
499
+ # http://reference.wolfram.com/language/guide/FunctionalIteration.html
500
+ describe "Iteratively Applying Functions" do
501
+
502
+ # TODO move #nest_list and #fold_list and others here?
503
+
504
+ describe "#nest" do
505
+
506
+ describe "Basic Examples" do
507
+
508
+ example "the function to nest can be a pure function" do
509
+ expect(MLL::nest(->(i){ (1+i)**2 }, 1, 3)).to eq 676
510
+ end
226
511
 
227
- example "subdivide(n)" do
228
- expect(MLL::subdivide(4)).to be_a Enumerator
229
- expect(MLL::subdivide(4).to_a).to eq [0,0.25,0.5,0.75,1]
230
512
  end
231
- example "subdivide(max, n)" do
232
- expect(MLL::subdivide(10,5)).to be_a Enumerator
233
- expect(MLL::subdivide(10,5).to_a).to eq [0,2,4,6,8,10]
513
+
514
+ describe "Scope" do
515
+
516
+ example "nesting can return a single number" do
517
+ pending "#sqrt is yet to be implemented"
518
+ fail
519
+ end
520
+
234
521
  end
235
- example "subdivide(min, max, n)" do
236
- expect(MLL::subdivide(-1,1,8)).to be_a Enumerator
237
- expect(MLL::subdivide(-1,1,8).to_a).to eq [-1,-0.75,-0.5,-0.25,0,0.25,0.5,0.75,1]
522
+
523
+ describe "Applications" do
524
+
525
+ example "newton iterations for" do
526
+ pending "need to deal with Rationals first"
527
+ fail
528
+ end
529
+ example "consecutive pairs of Fibonacci numbers" do
530
+ pending "implement #dot ?"
531
+ fail
532
+ end
533
+
238
534
  end
239
- example "subdivide(max, min, n)" do
240
- expect(MLL::subdivide(1,-1,8)).to be_a Enumerator
241
- expect(MLL::subdivide(1,-1,8).to_a).to eq [1,0.75,0.5,0.25,0,-0.25,-0.5,-0.75,-1]
535
+
536
+ describe "Properties & Relations" do
537
+
538
+ example "#fold automatically inserts second arguments from a list" do
539
+ expect(MLL::nest(->(i){ i*2 }, 3, 4)).to eq \
540
+ ([2]*4).inject(3){ |i,j| i*j }
541
+ end
542
+
242
543
  end
243
544
 
545
+ # TODO neat graphic examples
546
+
244
547
  end
245
548
 
246
549
  end
247
550
 
248
- # http://reference.wolfram.com/language/guide/ElementsOfLists.html
249
- # http://reference.wolfram.com/language/guide/RearrangingAndRestructuringLists.html
250
- # http://reference.wolfram.com/language/guide/ApplyingFunctionsToLists.html
251
- # http://reference.wolfram.com/language/guide/MathematicalAndCountingOperationsOnLists.html
252
-
253
551
  end
254
552
 
255
- # http://reference.wolfram.com/language/guide/FunctionalProgramming.html
256
-
257
553
  end
258
554
 
259
- # http://reference.wolfram.com/language/guide/HandlingArraysOfData.html
260
- # http://reference.wolfram.com/language/guide/ComputationWithStructuredDatasets.html
555
+ # TODO http://reference.wolfram.com/language/guide/HandlingArraysOfData.html
556
+ # TODO http://reference.wolfram.com/language/guide/ComputationWithStructuredDatasets.html
557
+
558
+ __END__
559
+
560
+ Table Array
561
+ Times Product
562
+ Plus Total Sum?
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mll
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Maslov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-08 00:00:00.000000000 Z
11
+ date: 2015-05-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler