mll 1.2.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem Version](https://badge.fury.io/rb/mll.svg)](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
|