Source code for ingenii_quantum.qubo.segmentation

import gurobipy as gp
from gurobipy import GRB
import time
import numpy as np

[docs] def decode_binary_string(x, height, width): """ Decode a binary string into a binary segmentation mask. Args: x (list): Binary string representing the segmentation. height (int): Height of the image. width (int): Width of the image. Returns: numpy.ndarray: Segmentation mask. """ mask = np.zeros([height, width]) for index, segment in enumerate(x): mask[index // width, index % width] = segment return mask
[docs] def QUBO_formulation(G, alpha=10, height=32): ''' Function that provides the QUBO formulation for quantum and simulated annealing. It provides the linear and quadratic constraints. Args: G (networkx.Graph): Weighted graph encoding the input image alpha (float): hyperparameter controlling the importance of the smoothness constraint. Returns: linear (dict): linear constraints of QUBO model quadratic (dict): quadratic constraints of QUBO model problem_formulation_time (float): Problem formulation time ''' # Problem formulation node_dict = {list(G.nodes())[i]:i for i in range(len(G.nodes()))} linear = {i:0 for i in range(len(node_dict))} quadratic1 = {(node_dict[i],node_dict[j]):0 for (i,j) in G.edges()} quadratic2 = {(i,i):0 for i in range(len(node_dict))} quadratic = {**quadratic1, **quadratic2} start_time = time.time() for edge in G.edges(): node1, node2 = edge[0], edge[1] w = G.get_edge_data(node1, node2)['weight'] node1_idx, node2_idx = node1[0]*height + node1[1], node2[0]*height + node2[1] # Min-cut constraints w_{ij}*x_i(1- x_j) linear[node1_idx] += w linear[node2_idx] += w quadratic[(node1_idx, node2_idx)] += -2*w # Smootheness constraints S = alpha*w_{ij}(q- delta(xi, xj)) = alpha*w_{ij}(1-(xi + xj - 1)^2) = alpha*w_{ij}(2xi + 2xj -2xixj -xi^2 - xj^2) linear[node1_idx] += alpha*2*w linear[node2_idx] += alpha*2*w quadratic[(node1_idx, node2_idx)] += -alpha*2*w quadratic[(node1_idx, node1_idx)] += -alpha*w quadratic[(node2_idx, node2_idx)] += -alpha*w problem_formulation_time = time.time() - start_time return linear, quadratic, problem_formulation_time
[docs] def gurobi_qubo_solver(G, alpha=10, height=32, width=32): ''' Gurobi solver. Args G (networkx.Graph): Weighted graph encoding the input image alpha (float): hyperparameter controlling the importance of the smoothness constraint. Returns: segmentation_mask (np.array): Segmentation mask gurobi_qubo_value (float): QUBO value of segmentation mask ''' # Problem formulation model = gp.Model() n = len(G.nodes()) x = model.addVars(n, vtype=GRB.BINARY) obj_expr = 0 model.update() for edge in G.edges(): node1, node2 = edge[0], edge[1] w = G.get_edge_data(node1, node2)['weight'] node1_idx, node2_idx = node1[0]*height + node1[1], node2[0]*height + node2[1] obj_expr += w*(x[node1_idx] + x[node2_idx] - 2*x[node1_idx]*x[node2_idx]) + alpha*w*(1-(x[node1_idx] + x[node2_idx] - 1)**2) model.setObjective(obj_expr) model.setParam('OutputFlag', 0) model.optimize() model.update() if model.status == GRB.OPTIMAL: solution = [int(x[i].X) for i in range(n)] binary_string = ''.join(str(bit) for bit in solution) gurobi_qubo_solution, gurobi_qubo_value = binary_string, model.objVal segmentation_mask = decode_binary_string(gurobi_qubo_solution, height, width) return segmentation_mask, gurobi_qubo_value else: print('No solution found') return None, None