mll 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -15
  3. data/lib/mll.rb +34 -16
  4. data/mll.gemspec +1 -1
  5. data/spec/_spec.rb +144 -19
  6. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 70676b9e4d6334e3e8391c256aa11c3ea5e9c033
4
- data.tar.gz: 7e8b55eb690a4ee783358750fd25ca1045475508
3
+ metadata.gz: 0b28b0ef583cd90f87454f37cebdc8a3088ba42a
4
+ data.tar.gz: 05757c078b5eade518f1895e71c9bf3e0af97f5f
5
5
  SHA512:
6
- metadata.gz: 449a0ca50feab9413c62cc1a67d37bb4a349ab97f0c842f676cea2ddea06ba03b29d96d8200bd846c9700d3388f60112ab3b900408f5a47aa7aa4b38d78342fd
7
- data.tar.gz: 8f5f8a226918468f4e3f636df329f4520c686181fccca13c26b04bd493018156da4f79101b07a27dfbbfab32de5306b223505dbc52f914d5a8a44bad8b9dd780
6
+ metadata.gz: cf8caa79c3a7cc275b234c1dcb1d1bc6a0bc9a772f585bddc171cc8d4bd2dacff587cc37c963df7fbab53880c48ca62579ba5c63e109235836288611b6011f8a
7
+ data.tar.gz: 8c3053016c69c2ead9e8fd965a661167332e45b00841e15fbdd570325888e5c74e03c5ee89b339bcd665ae75d24bf37574e201686ae0bf3a3b9f3127a1ea9331
data/README.md CHANGED
@@ -1,29 +1,34 @@
1
1
  # MLL (Mathematica Language Library)
2
2
 
3
- Этот гем не ставит перед собой цель полностью имитировать типы данных, синтаксис Wolfram Mathematica Language, или научить Ruby крутым визуализациям. Целью является вложить в Ruby мощь стандартной библиотеки. Прежде всего, List Manipulation. В перспективе визуализация возможна при помощи других гемов.
3
+ ## What
4
4
 
5
- ## Usage
5
+ Этот гем не ставит перед собой цель полностью имитировать типы данных, синтаксис Wolfram Mathematica Language, или научить Ruby крутым визуализациям. Целью является вложить в Ruby мощь стандартной библиотеки. В перспективе визуализация возможна при помощи других гемов.
6
6
 
7
- ~~Планируется несколько способов использования этой библиотеки -- как доступ к ней через `MLL::`, так и манкипатчинг стандартных типов, таких как Numeric и Array.~~
7
+ ## Why
8
8
 
9
- ### Examples:
9
+ 1. Важной является реализация https://reference.wolfram.com/language/ref/Listable.html: автоматическое применение функции ко всем элементам аргумента, если тот является List-ом (Array-ем в среде Ruby).
10
+ 2. `::range`, в отличие от рубишного, может иметь отрицательный step.
11
+ 3. `::table`, в отличие от рубишного `.map`, может создавать многомерные массивы одним вызовом, а не только вложенными.
10
12
 
11
- MLL::range(3).to_a #=> [1, 2, 3]
12
- MLL::range(2, 3).to_a #=> [
13
- #<Enumerator: 1..2:step(1)>,
14
- #<Enumerator: 1..3:step(1)>,
15
- ]
16
- MLL::range(1..3) #=> [
17
- #<Enumerator: 1..1:step(1)>,
18
- #<Enumerator: 1..2:step(1)>,
19
- #<Enumerator: 1..3:step(1)>
20
- ]
13
+ ## How
14
+
15
+ MLL::range(2, 3) #=> 2..3
16
+ MLL::range([2, 3]) #=> [1..2, 1..3]
17
+ MLL::range(1..3) #=> [1..1, 1..2, 1..3]
18
+
19
+ MLL::table ->(i,j){ i+j }, [[1, 0, 1]], [[0, 2, 0]]
20
+ #=> [[1, 3, 1],
21
+ [0, 2, 0],
22
+ [1, 3, 1]]
23
+ MLL::table ->(i,j,k){ 100*i + 10*j + k }, 2, 3, 4
24
+ # => [[[111, 112, 113, 114], [121, 122, 123, 124], [131, 132, 133, 134]],
25
+ [[211, 212, 213, 214], [221, 222, 223, 224], [231, 232, 233, 234]]]
21
26
 
