mll 0.3.0 → 0.4.0

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