예제 #1
0
    def test_construction(self):
        cqm = CQM()

        cqm.set_objective(dimod.AdjVectorBQM({'ab': 1}, 'SPIN'))
        label = cqm.add_constraint(dimod.AdjVectorBQM({'ab': 1}, 'SPIN'),
                                   sense='==',
                                   rhs=1)
        self.assertIsInstance(cqm.objective, BQM)
        self.assertIsInstance(cqm.constraints[label].lhs, BQM)
예제 #2
0
    def test_empty(self):
        bqm = dimod.AdjVectorBQM('BINARY')
        fixed = roof_duality(bqm, strict=True)
        self.assertEqual(fixed, {})

        fixed = roof_duality(bqm, strict=False)
        self.assertEqual(fixed, {})
예제 #3
0
def bqm_as_file(bqm, **options):
    """Encode in-memory BQM as DIMODBQM binary file format.

    Args:
        bqm (:class:`~dimod.BQM`):
            Binary quadratic model.

        **options (dict):
            :class:`~dimod.serialization.fileview.FileView` options.

    Returns:
        file-like:
            Binary stream with BQM encoded in DIMODBQM format.
    """
    # This now the preferred way of BQM binary serialization.

    # XXX: temporary implemented here, until something like
    # dwavesystems/dimod#599 is available.

    try:
        import dimod
        from dimod.serialization.fileview import FileView as BQMFileView
    except ImportError:  # pragma: no cover
        raise RuntimeError("Can't encode BQM without 'dimod'. "
                           "Re-install the library with 'bqm' support.")

    if isinstance(bqm, BQMFileView):
        return bqm

    # test explicitly to avoid copy on cast if possible
    fileviewable = (dimod.AdjArrayBQM, dimod.AdjVectorBQM, dimod.AdjMapBQM)
    if not isinstance(bqm, fileviewable):
        bqm = dimod.AdjVectorBQM(bqm)

    return BQMFileView(bqm, **options)
    def test_ferromagnet_chimera(self):
        # submit a maximum ferromagnet
        bqm = dimod.AdjVectorBQM('SPIN')
        for u, v in itertools.combinations(chimera_sampler.largest_clique(),
                                           2):
            bqm.quadratic[u, v] = -1

        chimera_sampler.sample(bqm).resolve()
예제 #5
0
    def test_empty(self):
        bqm = dimod.AdjVectorBQM('SPIN', _ignore_warning=True)

        with tempfile.TemporaryFile() as tf:
            with bqm.to_file() as bqmf:
                shutil.copyfileobj(bqmf, tf)
            tf.seek(0)
            new = dimod.AdjVectorBQM.from_file(tf)

        self.assertEqual(bqm, new)
예제 #6
0
    def test_construction(self):
        cqm = CQM()

        with self.assertWarns(DeprecationWarning):
            bqm = dimod.AdjVectorBQM({'ab': 1}, 'SPIN')

        cqm.set_objective(bqm)
        label = cqm.add_constraint(bqm, sense='==', rhs=1)
        self.assertIsInstance(cqm.objective, dimod.QuadraticModel)
        self.assertIsInstance(cqm.constraints[label].lhs, BQM)