22
27
  ## Installation
23
28
 
24
29
  $ gem install mll
25
30
 
26
- ### Testing with RSpec before contributing
31
+ ## Testing with RSpec before contributing
27
32
 
28
33
  rspec
29
34
 
data/lib/mll.rb CHANGED
@@ -1,22 +1,22 @@
1
1
  module MLL
2
2
 
3
- def self.define_function_that_can_enumerate name, &block
4
- # http://stackoverflow.com/a/12792313/322020
5
- (class << self; self end).class_eval do
3
+ # https://reference.wolfram.com/language/ref/Listable.html
4
+ def self.define_listable_function name, &block
5
+ (class << self; self end).class_eval do # http://stackoverflow.com/a/12792313/322020
6
6
  define_method name do |*args|
7
- if args.size == 1 && args.first.respond_to?(:map)
8
- args.first.lazy.map &method(name)
9
- else
10
- block.call *args
11
- end
7
+ # p [name, args]
8
+ next block.call *args unless args[0].respond_to? :map
9
+ next args[0].lazy.map{ |i| send name, i, *args.drop(1) } unless args[1].respond_to? :map
10
+ # raise "idk how to list this function" if args.size > 2
11
+ next args[0].lazy.zip(args[1]).map{ |i,j| send name, i, j, *args.drop(2) }
12
12
  end
13
13
  end
14
14
  end
15
15
 
16
- define_function_that_can_enumerate :range do |*args|
16
+ define_listable_function :range do |*args|
17
17
  case args.size
18
18
  when 1 ; range 1, args[0] # TODO do smth with #table(-n)
19
- when 2 ; Range.new(args[0], args[1])
19
+ when 2 ; Range.new(args[0], args[1]).step
20
20
  when 3
21
21
  case args[2] <=> 0
22
22
  when 0 ; raise ArgumentError.new("step can't be zero")
@@ -24,34 +24,52 @@ module MLL
24
24
  else
25
25
  Enumerator.new do |e|
26
26
  from, to, step = *args
27
- while (step > 0) ? from <= to : from >= to
27
+ # while (step > 0) ? from <= to : from >= to
28
+ while from >= to
28
29
  e << from
29
30
  from += step
30
31
  end
31
32
  end
32
33
  end
33
34
  else
34
- raise ArgumentError.new("wrong number of arguments (#{args.size} for 1..3)") # unless (1..3).include? args.size
35
+ raise ArgumentError.new("wrong number of arguments (#{args.size} for 1..3)")
35
36
  end
36
37
  end
37
38
 
38
39
  def self.table f, *args
39
- # TODO make it lazy?
40
-
41
40
  [].tap do |result|
42
- [[result, args.map{ |r| range(*r).to_a }]].tap do |stack|
41
+ [[result, args.map{ |r| # add lazy?
42
+ r.respond_to?(:map) && r.first.respond_to?(:map) ?
43
+ r.first : range(*r)
44
+ }]].tap do |stack|
43
45
  stack.each do |ai, ri|
46
+ # TODO try to make #table lazy (Enumerator instead of Array)
47
+ # "no implicit conversion of Enumerator::Lazy into Array"
48
+ # "undefined method `replace' for #<Enumerator::Lazy: []>"
44
49
  ai.replace ri.first.map{ |i|
45
50
  if ri.size == 1
46
51
  f.call(*ai, i)
47
52
  else
48
53
  [*ai.dup, i].tap{ |t| stack << [t, ri.drop(1)] }
49
54
  end
50
- }
55
+ }#.to_a # WTF
51
56
  end
52
57
  end
53
58
  end
59
+ end
60
+
61
+ define_listable_function :divide do |a, b|
62
+ a / b
63
+ end
54
64
 
