mll 1.1.0 → 1.2.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.
- checksums.yaml +4 -4
- data/README.md +58 -21
- data/Rakefile +1 -0
- data/lib/mll.rb +105 -68
- data/mll.gemspec +1 -1
- data/spec/_spec.rb +168 -40
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ce709bc99f6cbd85ca763a4752346b0b5e4112cb
|
4
|
+
data.tar.gz: 0e6ba411ce044ecffbc476fcbefcb61a8cf18926
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
+
[](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
|
14
|
-
4.
|
15
|
-
5.
|
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::
|
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
|
-
|
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
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
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
data/lib/mll.rb
CHANGED
@@ -1,77 +1,114 @@
|
|
1
1
|
module MLL
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
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
|
data/mll.gemspec
CHANGED
data/spec/_spec.rb
CHANGED
@@ -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
|
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
|
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.
|
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-
|
11
|
+
date: 2015-07-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|