mll 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (7) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +58 -21
  3. data/Rakefile +1 -0
  4. data/lib/mll.rb +105 -68
  5. data/mll.gemspec +1 -1
  6. data/spec/_spec.rb +168 -40
  7. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 812325964160837ba11226c5585e372463dd9fd7
4
- data.tar.gz: fb060b7f5a405a230b21a20c9cc8426e5bd7e19b
3
+ metadata.gz: ce709bc99f6cbd85ca763a4752346b0b5e4112cb
4
+ data.tar.gz: 0e6ba411ce044ecffbc476fcbefcb61a8cf18926
5
5
  SHA512:
6
- metadata.gz: 5fe15ad50531a0b9740847b01c27ed76e598d0345a0158b22474715a7fbb8bc917479c406ef1cac3580b167dd19b30bca820665888792657e8be6bc2a1f67b81
7
- data.tar.gz: dd3547ff6b62c5ecd29d91529aee42e1552cb0d90bde926e7d8e090cdcf1df7ca1792aa110835a82133127f2f33d2c56a6421ab2ca56e778acbead64537c7380
6
+ metadata.gz: 6464f5860f02778245155c5f7ec98b61bde188482ef2fb90593baf1cf72fbede13ddd47654288745684d0fdc314cbe3e2609284fcb53cd329c6175b288686845
7
+ data.tar.gz: 00014f6f4d963c1512f844703b39888f084ebe1495e2fedffc3abe0bc29db2af3f78b40618c3280560414b6729c6d490cd2923faf6397fb26645a891f7f7b657
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # MLL (Mathematica Language Library)
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/mll.svg)](http://badge.fury.io/rb/mll)
4
+
3
5
  ## What
4
6
 
5
7
  This gem isn't supposed to mimic all data types, exact syntax of Wolfram Mathematica or make Ruby able to make the same visualisations.
@@ -8,11 +10,13 @@ The main goal is to make Ruby more powerful by including the most used functions
8
10
 
9
11
  ## Why
10
12
 
13
+ 0. `::map` can map Arrays at specified depth!
11
14
  1. One of the most useful things is automatic zipping vectors (`Array`s) when you apply scalar functions to them. https://reference.wolfram.com/language/ref/Listable.html
12
15
  2. unlike Ruby's `Range` class, `::range` can handle negative `step` and even have `float` starting value
13
- 3. unlike Ruby's `Array#map`, `::table` can create multidimensional arrays with a single call, not nested
14
- 4. `#fold_list` was wanted [here](http://stackoverflow.com/q/1475808/322020) in Ruby while being already implemented as [FoldList[]](http://reference.wolfram.com/language/ref/FoldList.html) in Mathematica and [scanl](http://hackage.haskell.org/package/base-4.8.0.0/docs/Prelude.html#v:scanl) in Haskell
15
- 5. `#nest` (n times) and `#nest_list` for repetitive applying the same function -- `#nest_while` and `#nest_while_list` are going to be implemented later
16
+ 3. unlike Ruby's `Array.new`, `::table` can create multidimensional arrays with a single call, not nested
17
+ 4. `::fold_list` was wanted [here](http://stackoverflow.com/q/1475808/322020) in Ruby while being already implemented as [FoldList[]](http://reference.wolfram.com/language/ref/FoldList.html) in Mathematica and [scanl](http://hackage.haskell.org/package/base-4.8.0.0/docs/Prelude.html#v:scanl) in Haskell
18
+ 5. `::nest` (n times) and `::nest_list` for repetitive applying the same function -- `::nest_while` and `::nest_while_list` are going to be implemented later
19
+ 6. `::tally` -- shortcut to a probably the most common usage of `#group_by` -- calculating total occurences.
16
20
 
17
21
  ## How
18
22
 
@@ -20,11 +24,20 @@ The main goal is to make Ruby more powerful by including the most used functions
20
24
  MLL::range[[2, 3]] # => [1..2, 1..3]
21
25
  MLL::range[ 1..3 ] # => [1..1, 1..2, 1..3]
22
26
 
23
- MLL::table[ ->(i,j){ i+j }, [[1, 0, 1]], [[0, 2, 0]] ]
27
+ t = MLL::table[ ->(i,j){ i+j }, [[1, 0, 1]], [[0, 2, 0]] ]
24
28
  # => [[1, 3, 1],
25
29
  [0, 2, 0],
26
30
  [1, 3, 1]]
27
- MLL::table[ MLL.method(:times), 9, 9 ]
31
+ t = MLL::map[ ->(i){ [i] }, t, [2] ]
32
+ # => [[ [1], [3], [1] ],
33
+ [ [0], [2], [0] ],
34
+ [ [1], [3], [1] ]]
35
+ MLL::map[ ->(i){ -i }, t, [3] ]
36
+ # => [[ [-1], [-3], [-1] ],
37
+ [ [ 0], [-2], [ 0] ],
38
+ [ [-1], [-3], [-1] ]]
39
+
40
+ MLL::table[ MLL::times, 9, 9 ]
28
41
  # => [[1, 2, 3, 4, 5, 6, 7, 8, 9],