65
+ def self.subdivide *args
66
+ case args.size
67
+ when 1 ; subdivide 1, args[0]
68
+ when 2 ; subdivide 0, args[0], args[1]
69
+ when 3 ; range(args[0], args[1], (args[1] - args[0]) * 1.0 / args[2])
70
+ else
71
+ raise ArgumentError.new("wrong number of arguments (#{args.size} for 1..3)")
72
+ end
55
73
  end
56
74
 
57
75
  end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "mll"
3
- spec.version = "0.2.0"
3
+ spec.version = "0.3.0"
4
4
  spec.authors = ["Victor Maslov"]
5
5
  spec.email = ["nakilon@gmail.com"]
6
6
  spec.summary = "Mathematica Language Library in Ruby"
@@ -1,9 +1,74 @@
1
1
  require_relative File.join "..", "lib", "mll"
2
2
 
3
3
 
4
+ # PERMANENT TODO test all implemented exceptions
5
+ # PERMANENT TODO test all types returned
6
+
7
+
4
8
  # http://reference.wolfram.com/language/guide/LanguageOverview.html
5
9
  describe MLL do
6
10
 
11
+ # http://reference.wolfram.com/language/guide/Syntax.html
12
+ describe "Syntax" do
13
+
14
+ # NO URL
15
+ describe "Mathematics & Operators" do
16
+
17
+ # http://reference.wolfram.com/language/ref/Divide.html
18
+ describe "#divide" do
19
+
20
+ describe "Basic Examples" do
21
+
22
+ example "n1 / n2" do
23
+ expect(MLL::divide(77,11)).to be_a Fixnum
24
+ expect(MLL::divide(77,11)).to eq 7
25
+ end
26
+
27
+ end
28
+
29
+ describe "Scope" do
30
+
31
+ example "list / n" do
32
+ expect(MLL::divide([2,3,4,5],2.0)).to be_a Enumerator
33
+ expect(MLL::divide([2,3,4,5],2.0).to_a).to eq [1,1.5,2,2.5]
34
+ end
35
+ example "list / list" do
36
+ expect(MLL::divide([2,3,4],[2,1,4])).to be_a Enumerator
37
+ expect(MLL::divide([2,3,4],[2,1,4]).to_a).to eq [1,3,1]
38
+ end
39
+
40
+ end
41
+
42
+ describe "Applications" do
43
+
44
+ example "foldlist(divide, 1, range(10))" do
45
+ pending "#foldlist is yet to be implemented"
46
+ fail
47
+ end
48
+
49
+ # TODO: "Successive ratios in a list:"
50
+
51
+ end
52
+
53
+ describe "Neat Examples" do
54
+
55
+ example "nest_list(lambda_with_divide), n" do
56
+ pending "#nestlist is yet to be implemented"
57
+ fail
58
+ end
59
+ example "table(divide, n1, n2)" do
60
+ expect(MLL::table(MLL.method(:divide), [[3,6]], 4.0)).to be_a Array
61
+ expect(MLL::table(MLL.method(:divide), [[6]], 4.0)).to eq [[6.0,3.0,2.0,1.5]]
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+
7
72
  # http://reference.wolfram.com/language/guide/ListManipulation.html
8
73
  describe "List Manipulation" do
9
74
 
@@ -13,7 +78,7 @@ describe MLL do
13
78
  # http://reference.wolfram.com/language/ref/Range.html
14
79
  describe "#range" do
15
80
 
16
- # TODO negative step and add it to README.rb
81
+ # TODO take from docs more examples that involve other functions
17
82
 
18
83
  example "range( >3 args )" do
19
84
  expect{ MLL::range(1,2,3,4) }.to raise_error ArgumentError
@@ -22,22 +87,24 @@ describe MLL do
22
87
  describe "Basic Examples" do
23
88
 
24
89
  example "range(n)" do
25
- expect(MLL::range(4)).to be_a Range
90
+ expect(MLL::range(4)).to be_a Enumerator
26
91
  expect(MLL::range(4).to_a).to eq [1,2,3,4]
27
92
  end
28
- example "range(imin, imax)" do
29
- expect(MLL::range(2,5)).to be_a Range
93
+ example "range(min, max)" do
94
+ expect(MLL::range(2,5)).to be_a Enumerator
30
95
  expect(MLL::range(2,5).to_a).to eq [2,3,4,5]
