mll 1.2.0 → 2.1.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 +33 -11
- data/Rakefile +9 -12
- data/lib/mll.rb +51 -23
- data/mll.gemspec +1 -1
- data/spec/_spec.rb +186 -56
- 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: 1bfa93d983183ee395ce32f023a9536220884f0d
|
4
|
+
data.tar.gz: fd3504c892015ccf15a5f451c7877115186a138b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 38fd3e00c764eae431fa980369b2f7deff86908529343a3fb07fe37ad6c02e354b87e9ebdfd13a1581f9af8b4e3ce7cd00547840b78132a43c2ecede1ffa135d
|
7
|
+
data.tar.gz: f4f393855791bf20d726cecef3d6858a7f9cde8267b91abd59a413d689b0a3e613113958bab3c3b33205771eec42f56cd8fe7dca8cb9170f737ee2dd69f7a5fe
|
data/README.md
CHANGED
@@ -2,13 +2,13 @@
|
|
2
2
|
|
3
3
|
[](http://badge.fury.io/rb/mll)
|
4
4
|
|
5
|
-
|
5
|
+
### What
|
6
6
|
|
7
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
8
|
|
9
9
|
The main goal is to make Ruby more powerful by including the most used functions, that Ruby lacks, such as `Table[]`, `FoldList[]`, etc. Visualisations are possible later by using additional gems.
|
10
10
|
|
11
|
-
|
11
|
+
### Why
|
12
12
|
|
13
13
|
0. `::map` can map Arrays at specified depth!
|
14
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
|
@@ -18,7 +18,7 @@ The main goal is to make Ruby more powerful by including the most used functions
|
|
18
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
19
|
6. `::tally` -- shortcut to a probably the most common usage of `#group_by` -- calculating total occurences.
|
20
20
|
|
21
|
-
|
21
|
+
### How
|
22
22
|
|
23
23
|
MLL::range[ 2, 3 ] # => 2..3
|
24
24
|
MLL::range[[2, 3]] # => [1..2, 1..3]
|
@@ -77,11 +77,11 @@ The main goal is to make Ruby more powerful by including the most used functions
|
|
77
77
|
|
78
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.
|
79
79
|
|
80
|
-
|
80
|
+
### Installation
|
81
81
|
|
82
82
|
$ gem install mll
|
83
83
|
|
84
|
-
|
84
|
+
### Testing with RSpec before contributing
|
85
85
|
|
86
86
|
rspec
|
87
87
|
|
@@ -89,15 +89,22 @@ or
|
|
89
89
|
|
90
90
|
rake spec
|
91
91
|
|
92
|
-
|
92
|
+
### TODO (this section is filled automatically by `rake todo` task -- do not remove)
|
93
93
|
|
94
94
|
#### lib/mll.rb
|
95
95
|
|
96
96
|
```
|
97
97
|
module MLL
|
98
98
|
class << self
|
99
|
+
def dimensions
|
100
|
+
lambda do |list, limit = nil|
|
101
|
+
enumerator = Enumerator.new do |e|
|
102
|
+
while list.map(&:class).uniq == [Array] &&
|
103
|
+
# TODO refactor into depth-first yielding
|
104
|
+
def nest_while
|
105
|
+
# TODO finish me
|
99
106
|
def fold_list
|
100
|
-
lambda do |
|
107
|
+
lambda do |x, list, f = nil|
|
101
108
|
# TODO use Ruby#inject ?
|
102
109
|
def map
|
103
110
|
# TODO validate depths
|
@@ -118,6 +125,8 @@ module MLL
|
|
118
125
|
# TODO @fraggedICE wishes using Rational -- would also allow implementing more examples
|
119
126
|
# TODO elegantly get rid of repetitive type checks
|
120
127
|
# TODO ? let(:fake_lambda){ ->(*args){fail} }
|
128
|
+
# TODO rewrite all Lazy#to_a into Lazy#force (it's not recursive and not documented)
|
129
|
+
# TODO maybe make indexes count from 0 not 1
|
121
130
|
describe MLL do
|
122
131
|
describe "List Manipulation" do
|
123
132
|
describe "Constructing Lists" do
|
@@ -134,7 +143,7 @@ describe MLL do
|
|
134
143
|
# TODO we'll need less nested mappings when we implement stop on depths depletion
|
135
144
|
describe "Details and Options:" do
|
136
145
|
example "levels n1 though n2" do
|
137
|
-
expect(map[
|
146
|
+
expect(map[[1,[2,[3,[4,[5,6]]]]], [2,4], ->(i){ [i] }].
|
138
147
|
# TODO smth _<>
|
139
148
|
# TODO "Level corresponds to the whole expression"
|
140
149
|
# TODO currying "Map[f][expr] is equivalent to Map[f,expr]"
|
@@ -145,14 +154,27 @@ describe MLL do
|
|
145
154
|
# TODO #mapthread ?
|
146
155
|
# TODO #mapindexed ?
|
147
156
|
# TODO "negative levels"
|
148
|
-
# TODO http://reference.wolfram.com/language/guide/ElementsOfLists.html
|
149
157
|
# TODO http://reference.wolfram.com/language/guide/RearrangingAndRestructuringLists.html
|
150
158
|
# TODO http://reference.wolfram.com/language/guide/MathematicalAndCountingOperationsOnLists.html
|
151
159
|
describe "Functional Programming" do
|
152
160
|
describe "Iteratively Applying Functions" do
|
153
161
|
# TODO move #nest_list and #fold_list and others here?
|
154
|
-
|
155
|
-
|
162
|
+
# TODO examples in README.rb
|
163
|
+
describe "#nest_while" do
|
164
|
+
describe "Details:" do
|
165
|
+
# TODO a lot
|
166
|
+
describe "Scope:" do
|
167
|
+
# TODO "always compare all values generated" do
|
168
|
+
# TODO "compare the last two values generated" do
|
169
|
+
# TODO "start comparisons after 4 iterations, and compare using the 4 last values" do
|
170
|
+
# TODO "start comparisons after 4 iterations, and compare using the 6 last values" do
|
171
|
+
# TODO example "stop after at most 4 iterations, even if the test is still true" do
|
172
|
+
describe "Generalizations & Extensions:" do
|
173
|
+
# TODO "return the last value for which the condition was still true" do
|
174
|
+
describe "Applications:" do
|
175
|
+
# TODO example "find the next twin prime after 888" do
|
176
|
+
describe "Properties & Relations:" do
|
177
|
+
# TODO "#nest_while can be expressed in terms of a while loop" do
|
156
178
|
# TODO http://reference.wolfram.com/language/guide/HandlingArraysOfData.html
|
157
179
|
# TODO http://reference.wolfram.com/language/guide/ComputationWithStructuredDatasets.html
|
158
180
|
```
|
data/Rakefile
CHANGED
@@ -6,32 +6,29 @@ task :todo do |t|
|
|
6
6
|
fail unless File.exist? "README.md"
|
7
7
|
File.open("README.md", "r+") do |readme_file|
|
8
8
|
# begin readme_file.gets end until $_[/^## TODO/]
|
9
|
-
readme_file.gets "
|
9
|
+
readme_file.gets "### TODO"
|
10
10
|
readme_file.gets
|
11
11
|
%w{ lib/mll.rb spec/_spec.rb }.each do |file|
|
12
12
|
readme_file.puts "", "#### #{file}", "", "```"
|
13
13
|
stack = []
|
14
|
-
|
15
|
-
File.foreach(file).with_index do |line, i|
|
14
|
+
File.foreach(file) do |line|
|
16
15
|
next unless shift = /\S/ =~ line
|
17
16
|
depth = shift / 2
|
18
|
-
stack[depth] =
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
next unless i == next_line_to_print
|
24
|
-
readme_file.puts line
|
25
|
-
next_line_to_print = lines.shift
|
17
|
+
stack[depth] = line
|
18
|
+
if line[/^\s*# TODO/]
|
19
|
+
readme_file.puts stack.take(depth + 1).compact
|
20
|
+
stack.clear
|
21
|
+
end
|
26
22
|
end
|
27
23
|
readme_file.puts "```"
|
28
24
|
end
|
29
25
|
readme_file.truncate readme_file.pos
|
30
26
|
end
|
27
|
+
puts `md5 README.md`
|
31
28
|
end
|
32
29
|
|
33
30
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
34
31
|
t.verbose = false
|
35
32
|
end
|
36
33
|
|
37
|
-
task :default => %w{ todo
|
34
|
+
task :default => %w{ spec todo }
|
data/lib/mll.rb
CHANGED
@@ -2,25 +2,44 @@ module MLL
|
|
2
2
|
|
3
3
|
class << self
|
4
4
|
|
5
|
+
def dimensions
|
6
|
+
lambda do |list, limit = nil|
|
7
|
+
list = [list]
|
8
|
+
enumerator = Enumerator.new do |e|
|
9
|
+
# String.size shall not pass
|
10
|
+
while list.map(&:class).uniq == [Array] &&
|
11
|
+
list.map(&:size).uniq.size == 1
|
12
|
+
# TODO refactor into depth-first yielding
|
13
|
+
e << list.first.size
|
14
|
+
list.flatten! 1
|
15
|
+
end
|
16
|
+
end
|
17
|
+
limit ? enumerator.lazy.take(limit) : enumerator
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
5
21
|
def tally
|
6
|
-
lambda do |list, test =
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
break
|
14
|
-
end
|
22
|
+
lambda do |list, test = nil| # implement #sameq ?
|
23
|
+
return Hash[ list.group_by{ |i| i }.map{ |k, v| [k, v.size] } ] unless test
|
24
|
+
Hash.new{ 0 }.tap do |result|
|
25
|
+
list.each do |item|
|
26
|
+
result[
|
27
|
+
list.find{ |key| test[key, item] }
|
28
|
+
] += 1
|
15
29
|
end
|
16
|
-
keys << item
|
17
30
|
end
|
18
|
-
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def nest
|
35
|
+
lambda do |expr, n, f|
|
36
|
+
n.times{ expr = f.call expr }
|
37
|
+
expr
|
19
38
|
end
|
20
39
|
end
|
21
40
|
|
22
41
|
def nest_list
|
23
|
-
lambda do |
|
42
|
+
lambda do |expr, n, f|
|
24
43
|
Enumerator.new do |e|
|
25
44
|
e << expr
|
26
45
|
n.times do
|
@@ -29,19 +48,21 @@ module MLL
|
|
29
48
|
end
|
30
49
|
end
|
31
50
|
end
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
n.times{ expr = f.call expr }
|
51
|
+
|
52
|
+
def nest_while
|
53
|
+
# TODO finish me
|
54
|
+
lambda do |expr, f, test|
|
55
|
+
expr = f[expr] while test[expr]
|
38
56
|
expr
|
39
57
|
end
|
40
58
|
end
|
41
59
|
|
42
60
|
def fold_list
|
43
|
-
lambda do |
|
44
|
-
|
61
|
+
lambda do |x, list, f = nil|
|
62
|
+
unless f
|
63
|
+
f = list
|
64
|
+
x, *list = x.to_a
|
65
|
+
end
|
45
66
|
# TODO use Ruby#inject ?
|
46
67
|
Enumerator.new do |e|
|
47
68
|
e << x
|
@@ -55,13 +76,14 @@ module MLL
|
|
55
76
|
def map
|
56
77
|
# TODO validate depths
|
57
78
|
# TODO break on passing all depths
|
58
|
-
lambda do |
|
79
|
+
lambda do |list, depths, f = nil|
|
80
|
+
depths, f = [1], depths unless f
|
59
81
|
depths = Range.new(*depths) if depths.size == 2
|
60
82
|
depths = Range.new(1,depths) if depths.is_a? Integer
|
61
83
|
g = lambda do |list, depth|
|
62
|
-
next list unless list.
|
84
|
+
next list unless list.is_a? Array
|
63
85
|
temp = list.lazy.map{ |i| g[i, depth + 1] }
|
64
|
-
temp = temp.map &f if depths.include? depth
|
86
|
+
temp = temp.lazy.map &f if depths.include? depth
|
65
87
|
temp
|
66
88
|
end
|
67
89
|
g[list, 1]
|
@@ -170,5 +192,11 @@ module MLL
|
|
170
192
|
|
171
193
|
define_orderless_function(:plus, 0) { |a, b| _plus.call a, b }
|
172
194
|
define_orderless_function(:times, 1) { |a, b| _times.call a, b }
|
195
|
+
|
196
|
+
def self.mean
|
197
|
+
lambda do |list|
|
198
|
+
divide[times[plus[*list], 1.0], list.size]
|
199
|
+
end
|
200
|
+
end
|
173
201
|
|
174
202
|
end
|
data/mll.gemspec
CHANGED
data/spec/_spec.rb
CHANGED
@@ -14,6 +14,9 @@ require_relative File.join "..", "lib", "mll"
|
|
14
14
|
# TODO elegantly get rid of repetitive type checks
|
15
15
|
# TODO ? let(:fake_lambda){ ->(*args){fail} }
|
16
16
|
|
17
|
+
# TODO rewrite all Lazy#to_a into Lazy#force (it's not recursive and not documented)
|
18
|
+
|
19
|
+
# TODO maybe make indexes count from 0 not 1
|
17
20
|
|
18
21
|
# http://reference.wolfram.com/language/guide/LanguageOverview.html
|
19
22
|
describe MLL do
|
@@ -168,8 +171,8 @@ describe MLL do
|
|
168
171
|
|
169
172
|
# idk why not in 'Properties & Relations'
|
170
173
|
example "accumulate makes a cumulative sum" do
|
171
|
-
expect(fold_list[
|
172
|
-
expect(fold_list[
|
174
|
+
expect(fold_list[0, [1,2,3], plus]).to be_a Enumerator
|
175
|
+
expect(fold_list[0, [1,2,3], plus].to_a).to eq [0,1,3,6]
|
173
176
|
end
|
174
177
|
|
175
178
|
end
|
@@ -464,8 +467,8 @@ describe MLL do
|
|
464
467
|
describe "#nest_list" do
|
465
468
|
|
466
469
|
example "gives a list of length n+1" do
|
467
|
-
expect(nest_list[
|
468
|
-
expect(nest_list[->(*
|
470
|
+
expect(nest_list[0, 5, ->(*){}]).to be_a Enumerator
|
471
|
+
expect(nest_list[0, 5, ->(*){}].to_a.size).to eq 6
|
469
472
|
end
|
470
473
|
|
471
474
|
describe "Basic Examples:" do
|
@@ -487,24 +490,24 @@ describe MLL do
|
|
487
490
|
describe "Applications:" do
|
488
491
|
|
489
492
|
example "powers of 2" do
|
490
|
-
expect(nest_list[->(i){ 2*i }
|
491
|
-
expect(nest_list[->(i){ 2*i }
|
493
|
+
expect(nest_list[1, 10, ->(i){ 2*i }]).to be_a Enumerator
|
494
|
+
expect(nest_list[1, 10, ->(i){ 2*i }].to_a).to eq [1,2,4,8,16,32,64,128,256,512,1024]
|
492
495
|
end
|
493
496
|
example "iterates in the problem" do
|
494
|
-
expect(nest_list[->(i){ i.even? ? i/2 : (i*3+1)/2 }
|
495
|
-
expect(nest_list[->(i){ i.even? ? i/2 : (i*3+1)/2 }
|
497
|
+
expect(nest_list[100, 20, ->(i){ i.even? ? i/2 : (i*3+1)/2 }]).to be_a Enumerator
|
498
|
+
expect(nest_list[100, 20, ->(i){ i.even? ? i/2 : (i*3+1)/2 }].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]
|
496
499
|
end
|
497
500
|
example "linear congruential pseudorandom generator" do
|
498
|
-
expect(nest_list[->(i){ (i*59)%101 }
|
499
|
-
expect(nest_list[->(i){ (i*59)%101 }
|
501
|
+
expect(nest_list[1, 15, ->(i){ (i*59)%101 }]).to be_a Enumerator
|
502
|
+
expect(nest_list[1, 15, ->(i){ (i*59)%101 }].to_a).to eq [1,59,47,46,88,41,96,8,68,73,65,98,25,61,64,39]
|
500
503
|
end
|
501
504
|
example "random walk" do
|
502
|
-
expect(( r = Random.new(0); nest_list[->(i){ i+[-1,1][r.rand(2)] }
|
503
|
-
expect(( r = Random.new(0); nest_list[->(i){ i+[-1,1][r.rand(2)] }
|
505
|
+
expect(( r = Random.new(0); nest_list[0, 20, ->(i){ i+[-1,1][r.rand(2)] }] )).to be_a Enumerator
|
506
|
+
expect(( r = Random.new(0); nest_list[0, 20, ->(i){ i+[-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]
|
504
507
|
end
|
505
508
|
example "successively rotate a list" do
|
506
|
-
expect(nest_list[->(i){ i.rotate 1 }
|
507
|
-
expect(nest_list[->(i){ i.rotate 1 }
|
509
|
+
expect(nest_list[[1,2,3,4], 4, ->(i){ i.rotate 1 }]).to be_a Enumerator
|
510
|
+
expect(nest_list[[1,2,3,4], 4, ->(i){ i.rotate 1 }].to_a).to eq [[1,2,3,4],[2,3,4,1],[3,4,1,2],[4,1,2,3],[1,2,3,4]]
|
508
511
|
end
|
509
512
|
|
510
513
|
end
|
@@ -512,16 +515,15 @@ describe MLL do
|
|
512
515
|
describe "Properties & Relations:" do
|
513
516
|
|
514
517
|
example "#nest gives the last element of #nest_list" do
|
515
|
-
expect(nest_list[->(i){ i*2 }
|
518
|
+
expect(nest_list[3, 4, ->(i){ i*2 }].to_a.last).to eq nest[3, 4, ->(i){ i*2 }]
|
516
519
|
end
|
517
|
-
|
518
520
|
example "nesting zero times simply returns to the original argument" do
|
519
|
-
expect(nest_list[->{fail}
|
520
|
-
expect(nest_list[->(*
|
521
|
+
expect(nest_list[5, 0, ->(*){fail}]).to be_a Enumerator
|
522
|
+
expect(nest_list[5, 0, ->(*){fail}].to_a).to eq [5]
|
521
523
|
end
|
522
524
|
example "#fold_list automatically inserts second arguments from a list" do
|
523
|
-
expect(nest_list[->(i ){ i*2 }
|
524
|
-
fold_list[->(i,j){ i*j }
|
525
|
+
expect(nest_list[3, 4, ->(i ){ i*2 }].to_a).to eq \
|
526
|
+
fold_list[3, [2]*4, ->(i,j){ i*j }].to_a
|
525
527
|
end
|
526
528
|
|
527
529
|
end
|
@@ -542,8 +544,8 @@ describe MLL do
|
|
542
544
|
skip "waiting got Wolfram team to fix the reported bug"
|
543
545
|
end
|
544
546
|
example "#fold_list[f,list] is equivalent to #fold_list[f,[list][0],list[1..-1]]" do
|
545
|
-
expect(fold_list[
|
546
|
-
expect(fold_list[
|
547
|
+
expect(fold_list[[1,2,3], plus]).to be_a Enumerator
|
548
|
+
expect(fold_list[[1,2,3], plus].to_a).to eq fold_list[1, [2,3], plus].to_a
|
547
549
|
end
|
548
550
|
|
549
551
|
end
|
@@ -551,16 +553,16 @@ describe MLL do
|
|
551
553
|
describe "Basic Examples:" do
|
552
554
|
|
553
555
|
example "cumulative sums of the elements of the list" do
|
554
|
-
expect(fold_list[
|
555
|
-
expect(fold_list[
|
556
|
+
expect(fold_list[5, [1,2,3,4], plus]).to be_a Enumerator
|
557
|
+
expect(fold_list[5, [1,2,3,4], plus].to_a).to eq [5,6,8,11,15]
|
556
558
|
end
|
557
559
|
example "cumulative powers" do
|
558
|
-
expect(fold_list[->(base, power){ base ** power }
|
559
|
-
expect(fold_list[->(base, power){ base ** power }
|
560
|
+
expect(fold_list[2, [3,2,1], ->(base, power){ base ** power }]).to be_a Enumerator
|
561
|
+
expect(fold_list[2, [3,2,1], ->(base, power){ base ** power }].to_a).to eq [2,8,64,64]
|
560
562
|
end
|
561
563
|
example "start from the first element of the list" do
|
562
|
-
expect(fold_list[
|
563
|
-
expect(fold_list[
|
564
|
+
expect(fold_list[[1,2,3,4], plus]).to be_a Enumerator
|
565
|
+
expect(fold_list[[1,2,3,4], plus].to_a).to eq [1,3,6,10]
|
564
566
|
end
|
565
567
|
|
566
568
|
end
|
@@ -569,13 +571,13 @@ describe MLL do
|
|
569
571
|
|
570
572
|
# TODO maybe move it to README.md
|
571
573
|
example "generate a random walk" do
|
572
|
-
expect(( r = Random.new(0); fold_list[
|
573
|
-
expect(( r = Random.new(0); fold_list[
|
574
|
+
expect(( r = Random.new(0); fold_list[0, Array.new(20){ [-1,1][r.rand(2)] }, plus] )).to be_a Enumerator
|
575
|
+
expect(( r = Random.new(0); fold_list[0, Array.new(20){ [-1,1][r.rand(2)] }, plus] ).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
576
|
end
|
575
577
|
|
576
578
|
example "find successively deeper parts in an expression" do
|
577
|
-
expect(fold_list[
|
578
|
-
expect(fold_list[
|
579
|
+
expect(fold_list[[[1,2],[3,[4,5],6,7],8], [1,1,0], ->(list,index){ list[index] }]).to be_a Enumerator
|
580
|
+
expect(fold_list[[[1,2],[3,[4,5],6,7],8], [1,1,0], ->(list,index){ list[index] }].to_a).to eq [[[1,2],[3,[4,5],6,7],8],[3,[4,5],6,7],[4,5],4]
|
579
581
|
end
|
580
582
|
|
581
583
|
end
|
@@ -583,20 +585,20 @@ describe MLL do
|
|
583
585
|
describe "Properties & Relations:" do
|
584
586
|
|
585
587
|
example "makes a list of length n+1" do
|
586
|
-
expect(fold_list[
|
587
|
-
expect(fold_list[
|
588
|
+
expect(fold_list[0, [*1..10], ->(*){}]).to be_a Enumerator
|
589
|
+
expect(fold_list[0, [*1..10], ->(*){}].to_a.size).to eq 11
|
588
590
|
end
|
589
591
|
example "folding with an empty list does not apply the function at all" do
|
590
|
-
expect(fold_list[
|
591
|
-
expect(fold_list[->(*
|
592
|
+
expect(fold_list[0, [], ->(*){}]).to be_a Enumerator
|
593
|
+
expect(fold_list[0, [], ->(*){}].to_a).to eq [0]
|
592
594
|
end
|
593
595
|
example "Ruby#inject gives the last element of #fold_list" do
|
594
596
|
f = ->(i,j){ i+j }
|
595
|
-
expect(fold_list[
|
596
|
-
expect(fold_list[
|
597
|
+
expect(fold_list[[1,2,3], f]).to be_a Enumerator
|
598
|
+
expect(fold_list[[1,2,3], f].to_a.last).to eq [1,2,3].inject(&f)
|
597
599
|
end
|
598
600
|
example "functions that ignore their second argument give the same result as in #nest_list" do
|
599
|
-
expect(fold_list[->(i,_){ [i] }
|
601
|
+
expect(fold_list[0, range[5], ->(i,_){ [i] }].to_a).to eq nest_list[0, 5, ->(i){ [i] }].to_a
|
600
602
|
end
|
601
603
|
|
602
604
|
end
|
@@ -619,8 +621,8 @@ describe MLL do
|
|
619
621
|
describe "Details and Options:" do
|
620
622
|
|
621
623
|
example "levels n1 though n2" do
|
622
|
-
expect(map[
|
623
|
-
expect(map[
|
624
|
+
expect(map[[1,[2,[3,[4,[5,6]]]]], [2,4], ->(i){ [i] }]).to be_a Enumerator
|
625
|
+
expect(map[[1,[2,[3,[4,[5,6]]]]], [2,4], ->(i){ [i] }].
|
624
626
|
to_a.map{ |i| i.respond_to?(:to_a) ? i.
|
625
627
|
to_a.map{ |i| i.respond_to?(:to_a) ? i.
|
626
628
|
to_a.map{ |i| i.respond_to?(:to_a) ? i.
|
@@ -640,24 +642,24 @@ describe MLL do
|
|
640
642
|
describe "Basic Examples:" do
|
641
643
|
|
642
644
|
example "???" do
|
643
|
-
expect(map[
|
644
|
-
expect(map[
|
645
|
+
expect(map[[1,2,3], range]).to be_a Enumerator
|
646
|
+
expect(map[[1,2,3], range].to_a.map(&:to_a)).to eq [[1],[1,2],[1,2,3]]
|
645
647
|
end
|
646
648
|
example "use explicit pure functions" do
|
647
|
-
expect(map[->(i){ i**2 }
|
648
|
-
expect(map[->(i){ i**2 }
|
649
|
+
expect(map[[1,2,3,4], ->(i){ i**2 }]).to be_a Enumerator
|
650
|
+
expect(map[[1,2,3,4], ->(i){ i**2 }].to_a).to eq [1,4,9,16]
|
649
651
|
end
|
650
652
|
example "map at top level" do
|
651
|
-
expect(map[
|
652
|
-
expect(map[
|
653
|
+
expect(map[[[1,2],[3,4,5]], ->(i){ [i] }]).to be_a Enumerator
|
654
|
+
expect(map[[[1,2],[3,4,5]], ->(i){ [i] }].to_a.map{ |i| i.to_a.map &:to_a }).to eq [[[1,2]],[[3,4,5]]]
|
653
655
|
end
|
654
656
|
example "map at level 2" do
|
655
|
-
expect(map[
|
656
|
-
expect(map[
|
657
|
+
expect(map[[[1,2],[3,4,5]], [2], ->(i){ [i] }]).to be_a Enumerator
|
658
|
+
expect(map[[[1,2],[3,4,5]], [2], ->(i){ [i] }].to_a.map(&:to_a)).to eq [[[1],[2]],[[3],[4],[5]]]
|
657
659
|
end
|
658
660
|
example "map at levels 1 and 2" do
|
659
|
-
expect(map[
|
660
|
-
expect(map[
|
661
|
+
expect(map[[[1,2],[3,4,5]], 2, ->(i){ [i] }]).to be_a Enumerator
|
662
|
+
expect(map[[[1,2],[3,4,5]], 2, ->(i){ [i] }].to_a.map{ |i| i.to_a.map(&:to_a) }).to eq [[[[1],[2]]],[[[3],[4],[5]]]]
|
661
663
|
end
|
662
664
|
|
663
665
|
end
|
@@ -692,7 +694,45 @@ describe MLL do
|
|
692
694
|
|
693
695
|
end
|
694
696
|
|
695
|
-
#
|
697
|
+
# http://reference.wolfram.com/language/guide/ElementsOfLists.html
|
698
|
+
describe "Elements of Lists" do
|
699
|
+
|
700
|
+
describe "#dimensions" do
|
701
|
+
|
702
|
+
describe "Basic Examples:" do
|
703
|
+
|
704
|
+
example "dimensions of a matrix" do
|
705
|
+
expect(dimensions[[[1,2,3],[4,5,6]]]).to be_a Enumerator
|
706
|
+
expect(dimensions[[[1,2,3],[4,5,6]]].to_a).to eq [2,3]
|
707
|
+
end
|
708
|
+
example "#dimensions counts only dimensions at which an expression is not 'ragged'" do
|
709
|
+
expect(dimensions[[[1,2,3],[4,5],[]]]).to be_a Enumerator
|
710
|
+
expect(dimensions[[[1,2,3],[4,5],[]]].to_a).to eq [3]
|
711
|
+
end
|
712
|
+
example "works with arrays of any depth" do
|
713
|
+
expect(dimensions[[[[[1,2]]]]]).to be_a Enumerator
|
714
|
+
expect(dimensions[[[[[1,2]]]]].to_a).to eq [1,1,1,2]
|
715
|
+
end
|
716
|
+
example "give dimensions only down to level 2" do
|
717
|
+
expect(dimensions[[[[[1,2]]]], 2]).to be_a Enumerator
|
718
|
+
expect(dimensions[[[[[1,2]]]], 2].to_a).to eq [1,1]
|
719
|
+
end
|
720
|
+
|
721
|
+
end
|
722
|
+
|
723
|
+
describe "Properties & Relations" do
|
724
|
+
|
725
|
+
example "???" do
|
726
|
+
expect(dimensions[table[->(*){ 0 }, 2,1,4,3]]).to be_a Enumerator
|
727
|
+
expect(dimensions[table[->(*){ 0 }, 2,1,4,3]].to_a).to eq [2,1,4,3]
|
728
|
+
end
|
729
|
+
|
730
|
+
end
|
731
|
+
|
732
|
+
end
|
733
|
+
|
734
|
+
end
|
735
|
+
|
696
736
|
# TODO http://reference.wolfram.com/language/guide/RearrangingAndRestructuringLists.html
|
697
737
|
# TODO http://reference.wolfram.com/language/guide/MathematicalAndCountingOperationsOnLists.html
|
698
738
|
|
@@ -706,13 +746,15 @@ describe MLL do
|
|
706
746
|
|
707
747
|
# TODO move #nest_list and #fold_list and others here?
|
708
748
|
|
749
|
+
# TODO examples in README.rb
|
750
|
+
|
709
751
|
# http://reference.wolfram.com/language/ref/Nest.html
|
710
752
|
describe "#nest" do
|
711
753
|
|
712
754
|
describe "Basic Examples:" do
|
713
755
|
|
714
756
|
example "the function to nest can be a pure function" do
|
715
|
-
expect(nest[->(i){ (1+i)**2 }
|
757
|
+
expect(nest[1, 3, ->(i){ (1+i)**2 }]).to eq 676
|
716
758
|
end
|
717
759
|
|
718
760
|
end
|
@@ -720,7 +762,7 @@ describe MLL do
|
|
720
762
|
describe "Scope:" do
|
721
763
|
|
722
764
|
example "nesting can return a single number" do
|
723
|
-
skip "#sqrt is yet to be implemented"
|
765
|
+
skip "#sqrt is yet to be implemented" # maybe use Array#zip instead?
|
724
766
|
end
|
725
767
|
|
726
768
|
end
|
@@ -739,12 +781,67 @@ describe MLL do
|
|
739
781
|
describe "Properties & Relations:" do
|
740
782
|
|
741
783
|
example "Ruby#inject automatically inserts second arguments from a list" do
|
742
|
-
expect(nest[->(i){ i*2 }
|
784
|
+
expect(nest[3, 4, ->(i){ i*2 }]).to eq ([2]*4).inject(3){ |i,j| i*j }
|
743
785
|
end
|
744
786
|
|
745
787
|
end
|
746
788
|
|
747
|
-
|
789
|
+
end
|
790
|
+
|
791
|
+
# http://reference.wolfram.com/language/ref/NestWhile.html
|
792
|
+
describe "#nest_while" do
|
793
|
+
|
794
|
+
describe "Details:" do
|
795
|
+
# TODO a lot
|
796
|
+
end
|
797
|
+
|
798
|
+
describe "Basic Examples:" do
|
799
|
+
|
800
|
+
example "keep dividing by 2 until the result is no longer an even number" do
|
801
|
+
expect(nest_while[123456, ->(i){ i / 2 }, ->(i){ i.even? }]).to eq 1929
|
802
|
+
end
|
803
|
+
|
804
|
+
end
|
805
|
+
|
806
|
+
describe "Scope:" do
|
807
|
+
|
808
|
+
# TODO "always compare all values generated" do
|
809
|
+
# TODO "compare the last two values generated" do
|
810
|
+
# TODO "start comparisons after 4 iterations, and compare using the 4 last values" do
|
811
|
+
# TODO "start comparisons after 4 iterations, and compare using the 6 last values" do
|
812
|
+
# TODO example "stop after at most 4 iterations, even if the test is still true" do
|
813
|
+
# expect(nest_while[123456, 1, 4, ->(i){ i / 2 }, ->(i){ i.even? }]).to eq 7716
|
814
|
+
# end
|
815
|
+
|
816
|
+
end
|
817
|
+
|
818
|
+
describe "Generalizations & Extensions:" do
|
819
|
+
|
820
|
+
# TODO "return the last value for which the condition was still true" do
|
821
|
+
|
822
|
+
end
|
823
|
+
|
824
|
+
describe "Applications:" do
|
825
|
+
|
826
|
+
example "find the next prime after 888" do
|
827
|
+
require "prime"
|
828
|
+
expect(nest_while[888, ->(i){ i+1 }, ->(i){ !i.prime? }]).to eq 907
|
829
|
+
end
|
830
|
+
# TODO example "find the next twin prime after 888" do
|
831
|
+
# require "prime"
|
832
|
+
# expect(nest_while[888, 3, ->(i){ i+1 }, ->(i,_,k){ !i.prime? || !k.prime? }]).to eq 1021
|
833
|
+
# end
|
834
|
+
|
835
|
+
end
|
836
|
+
|
837
|
+
describe "Properties & Relations:" do
|
838
|
+
|
839
|
+
example "#fixed_point always compares the last two values" do
|
840
|
+
skip "#fixed_point is yet to be implemented"
|
841
|
+
end
|
842
|
+
# TODO "#nest_while can be expressed in terms of a while loop" do
|
843
|
+
|
844
|
+
end
|
748
845
|
|
749
846
|
end
|
750
847
|
|
@@ -799,6 +896,39 @@ describe MLL do
|
|
799
896
|
|
800
897
|
end
|
801
898
|
|
899
|
+
# http://reference.wolfram.com/language/ref/Mean.html
|
900
|
+
describe "#mean" do
|
901
|
+
|
902
|
+
describe "Basic Examples" do
|
903
|
+
|
904
|
+
example "mean of numeric values" do
|
905
|
+
expect(mean[[1.21, 3.4, 2.15, 4, 1.55]]).to eq 2.462
|
906
|
+
end
|
907
|
+
example "means of elements in each column" do
|
908
|
+
expect(mean[[[1, 2], [3, 4], [5, 6]]]).to be_a Enumerator
|
909
|
+
expect(mean[[[1, 2], [3, 4], [8, 9]]].to_a).to eq [4, 5]
|
910
|
+
end
|
911
|
+
|
912
|
+
end
|
913
|
+
|
914
|
+
describe "Applications" do
|
915
|
+
|
916
|
+
example "a 90-day moving mean" do
|
917
|
+
skip "#moving_map is yet to be implemented"
|
918
|
+
end
|
919
|
+
|
920
|
+
end
|
921
|
+
|
922
|
+
describe "Properties & Relations" do
|
923
|
+
|
924
|
+
example "#moving_average is a sequence of means" do
|
925
|
+
skip "#moving_average is yet to be implemented"
|
926
|
+
end
|
927
|
+
|
928
|
+
end
|
929
|
+
|
930
|
+
end
|
931
|
+
|
802
932
|
end
|
803
933
|
|
804
934
|
end
|
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: 2.1.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-07-
|
11
|
+
date: 2015-07-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|