29
42
  [2, 4, 6, 8, 10, 12, 14, 16, 18],
30
43
  [3, 6, 9, 12, 15, 18, 21, 24, 27],
@@ -34,6 +47,10 @@ The main goal is to make Ruby more powerful by including the most used functions
34
47
  [7, 14, 21, 28, 35, 42, 49, 56, 63],
35
48
  [8, 16, 24, 32, 40, 48, 56, 64, 72],
36
49
  [9, 18, 27, 36, 45, 54, 63, 72, 81]]
50
+ # ::times means *
51
+ # ::divide means /
52
+ # ::subtract means -
53
+ # ::plus means +
37
54
 
38
55
  MLL::fold_list[ MLL::times, MLL::range[10] ]
39
56
  # => [1,2,6,24,120,720,5040,40320,362880,3628800]
@@ -42,10 +59,6 @@ The main goal is to make Ruby more powerful by including the most used functions
42
59
  # even of different dimensions with basic operations
43
60
  MLL::times[ [[1,2],[3,4]], [5,6] ]
44
61
  # => [[5,10], [18,24]]
45
- # ::times means *
46
- # ::divide means /
47
- # ::subtract means -
48
- # ::plus means +
49
62
 
50
63
  # http://en.wikipedia.org/wiki/Collatz_conjecture
51
64
  MLL::nest_list[ ->(i){ i.even? ? i/2 : (i*3+1)/2 }, 20, 10 ]
@@ -57,7 +70,12 @@ The main goal is to make Ruby more powerful by including the most used functions
57
70
  MLL::subdivide[ 5, 10, 4 ]
58
71
  # => [5.0, 6.25, 7.5, 8.75, 10.0]
59
72
 
60
- Note that to see some of above examples working you need `.to_a`, `.map(&:to_a)` or even `.to_a.map(&:to_a)` since lazyness is intensively used.
73
+ MLL::tally[ "the quick brown fox jumps over the lazy dog".chars ]
74
+ # => {"t"=>2, "h"=>2, "e"=>3, " "=>8, "q"=>1, "u"=>2, "i"=>1, "c"=>1, "k"=>1,
75
+ "b"=>1, "r"=>2, "o"=>4, "w"=>1, "n"=>1, "f"=>1, "x"=>1, "j"=>1, "m"=>1,
76
+ "p"=>1, "s"=>1, "v"=>1, "l"=>1, "a"=>1, "z"=>1, "y"=>1, "d"=>1, "g"=>1}
77
+
78
+ Note that to see some of above examples working in the same way you need `.to_a`, `.map(&:to_a)` or even `.to_a.map(&:to_a)` since lazyness is intensively used.
61
79
 
62
80
  ## Installation
63
81
 
@@ -77,15 +95,19 @@ or
77
95
 
78
96
  ```
79
97
  module MLL
80
- def self.fold_list
81
- lambda do |f, x, list = nil|
82
- # TODO use Ruby#inject ?
83
- def self.table
84
- lambda do |f, *args|
85
- [].tap do |result|
86
- }]].tap do |stack|
87
- stack.each do |ai, ri|
88
- # TODO try to make #table lazy (Enumerator instead of Array)
98
+ class << self
99
+ def fold_list
100
+ lambda do |f, x, list = nil|
101
+ # TODO use Ruby#inject ?
102
+ def map
103
+ # TODO validate depths
104
+ # TODO break on passing all depths
105
+ def table
106
+ lambda do |f, *args|
107
+ [].tap do |result|
108
+ }]].tap do |stack|
109
+ stack.each do |ai, ri|
110
+ # TODO try to make #table lazy (Enumerator instead of Array)
89
111
  # TODO not sure if we need any other kind of Listability except of #range[[Array]]
90
112
  ```
91
113
 
@@ -100,14 +122,29 @@ describe MLL do
100
122
  describe "List Manipulation" do
101
123
  describe "Constructing Lists" do
102
124
  describe "#table" do
103
- describe "Scope" do
125
+ describe "Scope:" do
104
126
  # TODO: "Make a triangular array:"
105
127
  describe "#range" do
106
128
  # TODO take from docs more examples that involve other functions
107
129
  describe "Applying Functions to Lists" do
108
130
  describe "#fold_list" do
109
- describe "Applications" do
131
+ describe "Applications:" do
110
132
  # TODO maybe move it to README.md