예제 #7
0
def bqm_as_file(bqm, **options):
    """Encode in-memory BQM as DIMODBQM binary file format.

    Args:
        bqm (:class:`~dimod.BQM`):
            Binary quadratic model.

        **options (dict):
            :class:`~dimod.serialization.fileview.FileView` options.

    Returns:
        file-like:
            Binary stream with BQM encoded in DIMODBQM format.
    """
    # TODO: replace with `bqm.to_file` when we drop support for dimod 0.9.x

    try:
        import dimod
    except ImportError:  # pragma: no cover
        raise RuntimeError("Can't encode BQM without 'dimod'. "
                           "Re-install the library with 'bqm' support.")

    try:
        # Using `bqm.to_file()` for serialization is preferred since
        # dwavesystems/dimod#599, but we need a fallback for older dimods.
        # Specifically:
        # - `Adj{Vector,Array,Map}BQM.to_file` was added in dimod 0.9.6.
        # - `BQM.to_file` method was added in dimod 0.10.0.
        bqm.to_file
    except AttributeError:  # pragma: no cover
        pass
    else:
        return bqm.to_file(**options)

    try:
        # we need FileView in dimod < 0.9.6
        from dimod.serialization.fileview import FileView as BQMFileView
    except ImportError:  # pragma: no cover
        # this should never happen
        raise RuntimeError(
            f"Can't import FileView serializer from dimod=={dimod.__version__}"
        )

    if isinstance(bqm, BQMFileView):
        return bqm

    # test explicitly to avoid copy on cast if possible
    # note: it's safe to use Adj*BQMs (removed in dimod 0.10), as we never get
    # here if dimod 0.10 is used
    fileviewable = (dimod.AdjArrayBQM, dimod.AdjVectorBQM, dimod.AdjMapBQM)
    if not isinstance(bqm, fileviewable):
        bqm = dimod.AdjVectorBQM(bqm)

    return BQMFileView(bqm, **options)
예제 #8
0
    def test_all_zero(self):
        num_vars = 3

        bqm = dimod.AdjVectorBQM(num_vars, 'BINARY')
        fixed = roof_duality(bqm, strict=True)
        self.assertEqual(fixed, {})

        fixed = roof_duality(bqm, strict=False)
        self.assertEqual(len(fixed), num_vars)
        for val in fixed.values():
            self.assertEqual(val, 1)
예제 #9
0
def knapsack_bqm(costs, weights, weight_capacity):

    costs = costs

    # Initialize BQM - use large-capacity BQM so that the problem can be
    # scaled by the user.
    bqm = dimod.AdjVectorBQM(dimod.Vartype.BINARY)

    # Lagrangian multiplier
    # First guess as suggested in Lucas's paper
    lagrange = max(costs)

    # Number of objects
    x_size = len(costs)

    # Lucas's algorithm introduces additional slack variables to handle
    # the inequality. max_y_index indicates the maximum index in the y
    # sum; hence the number of slack variables.
    max_y_index = ceil(log(weight_capacity))

    # Slack variable list for Lucas's algorithm. The last variable has
    # a special value because it terminates the sequence.
    y = [2**n for n in range(max_y_index - 1)]
    y.append(weight_capacity + 1 - 2**(max_y_index - 1))

    # Hamiltonian xi-xi terms
    for k in range(x_size):
        bqm.set_linear('x' + str(k), lagrange * (weights[k]**2) - costs[k])

    # Hamiltonian xi-xj terms
    for i in range(x_size):
        for j in range(i + 1, x_size):
            key = ('x' + str(i), 'x' + str(j))
            bqm.quadratic[key] = 2 * lagrange * weights[i] * weights[j]

    # Hamiltonian y-y terms
    for k in range(max_y_index):
        bqm.set_linear('y' + str(k), lagrange * (y[k]**2))

    # Hamiltonian yi-yj terms
    for i in range(max_y_index):
        for j in range(i + 1, max_y_index):
            key = ('y' + str(i), 'y' + str(j))
            bqm.quadratic[key] = 2 * lagrange * y[i] * y[j]

    # Hamiltonian x-y terms
    for i in range(x_size):
        for j in range(max_y_index):
            key = ('x' + str(i), 'y' + str(j))
            bqm.quadratic[key] = -2 * lagrange * weights[i] * y[j]

    return bqm
