예제 #1
0
def generate_sk_problem(task: SKProblemGenerationTask, base_dir=None):
    """Execute a :py:class:`SKProblemGenerationTask` task."""
    if base_dir is None:
        base_dir = DEFAULT_BASE_DIR

    if recirq.exists(task, base_dir=base_dir):
        print(f"{task.fn} already exists. Skipping.")
        return

    problem = _get_all_sk_problems()[task.n_qubits, task.instance_i]
    recirq.save(task=task, data={
        'problem': problem,
    }, base_dir=base_dir)
    print(f"{task.fn} complete.")
예제 #2
0
def run_readout_scan(task: ReadoutScanTask, base_dir=None):
    """Execute a :py:class:`ReadoutScanTask` task."""
    if base_dir is None:
        base_dir = DEFAULT_BASE_DIR

    if recirq.exists(task, base_dir=base_dir):
        print(f"{task} already exists. Skipping.")
        return

    # Create a simple circuit
    theta = sympy.Symbol('theta')
    circuit = cirq.Circuit(
        [cirq.ry(theta).on(task.qubit),
         cirq.measure(task.qubit, key='z')])

    # Use utilities to map sampler names to Sampler objects
    sampler = recirq.get_sampler_by_name(device_name=task.device_name)

    # Use a sweep over theta values.
    # Set up limits so we include (-1/2, 0, 1/2, 1, 3/2) * pi
    # The total number of points is resolution_factor * 4 + 1
    n_special_points: int = 5
    resolution_factor = task.resolution_factor
    theta_sweep = cirq.Linspace(theta, -np.pi / 2, 3 * np.pi / 2,
                                resolution_factor * (n_special_points - 1) + 1)
    thetas = np.asarray([v for ((k, v), ) in theta_sweep.param_tuples()])
    flat_circuit, flat_sweep = cirq.flatten_with_sweep(circuit, theta_sweep)

    # Run the jobs
    print(f"Collecting data for {task.qubit}", flush=True)
    results = sampler.run_sweep(program=flat_circuit,
                                params=flat_sweep,
                                repetitions=task.n_shots)

    # Save the results
    recirq.save(task=task,
                data={
                    'thetas':
                    thetas,
                    'all_bitstrings': [
                        recirq.BitArray(np.asarray(r.measurements['z']))
                        for r in results
                    ]
                },
                base_dir=base_dir)
예제 #3
0
async def collect_readout_calibration(task: ReadoutCalibrationTask, base_dir=None):
    if base_dir is None:
        base_dir = DEFAULT_BASE_DIR

    if recirq.exists(task, base_dir=base_dir):
        print(f"{task.fn} already exists. Skipping.")
        return

    sampler = recirq.get_sampler_by_name(device_name=task.device_name)
    device = recirq.get_device_obj_by_name(device_name=task.device_name)

    readout_calibration_result = await _estimate_single_qubit_readout_errors_async(
        sampler=sampler,
        qubits=sorted(device.qubits),
        repetitions=task.n_shots)

    recirq.save(task=task, data={
        'calibration': readout_calibration_result,
    }, base_dir=base_dir)
예제 #4
0
def precompute_angles(task: AnglePrecomputationTask,
                      base_dir=None, problem_generation_base_dir=None):
    """Execute a :py:func:`AnglePrecomputationTask` task."""
    if base_dir is None:
        base_dir = DEFAULT_BASE_DIR

    if problem_generation_base_dir is None:
        problem_generation_base_dir = DEFAULT_PROBLEM_GENERATION_BASE_DIR

    if recirq.exists(task, base_dir=base_dir):
        print(f"{task.fn} already exists. Skipping.")
        return

    optimum = _get_optima(
        in_task=task.generation_task,
        problem_generation_base_dir=problem_generation_base_dir,
    )[task.p]
    recirq.save(task=task, data={
        'optimum': optimum,
    }, base_dir=base_dir)
    print(f"{task.fn} complete.")
