Mercurial > repo
diff interps/qbf/qubit.py @ 996:859f9b4339e6
<Gregor> tar xf egobot.tar.xz
author | HackBot |
---|---|
date | Sun, 09 Dec 2012 19:30:08 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/interps/qbf/qubit.py Sun Dec 09 19:30:08 2012 +0000 @@ -0,0 +1,157 @@ +# A qubit library +# Author: Nikita Ayzikovsky (lament) +# You may use this freely, but it's neither GPL nor public domain (yet) + +# Note that everything starts out initialized to 1. This needs to be +# changed if this is to be used for something other than Quantum Brainfuck. +# Other than that, the library is completely generic. Just add your own +# gates and go ahead. + +# The things that should be actually used from outside are +# clases Gate and Register. + +import random # of course! + +def dotproduct(a,b): + """Because I'm too lazy to look for a lin. algebra module""" + return sum([x*y for (x,y) in zip(a,b)]) + +def mvmult(matrix, vector): + """Because I'm too lazy to look for a lin. algebra module""" + #no error checking for now + result = [] + for row in matrix: + result.append(dotproduct(row, vector)) + return result + +def bit(num, bitnum): + return int((num&(1<<bitnum)) != 0) + +def n2bits(n, length): + return [bit(n, x) for x in range(length)] + +def bits2n(bitlist): + result = 0 + for x in range(len(bitlist)): + result += bitlist[x] * (1<<x) + return result + +class Gate: + def __init__(self, num_bits, matrix): + self.num_bits = num_bits + self.N = 1<<num_bits + self.matrix = matrix + def apply(self, register, bitlist): + """Applies this gate to bits from bitlist (size of bitlist should + be N) in the register object given""" + # let's do this the least efficient way possible + # apply the gate to bits in bitlist for each individual combination + # of other bits + # We have register.length total bits, so register.length-N + # bit combinations + + new_contents = register.contents[:] + + num_bits = register.length + allbits = range(num_bits) + otherbits = [x for x in allbits if x not in bitlist] + # Iterate over each combination of other bits: + for i in range(2**len(otherbits)): + other_bit_values = n2bits(i, len(otherbits)) + positions = [] + for j in range(self.N): + current_position = [0] * num_bits + for index, value in zip(otherbits, other_bit_values): + current_position[index] = value + for index, value in zip(bitlist,n2bits(j, self.N)): + current_position[index] = value + positions.append(bits2n(current_position)) + values = [register.contents[x] for x in positions] + values = mvmult(self.matrix, values) + for x, index in zip(positions, range(self.N)): + new_contents[x] = values[index] + register.contents = new_contents + +class Register: + def __init__(self, length): + """Initialize to all 1s as per Quantum Brainfuck specs""" + self.length = length + self.contents = [0] * (2**length) + self.contents[-1] = 1 + def add_bit(self): + """Adds a new qubit, containing 1 and not entangled with anything""" + new_contents = [] + new_contents = [0] * len(self.contents) + self.contents + self.contents = new_contents + self.length += 1 + def observe(self, bit_index): + """Observes the value of the qubit at the given index, + changing that bit to |0> or |1> and updating all probabilities + accordingly. Returns 0 or 1""" + + # first, find out the probability that the qubit is set. + prob = 0 + for i in range(2 ** self.length): + prob += abs(bit(i, bit_index) * self.contents[i]) ** 2 + # prob is now set to the probability of bit set to 1 + # now "Observe" + if random.random() <= prob: + bit_value = 1 + else: + bit_value = 0 + # now that we know the "observed" value, adjust all other + # probabilities to account for it. + if prob == 0 or prob == 1: + # don't need adjustment + return bit_value + + adjustment = (1 / prob) ** 0.5 + for i in range(2 ** self.length): + if bit(i, bit_index) == bit_value: + self.contents[i] = self.contents[i] * adjustment + else: + self.contents[i] = 0 + return bit_value + + def set(self, bit_index, bit_value): + """Sets the indexed bit to 'value', which should be 1 or 0""" + for i in range(2 ** self.length): + if bit(i, bit_index) == bit_value: + # take the 'sister' bit combination and add its + # probability to this one + if bit_value: + sister = i & (~ 1<<bit_index) + else: + sister = i | bit_index + total_prob = self.contents[i] **2 + self.contents[sister]**2 + self.contents[i] = math.sqrt(total_prob) + self.contents[sister] = 0 + + +############################################################# + +import math +st = 1/math.sqrt(2) + +Hadamard = Gate(1, [[st, st], + [st, -st]]) + +CNOT = Gate(2, [[1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 0, 1], + [0, 0, 1, 0]]) + +CV = Gate(2, [[1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 1j]]) + +if __name__ == '__main__': + # just testing stuff + r = Register(2) + Hadamard.apply(r, [0]) + print r.contents + CNOT.apply(r,[1,0]) + print r.contents + r.set(0, 1) + print r.contents