133
+ describe "#map" do
134
+ # TODO we'll need less nested mappings when we implement stop on depths depletion
135
+ describe "Details and Options:" do
136
+ example "levels n1 though n2" do
137
+ expect(map[->(i){ [i] }, [1,[2,[3,[4,[5,6]]]]], [2,4]].
138
+ # TODO smth _<>
139
+ # TODO "Level corresponds to the whole expression"
140
+ # TODO currying "Map[f][expr] is equivalent to Map[f,expr]"
141
+ describe "Scope:" do
142
+ # TODO "Map on all levels, starting at level" ant other about Infinity
143
+ describe "Properties & Relations:" do
144
+ # TODO #mapall
145
+ # TODO #mapthread ?
146
+ # TODO #mapindexed ?
147
+ # TODO "negative levels"
111
148
  # TODO http://reference.wolfram.com/language/guide/ElementsOfLists.html
112
149
  # TODO http://reference.wolfram.com/language/guide/RearrangingAndRestructuringLists.html
113
150
  # TODO http://reference.wolfram.com/language/guide/MathematicalAndCountingOperationsOnLists.html
data/Rakefile CHANGED
@@ -26,6 +26,7 @@ task :todo do |t|
26
26
  end
27
27
  readme_file.puts "```"
28
28
  end
29
+ readme_file.truncate readme_file.pos
29
30
  end
30
31
  end
31
32
 
data/lib/mll.rb CHANGED
@@ -1,77 +1,114 @@
1
1
  module MLL
2
2
 
3
- def self.nest_list
4
- lambda do |f, expr, n|
5
- Enumerator.new do |e|
6
- e << expr
7
- n.times do
8
- e << expr = f.call(expr)
3
+ class << self
4
+
5
+ def tally
6
+ lambda do |list, test = ->(i,j){ i == j } | # TODO implement #sameq ?
7
+ h = Hash.new{ 0 }
8
+ keys = []
9
+ list.each do |item|
10
+ h[item] += 1 if keys.each do |key|
11
+ if test[key, item]
12
+ h[key] += 1
13
+ break
14
+ end
15
+ end
16
+ keys << item
9
17
  end
18
+ h
10
19
  end
11
20
  end
12
- end
13
- # def self.nest *args
14
- # nest_list(*args).last
15
- # end
16
- def self.nest
17
- lambda do |f, expr, n|
18
- n.times{ expr = f.call expr }
19
- expr
21
+
22
+ def nest_list
23
+ lambda do |f, expr, n|
24
+ Enumerator.new do |e|
25
+ e << expr
26
+ n.times do
27
+ e << expr = f.call(expr)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ # def self.nest *args
33
+ # nest_list(*args).last
34
+ # end
35
+ def nest
36
+ lambda do |f, expr, n|
37
+ n.times{ expr = f.call expr }
38
+ expr
39
+ end
20
40
  end
21
- end
22
41
 
23
- def self.fold_list
24
- lambda do |f, x, list = nil|
25
- x, *list = x.to_a unless list
26
- # TODO use Ruby#inject ?
27
- Enumerator.new do |e|
28
- e << x
29
- list.each do |i|
30
- e << x = f.call(x, i)
42
+ def fold_list
43
+ lambda do |f, x, list = nil|
44
+ x, *list = x.to_a unless list
45
+ # TODO use Ruby#inject ?
46
+ Enumerator.new do |e|
47
+ e << x
48
+ list.each do |i|
49
+ e << x = f.call(x, i)
50
+ end
31
51
  end
32
52
  end
33
53
  end
34
- end
35
54
 
36
- def self.table
37
- lambda do |f, *args|
38
- [].tap do |result|
39
- [[result, args.map{ |r| # add lazy?
40
- r.respond_to?(:map) && r.first.respond_to?(:map) ?
41
- r.first : range[*r]
42
- }]].tap do |stack|
43
- stack.each do |ai, ri|
44
- # TODO try to make #table lazy (Enumerator instead of Array)
45
- # "no implicit conversion of Enumerator::Lazy into Array"
46
- # "undefined method `replace' for #<Enumerator::Lazy: []>"
47
- ai.replace ri.first.map{ |i|
48
- if ri.size == 1
49
- f.call(*ai, i)
50
- else
51
- [*ai.dup, i].tap{ |t| stack << [t, ri.drop(1)] }
52
- end
53
- }
55
+ def map
56
+ # TODO validate depths
57
+ # TODO break on passing all depths
58
+ lambda do |f, list, depths = [1]|
59
+ depths = Range.new(*depths) if depths.size == 2
60
+ depths = Range.new(1,depths) if depths.is_a? Integer
61
+ g = lambda do |list, depth|
62
+ next list unless list.respond_to? :map
63
+ temp = list.lazy.map{ |i| g[i, depth + 1] }
64
+ temp = temp.map &f if depths.include? depth
65
+ temp
66
+ end
67
+ g[list, 1]
68
+ end
69
+ end
70
+
71
+ def table
72
+ lambda do |f, *args|
73
+ [].tap do |result|
74
+ [[result, args.map{ |r| # add lazy?
75
+ r.respond_to?(:map) && r.first.respond_to?(:map) ?
76
+ r.first : range[*r]
77
+ }]].tap do |stack|
78
+ stack.each do |ai, ri|
79
+ # TODO try to make #table lazy (Enumerator instead of Array)
80
+ # "no implicit conversion of Enumerator::Lazy into Array"
81
+ # "undefined method `replace' for #<Enumerator::Lazy: []>"
82
+ ai.replace ri.first.map{ |i|
83
+ if ri.size == 1
84
+ f.call(*ai, i)
85
+ else
86
+ [*ai.dup, i].tap{ |t| stack << [t, ri.drop(1)] }
87
+ end
88
+ }
89
+ end
54
90
  end
55
91
  end
56
92
  end
57
93
  end
58
- end
59
94
 
60
- def self.define_listable_function name, &block
61
- (class << self; self end).class_eval do
62
- define_method name do
63
- lambda do |*args|
64
- case args.map{ |i| i.respond_to? :map }
65
- when [true] ; args.first.lazy.map &method(name).call
66
- when [true, true] ; args.first.lazy.zip(args.last).map{ |i, j| send(name)[i, j] }
67
- when [true, false] ; args.first.lazy.map{ |i| send(name)[i, args.last] }
68
- when [false, true] ; args.last.lazy.map{ |i| send(name)[args.first, i] }
69
- else
70
- block.call *args
95
+ def define_listable_function name, &block
96
+ (class << self; self end).class_eval do
97
+ define_method name do
98
+ lambda do |*args|
99
+ case args.map{ |i| i.respond_to? :map }
100
+ when [true] ; args.first.lazy.map &method(name).call
101
+ when [true, true] ; args.first.lazy.zip(args.last).map{ |i, j| send(name)[i, j] }
102
+ when [true, false] ; args.first.lazy.map{ |i| send(name)[i, args.last] }
103
+ when [false, true] ; args.last.lazy.map{ |i| send(name)[args.first, i] }
104
+ else
105
+ block.call *args
106
+ end
71
107
  end
72
108
  end
73
109
  end
74
110
  end
111
+
75
112
  end
76
113
 
77
114
  # TODO not sure if we need any other kind of Listability except of #range[[Array]]
@@ -98,6 +135,20 @@ module MLL
98
135
  end
99
136
  end
100
137
 
138
+ def self.subdivide
139
+ lambda do |*args|
140
+ case args.size
141
+ when 1 ; subdivide[1, args[0]]
142
+ when 2 ; subdivide[0, args[0], args[1]]
143
+ when 3
144
+ # raise ArgumentError.new("can't divide into 0 parts") if args[2].zero?
145
+ range[args[0], args[1], (args[1] - args[0]) * 1.0 / args[2]]
146
+ else
147
+ raise ArgumentError.new("wrong number of arguments (#{args.size} for 1..3)")
148
+ end
149
+ end
150
+ end
151
+
101
152
  define_listable_function(:subtract) { |*args| raise ArgumentError.new("need two arguments") unless args.size == 2 ; args[0] - args[1] }
102
153
  define_listable_function(:divide) { |*args| raise ArgumentError.new("need two arguments") unless args.size == 2 ; args[0] / args[1] }
103
154
  define_listable_function(:_plus) { |*args| raise ArgumentError.new("need two arguments") unless args.size == 2 ; args[0] + args[1] }
@@ -120,18 +171,4 @@ module MLL
120
171
  define_orderless_function(:plus, 0) { |a, b| _plus.call a, b }
121
172
  define_orderless_function(:times, 1) { |a, b| _times.call a, b }
122
173
 
123
- def self.subdivide
124
- lambda do |*args|
125
- case args.size
126
- when 1 ; subdivide[1, args[0]]
127
- when 2 ; subdivide[0, args[0], args[1]]
128
- when 3
129
- # raise ArgumentError.new("can't divide into 0 parts") if args[2].zero?
130
- range[args[0], args[1], (args[1] - args[0]) * 1.0 / args[2]]
131
- else
132
- raise ArgumentError.new("wrong number of arguments (#{args.size} for 1..3)")
133
- end
134
- end
135
- end
136
-
137
174
  end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "mll"
3
- spec.version = "1.1.0"
3
+ spec.version = "1.2.0"
4
4
  spec.authors = ["Victor Maslov"]
5
5
  spec.email = ["nakilon@gmail.com"]
6
6
  spec.summary = "Mathematica Language Library in Ruby"
@@ -38,7 +38,7 @@ describe MLL do
38
38
  expect{ subtract[0,0,0] }.to raise_error ArgumentError
39
39
  end
40
40
 
41
- describe "Basic Examples" do
41
+ describe "Basic Examples:" do
42
42
 
43
43
  example "subtract numbers" do
44
44
  expect(subtract[10,3]).to eq 7
@@ -46,7 +46,7 @@ describe MLL do
46
46
 
47
47
  end
48
48
 
49
- describe "Scope" do
49
+ describe "Scope:" do
50
50
 
51
51
  example "threads element‐wise over lists" do
52
52
  expect(subtract[[1,2,3,4],0.5]).to be_a Enumerator
@@ -79,7 +79,7 @@ describe MLL do
79
79
  expect{ divide[0,0,0] }.to raise_error ArgumentError
80
80
  end
81
81
 
82
- describe "Basic Examples" do
82
+ describe "Basic Examples:" do
83
83
 
84
84
  example "divide numbers" do
85
85
  expect(divide[77,11]).to eq 7
@@ -87,7 +87,7 @@ describe MLL do
87
87
 
88
88
  end
89
89
 
90
- describe "Scope" do
90
+ describe "Scope:" do
91
91
 
92
92
  example "threads element‐wise over lists" do
93
93
  expect(divide[[2,3,4,5],2.0]).to be_a Enumerator
@@ -108,7 +108,7 @@ describe MLL do
108
108
 
109
109
  end
110
110
 
111
- describe "Applications" do
111
+ describe "Applications:" do
112
112
 
113
113
  example "successive ratios in a list" do
114
114
  skip "waiting for Rationals to be used"
@@ -121,7 +121,7 @@ describe MLL do
121
121
  # http://reference.wolfram.com/language/ref/Plus.html
122
122
  describe "#plus" do
123
123
 
124
- describe "Details" do
124
+ describe "Details:" do
125
125
 
126
126
  example "#plus[] is taken to be 0" do
127
127
  expect(plus[]).to eq 0
@@ -132,7 +132,7 @@ describe MLL do
132
132
 
133
133
  end
134
134
 
135
- describe "Basic Examples" do
135
+ describe "Basic Examples:" do
136
136
 
137
137
  example "sums numbers" do
138
138
  expect(plus[2,3,4]).to eq 9
@@ -149,7 +149,7 @@ describe MLL do
149
149
 
150
150
  end
151
151
 
152
- describe "Scope" do
152
+ describe "Scope:" do
153
153
 
154
154
  example "threads element‐wise over lists" do
155
155
  expect(plus[[10,20,30],[1,2,3]]).to be_a Enumerator
@@ -164,7 +164,7 @@ describe MLL do
164
164
 
165
165
  end
166
166
 
167
- describe "Possible Issues" do
167
+ describe "Possible Issues:" do
168
168
 
169
169
  # idk why not in 'Properties & Relations'
170
170
  example "accumulate makes a cumulative sum" do
@@ -179,7 +179,7 @@ describe MLL do
179
179
  # http://reference.wolfram.com/language/ref/Times.html
180
180
  describe "#times" do
181
181
 
182
- describe "Details" do
182
+ describe "Details:" do
183
183
 
184
184
  example "#times[] is taken to be 1" do
185
185
  expect(times[]).to eq 1
@@ -190,7 +190,7 @@ describe MLL do
190
190
 
191
191
  end
192
192
 
193
- describe "Basic Examples" do
193
+ describe "Basic Examples:" do
194
194
 
195
195
  example "multiplies numbers" do
196
196
  expect(times[2,3,4]).to eq 24
@@ -206,7 +206,7 @@ describe MLL do
206
206
 
207
207
  end
208
208
 
209
- describe "Scope" do
209
+ describe "Scope:" do
210
210
 
211
211
  example "threads element‐wise over lists" do
212
212
  expect(times[[2,3],[4,5]]).to be_a Enumerator
@@ -236,7 +236,7 @@ describe MLL do
236
236
  # http://reference.wolfram.com/language/ref/Table.html
237
237
  describe "#table" do
238
238
 
239
- describe "Details" do
239
+ describe "Details:" do
240
240
 
241
241
  example "#table[expr,spec1,spec2] is effectively equivalent to #table[#table[expr,spec2],spec1]" do
242
242
  expect(table[->(i,j){ [i,j] }, 2, 3]).to eq table[->(i){ table[->(j){ [i,j] }, 3] }, 2]
@@ -244,7 +244,7 @@ describe MLL do
244
244
 
245
245
  end
246
246
 
247
- describe "Basic Examples" do
247
+ describe "Basic Examples:" do
248
248
 
249
249
  example "a table of the first 10 squares" do
250
250
  expect(table[->(i){ i**2 }, 10]).to be_a Array
@@ -271,7 +271,7 @@ describe MLL do
271
271
  ]