async def collect_data(task: PrecomputedDataCollectionTask,
                       base_dir=None,
                       problem_generation_base_dir=None,
                       precomputation_base_dir=None,
                       ):
    """Collect and save data for the experiment specified by params.

    The associated problem generation data must already exist.
    """
    if base_dir is None:
        base_dir = DEFAULT_BASE_DIR

    if problem_generation_base_dir is None:
        problem_generation_base_dir = DEFAULT_PROBLEM_GENERATION_BASE_DIR

    if precomputation_base_dir is None:
        precomputation_base_dir = DEFAULT_PRECOMPUTATION_BASE_DIR

    if recirq.exists(task, base_dir=base_dir):
        print(f"{task.fn} already exists. Skipping.")
        return

    precompute_task = task.precomputation_task
    generation_task = precompute_task.generation_task

    problem = recirq.load(generation_task, base_dir=problem_generation_base_dir)[
        'problem']  # type: ProblemT
    optimum = recirq.load(precompute_task, base_dir=precomputation_base_dir)[
        'optimum']  # type: OptimizationResult
    sampler = recirq.get_sampler_by_name(device_name=task.device_name)
    device = recirq.get_device_obj_by_name(device_name=task.device_name)

    try:
        if isinstance(problem, HardwareGridProblem):
            initial_qubits = [cirq.GridQubit(r, c) for r, c in problem.coordinates]
            circuit, final_qubits = get_compiled_hardware_grid_circuit(
                problem=problem,
                qubits=initial_qubits,
                gammas=optimum.gammas,
                betas=optimum.betas,
                non_negligible=False)
        elif isinstance(problem, SKProblem):
            initial_qubits = place_line_on_device(
                device_name=task.device_name,
                n=problem.graph.number_of_nodes(),
                line_placement_strategy='mixed')
            circuit, final_qubits = get_compiled_sk_model_circuit(
                problem=problem,
                qubits=initial_qubits,
                gammas=optimum.gammas,
                betas=optimum.betas,
                non_negligible=False)
        elif isinstance(problem, ThreeRegularProblem):
            initial_qubits, circuit, final_qubits = get_compiled_3_regular_maxcut_circuit(
                problem=problem,
                device=device,
                gammas=optimum.gammas,
                betas=optimum.betas)
        else:
            raise ValueError("Unknown problem: {}".format(problem))
    except BadlyStructuredCircuitError:
        print("!!!! Badly structured circuit: {}".format(task))
        # TODO https://github.com/quantumlib/Cirq/issues/2553
        return

    if not task.structured:
        # Left align
        circuit = compile_to_non_negligible(circuit)
        circuit = cirq.Circuit(circuit.all_operations())

    if task.echoed:
        assert task.structured
        raise NotImplementedError("To be implemented in follow-up PR")

    violation_indices = find_circuit_structure_violations(circuit)
    circuit.program_id = task.fn
    result = await sampler.run_async(program=circuit,
                                     repetitions=task.n_shots)
    bitstrings = result.measurements['z']

    recirq.save(task=task, data={
        'bitstrings': recirq.BitArray(bitstrings),
        'qubits': initial_qubits,
        'final_qubits': final_qubits,
        'circuit': circuit,
        'violation_indices': violation_indices,
    }, base_dir=base_dir)
    print(f"{task.fn} complete.")
예제 #6
0
def collect_optimization_data(
        task: OptimizationTask,
        base_dir: str = DEFAULT_BASE_DIR,
        problem_generation_base_dir: str = DEFAULT_PROBLEM_GENERATION_BASE_DIR,
        precomputation_base_dir: str = DEFAULT_PRECOMPUTATION_BASE_DIR
) -> None:
    """Collect data for a QAOA optimization experiment.

    Args:
        task: The optimization task.
        base_dir: The base directory in which to save data.
        problem_generation_base_dir: The base directory of the problem.
    """
    if recirq.exists(task, base_dir=base_dir):
        print(f'{task.fn} already exists. Skipping.')
        return

    sampler = recirq.get_sampler_by_name(device_name=task.device_name)
    problem = recirq.load(
        task.generation_task,
        base_dir=problem_generation_base_dir)['problem']  # type: ProblemT

    lowest_energy_found = np.inf
    best_bitstring_found = None
    evaluated_points = []
    bitstring_lists = []
    energy_lists = []
    mean_energies = []

    def f(x):
        print('Evaluating objective ...')
        # Create circuit
        gammas = x[:task.p]
        betas = x[task.p:]
        initial_qubits, circuit, final_qubits = _get_circuit(
            problem, gammas, betas, task.device_name)
        # Sample bitstrings from circuit
        result = sampler.run(program=circuit,
                             repetitions=task.algorithm.n_shots)
        # Process bitstrings
        nonlocal lowest_energy_found
        nonlocal best_bitstring_found
        bitstrings = result.measurements['z']
        initial_indices = {q: i for i, q in enumerate(initial_qubits)}
        final_indices = [initial_indices[q] for q in final_qubits]
        nodelist = np.argsort(final_indices)
        energies = hamiltonian_objectives(bitstrings,
                                          problem.graph,
                                          nodelist=nodelist)
        lowest_energy_index = np.argmin(energies)
        lowest_energy = energies[lowest_energy_index]
        if lowest_energy < lowest_energy_found:
            lowest_energy_found = lowest_energy
            best_bitstring_found = bitstrings[lowest_energy_index]
        mean = np.mean(energies)
        # Save bitstrings and other data
        evaluated_points.append(recirq.NumpyArray(x))
        bitstring_lists.append(recirq.BitArray(bitstrings))
        energy_lists.append(recirq.NumpyArray(np.array(energies)))
        mean_energies.append(mean)
        print('Objective function: {}'.format(mean))
        print()
        return mean

    result = recirq.optimize.minimize(f,
                                      task.x0,
                                      method=task.algorithm.method,
                                      **(task.algorithm.options or {}))

    result_data = {
        'x': result.x,
        'fun': result.fun,
        'nit': result.nit,
        'nfev': result.nfev,
        'lowest_energy_found': lowest_energy_found,
        'best_bitstring_found': best_bitstring_found,
        'evaluated_points': evaluated_points,
        'bitstring_lists': bitstring_lists,
        'energy_lists': energy_lists,
        'mean_energies': mean_energies
    }
    if hasattr(result, 'x_iters'):
        result_data['x_iters'] = result['x_iters']
    if hasattr(result, 'func_vals'):
        result_data['func_vals'] = result['func_vals']
    if hasattr(result, 'model_vals'):
        result_data['model_vals'] = result['model_vals']

    # Evaluate at optimal angles if they have been precomputed
    angle_precomputation_task = AnglePrecomputationTask(
        dataset_id=task.dataset_id,
        generation_task=task.generation_task,
        p=task.p)
    if recirq.exists(angle_precomputation_task,
                     base_dir=precomputation_base_dir):
        optimum = recirq.load(angle_precomputation_task,
                              base_dir=precomputation_base_dir)['optimum']
        gammas = optimum.gammas
        betas = optimum.betas
        initial_qubits, circuit, final_qubits = _get_circuit(
            problem, gammas, betas, task.device_name)
        result = sampler.run(program=circuit, repetitions=50_000)
        bitstrings = result.measurements['z']
        initial_indices = {q: i for i, q in enumerate(initial_qubits)}
        final_indices = [initial_indices[q] for q in final_qubits]
        nodelist = np.argsort(final_indices)
        energies = hamiltonian_objectives(bitstrings,
                                          problem.graph,
                                          nodelist=nodelist)
        mean = np.mean(energies)
        result_data['optimal_angles'] = gammas + betas
        result_data['optimal_angles_fun'] = mean

    recirq.save(task=task, data=result_data, base_dir=base_dir)