예제 #10
0
def build_bqm(potential_new_cs_nodes, num_poi, pois, num_cs, charging_stations, num_new_cs):
    """ Build bqm that models our problem scenario for the hybrid sampler. """

    # Tunable parameters
    gamma1 = len(potential_new_cs_nodes) * 4
    gamma2 = len(potential_new_cs_nodes) / 3
    gamma3 = len(potential_new_cs_nodes) * 1.7
    gamma4 = len(potential_new_cs_nodes) ** 3

    # Build BQM using adjVectors to find best new charging location s.t. min 
    # distance to POIs and max distance to existing charging locations
    bqm = dimod.AdjVectorBQM(len(potential_new_cs_nodes), 'BINARY')

    # Constraint 1: Min average distance to POIs
    if num_poi > 0:
        for i in range(len(potential_new_cs_nodes)):
            # Compute average distance to POIs from this node
            avg_dist = 0
            cand_loc = potential_new_cs_nodes[i]
            for loc in pois:
                dist = (cand_loc[0]**2 - 2*cand_loc[0]*loc[0] + loc[0]**2 
                                    + cand_loc[1]**2 - 2*cand_loc[1]*loc[1] + loc[1]**2)
                avg_dist += dist / num_poi 
            bqm.linear[i] += avg_dist * gamma1

    # Constraint 2: Max distance to existing chargers
    if num_cs > 0:
        for i in range(len(potential_new_cs_nodes)):
            # Compute average distance to POIs from this node
            avg_dist = 0
            cand_loc = potential_new_cs_nodes[i]
            for loc in charging_stations:
                dist = (-1*cand_loc[0]**2 + 2*cand_loc[0]*loc[0] - loc[0]**2
                                    - cand_loc[1]**2 + 2*cand_loc[1]*loc[1] - loc[1]**2)
                avg_dist += dist / num_cs
            bqm.linear[i] += avg_dist * gamma2

    # Constraint 3: Max distance to other new charging locations
    if num_new_cs > 1:
        for i in range(len(potential_new_cs_nodes)):
            for j in range(i+1, len(potential_new_cs_nodes)):
                ai = potential_new_cs_nodes[i]
                aj = potential_new_cs_nodes[j]
                dist = (-1*ai[0]**2 + 2*ai[0]*aj[0] - aj[0]**2 - ai[1]**2 
                        + 2*ai[1]*aj[1] - aj[1]**2)
                bqm.add_interaction(i, j, dist * gamma3)

    # Constraint 4: Choose exactly num_new_cs new charging locations
    bqm.update(dimod.generators.combinations(bqm.variables, num_new_cs, strength=gamma4))

    return bqm
def knapsack_bqm(costs, weights, weight_capacity):

    costs = costs

    # Initialize BQM - use large-capacity BQM so that the problem can be
    # scaled by the user.
    bqm = dimod.AdjVectorBQM(dimod.Vartype.BINARY)

    # Lagrangian multiplier (A in Lucas's paper)
    #   Note: 0 < B*max(c_a) < A
    #         0.2 <= B <= 0.5 seems like a good range
    lagrange = max(costs)
    B = 0.5

    # Number of objects
    x_size = len(costs)

    # Lucas's algorithm introduces additional slack variables to handle
    # the inequality. In Lucas' paper y = [1, ..., W_max]
    y = [n for n in range(1, weight_capacity + 1)]
    max_y_index = len(y)

    # Hamiltonian xi-xi terms
    for k in range(x_size):
        bqm.set_linear('x' + str(k),
                       (lagrange * weights[k]**2) - (B * costs[k]))

    # Hamiltonian xi-xj terms
    for i in range(x_size):
        for j in range(i + 1, x_size):
            key = ('x' + str(i), 'x' + str(j))
            bqm.quadratic[key] = 2 * lagrange * weights[i] * weights[j]

    # Hamiltonian y-y terms
    for k in range(max_y_index):
        bqm.set_linear('y' + str(k), lagrange * (y[k]**2 - 1))

    # Hamiltonian yi-yj terms
    for i in range(max_y_index):
        for j in range(i + 1, max_y_index):
            key = ('y' + str(i), 'y' + str(j))
            bqm.quadratic[key] = 2 * lagrange * (y[i] * y[j] + 1)

    # Hamiltonian x-y terms
    for i in range(x_size):
        for j in range(max_y_index):
            key = ('x' + str(i), 'y' + str(j))
            bqm.quadratic[key] = -2 * lagrange * weights[i] * y[j]

    return bqm
    def test_pegasus(self):
        try:
            sampler = DWaveCliqueSampler(solver=dict(topology__type='pegasus'))
        except (ValueError, ConfigFileError, SolverNotFoundError):
            raise unittest.SkipTest("no Pegasus-structured QPU available")

        dimod.testing.assert_sampler_api(sampler)

        # submit a maximum ferromagnet
        bqm = dimod.AdjVectorBQM('SPIN')
        for u, v in itertools.combinations(sampler.largest_clique(), 2):
            bqm.quadratic[u, v] = -1

        sampler.sample(bqm).resolve()
