Пример #1
0
 def convert_to_qubo(self):
     """Transform an Ising problem into a QUBO problem.  Return the new
     QUBO problem."""
     if self.qubo:
         raise TypeError("Can convert only Ising problems to QUBO problems")
     new_obj = copy.deepcopy(self)
     qmatrix, _ = ising_to_qubo(self.weights, self.strengths)
     new_obj.weights = [0] * len(self.weights)
     for (q1, q2), wt in qmatrix.items():
         if q1 == q2:
             new_obj.weights[q1] = wt
     new_obj.strengths = {(q1, q2): wt for (q1, q2), wt in qmatrix.items() if q1 != q2}
     return new_obj
Пример #2
0
 def convert_to_qubo(self):
     """Transform an Ising problem into a QUBO problem.  Return the new
     QUBO problem."""
     if self.qubo:
         raise TypeError("Can convert only Ising problems to QUBO problems")
     new_obj = copy.deepcopy(self)
     qmatrix, _ = ising_to_qubo(qmasm.dict_to_list(self.weights), self.strengths)
     new_obj.weights = defaultdict(lambda: 0.0,
                                   {q1: wt
                                    for (q1, q2), wt in list(qmatrix.items())
                                    if q1 == q2})
     new_obj.strengths = defaultdict(lambda: 0.0,
                                     {(q1, q2): wt
                                      for (q1, q2), wt in list(qmatrix.items())
                                      if q1 != q2})
     new_obj.qubo = True
     return new_obj
Пример #3
0
 def convert_to_qubo(self):
     """Transform an Ising problem into a QUBO problem.  Return the new
     QUBO problem."""
     if self.qubo:
         raise TypeError("Can convert only Ising problems to QUBO problems")
     new_obj = copy.deepcopy(self)
     qmatrix, qoffset = ising_to_qubo(qmasm.dict_to_list(self.weights), self.strengths)
     new_obj.offset = qoffset
     new_obj.weights = defaultdict(lambda: 0.0,
                                   {q1: wt
                                    for (q1, q2), wt in qmatrix.items()
                                    if q1 == q2})
     new_obj.strengths = qmasm.canonicalize_strengths({(q1, q2): wt
                                                       for (q1, q2), wt in qmatrix.items()
                                                       if q1 != q2})
     new_obj.qubo = True
     return new_obj
