ragni-cas 0.2.5 → 0.2.6

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.
@@ -61,9 +61,9 @@ module CAS
61
61
  xs.flatten!
62
62
  CAS::Help.assert_name name
63
63
  xs.each do |x|
64
- CAS::Help.assert x, CAS::Variable
64
+ CAS::Help.assert x, CAS::Op
65
65
  end
66
- raise CASError, "Function #{name} already exists" if CAS::Function.exist? name
66
+ # raise CASError, "Function #{name} already exists" if CAS::Function.exist? name
67
67
 
68
68
  @x = xs.uniq
69
69
  @name = name
@@ -78,19 +78,31 @@ module CAS
78
78
  def Function.new(name, *xs)
79
79
  xs.flatten!
80
80
  if @@container[name]
81
- return @@container[name] if (@@container[name].args - xs.uniq == [] or xs.size == 0)
81
+ # return @@container[name] if (@@container[name].x.uniq - xs.uniq == [] or xs.size == 0)
82
+ return @@container[name] if (@@container[name].x.uniq.map(&:to_s).sort == xs.uniq.map(&:to_s).sort or xs.size == 0)
82
83
  raise CASError, "Function #{name} already defined with different arguments!"
83
84
  end
84
85
  super
85
86
  end
86
87
 
87
88
  # Returns an array containing `CAS::Variable`s argument of the function
89
+ # Plese note that sub Op will return their args.
88
90
  #
89
- # * **returns**: `Array` containing `CAs:;Variable`
91
+ # * **returns**: `Array` containing `CAs::Variable`
90
92
  def args
91
- @x
93
+ ret = []
94
+ @x.each do |e|
95
+ ret << e.args
96
+ end
97
+ ret.flatten.uniq
92
98
  end
93
99
 
100
+ # Get an element in a particular position of the argument
101
+ #
102
+ # * **requires**: an iterator
103
+ # * **returns**: element of the argument `CAS::Op` or `NilClass`
104
+ def [](i); @x[i]; end
105
+
94
106
  # Simplifications cannot be performed on anonymous function, thus it will always return
95
107
  # the `self` `CAS::Function` object
96
108
  #
@@ -117,14 +129,7 @@ module CAS
117
129
  # * **returns**: a `CAS::Function` with modified argument list
118
130
  # * **raises**: `CASError` if something different with resppect to a `CAS::Variable` is a active substitution
119
131
  def subs(s)
120
- s.each do |k, v|
121
- next unless self.depend? k
122
- if v.is_a? CAS::Variable
123
- (@x.collect! { |e| (e == k) ? v : e }).uniq!
124
- next
125
- end
126
- raise CASError, "Cannot perform a substitution in #{self.class}"
127
- end
132
+ @x.each { |e| e.subs(s) }
128
133
  self
129
134
  end
130
135
 
@@ -134,11 +139,15 @@ module CAS
134
139
  # * **requires**: a `CAS::Variable` for derivative
135
140
  # * **returns**: the `CAS::Variable` derivated function
136
141
  def diff(v)
137
- if self.depend? v
138
- return CAS.declare :"d#{@name}[#{v}]", @x
139
- else
140
- return CAS::Zero
142
+ # return CAS.declare :"d#{@name}[#{v}]", @x
143
+ ret = []
144
+ @x.each_with_index do |x, k|
145
+ dx = (x.depend?(v) ? x.diff(v) : CAS::Zero)
146
+ dfx = CAS.declare :"D#{@name}[#{k}]", @x
147
+ ret << dx * dfx
141
148
  end
149
+ return CAS::Zero if ret == []
150
+ return ret.inject { |d, e| d += e }
142
151
  end
143
152
 
144
153
  # Trying to call a `CAS::Function` will always return a `CAS::Error`
@@ -166,7 +175,7 @@ module CAS
166
175
  # * **returns**: `TrueClass` if functions are equal, `FalseClass` if not equal
167
176
  def ==(op)
168
177
  return false if not self.class == op.class
169
- return false if not (@name == op.name and @x == op.args)
178
+ return false if not (@name == op.name and @x.uniq == op.x.uniq)
170
179
  true
171
180
  end
172
181
  end # Function
@@ -79,14 +79,14 @@ module CAS
79
79
  # * **returns**: `CAS::BinaryOp`, in practice `self`
80
80
  def subs_lhs(dt)
81
81
  CAS::Help.assert(dt, Hash)
82
-
83
- if dt.keys.include? @x
84
- if dt[@x].is_a? CAS::Op
85
- @x = dt[@x]
86
- elsif dt[@x].is_a? Numeric
87
- @x = CAS::const dt[@x]
82
+ sub = dt.keys.select { |e| e == @x }[0]
83
+ if sub
84
+ if dt[sub].is_a? CAS::Op
85
+ @x = dt[sub]
86
+ elsif dt[sub].is_a? Numeric
87
+ @x = CAS::const dt[sub]
88
88
  else
