symbo 0.1.0pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -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