31
96
  end
32
- example "range(imin, imax, id)" do
97
+ example "range(min, max, step)" do
33
98
  expect(MLL::range(1,2,3)).to be_a Enumerator
34
99
  expect(MLL::range(1,2,0.5).to_a).to eq [1,1.5,2] # can be precision problems
35
100
  expect(MLL::range(2,6,2).to_a).to eq [2,4,6]
36
101
  expect(MLL::range(-4,9,3).to_a).to eq [-4,-1,2,5,8]
37
- # Ruby can't negative Range#step, haha!
102
+ end
103
+ example "range(max, min, -step)" do
38
104
  expect(MLL::range(10,-5,-2).to_a).to eq [10,8,6,4,2,0,-2,-4]
39
105
  expect(MLL::range(3,1,-1).to_a).to eq [3,2,1]
40
106
  end
107
+
41
108
  end
42
109
 
43
110
  describe "Generalizations & Extensions" do
@@ -45,7 +112,7 @@ describe MLL do
45
112
  example "range([n1, n2, n3, n4])" do
46
113
  expect(MLL::range([5,2,6,3])).to be_a Enumerator
47
114
  MLL::range([5,2,6,3]).each do |i|
48
- expect(i).to be_a Range
115
+ expect(i).to be_a Enumerator
49
116
  end
50
117
  expect(MLL::range([5,2,6,3]).to_a.map(&:to_a)).to eq [[1,2,3,4,5],[1,2],[1,2,3,4,5,6],[1,2,3]]
51
118
  end
@@ -63,10 +130,10 @@ describe MLL do
63
130
 
64
131
  describe "Neat Examples" do
65
132
 
66
- example "range(imin..imax)" do
67
- expect(MLL::range(MLL::range(3))).to be_a Enumerator
68
- MLL::range(MLL::range(3)).each do |i|
69
- expect(i).to be_a Range
133
+ example "range(min..max)" do
134
+ expect(MLL::range(1..3)).to be_a Enumerator
135
+ MLL::range(1..3).each do |i|
136
+ expect(i).to be_a Enumerator
70
137
  end
71
138
  expect(MLL::range(1..3).to_a.map(&:to_a)).to eq [[1],[1,2],[1,2,3]]
72
139
  end
@@ -77,7 +144,7 @@ describe MLL do
77
144
  o.each do |i|
78
145
  expect(i).to be_a Enumerator
79
146
  i.each do |j|
80
- expect(j).to be_a Range
147
+ expect(j).to be_a Enumerator
81
148
  end
82
149
  end
83
150
  end
@@ -95,27 +162,85 @@ describe MLL do
95
162
 
96
163
  # http://reference.wolfram.com/language/ref/Table.html
97
164
  describe "#table" do
165
+ # TODO type checks
98
166
 
99
167
  describe "Basic Examples" do
100
168
 
101
- example "table(lambda, [n])" do
102
- expect(MLL::table(->(i){ i**2 }, [10])).to eq [1,4,9,16,25,36,49,64,81,100]
169
+ example "table(lambda, n)" do
170
+ expect(MLL::table(->(i){ i**2 }, 10)).to be_a Array
171
+ expect(MLL::table(->(i){ i**2 }, 10)).to eq [1,4,9,16,25,36,49,64,81,100]
103
172
  end
104
- example "table(lambda, [imin, imax, id])" do
173
+ example "table(lambda, [min, max, step])" do
174
+ expect(MLL::table(->(i){ i+2 }, [0, 20, 2])).to be_a Array
105
175
  expect(MLL::table(->(i){ i+2 }, [0, 20, 2])).to eq [2,4,6,8,10,12,14,16,18,20,22]
106
176
  end