예제 #13
0
def createBQM(incidencias, controles):

    idIncidencias = incidencias.keys()
    idControles = controles.keys()
    Q = dimod.AdjVectorBQM(dimod.Vartype.BINARY)
    J = {}

    tiempos = []
    for i in idIncidencias:
        tiempos.append(incidencias[i]['tiempo'])

    penalizacion = max(tiempos) + 1
    print(tiempos)

    for i, j in zip(idIncidencias, range(len(idIncidencias))):
        Q.set_linear(str(i), tiempos[j])
        J[(i, i)] = tiempos[j]

    for k in idControles:
        cIncidencias = controles[k]
        for i in cIncidencias:
            key = (str(i))

            Q.linear[key] -= penalizacion
            J[(i, i)] -= int(penalizacion)

        for i in range(len(idIncidencias)):
            for j in range(i + 1, len(idIncidencias)):
                incidencia1 = list(idIncidencias)[i]
                incidencia2 = list(idIncidencias)[j]

                key = (str(incidencia1), str(incidencia2))

                Q.quadratic[key] = 0
                J[(incidencia1, incidencia2)] = 0

    for k in idControles:
        cIncidencias = controles[k]
        for i in range(len(cIncidencias)):
            for j in range(i + 1, len(cIncidencias)):
                incidencia1 = cIncidencias[i]
                incidencia2 = cIncidencias[j]

                key = (str(incidencia1), str(incidencia2))

                Q.quadratic[key] += 2 * penalizacion
                J[(incidencia1, incidencia2)] += 2 * penalizacion

    return Q, J
예제 #14
0
    def test_saved_adjvector_5x5_v1(self):
        bqm = dimod.AdjVectorBQM(np.triu(np.arange(25).reshape((5, 5))),
                                 'BINARY')

        filename = os.path.join(TEST_DATA_DIR, '5x5_v1.bqm')

        # with open(filename, 'wb') as fp:
        #     with FileView(bqm, version=1) as fv:
        #         fp.write(fv.readall())

        with open(filename, 'rb') as fp:
            buff = fp.read()

        # test that we still encode the same way
        with FileView(bqm, version=1) as fv:
            self.assertEqual(buff, fv.read())

        # and that loading gives the same
        new = load(buff)
        self.assertEqual(new, bqm)
예제 #15
0
파일: knapsack.py 프로젝트: qfizik/knapsack
def build_knapsack_bqm(costs, weights, weight_capacity):
    """Construct BQM for the knapsack problem
    
    Args:
        costs (array-like):
            Array of costs associated with the items
        weights (array-like):
            Array of weights associated with the items
        weight_capacity (int):
            Maximum allowable weight
    
    Returns:
        Binary quadratic model instance
    """

    # Initialize BQM - use large-capacity BQM so that the problem can be
    # scaled by the user.
    bqm = dimod.AdjVectorBQM(dimod.Vartype.BINARY)

    # Lagrangian multiplier
    # First guess as suggested in Lucas's paper
    lagrange = max(costs)

    # Number of objects
    x_size = len(costs)

    # Lucas's algorithm introduces additional slack variables to
    # handle the inequality. M+1 binary slack variables are needed to
    # represent the sum using a set of powers of 2.
    M = floor(log2(weight_capacity))
    num_slack_variables = M + 1

    # Slack variable list for Lucas's algorithm. The last variable has
    # a special value because it terminates the sequence.
    y = [2**n for n in range(M)]
    y.append(weight_capacity + 1 - 2**M)

    # Hamiltonian xi-xi terms
    for k in range(x_size):
        bqm.set_linear('x' + str(k), lagrange * (weights[k]**2) - costs[k])

    # Hamiltonian xi-xj terms
    for i in range(x_size):
        for j in range(i + 1, x_size):
            key = ('x' + str(i), 'x' + str(j))
            bqm.quadratic[key] = 2 * lagrange * weights[i] * weights[j]

    # Hamiltonian y-y terms
    for k in range(num_slack_variables):
        bqm.set_linear('y' + str(k), lagrange * (y[k]**2))

    # Hamiltonian yi-yj terms
    for i in range(num_slack_variables):
        for j in range(i + 1, num_slack_variables):
            key = ('y' + str(i), 'y' + str(j))
            bqm.quadratic[key] = 2 * lagrange * y[i] * y[j]

    # Hamiltonian x-y terms
    for i in range(x_size):
        for j in range(num_slack_variables):
            key = ('x' + str(i), 'y' + str(j))
            bqm.quadratic[key] = -2 * lagrange * weights[i] * y[j]

    return bqm