89
- raise CASError, "Impossible subs. Received a #{dt[@x].class} = #{dt[@x]}"
89
+ raise CASError, "Impossible subs. Received a #{dt[sub].class} = #{dt[sub]}"
90
90
  end
91
91
  else
92
92
  @x.subs(dt)
@@ -100,13 +100,14 @@ module CAS
100
100
  # * **returns**: `CAS::BinaryOp`, in practice `self`
101
101
  def subs_rhs(dt)
102
102
  CAS::Help.assert(dt, Hash)
103
- if dt.keys.include? @y
104
- if dt[@y].is_a? CAS::Op
105
- @y = dt[@y]
106
- elsif dt[@y].is_a? Numeric
107
- @y = CAS::const dt[@y]
103
+ sub = dt.keys.select { |e| e == @y }[0]
104
+ if sub
105
+ if dt[sub].is_a? CAS::Op
106
+ @y = dt[sub]
107
+ elsif dt[sub].is_a? Numeric
108
+ @y = CAS::const dt[sub]
108
109
  else
109
- raise CASError, "Impossible subs. Received a #{dt[@y].class} = #{dt[@y]}"
110
+ raise CASError, "Impossible subs. Received a #{dt[sub].class} = #{dt[sub]}"
110
111
  end
111
112
  else
112
113
  @y.subs(dt)
@@ -17,7 +17,7 @@ module CAS
17
17
  # * **returns**: `CAS::NaryOp` instance
18
18
  def initialize(*xs)
19
19
  @x = []
20
- xs.each do |x|
20
+ xs.flatten.each do |x|
21
21
  if x.is_a? Numeric
22
22
  x = Op.numeric_to_const x
23
23
  end
@@ -93,14 +93,16 @@ module CAS
93
93
  # * **returns**: `CAS::NaryOp` (`self`) with substitution performed
94
94
  def subs(dt)
95
95
  CAS::Help.assert(dt, Hash)
96
+ @x = @x.map { |z| z.subs(dt) || z }
96
97
  @x.each_with_index do |x, k|
97
- if dt.keys.include? x
98
- if dt[x].is_a? CAS::Op
99
- @x[k] = dt[x]
100
- elsif dt[x].is_a? Numeric
101
- @x[k] = CAS::const dt[x]
98
+ sub = dt.keys.select { |e| e == x }[0]
99
+ if sub
100
+ if dt[sub].is_a? CAS::Op
101
+ @x[k] = dt[sub]
102
+ elsif dt[sub].is_a? Numeric
103
+ @x[k] = CAS::const dt[sub]
102
104
  else
103
- raise CAS::CASError, "Impossible subs. Received a #{dt[x].class} = #{dt[x]}"
105
+ raise CAS::CASError, "Impossible subs. Received a #{dt[sub].class} = #{dt[sub]}"
104
106
  end
105
107
  end
106
108
  end
@@ -168,6 +170,63 @@ module CAS
168
170
  @x.each { |x| r += x.args }
169
171
  return r.uniq
170
172
  end
173
+
174
+ # Reduce multeplicity will scan for elements that are equal in the definition
175
+ # of the sum and will reduce their multeplicity. A block can be used to do something
176
+ # different. For example in nary-product we use it like this:
177
+ #
178
+ # ``` ruby
179
+ # @x = self.__reduce_multeplicity(@x) do |count, op|
180
+ # count > 1 ? (op ** count) : op
181
+ # end
182
+ # ```
183
+ #
184
+ # In general it works like that:
185
+ #
186
+ # ```
187
+ # a + a + b + c => 2 * a + b + c
188
+ # a * a * b * a => (a ** b) * b
189
+ # ```
190
+ # But operates only on Array level! This is an internal function
191
+ # and should never be used
192
+ #
193
+ # * **requires**: An `Array`
194
+ # * **returns**: An `Array` with multeplicity reduced
195
+ # * **block**: yields the count and the op. Get the value to insert in a new
196
+ # `Array` that is the returned `Array`
197
+ def __reduce_multeplicity(xs)
198
+ count = Hash.new(0)
199
+ xs.each do |x|
200
+ e = x
201
+ count.keys.each { |d| e = d if x == d }
202
+ count[e] += 1
203
+ end
204
+ count.map do |k, v|
205
+ if block_given?
206
+ yield(k, v)
207
+ else
208
+ v > 1 ? CAS.const(v) * k : k
209
+ end
210
+ end
211
+ end
212
+
213
+ # Collects all the constants and tries to reduce them to a single constant.
214
+ # Requires a block to understand what it should do with the constants
215
+ #
216
+ # * **requires**: input `Array` of `CAS::Op`
217
+ # * **returns**: new `Array` of `CAS::Op`
218
+ # * **block**: yields an `Array` of `CAS::Constant` and an `Array` of others `CAS::Op`,
219
+ # requires an `Array` back
220
+ def __reduce_constants(xs)
221
+ const = []
222
+ xs.each { |x| const << x if x.is_a? CAS::Constant }
223
+ if const.size > 0
224
+ yield const, (xs - const)
225
+ else
226
+ xs
227
+ end
228
+ end
229
+
171
230
  end # NaryOp