107
- example "table(lambda, [n1], [n2])" do
108
- expect(MLL::table(->(i, j){ 10*i + j }, [4], [3])).to eq [[11,12,13],[21,22,23],[31,32,33],[41,42,43]]
177
+ example "table(lambda, n1, n2)" do
178
+ # TODO example to README.rb about multiplication table
179
+ expect(MLL::table(->(i, j){ 10*i + j }, 4, 3)).to be_a Array
180
+ expect(MLL::table(->(i, j){ 10*i + j }, 4, 3)).to eq [[11,12,13],[21,22,23],[31,32,33],[41,42,43]]
181
+ end
182
+ example "table(lambda, n1, min..max, [max, min, -step])" do
183
+ expect(MLL::table(->(i,j,k){ [i,j,k] }, 3, 2..3, [5, 1, -2])).to be_a Array
184
+ expect(MLL::table(->(i,j,k){ [i,j,k] }, 3, 2..3, [5, 1, -2])).to eq \
185
+ [
186
+ [[[1, 2, 5], [1, 2, 3], [1, 2, 1]], [[1, 3, 5], [1, 3, 3], [1, 3, 1]]],
187
+ [[[2, 2, 5], [2, 2, 3], [2, 2, 1]], [[2, 3, 5], [2, 3, 3], [2, 3, 1]]],
188
+ [[[3, 2, 5], [3, 2, 3], [3, 2, 1]], [[3, 3, 5], [3, 3, 3], [3, 3, 1]]]
189
+ ]
109
190
  end
110
191
 
111
- example "matrix_form table(lambda, [n1], [n2])" do
192
+ example "matrix_form table(lambda, n1, n2)" do
112
193
  pending "#matrix_form is yet to be implemented"
113
- expect(MLL::matrix_form MLL::table(->(i, j){ 10*i + j }, [4], [3])).to eq "
194
+ expect(MLL::matrix_form MLL::table(->(i, j){ 10*i + j }, 4, 3)).to eq "
114
195
  "
115
196
  end
116
197
 
117
198
  end
118
199
 
200
+ describe "Scope" do
201
+
202
+ # TODO: "Make a triangular array:"
203
+
204
+ example "table(lambda, [list1], [list2])" do
205
+ expect(MLL::table(->(base, power){ base ** power }, [[1,2,4]], [[1,3,4]])).to be_a Array
206
+ expect(MLL::table(->(base, power){ base ** power }, [[1,2,4]], [[1,3,4]])).to eq [[1,1,1],[2,8,16],[4,64,256]]
207
+ expect(MLL::table(->(i,j){ i+j }, [[1]], [[2]])).to be_a Array
208
+ expect(MLL::table(->(i,j){ i+j }, [[1]], [[2]])).to eq [[3]]
209
+ end
210
+
211
+ end
212
+
213
+ describe "Applications" do
214
+
215
+ example "column table(binomial, )" do
216
+ pending "#binomial and #column are yet to be implemented"
217
+ fail
218
+ end
219
+
220
+ end
221
+
222
+ end
223
+
224
+ # http://reference.wolfram.com/language/ref/Subdivide.html
225
+ describe "#subdivide" do
226
+
227
+ example "subdivide(n)" do
228
+ expect(MLL::subdivide(4)).to be_a Enumerator
229
+ expect(MLL::subdivide(4).to_a).to eq [0,0.25,0.5,0.75,1]
230
+ end
231
+ example "subdivide(max, n)" do
232
+ expect(MLL::subdivide(10,5)).to be_a Enumerator
233
+ expect(MLL::subdivide(10,5).to_a).to eq [0,2,4,6,8,10]
234
+ end
235
+ example "subdivide(min, max, n)" do
236
+ expect(MLL::subdivide(-1,1,8)).to be_a Enumerator
237
+ expect(MLL::subdivide(-1,1,8).to_a).to eq [-1,-0.75,-0.5,-0.25,0,0.25,0.5,0.75,1]
238
+ end
239
+ example "subdivide(max, min, n)" do
240
+ expect(MLL::subdivide(1,-1,8)).to be_a Enumerator
241
+ expect(MLL::subdivide(1,-1,8).to_a).to eq [1,0.75,0.5,0.25,0,-0.25,-0.5,-0.75,-1]
242
+ end
243
+
119
244
  end
120
245
 
121
246
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mll
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Maslov