Пример #4
0
def simplify_problem(logical, verbosity):
    """Try to find spins that can be removed from the problem because their
    value is known a priori."""
    # SAPI's fix_variables function works only on QUBOs so we have to convert.
    # We directly use SAPI's ising_to_qubo function instead of our own
    # convert_to_qubo because the QUBO has to be in matrix form.
    hs = qmasm.dict_to_list(logical.weights)
    Js = logical.strengths
    Q, qubo_offset = ising_to_qubo(hs, Js)

    # Simplify the problem if possible.
    simple = fix_variables(Q, method="optimized")
    fixed_vars = simple["fixed_variables"]

    # At high verbosity levels, list all of the known symbols and their value.
    if verbosity >= 2:
        # Map each logical qubit to one or more symbols.
        num2syms = [[] for _ in range(len(qmasm.sym2num))]
        max_sym_name_len = 7
        for q, n in qmasm.sym2num.items():
            num2syms[n].append(q)
            max_sym_name_len = max(max_sym_name_len,
                                   len(repr(num2syms[n])) - 1)

        # Output a table of know values
        sys.stderr.write(
            "Elided qubits whose low-energy value can be determined a priori:\n\n"
        )
        if len(fixed_vars) > 0:
            sys.stderr.write("    Logical  %-*s  Value\n" %
                             (max_sym_name_len, "Name(s)"))
            sys.stderr.write("    -------  %s  -----\n" %
                             ("-" * max_sym_name_len))
            truval = {0: "False", +1: "True"}
            for q, b in sorted(fixed_vars.items()):
                if num2syms[q] == []:
                    continue
                name_list = " ".join(sorted(num2syms[q]))
                sys.stderr.write("    %7d  %-*s  %-s\n" %
                                 (q, max_sym_name_len, name_list, truval[b]))
            sys.stderr.write("\n")

    # Return the original problem if no qubits could be elided.
    if verbosity >= 2:
        sys.stderr.write("  %6d logical qubits before elision\n" %
                         (qmasm.next_sym_num + 1))
    if len(fixed_vars) == 0:
        if verbosity >= 2:
            sys.stderr.write("  %6d logical qubits after elision\n\n" %
                             (qmasm.next_sym_num + 1))
        return logical

    # Construct a simplified problem, renumbering so as to compact qubit
    # numbers.
    new_obj = copy.deepcopy(logical)
    new_obj.known_values = {
        s: 2 * fixed_vars[n] - 1
        for s, n in qmasm.sym2num.items() if n in fixed_vars
    }
    new_obj.simple_offset = simple["offset"]
    hs, Js, ising_offset = qubo_to_ising(simple["new_Q"])
    qubits_used = set([i for i in range(len(hs)) if hs[i] != 0.0])
    for q1, q2 in Js.keys():
        qubits_used.add(q1)
        qubits_used.add(q2)
    qmap = dict(zip(sorted(qubits_used), range(len(qubits_used))))
    new_obj.chains = {(qmap[q1], qmap[q2]): None
                      for q1, q2 in new_obj.chains.keys()
                      if q1 in qmap and q2 in qmap}
    new_obj.weights = defaultdict(
        lambda: 0.0, {qmap[i]: hs[i]
                      for i in range(len(hs)) if hs[i] != 0.0})
    new_obj.strengths = qmasm.canonicalize_strengths({
        (qmap[q1], qmap[q2]): wt
        for (q1, q2), wt in Js.items()
    })
    new_obj.pinned = [(qmap[q], b) for q, b in new_obj.pinned if q in qmap]
    qmasm.sym2num = {s: qmap[q] for s, q in qmasm.sym2num.items() if q in qmap}
    try:
        qmasm.next_sym_num = max(qmasm.sym2num.values())
    except ValueError:
        qmasm.next_sym_num = -1
    if verbosity >= 2:
        sys.stderr.write("  %6d logical qubits after elision\n\n" %
                         (qmasm.next_sym_num + 1))
    return new_obj
