Class: State

Inherits:
Object
  • Object
show all
Includes:
QuantumVector
Defined in:
lib/quantum_ruby.rb

Constant Summary

Constants included from QuantumVector

QuantumVector::PRECISION

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from QuantumVector

#==, #state

Constructor Details

#initialize(vector, *qubits) ⇒ State

Returns a new instance of State.



167
168
169
170
171
172
173
# File 'lib/quantum_ruby.rb', line 167

def initialize(vector, *qubits)
  @vector = vector
  column_vector?
  normalized?

  @qubits = qubits.flatten.tap { |i| i.each { |j| j.entangled = true } }
end

Instance Attribute Details

#qubitsObject (readonly)

Returns the value of attribute qubits.



164
165
166
# File 'lib/quantum_ruby.rb', line 164

def qubits
  @qubits
end

#vectorObject (readonly)

Returns the value of attribute vector.



163
164
165
# File 'lib/quantum_ruby.rb', line 163

def vector
  @vector
end

Instance Method Details

#measureObject



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/quantum_ruby.rb', line 175

def measure
  # "determine' 'winner'
  acc = 0
  out = nil
  secret = rand

  @vector.to_a.each_with_index do |probability, index|
    acc += probability[0].abs2
    if acc > secret
      out = index
      break
    end
  end

  # Reset state
  @vector = Matrix.column_vector Array.new(@vector.row_count, 0)
  # Update state
  @vector.send(:[]=, out, 0, 1)

  # Update each qubit
  out = out.to_s(2).rjust(size, '0')
  @qubits.each_with_index do |qubit, index|
    qubit.entangled = false
    qubit.send(:vector=, Array.new(2, 0).tap { |vector| vector[out[index].to_i] = 1 })
  end

  freeze
  out.split('').map(&:to_i)
end

#measure_partial(*qubit) ⇒ Object



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/quantum_ruby.rb', line 205

def measure_partial(*qubit)
  # find location of our desired qubit(s)
  qubit_ids = qubit.map { |i| @qubits.find_index { |j| j.hash == i .hash } }.sort

  # collect probabilities for qubit(s) states
  sub_result = @vector.to_a.flatten.each_with_index.group_by do |_probability, index|
    qubit_ids.map do |id|
      index.to_s(2).rjust(size, '0')[id]
    end.join
  end

  # calculate final probabilities for qubit(s) state
  probabilities = sub_result.sort.to_h.transform_values { |v| v.reduce(0) { |i, p| i + p[0].abs2 } }.values
  acc = 0
  out = nil
  secret = rand

  # "determine' 'winner'
  probabilities.each_with_index do |probability, index|
    acc += probability
    if acc > secret
      out = index
      break
    end
  end

  # Renormalize
  squared_sum_mag = Math.sqrt(probabilities[out])
  out = out.to_s(2).rjust(qubit.length, '0')
  new_state = sub_result.fetch(out).map { |i| i[0] / squared_sum_mag }

  # Update each qubit
  @qubits.each_with_index do |q, i|
    q.entangled = false
    if index = qubit_ids.find_index(i)
      q.send(:vector=, Array.new(2, 0).tap { |vector| vector[out[index].to_i] = 1 })
    else
      q.send(:vector=, new_state)
    end
  end
  freeze
  out.split('').map(&:to_i)
end