예제 #16
0
def construct_bqm(demand, nfreq, reuse_distances, penalty_coef=1.0):
    """Construct BQM for feasibility frequency assignment problem.
    
    Args:
        demand (dict):
            Dictionary mapping each node number to a demand value
        nfreq (int):
            Number of frequencies to consider
        reuse_distances (list):
            List of reuse distances
        penalty_coef (float):
            Penalty coefficient associated with constraint penalty
            function.  Not needed in current formulation, which does
            not include an objective component of the problem
            formulation.  Retained only as a placeholder in case the
            problem is extended to include an objective.

    Returns:
        AdjVectorBQM
    """
    # Variables:
    # x_vf, v in nodes, f in frequencies: Is f assigned to node v?

    nodes = sorted(list(demand.keys()))

    bqm = dimod.AdjVectorBQM(dimod.BINARY)

    # Constraints to enforce demand at each node:
    # Sum_f[ (1-2C) xvf ] + Sum_j>i[ 2 xvfi xvfj ] + C^2

    # Linear parts:
    for v in nodes:
        for f in range(nfreq):
            bqm.add_variable('x_{}_{}'.format(v, f),
                             penalty_coef * (1.0 - 2 * demand[v]))
    # Interactions:
    for v in nodes:
        for fi in range(nfreq):
            for fj in range(fi + 1, nfreq):
                bqm.add_interaction('x_{}_{}'.format(v, fi),
                                    'x_{}_{}'.format(v,
                                                     fj), penalty_coef * 2.0)

    # Define penalties associated with the interference constraints.
    # The interference constraints are represented by the inequality
    # xvf + xwg <= 1 for all combinations that would produce
    # interference.

    # First enforce the self-conflicts between frequencies in the same node:
    T = get_forbidden_set(1, 1, reuse_distances)
    for v in nodes:
        for f in range(nfreq):
            for g in range(f + 1, nfreq):
                if abs(f - g) in T:
                    bqm.add_interaction('x_{}_{}'.format(v, f),
                                        'x_{}_{}'.format(v, g), penalty_coef)

    # Now enforce the cross-node conflicts:
    for iv, v in enumerate(nodes):
        for w in nodes[iv + 1:]:
            T = get_forbidden_set(v, w, reuse_distances)
            if not T:
                # No disallowed frequencies at this distance
                continue
            for f in range(nfreq):
                # Note f and g are frequencies on different nodes, so we do need to look at all combinations
                for g in range(nfreq):
                    if abs(f - g) in T:
                        bqm.add_interaction('x_{}_{}'.format(v, f),
                                            'x_{}_{}'.format(w,
                                                             g), penalty_coef)

    return bqm
예제 #17
0
charging_stations = random.sample(nodes, k=num_cs)

# Number of new charging stations to place
num_new_cs = 2