Пример #5
0
def anneal(C_i, C_ij, mu, sigma, l, strength_scale, energy_fraction, ngauges,
           max_excited_states):
    url = "https://usci.qcc.isi.edu/sapi"
    token = "your-token"

    h = np.zeros(len(C_i))
    J = {}
    for i in range(len(C_i)):
        h_i = -2 * sigma[i] * C_i[i]
        for j in range(len(C_ij[0])):
            if j > i:
                J[(i, j)] = 2 * C_ij[i][j] * sigma[i] * sigma[j]
            h_i += 2 * (sigma[i] * C_ij[i][j] * mu[j])
        h[i] = h_i

    vals = np.array(J.values())
    cutoff = np.percentile(vals, AUGMENT_CUTOFF_PERCENTILE)
    to_delete = []
    for k, v in J.items():
        if v < cutoff:
            to_delete.append(k)
    for k in to_delete:
        del J[k]

    isingpartial = []

    if FIXING_VARIABLES:
        Q, _ = ising_to_qubo(h, J)
        simple = fix_variables(Q, method='standard')
        new_Q = simple['new_Q']
        print('new length', len(new_Q))
        isingpartial = simple['fixed_variables']
    if (not FIXING_VARIABLES) or len(new_Q) > 0:
        cant_connect = True
        while cant_connect:
            try:
                print('about to call remote')
                conn = dwave_sapi2.remote.RemoteConnection(url, token)
                solver = conn.get_solver("DW2X")
                print('called remote', conn)
                cant_connect = False
            except IOError:
                print('Network error, trying again', datetime.datetime.now())
                time.sleep(10)
                cant_connect = True

        A = get_hardware_adjacency(solver)

        mapping = []
        offset = 0
        for i in range(len(C_i)):
            if i in isingpartial:
                mapping.append(None)
                offset += 1
            else:
                mapping.append(i - offset)
        if FIXING_VARIABLES:
            new_Q_mapped = {}
            for (first, second), val in new_Q.items():
                new_Q_mapped[(mapping[first], mapping[second])] = val
            h, J, _ = qubo_to_ising(new_Q_mapped)

        # run gauges
        nreads = 200
        qaresults = np.zeros((ngauges * nreads, len(h)))
        for g in range(ngauges):
            embedded = False
            for attempt in range(5):
                a = np.sign(np.random.rand(len(h)) - 0.5)
                h_gauge = h * a
                J_gauge = {}
                for i in range(len(h)):
                    for j in range(len(h)):
                        if (i, j) in J:
                            J_gauge[(i, j)] = J[(i, j)] * a[i] * a[j]

                embeddings = find_embedding(J.keys(), A)
                try:
                    (h0, j0, jc,
                     new_emb) = embed_problem(h_gauge, J_gauge, embeddings, A,
                                              True, True)
                    embedded = True
                    break
                except ValueError:  # no embedding found
                    print('no embedding found')
                    embedded = False
                    continue

            if not embedded:
                continue

            # adjust chain strength
            rescale_couplers = strength_scale * max(
                np.amax(np.abs(np.array(h0))),
                np.amax(np.abs(np.array(list(j0.values())))))
            #         print('scaling by', rescale_couplers)
            for k, v in j0.items():
                j0[k] /= strength_scale
            for i in range(len(h0)):
                h0[i] /= strength_scale

            emb_j = j0.copy()
            emb_j.update(jc)

            print("Quantum annealing")
            try_again = True
            while try_again:
                try:
                    qaresult = solve_ising(solver,
                                           h0,
                                           emb_j,
                                           num_reads=nreads,
                                           annealing_time=a_time,
                                           answer_mode='raw')
                    try_again = False
                except:
                    print('runtime or ioerror, trying again')
                    time.sleep(10)
                    try_again = True
            print("Quantum done")

            qaresult = np.array(
                unembed_answer(qaresult["solutions"], new_emb, 'vote', h_gauge,
                               J_gauge))
            qaresult = qaresult * a
            qaresults[g * nreads:(g + 1) * nreads] = qaresult

        if FIXING_VARIABLES:
            j = 0
            for i in range(len(C_i)):
                if i in isingpartial:
                    full_strings[:, i] = 2 * isingpartial[i] - 1
                else:
                    full_strings[:, i] = qaresults[:, j]
                    j += 1
        else:
            full_strings = qaresults

        s = full_strings
        energies = np.zeros(len(qaresults))
        s[np.where(s > 1)] = 1.0
        s[np.where(s < -1)] = -1.0
        bits = len(s[0])
        for i in range(bits):
            energies += 2 * s[:, i] * (-sigma[i] * C_i[i])
            for j in range(bits):
                if j > i:
                    energies += 2 * s[:, i] * s[:, j] * sigma[i] * sigma[
                        j] * C_ij[i][j]
                energies += 2 * s[:, i] * sigma[i] * C_ij[i][j] * mu[j]

        unique_energies, unique_indices = np.unique(energies,
                                                    return_index=True)
        ground_energy = np.amin(unique_energies)
        #         print('ground energy', ground_energy)
        if ground_energy < 0:
            threshold_energy = (1 - energy_fraction) * ground_energy
        else:
            threshold_energy = (1 + energy_fraction) * ground_energy
        lowest = np.where(unique_energies < threshold_energy)
        unique_indices = unique_indices[lowest]
        if len(unique_indices) > max_excited_states:
            sorted_indices = np.argsort(
                energies[unique_indices])[-max_excited_states:]
            unique_indices = unique_indices[sorted_indices]
        final_answers = full_strings[unique_indices]
        print('number of selected excited states', len(final_answers))

        return final_answers

    else:
        final_answer = []
        for i in range(len(C_i)):
            if i in isingpartial:
                final_answer.append(2 * isingpartial[i] - 1)
        final_answer = np.array(final_answer)
        return np.array([final_answer])