272
272
  end
273
273
 
274
- describe "Scope" do
274
+ describe "Scope:" do
275
275
 
276
276
  # TODO: "Make a triangular array:"
277
277
 
@@ -284,7 +284,7 @@ describe MLL do
284
284
 
285
285
  end
286
286
 
287
- describe "Applications" do
287
+ describe "Applications:" do
288
288
 
289
289
  example "column table(binomial, )" do
290
290
  skip "#binomial and #column are yet to be implemented"
@@ -309,7 +309,7 @@ describe MLL do
309
309
  expect{ range[1,2,0] }.to raise_error ArgumentError
310
310
  end
311
311
 
312
- describe "Details" do
312
+ describe "Details:" do
313
313
 
314
314
  example "the arguments need not be integers" do
315
315
  expect(range[0.25,2.9,1.25]).to be_a Enumerator
@@ -318,7 +318,7 @@ describe MLL do
318
318
 
319
319
  end
320
320
 
321
- describe "Basic Examples" do
321
+ describe "Basic Examples:" do
322
322
 
323
323
  example "range(n)" do
324
324
  expect(range[4]).to be_a Enumerator
@@ -344,7 +344,7 @@ describe MLL do
344
344
  expect(range[3,1,-1].to_a).to eq [3,2,1]
345
345
  end