poi_cs_list = set(pois) - (set(pois) - set(charging_stations))
poi_cs_graph = G.subgraph(poi_cs_list)
poi_graph = G.subgraph(pois)
cs_graph = G.subgraph(charging_stations)

# Identify potential new charging locations
potential_new_cs_nodes = list(nodes - charging_stations)

# Build BQM using adjVectors to find best new charging location s.t. min
# distance to POIs and max distance to existing charging locations
bqm = dimod.AdjVectorBQM(len(potential_new_cs_nodes), 'BINARY')

# Constraint 1: Min average distance to POIs
for i in range(len(potential_new_cs_nodes)):
    # Compute average distance to POIs from this node
    ave_dist = 0
    cand_loc = potential_new_cs_nodes[i]
    for loc in pois:
        dist = (cand_loc[0]**2 - 2 * cand_loc[0] * loc[0] + loc[0]**2 +
                cand_loc[1]**2 - 2 * cand_loc[1] * loc[1] + loc[1]**2)
        ave_dist += dist / num_cs
    bqm.linear[i] = ave_dist * gamma1

# Constraint 2: Max distance to existing chargers
for i in range(len(potential_new_cs_nodes)):
    # Compute average distance to POIs from this node
예제 #18
0
def knapsack_bqm(cities, values, weights, total_capacity, value_r=0, weight_r=0):
    """
    build the knapsack binary quadratic model
    
    From DWave Knapsack examples
    Originally from Andrew Lucas, NP-hard combinatorial problems as Ising spin glasses
    Workshop on Classical and Quantum Optimization; ETH Zuerich - August 20, 2014
    based on Lucas, Frontiers in Physics _2, 5 (2014) 

    See # Q-Alpha version for original introduction of value_r and weight_r
    
        value_r: the proportion of value contributed from the objects outside of the knapsack. 
                For the standard knapsack problem this is 0,
                but in the case of GDP a closed city retains some % of GDP value;
                or for health problems it may contribute negative value (-1).
                
        weight_r: the proportion of weight contributed from the objects outside of the knapsack. 
                For the standard knapsack problem this is 0,
                but in the case of sick people we might consider that a closed city
                retains some % of its sick people over time;
                or for health problems it may contribute negative value (-1)
   
    """

    # Initialize BQM - use large-capacity BQM so that the problem can be
    # scaled by the user.
    bqm = dimod.AdjVectorBQM(dimod.Vartype.BINARY)

    # Lagrangian multiplier
    # First guess as suggested in Lucas's paper
    lagrange = max(values)

    # Number of objects
    x_size = len(values)

    # Lucas's algorithm introduces additional slack variables to handle
    # the inequality. max_y_index indicates the maximum index in the y
    # sum; hence the number of slack variables.
    max_y_index = ceil(log(total_capacity))

    # Slack variable list for Lucas's algorithm. The last variable has
    # a special value because it terminates the sequence.
    y = [2**n for n in range(max_y_index - 1)]
    y.append(total_capacity + 1 - 2**(max_y_index - 1))

    # Q-Alpha - calculate the extra constant in second part of problem hamiltonian
    C = sum([weight * weight_r for weight in weights])
    
    # Q-Alpha - change weights to weight*(1-weight_r)
    weights = [weight*(1-weight_r) for weight in weights]

    # Q-Alpha - change values to value*(1-value_r)
    values = [value*(1-value_r) for value in values]

    # Hamiltonian xi-xi terms
    for k in range(x_size):
        # Q-Alpha add final term lagrange * C * weights[k]
        bqm.set_linear(
            cities[k],
            lagrange * (weights[k] ** 2) - values[k] + lagrange * C * weights[k])

    # Hamiltonian xi-xj terms
    for i in range(x_size):
        for j in range(i + 1, x_size):
            key = (cities[i], cities[j])
            bqm.quadratic[key] = 2 * lagrange * weights[i] * weights[j]

    # Hamiltonian y-y terms
    for k in range(max_y_index):
        # Q-Alpha add final term -lagrange * C * y[k]
        bqm.set_linear('y' + str(k), lagrange *
                       (y[k]**2) - lagrange * C * y[k])

    # Hamiltonian yi-yj terms
    for i in range(max_y_index):
        for j in range(i + 1, max_y_index):
            key = ('y' + str(i), 'y' + str(j))
            bqm.quadratic[key] = 2 * lagrange * y[i] * y[j]

    # Hamiltonian x-y terms
    for i in range(x_size):
        for j in range(max_y_index):
            key = (cities[i], 'y' + str(j))
            bqm.quadratic[key] = -2 * lagrange * weights[i] * y[j]

    return bqm
