Source code for qrisp.qiro.qiroproblems.qiroMaxSat

"""
\********************************************************************************
* Copyright (c) 2024 the Qrisp authors
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License, v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is
* available at https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
"""

# just write a replacement_routine and throw out not relevant sets

from qrisp import rz, x, cx
import numpy as np
import math
import copy
from qrisp.algorithms.qiro.qiroproblems.qiro_utils import * 


[docs] def create_maxsat_replacement_routine(res, problem, solutions, exclusions): """ Creates a replacement routine for the problem structure, i.e., defines the replacement rules. See the `original paper <https://journals.aps.org/prxquantum/abstract/10.1103/PRXQuantum.5.020327>`_ for a description of the update rules. Parameters ---------- res : dict Result dictionary of QAOA optimization procedure. problem : tuple(int, list[list[int]]) The number of variables and a list of clauses for the MaxSat instance. solutions : list Qubits which were found to be positively correlated, i.e., part of the problem solution. exclusions : list Qubits which were found to be negatively correlated, i.e., not part of the problem solution, or contradict solution qubits in accordance with the update rules. Returns ------- new_problem: list Updated clauses of the problem instance. solutions : list Updated set of solutions to the problem. sign : int The sign of the correlation. exclusions : list Updated set of exclusions to the problem. """ numVars = problem[0] clauses = copy.deepcopy(problem[1]) # FOR SINGLE QUBIT CORRELATIONS # make -1 here for consistency in the find max orig_nodes = [i - 1 for i in list(range(1,numVars + 1)) if not i in exclusions] combinations = [] # add check for solution nodes for index1 in range(len(orig_nodes)-1): for index2 in range(index1, len(orig_nodes)): combinations.append((orig_nodes[index1],orig_nodes[index2])) max_item, sign = find_max(orig_nodes, combinations, res, solutions) # we just directly remove clauses from clauses if isinstance(max_item, int): max_item += 1 if sign > 0: for item in clauses: # if negation in item --> remove it if -1 * max_item in item: clauses.remove(item) solutions.append(max_item) exclusions.append(max_item) elif sign < 0: for item in clauses: # if number in item --> remove it if max_item in item: clauses.remove(item) exclusions.append(max_item) else: max_item[0] += 1 max_item[1] += 1 if sign > 0: for item in clauses: # replace with pos. correlated number if its in an item if max_item[1] in item: temp = item.index[max_item[1]] item[temp] = max_item[0] if -1* max_item[1] in item: temp = item.index[-1* max_item[1]] item[temp] = -1* max_item[0] exclusions.append(max_item[1]) elif sign < 0: for item in clauses: # replace with neg. correlated number if its in an item if max_item[1] in item: temp = item.index[max_item[1]] item[temp] = -1 * max_item[0] if -1* max_item[1] in item: temp = item.index[ -1 * max_item[1]] item[temp] = max_item[0] exclusions.append(max_item[1]) # create sign list somewhere? return [numVars, clauses], solutions, sign, exclusions
[docs] def create_maxsat_cost_operator_reduced(problem, solutions=[]): """ Creates the ``cost_operator`` for the problem instance. This operator is adjusted to consider qubits that were found to be a part of the problem solution. Parameters ---------- problem : tuple(int, list[list[int]]) The number of variables and a list of clauses for the MaxSat instance. solutions : list Variables that were found to be a part of the solution. Returns ------- cost_operator : function A function receiving a :ref:`QuantumVariable` and a real parameter $\gamma$. This function performs the application of the cost operator. """ clauses = problem[1] satlen = len(clauses[0]) def maxSatcostEmbed(qv , gamma): import itertools #clauses = clauses qc = qv for numClause in range(len(clauses)): #go through clauses clause = clauses[numClause] for lenofCombination in range(1,satlen+1): # get all combinations to assign rz, rzz, rzzz, rzzzzzz.... combinations = list(itertools.combinations(clause, lenofCombination)) #print(combinations) #len == 1: just rz if lenofCombination == 1: for index in range(len(combinations)): if abs( combinations[index][0])-1 not in solutions: # sign for rz mixer signu = - np.sign(combinations[index][0]) # always have the "-1" at the end since clauses are not initiated with 0, see above #print(abs( combinations[index][0] - 1 )) rz(signu * gamma/8, qc[ abs( combinations[index][0]) -1 ] ) else: #for all combinations of this length for index in range(len(combinations)): signu = 1 # up to final value in combination perform cx gates --> set up the rzz, rzzz, rzzzz ... gates for index2 in range(lenofCombination-1): # (also remember the sign) signu *= - np.sign(combinations[index][index2]) cx(qc[abs( combinations[index][index2] ) -1], qc[abs( combinations[index][index2+1] ) -1]) signu *= np.sign(combinations[index][lenofCombination-1]) # finalize rzz, rzzz, rzzzz ... gates rz(signu*gamma/8, qc[abs( combinations[index][lenofCombination-1] ) -1]) # and cnot gates back for index2 in reversed(range(lenofCombination-1)): cx( qc[abs(combinations[index][index2] ) -1], qc[abs(combinations[index][index2+1] ) -1 ]) return qc return maxSatcostEmbed