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.
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Symbo
4
+ module RelationalOperators
5
+ # :section: Relational Operator Methods
6
+
7
+ def ==(other)
8
+ other.is_a?(self.class) && @operands == other.operands
9
+ end
10
+
11
+ def zero?
12
+ false
13
+ end
14
+ end
15
+ end
@@ -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