symbo 0.1.0pre
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 +7 -0
- data/.github/workflows/ruby.yml +26 -0
- data/.gitignore +56 -0
- data/.rubocop.yml +31 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +0 -0
- data/Gemfile +19 -0
- data/Gemfile.lock +65 -0
- data/LICENSE +21 -0
- data/README.md +37 -0
- data/Rakefile +12 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/symbo.rb +21 -0
- data/lib/symbo/algebraic_operators.rb +35 -0
- data/lib/symbo/complex.rb +78 -0
- data/lib/symbo/constant.rb +5 -0
- data/lib/symbo/cos.rb +94 -0
- data/lib/symbo/diff.rb +33 -0
- data/lib/symbo/e.rb +5 -0
- data/lib/symbo/expression.rb +114 -0
- data/lib/symbo/expression_type.rb +43 -0
- data/lib/symbo/factorial.rb +81 -0
- data/lib/symbo/float.rb +8 -0
- data/lib/symbo/fraction.rb +176 -0
- data/lib/symbo/function.rb +118 -0
- data/lib/symbo/integer.rb +126 -0
- data/lib/symbo/matrix.rb +22 -0
- data/lib/symbo/mergeable.rb +30 -0
- data/lib/symbo/pi.rb +5 -0
- data/lib/symbo/power.rb +198 -0
- data/lib/symbo/product.rb +218 -0
- data/lib/symbo/qubit.rb +124 -0
- data/lib/symbo/quot.rb +37 -0
- data/lib/symbo/relational_operators.rb +15 -0
- data/lib/symbo/sin.rb +91 -0
- data/lib/symbo/sqrt.rb +16 -0
- data/lib/symbo/sum.rb +211 -0
- data/lib/symbo/symbol.rb +102 -0
- data/lib/symbo/tensor_product.rb +15 -0
- data/lib/symbo/trigonometric_function.rb +26 -0
- data/lib/symbo/version.rb +5 -0
- data/symbo.gemspec +33 -0
- metadata +116 -0
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'symbo/expression'
|
4
|
+
require 'symbo/integer'
|
5
|
+
require 'symbo/symbol'
|
6
|
+
|
7
|
+
module Symbo
|
8
|
+
class Function < Expression
|
9
|
+
include Symbo
|
10
|
+
|
11
|
+
using Symbo
|
12
|
+
|
13
|
+
def name
|
14
|
+
@operands[0]
|
15
|
+
end
|
16
|
+
|
17
|
+
def parameters
|
18
|
+
@operands[1..-1]
|
19
|
+
end
|
20
|
+
|
21
|
+
# :section: Power Transformation Methods
|
22
|
+
|
23
|
+
# べき乗の低
|
24
|
+
#
|
25
|
+
# Function(:f, :x).base # => Function(:f, :x)
|
26
|
+
def base
|
27
|
+
dup
|
28
|
+
end
|
29
|
+
|
30
|
+
# べき指数
|
31
|
+
#
|
32
|
+
# Function(:f, :x).exponent # => 1
|
33
|
+
def exponent
|
34
|
+
1
|
35
|
+
end
|
36
|
+
|
37
|
+
# :section: Basic Distributive Transformation Methods
|
38
|
+
|
39
|
+
# 同類項の項部分
|
40
|
+
#
|
41
|
+
# Function(:f, :x).term # => Product(Function(:f, :x))
|
42
|
+
def term
|
43
|
+
Product[self]
|
44
|
+
end
|
45
|
+
|
46
|
+
# 同類項の定数部分
|
47
|
+
#
|
48
|
+
# Function(:f, :x).const # => 1
|
49
|
+
def const
|
50
|
+
1
|
51
|
+
end
|
52
|
+
|
53
|
+
# :section: Order Relation Methods
|
54
|
+
|
55
|
+
# 交換法則によるオペランド並べ替えに使う順序関係
|
56
|
+
#
|
57
|
+
# - 相手が関数の場合
|
58
|
+
# 関数名が異なる場合、関数名で順序を決定。
|
59
|
+
#
|
60
|
+
# Function(:f, :x).compare(Function(:g, :x)) # => true
|
61
|
+
#
|
62
|
+
# 関数名が同じの場合、関数の最左のオペランドから順に compare していき、
|
63
|
+
# 異なるものがあればそれで順序を決定する。
|
64
|
+
#
|
65
|
+
# Function(:f, :x).compare(Function(:f, :y)) # => true
|
66
|
+
#
|
67
|
+
# どちらかのオペランドがなくなれば、短いほうが左側。
|
68
|
+
#
|
69
|
+
# Function(:g, :x).compare(Function(:g, :x, :y)) # => true
|
70
|
+
#
|
71
|
+
# - シンボルの場合
|
72
|
+
# 関数名とシンボルが等しい場合 false
|
73
|
+
#
|
74
|
+
# Function(:f, :x).compare(:f) # => false
|
75
|
+
#
|
76
|
+
# 異なる場合、関数名とシンボルで比較
|
77
|
+
#
|
78
|
+
# Function(:f, :x).compare(:g) # => true
|
79
|
+
#
|
80
|
+
# - それ以外の場合
|
81
|
+
# 次のルールで比較
|
82
|
+
#
|
83
|
+
# !other.compare(self)
|
84
|
+
#
|
85
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
86
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
87
|
+
# rubocop:disable Metrics/AbcSize
|
88
|
+
def compare(other)
|
89
|
+
case other
|
90
|
+
when Function
|
91
|
+
if name != other.name
|
92
|
+
name.compare other.name
|
93
|
+
else
|
94
|
+
return parameters.first.compare other.parameters.first if parameters.first != other.parameters.first
|
95
|
+
|
96
|
+
m = parameters.length
|
97
|
+
n = other.parameters.length
|
98
|
+
0.upto([m, n].min - 2) do |j|
|
99
|
+
return parameters[j + 1].compare(other.parameters[j + 1]) if (parameters[j] == other.parameters[j]) && (parameters[j + 1] != other.parameters[j + 1])
|
100
|
+
end
|
101
|
+
|
102
|
+
m.compare(n)
|
103
|
+
end
|
104
|
+
when Symbol
|
105
|
+
if name == other
|
106
|
+
false
|
107
|
+
else
|
108
|
+
name.compare other
|
109
|
+
end
|
110
|
+
else
|
111
|
+
!other.compare(self)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
115
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
116
|
+
# rubocop:enable Metrics/AbcSize
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'symbo/algebraic_operators'
|
4
|
+
require 'symbo/constant'
|
5
|
+
require 'symbo/expression_type'
|
6
|
+
|
7
|
+
# Symbolic computation
|
8
|
+
module Symbo
|
9
|
+
# Integer refinements
|
10
|
+
refine Integer do
|
11
|
+
alias_method :mult, :*
|
12
|
+
alias_method :div, :/
|
13
|
+
|
14
|
+
include AlgebraicOperators
|
15
|
+
include ExpressionType
|
16
|
+
include Constant
|
17
|
+
|
18
|
+
def simplify
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
# :section: Power Transformation Methods
|
23
|
+
|
24
|
+
# べき乗の低
|
25
|
+
#
|
26
|
+
# 1.base # => UNDEFINED
|
27
|
+
def base
|
28
|
+
UNDEFINED
|
29
|
+
end
|
30
|
+
|
31
|
+
# べき指数
|
32
|
+
#
|
33
|
+
# 1.exponent # => UNDEFINED
|
34
|
+
def exponent
|
35
|
+
UNDEFINED
|
36
|
+
end
|
37
|
+
|
38
|
+
# :section: Basic Distributive Transformation Methods
|
39
|
+
|
40
|
+
# 同類項の項部分
|
41
|
+
#
|
42
|
+
# 1.term # => UNDEFINED
|
43
|
+
def term
|
44
|
+
UNDEFINED
|
45
|
+
end
|
46
|
+
|
47
|
+
# 同類項の定数部分
|
48
|
+
#
|
49
|
+
# 1.const # => UNDEFINED
|
50
|
+
def const
|
51
|
+
UNDEFINED
|
52
|
+
end
|
53
|
+
|
54
|
+
# :section: Order Relation Methods
|
55
|
+
|
56
|
+
# 交換法則によるオペランド並べ替えに使う順序関係
|
57
|
+
#
|
58
|
+
# - 相手が定数の場合
|
59
|
+
# 大小関係で順序を決定
|
60
|
+
#
|
61
|
+
# 2.compare(4) # => true
|
62
|
+
# 2.compare(5/2) # => true
|
63
|
+
#
|
64
|
+
# - それ以外の場合
|
65
|
+
# 常に true
|
66
|
+
#
|
67
|
+
# 2.compare(:x + :y) # => true
|
68
|
+
# 2.compare(:x * :y) # => true
|
69
|
+
# 2.compare(2**:x) # => true
|
70
|
+
# 2.compare(Factorial(2)) # => true
|
71
|
+
# 2.compare(Function(:f, :x)) # => true
|
72
|
+
def compare(other)
|
73
|
+
case other
|
74
|
+
when Integer
|
75
|
+
self < other
|
76
|
+
when Fraction
|
77
|
+
self < other.rational
|
78
|
+
else
|
79
|
+
true
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# :section:
|
84
|
+
|
85
|
+
def numerator
|
86
|
+
self
|
87
|
+
end
|
88
|
+
|
89
|
+
def denominator
|
90
|
+
1
|
91
|
+
end
|
92
|
+
|
93
|
+
def evaluate
|
94
|
+
self
|
95
|
+
end
|
96
|
+
|
97
|
+
def simplify_rational_number
|
98
|
+
self
|
99
|
+
end
|
100
|
+
|
101
|
+
def simplify_rne_rec
|
102
|
+
self
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Matrix などの中で使われる Integer#+ などをハイジャック
|
108
|
+
class Integer
|
109
|
+
include Symbo::Constant
|
110
|
+
include Symbo::ExpressionType
|
111
|
+
|
112
|
+
alias plus +
|
113
|
+
alias mult *
|
114
|
+
|
115
|
+
def +(other)
|
116
|
+
plus other
|
117
|
+
rescue TypeError
|
118
|
+
Symbo::Sum[self, other]
|
119
|
+
end
|
120
|
+
|
121
|
+
def *(other)
|
122
|
+
mult other
|
123
|
+
rescue TypeError
|
124
|
+
Symbo::Product[self, other]
|
125
|
+
end
|
126
|
+
end
|
data/lib/symbo/matrix.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'matrix'
|
4
|
+
|
5
|
+
module Symbo
|
6
|
+
# シンボリック演算を使う行列
|
7
|
+
refine Matrix do
|
8
|
+
alias_method :mult, :*
|
9
|
+
|
10
|
+
def *(other)
|
11
|
+
if other.respond_to?(:to_matrix)
|
12
|
+
(mult other.to_matrix).simplify
|
13
|
+
else
|
14
|
+
mult other
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def simplify
|
19
|
+
map(&:simplify)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Symbo
|
4
|
+
module Mergeable
|
5
|
+
private
|
6
|
+
|
7
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
8
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
9
|
+
def merge(p, q) # rubocop:disable Naming/MethodParameterName
|
10
|
+
return p if q.empty?
|
11
|
+
return q if p.empty?
|
12
|
+
|
13
|
+
p1 = p[0]
|
14
|
+
q1 = q[0]
|
15
|
+
h = simplify_rec([p1, q1])
|
16
|
+
case h
|
17
|
+
in []
|
18
|
+
merge p[1..-1], q[1..-1]
|
19
|
+
in [_]
|
20
|
+
h + merge(p[1..-1], q[1..-1])
|
21
|
+
in ^p1, ^q1
|
22
|
+
[p1] + merge(p[1..-1], q)
|
23
|
+
in ^q1, ^p1
|
24
|
+
[q1] + merge(p, q[1..-1])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
28
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
29
|
+
end
|
30
|
+
end
|
data/lib/symbo/pi.rb
ADDED
data/lib/symbo/power.rb
ADDED
@@ -0,0 +1,198 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'symbo/expression'
|
4
|
+
|
5
|
+
module Symbo
|
6
|
+
class Power < Expression
|
7
|
+
using Symbo
|
8
|
+
|
9
|
+
# :section: Power Transformation Methods
|
10
|
+
|
11
|
+
# べき乗の低
|
12
|
+
#
|
13
|
+
# (:x**2).base # => :x
|
14
|
+
def base
|
15
|
+
@operands[0]
|
16
|
+
end
|
17
|
+
|
18
|
+
# べき指数
|
19
|
+
#
|
20
|
+
# (:x**2).exponent # => 2
|
21
|
+
def exponent
|
22
|
+
@operands[1]
|
23
|
+
end
|
24
|
+
|
25
|
+
# :section: Basic Distributive Transformation Methods
|
26
|
+
|
27
|
+
# 同類項の項部分
|
28
|
+
#
|
29
|
+
# (:x**2).term # => Product(:x**2)
|
30
|
+
def term
|
31
|
+
Product[self]
|
32
|
+
end
|
33
|
+
|
34
|
+
# 同類項の定数部分
|
35
|
+
#
|
36
|
+
# (:x**2).const # => 1
|
37
|
+
def const
|
38
|
+
1
|
39
|
+
end
|
40
|
+
|
41
|
+
# :section: Order Relation Methods
|
42
|
+
|
43
|
+
# 交換法則によるオペランド並べ替えに使う順序関係
|
44
|
+
#
|
45
|
+
# - 相手がべき乗の場合
|
46
|
+
# 底が異なる場合、底同士で順序を決める。
|
47
|
+
# 底が等しい場合、べき指数同士で順序を決める。
|
48
|
+
#
|
49
|
+
# ((1 + :x)**3).compare((1 + :y)**2) # => true
|
50
|
+
# ((1 + :x)**2).compare((1 + :x)**3) # => true
|
51
|
+
#
|
52
|
+
# - 和、階乗、関数、シンボルの場合
|
53
|
+
# 相手を 1 乗のべき乗に変換して比較
|
54
|
+
#
|
55
|
+
# ((1 + :x)**3).compare(1 + :y) # => true
|
56
|
+
#
|
57
|
+
# - それ以外の場合
|
58
|
+
# 次のルールで比較
|
59
|
+
#
|
60
|
+
# !other.compare(self)
|
61
|
+
def compare(other)
|
62
|
+
case other
|
63
|
+
when Power
|
64
|
+
return base.compare(other.base) if base != other.base
|
65
|
+
|
66
|
+
exponent.compare other.exponent
|
67
|
+
when Sum, Factorial, Function, Symbol
|
68
|
+
compare Power[other, 1]
|
69
|
+
else
|
70
|
+
!other.compare(self)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# :section: Evaluation Methods
|
75
|
+
|
76
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
77
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
78
|
+
# rubocop:disable Metrics/AbcSize
|
79
|
+
def evaluate
|
80
|
+
raise unless base.constant?
|
81
|
+
raise unless exponent.integer?
|
82
|
+
|
83
|
+
if base.numerator != 0
|
84
|
+
if exponent.positive?
|
85
|
+
Product[Power[base, exponent - 1].evaluate, base].evaluate
|
86
|
+
elsif exponent.zero?
|
87
|
+
1
|
88
|
+
elsif exponent == -1
|
89
|
+
Fraction[1, base]
|
90
|
+
elsif exponent < -1
|
91
|
+
raise NotImplementedError
|
92
|
+
end
|
93
|
+
elsif base.numerator.zero?
|
94
|
+
if n >= 1
|
95
|
+
0
|
96
|
+
else
|
97
|
+
UNDEFINED
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
102
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
103
|
+
# rubocop:enable Metrics/AbcSize
|
104
|
+
|
105
|
+
def to_s
|
106
|
+
"#{base}^(#{exponent})"
|
107
|
+
end
|
108
|
+
|
109
|
+
protected
|
110
|
+
|
111
|
+
# :section: Simplification Methods
|
112
|
+
|
113
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
114
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
115
|
+
# rubocop:disable Metrics/AbcSize
|
116
|
+
def _simplify
|
117
|
+
return UNDEFINED if base == UNDEFINED || exponent == UNDEFINED
|
118
|
+
|
119
|
+
if base.zero?
|
120
|
+
return 1 if exponent.positive? && exponent.constant?
|
121
|
+
|
122
|
+
return UNDEFINED
|
123
|
+
end
|
124
|
+
|
125
|
+
return 1 if base == 1
|
126
|
+
return simplify_integer_power if exponent.integer?
|
127
|
+
return simplify_eulers_formula if base == E
|
128
|
+
|
129
|
+
self
|
130
|
+
end
|
131
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
132
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
133
|
+
# rubocop:enable Metrics/AbcSize
|
134
|
+
|
135
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
136
|
+
# rubocop:disable Metrics/AbcSize
|
137
|
+
def simplify_integer_power
|
138
|
+
return Power[base, exponent].simplify_rne if base.constant?
|
139
|
+
return 1 if exponent.zero?
|
140
|
+
return base if exponent == 1
|
141
|
+
|
142
|
+
case base
|
143
|
+
when Power
|
144
|
+
r = base.operands[0]
|
145
|
+
s = base.operands[1]
|
146
|
+
p = Product.new(s, exponent).simplify
|
147
|
+
|
148
|
+
if p.integer?
|
149
|
+
Power[r, p].simplify_integer_power
|
150
|
+
else
|
151
|
+
Power[r, p]
|
152
|
+
end
|
153
|
+
when Product
|
154
|
+
r = base.operands.map { |each| Power[each, exponent].simplify_integer_power }
|
155
|
+
Product[*r].simplify
|
156
|
+
else
|
157
|
+
self
|
158
|
+
end
|
159
|
+
end
|
160
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
161
|
+
# rubocop:enable Metrics/AbcSize
|
162
|
+
|
163
|
+
# e^ix = cos(x) + sin(x)
|
164
|
+
#
|
165
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
166
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
167
|
+
# rubocop:disable Metrics/AbcSize
|
168
|
+
def simplify_eulers_formula
|
169
|
+
if exponent.product? &&
|
170
|
+
exponent.operand(0).is_a?(Complex) && exponent.operand(0).real.zero? &&
|
171
|
+
exponent.operand(1) == PI
|
172
|
+
# eg e^{ki * π}
|
173
|
+
x = Product[exponent.operand(0).imag, exponent.operand(1)]
|
174
|
+
(Cos[x] + 1i * Sin[x]).simplify
|
175
|
+
elsif exponent.product? &&
|
176
|
+
exponent.operand(0).fraction? && exponent.operand(0).operand(0).is_a?(Complex) && exponent.operand(0).operand(0).real.zero? &&
|
177
|
+
exponent.operand(1) == PI
|
178
|
+
# eg e^{(k/n)i * π}
|
179
|
+
x = Product[Fraction[exponent.operand(0).operand(0).imag, exponent.operand(0).operand(1)], exponent.operand(1)]
|
180
|
+
(Cos[x] + 1i * Sin[x]).simplify
|
181
|
+
else
|
182
|
+
self
|
183
|
+
end
|
184
|
+
end
|
185
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
186
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
187
|
+
# rubocop:enable Metrics/AbcSize
|
188
|
+
|
189
|
+
def simplify_rne_rec
|
190
|
+
v = base.simplify_rne_rec
|
191
|
+
if v == UNDEFINED
|
192
|
+
UNDEFINED
|
193
|
+
else
|
194
|
+
Power[v, exponent].evaluate
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|