Пример #6
0
def simplify_problem(logical, verbosity):
    """Try to find spins that can be removed from the problem because their
    value is known a priori."""
    # SAPI's fix_variables function works only on QUBOs so we have to convert.
    # We directly use SAPI's ising_to_qubo function instead of our own
    # convert_to_qubo because the QUBO has to be in matrix form.
    hs = qmasm.dict_to_list(logical.weights)
    Js = logical.strengths
    Q, qubo_offset = ising_to_qubo(hs, Js)

    # Simplify the problem if possible.
    simple = fix_variables(Q, method="standard")
    fixed_vars = simple["fixed_variables"]
    if verbosity >= 2:
        # Also determine if we could get rid of more qubits if we care about
        # only *a* solution rather than *all* solutions.
        alt_simple = fix_variables(Q, method="optimized")
        all_gone = len(alt_simple["new_Q"]) == 0

    # At high verbosity levels, list all of the known symbols and their value.
    if verbosity >= 2:
        # Map each logical qubit to one or more symbols.
        num2syms = [[] for _ in range(qmasm.sym_map.max_number() + 1)]
        max_sym_name_len = 7
        for q, n in qmasm.sym_map.symbol_number_items():
            num2syms[n].append(q)
            max_sym_name_len = max(max_sym_name_len, len(repr(num2syms[n])) - 1)

        # Output a table of know values
        sys.stderr.write("Elided qubits whose low-energy value can be determined a priori:\n\n")
        if len(fixed_vars) > 0:
            sys.stderr.write("    Logical  %-*s  Value\n" % (max_sym_name_len, "Name(s)"))
            sys.stderr.write("    -------  %s  -----\n" % ("-" * max_sym_name_len))
            truval = {0: "False", +1: "True"}
            for q, b in sorted(fixed_vars.items()):
                try:
                    syms = qmasm.sym_map.to_symbols(q)
                except KeyError:
                    continue
                name_list = " ".join(sorted(syms))
                sys.stderr.write("    %7d  %-*s  %-s\n" % (q, max_sym_name_len, name_list, truval[b]))
            sys.stderr.write("\n")

    # Return the original problem if no qubits could be elided.
    if verbosity >= 2:
        sys.stderr.write("  %6d logical qubits before elision\n" % (qmasm.sym_map.max_number() + 1))
    if len(fixed_vars) == 0:
        if verbosity >= 2:
            sys.stderr.write("  %6d logical qubits after elision\n\n" % (qmasm.sym_map.max_number() + 1))
            if all_gone:
                sys.stderr.write("    Note: A complete solution can be found classically using roof duality and strongly connected components.\n\n")
        return logical

    # Construct a simplified problem, renumbering so as to compact qubit
    # numbers.
    new_obj = copy.deepcopy(logical)
    new_obj.known_values = {s: 2*fixed_vars[n] - 1
                            for s, n in qmasm.sym_map.symbol_number_items()
                            if n in fixed_vars}
    new_obj.simple_offset = simple["offset"]
    hs, Js, ising_offset = qubo_to_ising(simple["new_Q"])
    qubits_used = set([i for i in range(len(hs)) if hs[i] != 0.0])
    for q1, q2 in Js.keys():
        qubits_used.add(q1)
        qubits_used.add(q2)
    qmap = dict(zip(sorted(qubits_used), range(len(qubits_used))))
    new_obj.chains = set([(qmap[q1], qmap[q2])
                          for q1, q2 in new_obj.chains
                          if q1 in qmap and q2 in qmap])
    new_obj.weights = defaultdict(lambda: 0.0,
                                  {qmap[i]: hs[i]
                                   for i in range(len(hs))
                                   if hs[i] != 0.0})
    new_obj.strengths = qmasm.canonicalize_strengths({(qmap[q1], qmap[q2]): wt
                                                      for (q1, q2), wt in Js.items()})
    new_obj.pinned = [(qmap[q], b)
                      for q, b in new_obj.pinned
                      if q in qmap]
    qmasm.sym_map.overwrite_with({s: qmap[q]
                                  for s, q in qmasm.sym_map.symbol_number_items()
                                  if q in qmap})
    if verbosity >= 2:
        # Report the number of logical qubits that remain, but compute the
        # number that could be removed if only a single solution were required.
        sys.stderr.write("  %6d logical qubits after elision\n\n" % (qmasm.sym_map.max_number() + 1))
        if all_gone:
            sys.stderr.write("    Note: A complete solution can be found classically using roof duality and strongly connected components.\n\n")
    return new_obj