172
231
  CAS::NaryOp.init_simplify_dict
173
232
  end
data/lib/operators/op.rb CHANGED
@@ -107,11 +107,12 @@ module CAS
107
107
  # * **returns**: `CAS::Op` (`self`) with substitution performed
108
108
  def subs(dt)
109
109
  CAS::Help.assert(dt, Hash)
110
- if dt.keys.include? @x
111
- if dt[@x].is_a? CAS::Op
112
- @x = dt[@x]
113
- elsif dt[@x].is_a? Numeric
114
- @x = CAS::const dt[@x]
110
+ sub = dt.keys.select { |e| e == @x }[0]
111
+ if sub
112
+ if dt[sub].is_a? CAS::Op
113
+ @x = dt[sub]
114
+ elsif dt[sub].is_a? Numeric
115
+ @x = CAS::const dt[sub]
115
116
  else
116
117
  raise CAS::CASError, "Impossible subs. Received a #{dt[@x].class} = #{dt[@x]}"
117
118
  end
@@ -140,7 +141,7 @@ module CAS
140
141
  # * **argument**: `CAS::Op` tree
141
142
  # * **returns**: `CAS::Op` new object
142
143
  def +(op)
143
- CAS::Sum.new self, op
144
+ CAS::Sum.new [self, op]
144
145
  end
145
146
 
146
147
  # Returns a difference of two `CAS::Op`s
@@ -156,7 +157,7 @@ module CAS
156
157
  # * **argument**: `CAS::Op` tree
157
158
  # * **returns**: `CAS::Op` new object
158
159
  def *(op)
159
- CAS::Prod.new self, op
160
+ CAS::Prod.new [self, op]
160
161
  end
161
162
 
162
163
  # Returns a division of two `CAS::Op`s
data/lib/version.rb CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  #!/usr/bin/env ruby
3
2
 
4
3
  module CAS
@@ -8,6 +7,6 @@ module CAS
8
7
  # * Major version
9
8
  # * Minor version
10
9
  # * Patchlevel
11
- VERSION = [0, 2, 5]
10
+ VERSION = [0, 2, 6]
12
11
  end
13
12
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ragni-cas
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matteo Ragni
@@ -29,7 +29,7 @@ cert_chain:
29
29
  XorZtzkkLImvKFj35xKLFfVkv0Vd8tGQoiL8vdmQNJjAjtE+C+Y7OI4dpiZPKO4G
30
30
  R/8JOvUuk9jPbyLxjQH/sFaFqqYGX2xo1zk2CRy/A0WhJrSaXVw1r5lEi7b0W5gg
31
31
  -----END CERTIFICATE-----
32
- date: 2016-10-13 00:00:00.000000000 Z
32
+ date: 2016-11-28 00:00:00.000000000 Z
33
33
  dependencies: []
34
34
  description:
35
35
  email: info@ragni.me
@@ -37,10 +37,19 @@ executables: []
37
37
  extensions: []
38
38
  extra_rdoc_files: []
39
39
  files:
40
+ - lib/Mr.CAS.rb
41
+ - lib/Mr.CAS/auto-diff.rb
42
+ - lib/Mr.CAS/c-opt.rb
43
+ - lib/Mr.CAS/c.rb
44
+ - lib/Mr.CAS/graphviz.rb
45
+ - lib/Mr.CAS/latex.rb
46
+ - lib/Mr.CAS/matlab.rb
40
47
  - lib/functions/fnc-base.rb
41
48
  - lib/functions/fnc-box-conditions.rb
42
49
  - lib/functions/fnc-conditions.rb
43
50
  - lib/functions/fnc-piecewise.rb
51
+ - lib/functions/fnc-prod.rb
52
+ - lib/functions/fnc-sum.rb
44
53
  - lib/functions/fnc-trig.rb
45
54
  - lib/functions/fnc-trsc.rb
46
55
  - lib/numbers/constants.rb
@@ -51,9 +60,6 @@ files:
51
60
  - lib/operators/op.rb
52
61
  - lib/overloading/fixnum.rb
53
62
  - lib/overloading/float.rb
54
- - lib/ragni-cas.rb
55
- - lib/ragni-cas/plugins/graphviz.rb
56
- - lib/ragni-cas/plugins/latex.rb
57
63
  - lib/version.rb
58
64
  homepage: https://github.com/MatteoRagni/cas-rb
59
65
  licenses:
@@ -75,8 +81,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
75
81
  version: '0'
76
82
  requirements: []
77
83
  rubyforge_project:
78
- rubygems_version: 2.5.1
84
+ rubygems_version: 2.5.2
79
85
  signing_key:
80
86
  specification_version: 4
81
- summary: An extremely simple CAS, for rapid prototyping and meta-programming
87
+ summary: 'THIS IS OUTDATED! PLEASE CHECK: https://rubygems.org/gems/Mr.CAS'
82
88
  test_files: []
metadata.gz.sig CHANGED
Binary file