예제 #19
0
#        http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.

import dimod
import numpy as np

from parameterized import parameterized

BQMs = dict(
    bqm_k150=dimod.BinaryQuadraticModel(np.ones((150, 150)), 'BINARY'),
    adj_k150=dimod.AdjVectorBQM(np.ones((150, 150)), 'BINARY'),
    bqm_k500=dimod.BinaryQuadraticModel(np.ones((500, 500)), 'BINARY'),
    adj_k500=dimod.AdjVectorBQM(np.ones((500, 500)), 'BINARY'),
)


class BQMSuite:
    @parameterized.expand(BQMs.items())
    def time_iter_quadratic(self, _, bqm):
        for _ in bqm.iter_quadratic():
            pass

    @parameterized.expand((name, bqm, np.ones((1000, bqm.num_variables)))
                          for name, bqm in BQMs.items())
    def time_energies(self, _, bqm, samples):
        bqm.energies(samples)
from dwave.system import LeapHybridSampler
import dimod
import sys

# Graph partitioning on clique
N = int(sys.argv[1])
gamma = 3
linear = (N - 1) * (1 - gamma)
quad = (2 * gamma) - 2

bqm = dimod.AdjVectorBQM(dimod.Vartype.BINARY)
bqm.offset = gamma * N**2 / 4
for i in range(N):
    bqm.set_linear(i, linear)
    for j in range(i + 1, N):
        bqm.quadratic[i, j] = quad

sampler = LeapHybridSampler(profile='hss')
response = sampler.sample(bqm)

print(response.info)
for sample, energy in response.data(['sample', 'energy']):
    print(sample, energy)
