def generate_circuit_by_depth(L, D, W, gate_maker): """ This function this generates an IBM circuit. It is called with the following inputs: L, the number of bits per batch, D, the depth of the circuit as defined by IBM, W, the number of input 'wires' (batch inputs taken) in the circuit, and gate_maker, the function used to produce each gate. """ # Create the circuit: circuit = ic.IBMCircuit(L) # Create W input wires: wires = [iw.IBMInputWire("".join(("W", str(wire_ind))), circuit) for wire_ind in xrange(W)] circuit.set_input_wires(wires) ultimate_level = wires # the last level created penultimate_level = [] # the second-to-last level created # Keep track of the smallest gate depth at the last level: min_depth = 0 # Maintain a list of gates at depth D: depth_D_gates = [] # Maintain a list of gates between depth D and D+1, not including D: depth_around_D_gates = [] # Initialize the global gate counter, which acts as the unique numerical id # of each gate: unique_gate_num = W while (min_depth <= D): new_level = [] for gate_index in range(W): # create W new gates new_gate = gate_maker(L, ultimate_level, penultimate_level, "".join(["G", str(unique_gate_num)]), circuit) # If the new gate has depth D, add it to depth_D_gates: if (new_gate.get_depth() == D): depth_D_gates.append(new_gate) # If the new gate has D < depth <= D+1, add it to # depth_around_D_gates: if ((new_gate.get_depth() > D) and (new_gate.get_depth() < D+1)): depth_around_D_gates.append(new_gate) # Add the new gate to the new level: new_level.append(new_gate) # Increment the unique gate number: unique_gate_num += 1 # Increment the smallest gate depth at the last level as needed: min_depth = min(gate.get_depth() for gate in new_level) # Update the ultimate_level and penultimate_level pointers: penultimate_level = ultimate_level ultimate_level = new_level # If there is at least one gate of depth exactly D, select the output # gate from among such gates at random. Otherwise, select the output # gate from among gates between depth D and D+1. if(len(depth_D_gates) > 0): output_gate = sr.choice(depth_D_gates) else: output_gate = sr.choice(depth_around_D_gates) circuit.set_output_gate(output_gate) return circuit
def generate_circuit_by_depth(B, L, D, W, gate_maker): """ This function this generates an IBM circuit. It is called with the following inputs: L, the number of bits per batch, D, the depth of the circuit as defined by IBM, W, the number of input 'wires' (batch inputs taken) in the circuit, and gate_maker, the function used to produce each gate. """ # Create the circuit: circuit = ic.IBMCircuit(L) # Create W input wires: wires = [ iw.IBMInputWire("".join(("W", str(wire_ind))), circuit) for wire_ind in xrange(W) ] circuit.set_input_wires(wires) ultimate_level = wires # the last level created penultimate_level = [] # the second-to-last level created # Keep track of the smallest gate depth at the last level: min_depth = 0 # Maintain a list of gates at depth D: depth_D_gates = [] # Maintain a list of gates between depth D and D+1, not including D: depth_around_D_gates = [] # Initialize the global gate counter, which acts as the unique numerical id # of each gate: unique_gate_num = W while (min_depth <= D): new_level = [] for gate_index in range(W): # create W new gates new_gate = gate_maker(B, L, ultimate_level, penultimate_level, "".join(["G", str(unique_gate_num)]), circuit) # If the new gate has depth D, add it to depth_D_gates: if (new_gate.get_depth() == D): depth_D_gates.append(new_gate) # If the new gate has D < depth <= D+1, add it to # depth_around_D_gates: if ((new_gate.get_depth() > D) and (new_gate.get_depth() < D + 1)): depth_around_D_gates.append(new_gate) # Add the new gate to the new level: new_level.append(new_gate) # Increment the unique gate number: unique_gate_num += 1 # Increment the smallest gate depth at the last level as needed: min_depth = min(gate.get_depth() for gate in new_level) # Update the ultimate_level and penultimate_level pointers: penultimate_level = ultimate_level ultimate_level = new_level # If there is at least one gate of depth exactly D, select the output # gate from among such gates at random. Otherwise, select the output # gate from among gates between depth D and D+1. if (len(depth_D_gates) > 0): output_gate = sr.choice(depth_D_gates) else: output_gate = sr.choice(depth_around_D_gates) circuit.set_output_gate(output_gate) return circuit
def make_random_gate(B, L, ultimate_level, penultimate_level, gate_name, circuit): """Creates a random gate with uniformly distributed type.""" gate_type = sr.choice( [g_type for g_type in GATE_TYPES.numbers_generator()]) generate = TEST_TYPE_TO_GATE_MAKER[gate_type] return generate(B, L, ultimate_level, penultimate_level, gate_name, circuit)
def generate_circuit_by_level(B, L, num_levels, W, gate_maker): """ This function this generates a random IBM circuit with num_levels instead of depth specified. It is called with the following inputs: L, the number of bits per batch, num_levels, the the number of levels in the circuit, W, the number of input 'wires' (batch inputs taken) in the circuit, and gate_maker, the function used to produce each gate. """ # Create the circuit: circuit = ic.IBMCircuit(L) # Create W input wires: wires = [ iw.IBMInputWire("".join(("W", str(wire_ind))), circuit) for wire_ind in xrange(W) ] circuit.set_input_wires(wires) ultimate_level = wires # the last level created penultimate_level = [] # the second-to-last level created # Initialize the global gate counter, which acts as the unique numerical id # of each gate: unique_gate_num = W for level in xrange(num_levels): new_level = [] for gate_index in xrange(W): # create W new gates new_gate = gate_maker(B, L, ultimate_level, penultimate_level, "".join(["G", str(unique_gate_num)]), circuit) # Add the new gate to the new level: new_level.append(new_gate) # Increment the unique gate number: unique_gate_num += 1 # Update the ultimate_level and penultimate_level pointers: penultimate_level = ultimate_level ultimate_level = new_level # Select the output gate from the last level: output_gate = sr.choice(ultimate_level) circuit.set_output_gate(output_gate) return circuit
def generate_circuit_by_level(L, num_levels, W, gate_maker): """ This function this generates a random IBM circuit with num_levels instead of depth specified. It is called with the following inputs: L, the number of bits per batch, num_levels, the the number of levels in the circuit, W, the number of input 'wires' (batch inputs taken) in the circuit, and gate_maker, the function used to produce each gate. """ # Create the circuit: circuit = ic.IBMCircuit(L) # Create W input wires: wires = [iw.IBMInputWire("".join(("W",str(wire_ind))), circuit) for wire_ind in xrange(W)] circuit.set_input_wires(wires) ultimate_level = wires # the last level created penultimate_level = [] # the second-to-last level created # Initialize the global gate counter, which acts as the unique numerical id # of each gate: unique_gate_num = W for level in xrange(num_levels): new_level = [] for gate_index in xrange(W): # create W new gates new_gate = gate_maker(L, ultimate_level, penultimate_level, "".join(["G", str(unique_gate_num)]), circuit) # Add the new gate to the new level: new_level.append(new_gate) # Increment the unique gate number: unique_gate_num += 1 # Update the ultimate_level and penultimate_level pointers: penultimate_level = ultimate_level ultimate_level = new_level # Select the output gate from the last level: output_gate = sr.choice(ultimate_level) circuit.set_output_gate(output_gate) return circuit
def generate(self): """Populates the circuit, input and output files with a circuit, an input, and the corresponding output with the appropriate parameters.""" # create the header and write it to the circuit file: header_string = self._create_circuit_header() # create the input wires and write the inputs to the input file: input_wires = self._create_input_wires() # set set of all circuit objects already created: levels = [input_wires] # initialize the global gate counter, which acts as the unique numerical # id of each gate: unique_gate_num_gen = itertools.count() # for each level: for level_index in xrange(self._D): # Create the list of gates at this level: this_level = [None] * self._W for gate_ind in xrange(self._W): displayname = "".join(["G",str(unique_gate_num_gen.next())]) # make the new gate: new_gate = self._gate_maker(levels, displayname) new_gate_output = int(sr.getrandbits(1)) new_gate.balance(new_gate_output) # add this gate to our list of gates at this level: this_level[gate_ind] = new_gate # set things up for the next level: ultimate_level = this_level levels.append(this_level) output_gate = sr.choice(levels[-1]) output_gate.set_name("output_gate") # choose a random output, and write it to the output file: output = int(sr.getrandbits(1)) self._output_file.write(str(output)) # balance the output gate with respect to the chosen output: output_gate.balance(output) circ = sc.StealthCircuit(input_wires, output_gate) # write the circuit to the circuit file: self._circuit_file.write(circ.display())
def make_random_gate(L, ultimate_level, penultimate_level, gate_name, circuit): """Creates a random gate with uniformly distributed type.""" gate_type = sr.choice([g_type for g_type in GATE_TYPES.numbers_generator()]) generate = TEST_TYPE_TO_GATE_MAKER[gate_type] return generate(L, ultimate_level, penultimate_level, gate_name, circuit)