346
346
 
347
- describe "Generalizations & Extensions" do
347
+ describe "Generalizations & Extensions:" do
348
348
 
349
349
  example "use a list of range specifications" do
350
350
  expect(range[[5,2,6,3]]).to be_a Enumerator
@@ -356,7 +356,7 @@ describe MLL do
356
356
 
357
357
  end
358
358
 
359
- describe "Applications" do
359
+ describe "Applications:" do
360
360
 
361
361
  example "produce a geometric sequence" do
362
362
  skip "#power is yet to be implemented"
@@ -366,7 +366,7 @@ describe MLL do
366
366
 
367
367
  end
368
368
 
369
- describe "Properties & Relations" do
369
+ describe "Properties & Relations:" do
370
370
 
371
371
  example "#range[imin,imax,di] is equivalent to #table[i,[imin,imax,di]]" do
372
372
  expect(range[2,8,3].to_a).to eq table[->(i){ i }, [2,8,3]]
@@ -386,7 +386,7 @@ describe MLL do
386
386
  expect(range[1..3].to_a.map(&:to_a)).to eq [[1],[1,2],[1,2,3]]
387
387
  end
388
388
 
389
- describe "Neat Examples" do
389
+ describe "Neat Examples:" do
390
390
 
391
391
  example "make nested ranges" do