Пример #7
0
def simplify_problem(logical, verbosity):
    """Try to find spins that can be removed from the problem because their
    value is known a priori."""
    # SAPI's fix_variables function works only on QUBOs so we have to convert.
    # We directly use SAPI's ising_to_qubo function instead of our own
    # convert_to_qubo because the QUBO has to be in matrix form.
    hs = qmasm.dict_to_list(logical.weights)
    Js = logical.strengths
    Q, qubo_offset = ising_to_qubo(hs, Js)

    # Simplify the problem if possible.
    simple = fix_variables(Q, method="standard")
    new_Q = simple["new_Q"]
    fixed_vars = simple["fixed_variables"]
    if verbosity >= 2:
        # Also determine if we could get rid of more qubits if we care about
        # only *a* solution rather than *all* solutions.
        alt_simple = fix_variables(Q, method="optimized")
        all_gone = len(alt_simple["new_Q"]) == 0

    # Work around the rare case in which fix_variables drops a variable
    # entirely, leaving it neither in new_Q nor in fixed_variables.  If this
    # happenes, we explicitly re-add the variable from Q to new_Q and
    # transitively everything it touches (removing from fixed_vars if a
    # variable appears there).
    old_vars = qubo_vars(Q)
    new_vars = qubo_vars(new_Q)
    new_vars.update(fixed_vars)
    missing_vars = sorted(old_vars.difference(new_vars))
    while len(missing_vars) > 0:
        q = missing_vars.pop()
        for (q1, q2), val in Q.items():
            if q1 == q or q2 == q:
                new_Q[(q1, q2)] = val
                fixed_vars.pop(q1, None)
                fixed_vars.pop(q2, None)
                if q1 == q and q2 > q:
                    missing_vars.append(q2)
                elif q2 == q and q1 > q:
                    missing_vars.append(q1)

    # At high verbosity levels, list all of the known symbols and their value.
    if verbosity >= 2:
        # Map each logical qubit to one or more symbols.
        num2syms = [[] for _ in range(qmasm.sym_map.max_number() + 1)]
        max_sym_name_len = 7
        for q, n in qmasm.sym_map.symbol_number_items():
            num2syms[n].append(q)
            max_sym_name_len = max(max_sym_name_len, len(repr(num2syms[n])) - 1)

        # Output a table of know values
        sys.stderr.write("Elided qubits whose low-energy value can be determined a priori:\n\n")
        if len(fixed_vars) > 0:
            sys.stderr.write("    Logical  %-*s  Value\n" % (max_sym_name_len, "Name(s)"))
            sys.stderr.write("    -------  %s  -----\n" % ("-" * max_sym_name_len))
            truval = {0: "False", +1: "True"}
            for q, b in sorted(fixed_vars.items()):
                try:
                    syms = qmasm.sym_map.to_symbols(q)
                except KeyError:
                    continue
                name_list = " ".join(sorted(syms))
                sys.stderr.write("    %7d  %-*s  %-s\n" % (q, max_sym_name_len, name_list, truval[b]))
            sys.stderr.write("\n")

    # Return the original problem if no qubits could be elided.
    if verbosity >= 2:
        sys.stderr.write("  %6d logical qubits before elision\n" % (qmasm.sym_map.max_number() + 1))
    if len(fixed_vars) == 0:
        if verbosity >= 2:
            sys.stderr.write("  %6d logical qubits after elision\n\n" % (qmasm.sym_map.max_number() + 1))
            if all_gone:
                sys.stderr.write("    Note: A complete solution can be found classically using roof duality and strongly connected components.\n\n")
        return logical

    # Construct a simplified problem, renumbering so as to compact qubit
    # numbers.
    new_obj = copy.deepcopy(logical)
    new_obj.known_values = {s: 2*fixed_vars[n] - 1
                            for s, n in qmasm.sym_map.symbol_number_items()
                            if n in fixed_vars}
    new_obj.simple_offset = simple["offset"]
    hs, Js, ising_offset = qubo_to_ising(new_Q)
    qubits_used = set([i for i in range(len(hs)) if hs[i] != 0.0])
    for q1, q2 in Js.keys():
        qubits_used.add(q1)
        qubits_used.add(q2)
    qmap = dict(zip(sorted(qubits_used), range(len(qubits_used))))
    new_obj.chains = set([(qmap[q1], qmap[q2])
                          for q1, q2 in new_obj.chains
                          if q1 in qmap and q2 in qmap])
    new_obj.antichains = set([(qmap[q1], qmap[q2])
                              for q1, q2 in new_obj.antichains
                              if q1 in qmap and q2 in qmap])
    new_obj.weights = defaultdict(lambda: 0.0,
                                  {qmap[i]: hs[i]
                                   for i in range(len(hs))
                                   if hs[i] != 0.0})
    new_obj.strengths = qmasm.canonicalize_strengths({(qmap[q1], qmap[q2]): wt
                                                      for (q1, q2), wt in Js.items()})
    new_obj.pinned = [(qmap[q], b)
                      for q, b in new_obj.pinned
                      if q in qmap]
    qmasm.sym_map.overwrite_with({s: qmap[q]
                                  for s, q in qmasm.sym_map.symbol_number_items()
                                  if q in qmap})
    if verbosity >= 2:
        # Report the number of logical qubits that remain, but compute the
        # number that could be removed if only a single solution were required.
        sys.stderr.write("  %6d logical qubits after elision\n\n" % (qmasm.sym_map.max_number() + 1))
        if qmasm.sym_map.max_number() > -1 and all_gone:
            sys.stderr.write("    Note: A complete solution can be found classically using roof duality and strongly connected components.\n\n")
    return new_obj
