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,218 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'symbo/expression'
|
4
|
+
require 'symbo/mergeable'
|
5
|
+
require 'symbo/power'
|
6
|
+
|
7
|
+
module Symbo
|
8
|
+
class Product < Expression
|
9
|
+
include Mergeable
|
10
|
+
|
11
|
+
using Symbo
|
12
|
+
|
13
|
+
# :section: Power Transformation Methods
|
14
|
+
|
15
|
+
# べき乗の低
|
16
|
+
#
|
17
|
+
# (:x * :y).base # => :x * :y
|
18
|
+
def base
|
19
|
+
dup
|
20
|
+
end
|
21
|
+
|
22
|
+
# べき指数
|
23
|
+
#
|
24
|
+
# (:x * :y).exponent # => 1
|
25
|
+
def exponent
|
26
|
+
1
|
27
|
+
end
|
28
|
+
|
29
|
+
# :section: Basic Distributive Transformation Methods
|
30
|
+
|
31
|
+
# 同類項の項部分
|
32
|
+
#
|
33
|
+
# Product[2, :x, :y, :z].term # => Product[:x, :y, :z]
|
34
|
+
# Product[1/3, :x, :y, :z].term # => Product[:x, :y, :z]
|
35
|
+
# Product[:x, :y, :z].term # => Product[:x, :y, :z]
|
36
|
+
def term
|
37
|
+
if @operands.first.constant?
|
38
|
+
Product.new(*@operands[1..-1])
|
39
|
+
else
|
40
|
+
self
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# 同類項の定数部分
|
45
|
+
#
|
46
|
+
# Product[2, :x, :y, :z].const # => 2
|
47
|
+
# Product[1/3, :x, :y, :z].const # => 1/3
|
48
|
+
# Product[:x, :y, :z].const # => 1
|
49
|
+
def const
|
50
|
+
if @operands.first.constant?
|
51
|
+
@operands.first
|
52
|
+
else
|
53
|
+
1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# :section: Order Relation Methods
|
58
|
+
|
59
|
+
# 交換法則によるオペランド並べ替えに使う順序関係
|
60
|
+
#
|
61
|
+
# - 相手が積の場合
|
62
|
+
# 最右のオペランドから順に compare していき、異なるものがあればそれで順序を決定する。
|
63
|
+
#
|
64
|
+
# (:a * :b).compare(:a * :c) # => true
|
65
|
+
# Product[:a, :c, :d].compare(Product[:b, :c, :d]) # => true
|
66
|
+
#
|
67
|
+
# どちらかのオペランドがなくなれば、短いほうが左側。
|
68
|
+
#
|
69
|
+
# (:c * :d).compare(Product[:b, :c, :d]) # => true
|
70
|
+
#
|
71
|
+
# - べき乗、和、階乗、関数、シンボルの場合
|
72
|
+
# 相手を単項の積にして比較
|
73
|
+
#
|
74
|
+
# (:a * (:x**2)).compare(:x**3) # => true
|
75
|
+
#
|
76
|
+
# - それ以外の場合
|
77
|
+
# 次のルールで比較
|
78
|
+
#
|
79
|
+
# !other.compare(self)
|
80
|
+
#
|
81
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
82
|
+
def compare(other)
|
83
|
+
case other
|
84
|
+
when Product
|
85
|
+
return @operands.last.compare(other.operands.last) if @operands.last != other.operands.last
|
86
|
+
|
87
|
+
m = length
|
88
|
+
n = other.length
|
89
|
+
if [m, n].min >= 2
|
90
|
+
1.upto([m, n].min) do |j|
|
91
|
+
return operand(m - j).compare(other.operand(n - j)) if operand(m - j) != other.operand(n - j)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
m < n
|
95
|
+
when Power, Sum, Factorial, Function, Symbol
|
96
|
+
compare Product[other]
|
97
|
+
else
|
98
|
+
!other.compare(self)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
102
|
+
|
103
|
+
# :section:
|
104
|
+
|
105
|
+
# v * w
|
106
|
+
#
|
107
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
108
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
109
|
+
def evaluate
|
110
|
+
v = operand(0)
|
111
|
+
w = operand(1)
|
112
|
+
|
113
|
+
if (v.integer? || v.complex?) && (w.integer? || w.complex?)
|
114
|
+
v.mult w
|
115
|
+
elsif v.constant? && w.constant?
|
116
|
+
Fraction[Product[v.numerator, w.numerator].simplify,
|
117
|
+
Product[v.denominator, w.denominator].simplify].evaluate
|
118
|
+
else
|
119
|
+
Product[v.simplify, w.simplify]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
123
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
124
|
+
|
125
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
126
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
127
|
+
def to_s
|
128
|
+
return "-#{operand(1)}" if length == 2 && operand(0) == -1
|
129
|
+
|
130
|
+
@operands.map do |each|
|
131
|
+
case each
|
132
|
+
when Sum
|
133
|
+
"(#{each})"
|
134
|
+
when Product
|
135
|
+
if each.length == 2 && each.operand(0) == -1
|
136
|
+
"(-#{each.operand(1)})"
|
137
|
+
elsif each.length > 1
|
138
|
+
"(#{each})"
|
139
|
+
else
|
140
|
+
each.to_s
|
141
|
+
end
|
142
|
+
else
|
143
|
+
each.to_s
|
144
|
+
end
|
145
|
+
end.join('*')
|
146
|
+
end
|
147
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
148
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
149
|
+
|
150
|
+
protected
|
151
|
+
|
152
|
+
def _simplify
|
153
|
+
return UNDEFINED if @operands.any?(&:undefined?)
|
154
|
+
return 0 if @operands.any?(&:zero?)
|
155
|
+
return operand(0) if length == 1
|
156
|
+
|
157
|
+
v = simplify_rec(@operands)
|
158
|
+
if v.size == 1
|
159
|
+
v[0]
|
160
|
+
elsif v.size > 1
|
161
|
+
Product[*v]
|
162
|
+
else
|
163
|
+
1
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
private
|
168
|
+
|
169
|
+
# l = [u1, u2,...,un] is a non-empty list with n ≥ 2 non-zero ASAEs.
|
170
|
+
# Returns a list with zero or more operands that satisfy the condition of
|
171
|
+
# ASAE-4.
|
172
|
+
#
|
173
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
174
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
175
|
+
def simplify_rec(l) # rubocop:disable Naming/MethodParameterName
|
176
|
+
case l
|
177
|
+
in Constant, Constant # SPRDREC-1-1
|
178
|
+
p = Product[*l].simplify_rne
|
179
|
+
p == 1 ? [] : [p]
|
180
|
+
in 1, u2 unless u2.product? # SPRDREC-1-2
|
181
|
+
[u2]
|
182
|
+
in u1, 1 unless u1.product?
|
183
|
+
[u1]
|
184
|
+
in u1, u2 if l.none?(:product?) && u1.base == u2.base # SPRDREC-1-3
|
185
|
+
s = Sum[u1.exponent, u2.exponent].simplify
|
186
|
+
p = Power[u1.base, s].simplify
|
187
|
+
p == 1 ? [] : [p]
|
188
|
+
in u1, u2 if l.none?(&:product?) && u2.compare(u1) # SPRDREC-1-4
|
189
|
+
[u2, u1]
|
190
|
+
in _, _ if l.none?(&:product?) # SPRDREC-1-5
|
191
|
+
l
|
192
|
+
in Product => u1, Product => u2 # SPRDREC-2-1
|
193
|
+
merge u1.operands, u2.operands
|
194
|
+
in Product => u1, u2 # SPRDREC-2-2
|
195
|
+
merge u1.operands, [u2]
|
196
|
+
in u1, Product => u2 # SPRDREC-2-3
|
197
|
+
merge [u1], u2.operands
|
198
|
+
in Product => u1, *rest # SPRDREC-3-1
|
199
|
+
merge u1.operands, simplify_rec(rest)
|
200
|
+
in u1, *rest # SPRDREC-3-2
|
201
|
+
merge [u1], simplify_rec(rest)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
205
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
206
|
+
|
207
|
+
def simplify_rne_rec
|
208
|
+
v = operand(0).simplify_rne_rec
|
209
|
+
w = operand(1).simplify_rne_rec
|
210
|
+
|
211
|
+
if v.undefined? || w.undefined?
|
212
|
+
UNDEFINED
|
213
|
+
else
|
214
|
+
Product[v, w].evaluate
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
data/lib/symbo/qubit.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'matrix'
|
4
|
+
|
5
|
+
module Symbo
|
6
|
+
class Qubit < Matrix
|
7
|
+
include Symbo
|
8
|
+
extend Symbo
|
9
|
+
|
10
|
+
using Symbo
|
11
|
+
|
12
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
13
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
14
|
+
# rubocop:disable Metrics/AbcSize
|
15
|
+
def self.[](*state_or_value)
|
16
|
+
rows =
|
17
|
+
case state_or_value
|
18
|
+
in [String => bits] if /\A[0|1]+\Z/=~ bits
|
19
|
+
m = bits.split(//).inject(Matrix[[1]]) do |result, string|
|
20
|
+
each = case string
|
21
|
+
when '0'
|
22
|
+
Matrix[[1], [0]]
|
23
|
+
when '1'
|
24
|
+
Matrix[[0], [1]]
|
25
|
+
end
|
26
|
+
TensorProduct[result, each]
|
27
|
+
end
|
28
|
+
m.map(&:simplify).to_a
|
29
|
+
in [String => bit]
|
30
|
+
elms = case bit
|
31
|
+
when '0'
|
32
|
+
[1, 0]
|
33
|
+
when '1'
|
34
|
+
[0, 1]
|
35
|
+
when '+'
|
36
|
+
[1/√(2), 1/√(2)]
|
37
|
+
when '-'
|
38
|
+
[1/√(2), -1/√(2)]
|
39
|
+
when 'i'
|
40
|
+
[1/√(2), 1i/√(2)]
|
41
|
+
when '-i'
|
42
|
+
[1/√(2), -1i/√(2)]
|
43
|
+
else
|
44
|
+
raise "Invalid qubit state: #{bit}"
|
45
|
+
end
|
46
|
+
elms.map { |each| [each.simplify] }
|
47
|
+
else
|
48
|
+
state_or_value.map { |each| [each.simplify] }
|
49
|
+
end
|
50
|
+
|
51
|
+
super(*rows)
|
52
|
+
end
|
53
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
54
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
55
|
+
# rubocop:enable Metrics/AbcSize
|
56
|
+
|
57
|
+
def -@
|
58
|
+
map { |each| Product[-1, each].simplify }
|
59
|
+
end
|
60
|
+
|
61
|
+
def +(other)
|
62
|
+
super(other).map(&:simplify)
|
63
|
+
end
|
64
|
+
|
65
|
+
def -(other)
|
66
|
+
raise unless other.is_a?(Qubit) && row_size == other.row_size
|
67
|
+
|
68
|
+
rows = (0...row_size).map do |each|
|
69
|
+
Sum[self[each, 0], Product[-1, other[each, 0]]].simplify
|
70
|
+
end
|
71
|
+
Qubit[*rows]
|
72
|
+
end
|
73
|
+
|
74
|
+
def bra
|
75
|
+
map(&:conjugate).t
|
76
|
+
end
|
77
|
+
|
78
|
+
def ket
|
79
|
+
self
|
80
|
+
end
|
81
|
+
|
82
|
+
def state
|
83
|
+
map(&:simplify)
|
84
|
+
end
|
85
|
+
|
86
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
87
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
88
|
+
# rubocop:disable Metrics/AbcSize
|
89
|
+
def to_s
|
90
|
+
kets = []
|
91
|
+
ket_length = Math.log2(row_size).to_i
|
92
|
+
|
93
|
+
(0...row_size).each do |each|
|
94
|
+
x = self[each, 0]
|
95
|
+
kets << [x, "|%0*b>" % [ket_length, each]] unless x.zero?
|
96
|
+
end
|
97
|
+
|
98
|
+
kets.inject('') do |result, each|
|
99
|
+
coefficient = if each[0] == 1
|
100
|
+
''
|
101
|
+
elsif each[0].constant? || each[0].symbol? || each[0].power?
|
102
|
+
each[0].to_s
|
103
|
+
elsif !each[0].product? && each[0].length > 1
|
104
|
+
"(#{each[0]})"
|
105
|
+
elsif each[0].product? && each[0].operand(0) != -1
|
106
|
+
each[0].to_s
|
107
|
+
elsif each[0].product? && each[0].operand(0) == -1
|
108
|
+
each[0].to_s
|
109
|
+
end
|
110
|
+
|
111
|
+
result += if result.empty?
|
112
|
+
"#{coefficient}#{each[1]}"
|
113
|
+
elsif coefficient.to_s[0] != '-'
|
114
|
+
" + #{coefficient}#{each[1]}"
|
115
|
+
else
|
116
|
+
" - #{coefficient.to_s[1..-1]}#{each[1]}"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
121
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
122
|
+
# rubocop:enable Metrics/AbcSize
|
123
|
+
end
|
124
|
+
end
|
data/lib/symbo/quot.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'symbo/expression'
|
4
|
+
|
5
|
+
module Symbo
|
6
|
+
class Quot < Expression
|
7
|
+
using Symbo
|
8
|
+
|
9
|
+
def evaluate
|
10
|
+
if w.numerator.zero?
|
11
|
+
UNDEFINED
|
12
|
+
else
|
13
|
+
# v = vn/vd, w = wn/wd とすると
|
14
|
+
# v/w = Quot(vn/vd, wn/wd).evaluate = vn·wd / wn·vd
|
15
|
+
Fraction[v.numerator.mult(w.denominator), w.numerator.mult(v.denominator)]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def _simplify
|
22
|
+
Product[operand(0), Power[operand(1), -1]].simplify
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# an integer or a fraction with non-zero denominator
|
28
|
+
def v
|
29
|
+
@v ||= operand(0).evaluate
|
30
|
+
end
|
31
|
+
|
32
|
+
# an integer or a fraction with non-zero denominator
|
33
|
+
def w
|
34
|
+
@w ||= operand(1).evaluate
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/symbo/sin.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'symbo/trigonometric_function'
|
4
|
+
|
5
|
+
module Symbo
|
6
|
+
class Sin < TrigonometricFunction
|
7
|
+
using Symbo
|
8
|
+
|
9
|
+
def self.[](x) # rubocop:disable Naming/MethodParameterName
|
10
|
+
new(x)
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(x) # rubocop:disable Naming/MethodParameterName
|
14
|
+
super :sin, x
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
"cos(#{operand(1)})"
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
# rubocop:disable Metrics/AbcSize
|
24
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
25
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
26
|
+
def _simplify
|
27
|
+
if x.zero?
|
28
|
+
0
|
29
|
+
elsif x == PI
|
30
|
+
0
|
31
|
+
elsif x.constant? && x.negative?
|
32
|
+
(-Sin[Product[-1, x].simplify]).simplify
|
33
|
+
elsif x.product? && x.operand(0).integer? && x.operand(0).negative?
|
34
|
+
(-Sin[Product[-1, x.operand(0), *x.operands[1..-1]].simplify]).simplify
|
35
|
+
elsif kn_pi?
|
36
|
+
simplify_kn_pi.simplify
|
37
|
+
else
|
38
|
+
self
|
39
|
+
end
|
40
|
+
end
|
41
|
+
# rubocop:enable Metrics/AbcSize
|
42
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
43
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# Simplification of sin(kπ/n)
|
48
|
+
#
|
49
|
+
# rubocop:disable Metrics/AbcSize
|
50
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
51
|
+
def simplify_kn_pi
|
52
|
+
k = x.operand(0).numerator
|
53
|
+
n = x.operand(0).denominator
|
54
|
+
|
55
|
+
case n
|
56
|
+
when 1
|
57
|
+
0
|
58
|
+
when 2
|
59
|
+
case k % 4
|
60
|
+
when 1
|
61
|
+
1
|
62
|
+
when 3
|
63
|
+
-1
|
64
|
+
end
|
65
|
+
when 3
|
66
|
+
case k % 6
|
67
|
+
when 1, 2
|
68
|
+
√(3)/2
|
69
|
+
when 4, 5
|
70
|
+
Product[-1, √(3)/2]
|
71
|
+
end
|
72
|
+
when 4
|
73
|
+
case k % 8
|
74
|
+
when 1, 3
|
75
|
+
1/√(2)
|
76
|
+
when 5, 7
|
77
|
+
-1/√(2)
|
78
|
+
end
|
79
|
+
when 6
|
80
|
+
case k % 12
|
81
|
+
when 1, 5
|
82
|
+
1/2
|
83
|
+
when 7, 11
|
84
|
+
-1/2
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
# rubocop:enable Metrics/AbcSize
|
89
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
90
|
+
end
|
91
|
+
end
|