392
392
  range[range[range[3]]].tap do |o|
@@ -418,7 +418,7 @@ describe MLL do
418
418
  # expect{ subdivide[0] }.to raise_error ArgumentError
419
419
  # end
420
420
 
421
- describe "Details" do
421
+ describe "Details:" do
422
422
 
423
423
  example "generates a list of length n+1" do
424
424
  expect(subdivide[5]).to be_a Enumerator
@@ -427,7 +427,7 @@ describe MLL do
427
427
 
428
428
  end
429
429
 
430
- describe "Basic Examples" do
430
+ describe "Basic Examples:" do
431
431
 
432
432
  example "subdivide the unit interval into 4 equal parts" do
433
433
  expect(subdivide[4]).to be_a Enumerator
@@ -450,7 +450,7 @@ describe MLL do
450
450
 
451
451
  end
452
452
 
453
- describe "Properties & Relations" do
453
+ describe "Properties & Relations:" do
454
454
 
455
455
  example "subdivide[xmin,xmax,n] is equivalent to xmin+(xmax-xmin)Range[0,n]/n" do
456
456
  expect(subdivide[2,10,4].to_a).to eq plus[2,divide[times[10-2,range[0,4]],4]].to_a
@@ -468,7 +468,7 @@ describe MLL do
468
468
  expect(nest_list[->(*args){}, 0, 5].to_a.size).to eq 6
469
469
  end
470
470
 
471
- describe "Basic Examples" do
471
+ describe "Basic Examples:" do
472
472
 
473
473
  example "???" do
474
474
  skip "#cos (or #sqrt or anything unar is yet to be implemented"
@@ -476,7 +476,7 @@ describe MLL do
476
476
 
477
477
  end
478
478
 
479
- describe "Scope" do
479
+ describe "Scope:" do
480
480
 
481
481
  example "nesting can return a single number" do
482
482
  skip "#sqrt is yet to be implemented"
@@ -484,7 +484,7 @@ describe MLL do
484
484
 
485
485
  end
486
486
 
487
- describe "Applications" do
487
+ describe "Applications:" do
488
488
 
489
489
  example "powers of 2" do
490
490
  expect(nest_list[->(i){ 2*i }, 1, 10]).to be_a Enumerator
@@ -500,7 +500,7 @@ describe MLL do
500
500
  end
501
501
  example "random walk" do
502
502
  expect(( r = Random.new(0); nest_list[->(i){ i+[-1,1][r.rand(2)] }, 0, 20] )).to be_a Enumerator