def test_trivial():
    q, offset = ising_to_qubo([], {})
    assert q == {}
    assert offset == 0
def test_typical():
    h = [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]
    j = {
        (0, 0): -5,
        (0, 5): 2,
        (0, 8): 4,
        (1, 4): -5,
        (1, 7): 1,
        (2, 0): 5,
        (2, 1): 4,
        (3, 0): -1,
        (3, 6): -3,
        (3, 8): 3,
        (4, 0): 2,
        (4, 7): 3,
        (4, 9): 3,
        (5, 1): 3,
        (6, 5): -4,
        (6, 6): -5,
        (6, 7): -4,
        (7, 1): -4,
        (7, 8): 3,
        (8, 2): -4,
        (8, 3): -3,
        (8, 6): -5,
        (8, 7): -4,
        (9, 0): 4,
        (9, 1): -1,
        (9, 4): -5,
        (9, 7): 3
    }
    q, offset = ising_to_qubo(h, j)
    norm_q = normalized_matrix(q)
    assert norm_q == {
        (0, 0): -42,
        (0, 2): 20,
        (0, 3): -4,
        (0, 4): 8,
        (0, 5): 8,
        (0, 8): 16,
        (0, 9): 16,
        (1, 1): -4,
        (1, 2): 16,
        (1, 4): -20,
        (1, 5): 12,
        (1, 7): -12,
        (1, 9): -4,
        (2, 2): -16,
        (2, 8): -16,
        (3, 3): 4,
        (3, 6): -12,
        (4, 4): 2,
        (4, 7): 12,
        (4, 9): -8,
        (5, 5): -2,
        (5, 6): -16,
        (6, 6): 34,
        (6, 7): -16,
        (6, 8): -20,
        (7, 7): 8,
        (7, 8): -4,
        (7, 9): 12,
        (8, 8): 18
    }
    assert offset == -8
def test_j_diag():
    q, offset = ising_to_qubo([], {(0, 0): 1, (300, 300): 99})
    assert q == {}
    assert offset == 100
def test_no_zeros():
    q, offset = ising_to_qubo([0, 0, 0], {(0, 0): 0, (4, 5): 0})
    assert q == {}
    assert offset == 0