예제 #7
0
async def collect_p1_landscape_data(
        task: P1LandscapeDataCollectionTask,
        base_dir=None,
        problem_generation_base_dir=None) -> None:
    if base_dir is None:
        base_dir = DEFAULT_BASE_DIR

    if problem_generation_base_dir is None:
        problem_generation_base_dir = DEFAULT_PROBLEM_GENERATION_BASE_DIR

    if recirq.exists(task, base_dir=base_dir):
        print(f"{task.fn} already exists. Skipping.")
        return

    generation_task = task.generation_task
    problem = recirq.load(generation_task, base_dir=problem_generation_base_dir)[
        'problem']  # type: ProblemT
    sampler = recirq.get_sampler_by_name(device_name=task.device_name)
    device = recirq.get_device_obj_by_name(device_name=task.device_name)
    if isinstance(problem, HardwareGridProblem):
        initial_qubits = [cirq.GridQubit(r, c) for r, c in problem.coordinates]
        circuit, final_qubits = get_compiled_hardware_grid_circuit(
            problem=problem,
            qubits=initial_qubits,
            gammas=[task.gamma],
            betas=[task.beta],
            non_negligible=False)
    elif isinstance(problem, SKProblem):
        initial_qubits = place_line_on_device(
            device_name=task.device_name,
            n=problem.graph.number_of_nodes(),
            line_placement_strategy='mixed')
        circuit, final_qubits = get_compiled_sk_model_circuit(
            problem=problem,
            qubits=initial_qubits,
            gammas=[task.gamma],
            betas=[task.beta],
            non_negligible=False)
    elif isinstance(problem, ThreeRegularProblem):
        initial_qubits, circuit, final_qubits = get_compiled_3_regular_maxcut_circuit(
            problem=problem,
            device=device,
            gammas=[task.gamma],
            betas=[task.beta])
    else:
        raise ValueError("Unknown problem: {}".format(problem))

    flipped_circuit = circuit.copy()
    measurement_op = flipped_circuit[-1].operations[0]
    flipped_circuit = flipped_circuit[:-1]
    flipped_circuit.append(cirq.Moment(cirq.X.on_each(*measurement_op.qubits)))
    flipped_circuit.append(
        measurement_op.gate.with_bits_flipped(*range(problem.graph.number_of_nodes())).on(
            *measurement_op.qubits))
    unmodified_n_shots = task.n_shots // 2
    flipped_n_shots = task.n_shots - unmodified_n_shots

    t0 = timeit.default_timer()
    circuit.program_id = task.fn
    unmodified_result = await sampler.run_async(program=circuit,
                                                repetitions=unmodified_n_shots)
    circuit.program_id = task.fn + '-flip'
    flipped_result = await sampler.run_async(program=flipped_circuit,
                                             repetitions=flipped_n_shots)
    t1 = timeit.default_timer()
    result = unmodified_result + flipped_result
    execution_time = t1 - t0
    print(f'Circuit execution time: {execution_time} s')

    t0 = timeit.default_timer()
    bitstrings = result.measurements['z']
    recirq.save(task=task, data={
        'bitstrings': recirq.BitArray(bitstrings),
        'qubits': initial_qubits,
        'final_qubits': final_qubits,
        'execution_time': execution_time
    }, base_dir=base_dir)
    t1 = timeit.default_timer()
    print(f'Time to save bitstrings: {t1 - t0} s')
    print()