예제 #21
0
def createBQM(incidencias, controles):
    idIncidencias = incidencias.keys(
    )  #Se extraen las ids de las incidencias para mejor gestión.
    idControles = controles.keys(
    )  #Se extraen las ids de los controles para mejor gestión.

    Q = dimod.AdjVectorBQM(
        dimod.Vartype.BINARY
    )  #Este es el formato principal del BQM, una matriz cuadrática.
    J = {}  #Este formato se utiliza para usarlo con el inspector.

    tiempos = [
    ]  #Se extraen los tiempos para mejor gestión y para sacar el máximo.
    for i in idIncidencias:
        tiempos.append(incidencias[i]['tiempo'])

    y = {}
    slack_incidencias = {}

    for k in idControles:
        num_incidencias = len(controles[k])
        num_slack = ceil(log2(num_incidencias))
        slack_incidencias[k] = num_slack
        for i in range(num_slack):
            if k in y:
                y[str(k)].append(2**i)
            else:
                y[str(k)] = [2**i]

    penalizacion = max(
        tiempos
    ) + 10  #La penalización es el valor que nos va a ayudar a seleccionar qué incidencias tenemos
    #que seleccionar. La condición que necesitamos que se cumpla es que todos los controles
    #sean resueltos. Cualquier solución que no cumpla con esa condición, será descartada
    #gracias al valor de penalización. Se ha decidido que el valor sea el máximo tiempo
    #entre todas las incidencias para que pueda variar según sea necesario, y es
    #incrementado en 1 para que no interfiera con el peso de las decisiones.

    #Término linear xi (-P*xi).
    #Este término linear se encarga de relacionar el tiempo que se tarda en gestionar una incidencia. De forma muy simplificada,
    #esto es lo que determinará qué incidencias son las mejores en caso de que haya varias soluciones válidas. Se recomienda leer
    #la documentación para una explicación en mayor detalle y cómo se ha llegado a esta operación.
    for i, j in zip(idIncidencias, range(len(idIncidencias))):
        Q.set_linear('x' + str(i), tiempos[j])
        J[(i, i)] = tiempos[j]

    #Término linear xi (-P*xi).
    #Esta parte se utiliza para restar la penalización a cada incidencia que resuelva un control. De forma muy simplificada, si
    #una incidencia resuelve varios controles, es más probable que sea seleccionada. Se recomienda leer la documentación para
    #una explicación en mayor detalle y cómo se ha llegado a esta operación.
    for k in idControles:
        cIncidencias = controles[
            k]  #Se extraen todas las incidencias de las que forma parte cada control, de forma que se
        #pueda usar para acceder al BQM.

        for i in cIncidencias:
            key = ('x' + str(i))

            Q.linear[key] -= penalizacion
            J[(i, i)] -= penalizacion

    #Término linear y-y (sk² + 2Psk)
    for k in idControles:
        if k in y:
            slacks = y[k]
            if type(slacks) is int:
                Q.set_linear('y' + str(k) + '-' + str(slacks),
                             (slacks**2 + 2) * penalizacion)
            else:
                for i in slacks:
                    Q.set_linear('y' + str(k) + '-' + str(i),
                                 (i**2 + 2) * penalizacion)

    #Término cuadrático xi-xj (2P*xi*xj).
    #Esta parte sirve simplemente para inicializar los términos cuadráticos en el BQM.
    for k in idControles:
        cIncidencias = controles[k]
        for i in range(len(cIncidencias)):
            for j in range(i + 1, len(cIncidencias)):
                incidencia1 = cIncidencias[i]
                incidencia2 = cIncidencias[j]

                key = ('x' + str(incidencia1), 'x' + str(incidencia2))

                Q.quadratic[key] = 0
                J[(incidencia1, incidencia2)] = 0

    #Término cuadrático xi-xj (2P*xi*xj).
    #El término cuadrático se encarga de evitar redundancias entre los controles. De forma muy simplificada, si un control es
    #resuelto por dos incidencias, puede ser que una de esas incidencias sea innecesaria. Se recomienda leer la documentación
    #para una explicación en mayor detalle y cómo se ha llegado a esta operación.
    for k in idControles:
        cIncidencias = controles[k]
        for i in range(len(cIncidencias)):
            for j in range(i + 1, len(cIncidencias)):
                incidencia1 = cIncidencias[i]
                incidencia2 = cIncidencias[j]

                key = ('x' + str(incidencia1), 'x' + str(incidencia2))

                Q.quadratic[key] += 2 * penalizacion
                J[(incidencia1, incidencia2)] += 2 * penalizacion

    #Término cuadrático yi-yj
    for k in idControles:
        if k in y:
            slacks = y[k]
            if type(slacks) is not int:
                for i in range(len(slacks)):
                    for j in range(i + 1, len(slacks)):
                        slack1 = slacks[i]
                        slack2 = slacks[j]

                        key = ('y' + str(k) + '-' + str(i),
                               'y' + str(k) + '-' + str(j))
                        Q.quadratic[key] = 2 * penalizacion * slack1 * slack2

    #Término cuadrático y-x
    for k in idControles:
        if k in y:
            cIncidencias = controles[k]
            slacks = y[k]
            if type(slacks) is int:
                for i in range(len(cIncidencias)):
                    incidencia1 = cIncidencias[i]

                    key = ('x' + str(incidencia1),
                           'y' + str(k) + '-' + str(slacks))

                    Q.quadratic[key] = -2 * penalizacion * slacks
            else:
                for i in range(len(cIncidencias)):
                    for j in range(len(slacks)):
                        incidencia1 = cIncidencias[i]
                        slack1 = slacks[j]

                        key = ('x' + str(incidencia1),
                               'y' + str(k) + '-' + str(j))

                        Q.quadratic[key] = 2 * penalizacion * slack1

    print(Q)

    return Q, J