503
- expect(( r = Random.new(0); 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]
503
+ expect(( r = Random.new(0); 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]
504
504
  end
505
505
  example "successively rotate a list" do
506
506
  expect(nest_list[->(i){ i.rotate 1 }, [1,2,3,4], 4]).to be_a Enumerator
@@ -509,7 +509,7 @@ describe MLL do
509
509
 
510
510
  end
511
511
 
512
- describe "Properties & Relations" do
512
+ describe "Properties & Relations:" do
513
513
 
514
514
  example "#nest gives the last element of #nest_list" do
515
515
  expect(nest_list[->(i){ i*2 }, 3, 4].to_a.last).to eq nest[->(i){ i*2 }, 3, 4]
@@ -536,7 +536,7 @@ describe MLL do
536
536
  # http://reference.wolfram.com/language/ref/FoldList.html
537
537
  describe "#fold_list" do
538
538
 
539
- describe "Details" do
539
+ describe "Details:" do
540
540
 
541
541
  example "with a length n list, #fold_list generates a list of length n+1" do
542
542
  skip "waiting got Wolfram team to fix the reported bug"
@@ -548,7 +548,7 @@ describe MLL do
548
548
 
549
549
  end
550
550
 
551
- describe "Basic Examples" do
551
+ describe "Basic Examples:" do
552
552
 
553
553
  example "cumulative sums of the elements of the list" do
554
554
  expect(fold_list[plus,5,[1,2,3,4]]).to be_a Enumerator
@@ -565,12 +565,12 @@ describe MLL do
565
565
 
566
566
  end
567
567
 
568
- describe "Applications" do
568
+ describe "Applications:" do
569
569
 
570
570
  # TODO maybe move it to README.md
571
571
  example "generate a random walk" do
572
572
  expect(( r = Random.new(0); fold_list[plus, 0, Array.new(20){ [-1,1][r.rand(2)] }] )).to be_a Enumerator
573
- expect(( r = Random.new(0); fold_list[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]
573
+ expect(( r = Random.new(0); fold_list[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]
574
574
  end
575
575
 
576
576
  example "find successively deeper parts in an expression" do
@@ -580,7 +580,7 @@ describe MLL do
580
580
 
581
581
  end
582
582
 
583
- describe "Properties & Relations" do
583
+ describe "Properties & Relations:" do
584
584
 
585
585
  example "makes a list of length n+1" do
586
586
  expect(fold_list[->{}, 0, [*1..10]]).to be_a Enumerator
@@ -601,7 +601,7 @@ describe MLL do
601
601
 
602
602
  end
603
603
 
604
- describe "Neat Examples" do
604
+ describe "Neat Examples:" do
605
605
 
606
606
  example "compute the minimum number of coins of different value needed to make up an amount" do
607
607
  skip "at least #mod is yet to be implemented"
@@ -611,6 +611,85 @@ describe MLL do
611
611
 
612
612
  end
613
613
 
614
+ # http://reference.wolfram.com/language/ref/Map.html
615
+ describe "#map" do
616
+
617
+ # TODO we'll need less nested mappings when we implement stop on depths depletion
618
+
619
+ describe "Details and Options:" do
620
+
621
+ example "levels n1 though n2" do
622
+ expect(map[->(i){ [i] }, [1,[2,[3,[4,[5,6]]]]], [2,4]]).to be_a Enumerator
623
+ expect(map[->(i){ [i] }, [1,[2,[3,[4,[5,6]]]]], [2,4]].
624
+ to_a.map{ |i| i.respond_to?(:to_a) ? i.
625
+ to_a.map{ |i| i.respond_to?(:to_a) ? i.
626
+ to_a.map{ |i| i.respond_to?(:to_a) ? i.
627
+ to_a.map{ |i| i.respond_to?(:to_a) ? i.
628
+ to_a.map{ |i| i.respond_to?(:to_a) ? i.
629
+ to_a.map{ |i| i.respond_to?(:to_a) ? i.
630
+ to_a.map{ |i| i.respond_to?(:to_a) ? i.to_a : i } : i } : i } : i } : i } : i } : i }
631
+ # TODO smth _<>
632
+ ).to eq [1,[[2],[[[3],[[[4],[[5,6]]]]]]]]
633
+ end
634
+
635
+ # TODO "Level corresponds to the whole expression"
636
+ # TODO currying "Map[f][expr] is equivalent to Map[f,expr]"
637
+
638
+ end
639
+
640
+ describe "Basic Examples:" do
641
+
642
+ example "???" do
643
+ expect(map[range, [1,2,3]]).to be_a Enumerator
644
+ expect(map[range, [1,2,3]].to_a.map(&:to_a)).to eq [[1],[1,2],[1,2,3]]
645
+ end
646
+ example "use explicit pure functions" do
647
+ expect(map[->(i){ i**2 }, [1,2,3,4]]).to be_a Enumerator
648
+ expect(map[->(i){ i**2 }, [1,2,3,4]].to_a).to eq [1,4,9,16]
649
+ end
650
+ example "map at top level" do
651
+ expect(map[->(i){ [i] }, [[1,2],[3,4,5]]]).to be_a Enumerator
652
+ expect(map[->(i){ [i] }, [[1,2],[3,4,5]]].to_a.map{ |i| i.to_a.map &:to_a }).to eq [[[1,2]],[[3,4,5]]]
653
+ end
654
+ example "map at level 2" do
655
+ expect(map[->(i){ [i] }, [[1,2],[3,4,5]], [2]]).to be_a Enumerator
656
+ expect(map[->(i){ [i] }, [[1,2],[3,4,5]], [2]].to_a.map(&:to_a)).to eq [[[1],[2]],[[3],[4],[5]]]
657
+ end
658
+ example "map at levels 1 and 2" do
659
+ expect(map[->(i){ [i] }, [[1,2],[3,4,5]], 2]).to be_a Enumerator
660
+ expect(map[->(i){ [i] }, [[1,2],[3,4,5]], 2].to_a.map{ |i| i.to_a.map(&:to_a) }).to eq [[[[1],[2]]],[[[3],[4],[5]]]]
661
+ end
662
+
663
+ end
664
+
665
+ describe "Scope:" do
666
+ # TODO "Map on all levels, starting at level" ant other about Infinity
667
+ end
668
+
669
+ describe "Properties & Relations:" do
670
+
671
+ example "leaves are visited before roots" do
672
+ skip "waiting for infinite map to be implemented"
673
+ log = []
674
+ map[log.method(:<<), [[1,2],[3,4,5]]]
675
+ expect(log).to eq [1,2,[1,2],3,4,5,[3,4,5],[[1,2],[3,4,5]]]
676
+ end
677
+
678
+ # TODO #mapall
679
+
680
+ # TODO #mapthread ?
681
+ # TODO #mapindexed ?
682
+
683
+ # TODO "negative levels"
684
+
685
+ example "#scan does the same as #map, but without returning a result" do
686
+ skip "#scan is yet to be implemented"
687
+ end
688
+
689
+ end
690
+
691
+ end
692
+
614
693
  end
615
694
 
616
695
  # TODO http://reference.wolfram.com/language/guide/ElementsOfLists.html
@@ -630,7 +709,7 @@ describe MLL do
630
709
  # http://reference.wolfram.com/language/ref/Nest.html
631
710
  describe "#nest" do
632
711
 
633
- describe "Basic Examples" do
712
+ describe "Basic Examples:" do
634
713
 
635
714
  example "the function to nest can be a pure function" do
636
715
  expect(nest[->(i){ (1+i)**2 }, 1, 3]).to eq 676
@@ -638,7 +717,7 @@ describe MLL do
638
717
 
639
718
  end
640
719
 
641
- describe "Scope" do
720
+ describe "Scope:" do
642
721
 
643
722
  example "nesting can return a single number" do
644
723
  skip "#sqrt is yet to be implemented"
@@ -646,7 +725,7 @@ describe MLL do
646
725
 
647
726
  end
648
727
 
649
- describe "Applications" do
728
+ describe "Applications:" do
650
729
 
651
730
  example "newton iterations for" do
652
731
  skip "waiting for Rationals to be used"
@@ -657,7 +736,7 @@ describe MLL do
657
736
 
658
737
  end
659
738
 
660
- describe "Properties & Relations" do
739
+ describe "Properties & Relations:" do
661
740
 
662
741
  example "Ruby#inject automatically inserts second arguments from a list" do
663
742
  expect(nest[->(i){ i*2 }, 3, 4]).to eq ([2]*4).inject(3){ |i,j| i*j }
@@ -673,6 +752,55 @@ describe MLL do
673
752
 
674
753
  end
675
754
 
755
+ # http://reference.wolfram.com/language/guide/NumericalData.html
756
+ describe "Numerical Data" do
757
+
758
+ # http://reference.wolfram.com/language/ref/Tally.html
759
+ describe "#tally" do
760
+
761
+ describe "Details:" do
762
+
763
+ example "#tally[list] is equivalent to #tally[list,#sameq]" do
764
+ skip "#sameq is yet to be implemented"
765
+ end
766
+
767
+ end
768
+
769
+ describe "Basic Examples:" do
770
+
771
+ example "obtain tallies for a list" do
772
+ expect(tally[[1, 1, 2, 1, 3, 2, 1]]).to be_a Hash
773
+ expect(tally[[1, 1, 2, 1, 3, 2, 1]]).to eq({1=>4, 2=>2, 3=>1})
774
+ end
775
+
776
+ example "use test argument to count elements with the same class" do
777
+ expect(tally[[[1,2], [1,2,3,4], 1, [1,2,3,4], 1], ->(i,j){ i.class == j.class }]).to be_a Hash
778
+ expect(tally[[[1,2], [1,2,3,4], 1, [1,2,3,4], 1], ->(i,j){ i.class == j.class }]).to eq({[1,2]=>3, 1=>2})
779
+ end
780
+
781
+ example "count the instances of randomly generated integers" do
782
+ expect(( r = Random.new(0); tally[Array.new(50){ r.rand 10 }] )).to be_a Hash
783
+ expect(( r = Random.new(0); tally[Array.new(50){ r.rand 10 }] )).to eq({5=>4, 0=>6, 3=>10, 7=>7, 9=>5, 2=>4, 4=>3, 6=>2, 8=>5, 1=>4})
784
+ end
785
+
786
+ end
787
+
788
+ describe "Properties & Relations:" do
789
+
790
+ example "elements with highest frequencies are given by #commonest" do
791
+ skip "#commonest is yet to be implemented"
792
+ end
793
+
794
+ example "#tally is a discrete analog of #bincounts" do
795
+ skip "#bincounts is yet to be implemented"
796
+ end
797
+
798
+ end
799
+
800
+ end
801
+
802
+ end
803
+
676
804
  end
677
805
 
678
806
  # TODO http://reference.wolfram.com/language/guide/HandlingArraysOfData.html
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: 1.1.0
4
+ version: 1.2.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-12 00:00:00.000000000 Z
11
+ date: 2015-07-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler