diff --git a/dimod/higherorder/polynomial.py b/dimod/higherorder/polynomial.py index 654b3d539..e2201164c 100644 --- a/dimod/higherorder/polynomial.py +++ b/dimod/higherorder/polynomial.py @@ -16,11 +16,14 @@ import itertools import collections.abc as abc +from collections import defaultdict from numbers import Number import numpy as np +import cytoolz as tl + from dimod.decorators import vartype_argument from dimod.sampleset import as_samples from dimod.utilities import iter_safe_relabels @@ -34,6 +37,22 @@ def asfrozenset(term): return term if isinstance(term, frozenset) else frozenset(term) +def freeze_term(term, vartype): + return ( + term + if isinstance(term, frozenset) + else ( + frozenset(term) + if vartype is Vartype.BINARY + else frozenset( + var + for var, power in tl.frequencies(term).items() + if power % 2 + ) + ) + ) + + class BinaryPolynomial(abc.MutableMapping): """A polynomial with binary variables and real-valued coefficients. @@ -92,26 +111,11 @@ def __init__(self, poly, vartype): poly = poly.items() # we need to aggregate the repeated terms - self._terms = terms = {} - for term, bias in poly: - - fsterm = asfrozenset(term) - - # when SPIN-valued, s^2 == 1, so we need to handle that case - # in BINARY, x^2 == x - if len(fsterm) < len(term) and vartype is Vartype.SPIN: - new = set() - term = tuple(term) # make sure it has .count - for v in fsterm: - if term.count(v) % 2: - new.add(v) - fsterm = frozenset(new) - - if fsterm in terms: - terms[fsterm] += bias - else: - terms[fsterm] = bias + self._terms = terms = defaultdict(int) + for term, bias in poly: + terms[freeze_term(term, vartype)] += bias + self.vartype = vartype def __contains__(self, term): @@ -127,10 +131,10 @@ def __eq__(self, other): except Exception: # not a polynomial return False - + self_terms = self._terms other_terms = other._terms - + return ( self.vartype == other.vartype and all( diff --git a/dimod/higherorder/utils.py b/dimod/higherorder/utils.py index a343efcc2..93c57546c 100644 --- a/dimod/higherorder/utils.py +++ b/dimod/higherorder/utils.py @@ -17,6 +17,9 @@ from collections import Counter +from collections import defaultdict +from functools import partial + import numpy as np from dimod.binary_quadratic_model import BinaryQuadraticModel @@ -24,7 +27,7 @@ from dimod.sampleset import as_samples from dimod.vartypes import as_vartype, Vartype -__all__ = ['make_quadratic'] +__all__ = ['make_quadratic', 'reduce_terms'] def _spin_product(variables): @@ -97,9 +100,176 @@ def _new_aux(variables, u, v): return aux +def _decrement_count(idx, que, pair): + count = len(idx[pair]) + que_count = que[count] + que_count.remove(pair) + if not que_count: + del que[count] + if count > 1: + que[count - 1].add(pair) + + +def _remove_old(idx, term, pair): + idx_pair = idx[pair] + del idx_pair[term] + if not idx_pair: + del idx[pair] + + +def reduce_terms(bp): + variables = bp.variables + constraints = [] + + reduced_terms = [] + idx = defaultdict(dict) + for item in bp.items(): + term, bias = item + if len(term) <= 2: + reduced_terms.append(item) + else: + for pair in itertools.combinations(term, 2): + idx[frozenset(pair)][term] = bias + + que = defaultdict(set) + for pair, terms in idx.items(): + que[len(terms)].add(pair) + + while idx: + new_pairs = set() + most = max(que) + que_most = que[most] + pair = que_most.pop() + if not que_most: + del que[most] + terms = idx.pop(pair) + + prod_var = _new_product(variables, *pair) + constraints.append((pair, prod_var)) + prod_var_set = {prod_var} + + for old_term, bias in terms.items(): + common_subterm = (old_term - pair) + new_term = common_subterm | prod_var_set + + for old_pair in map(frozenset, itertools.product(pair, common_subterm)): + _decrement_count(idx, que, old_pair) + _remove_old(idx, old_term, old_pair) + + for common_pair in map(frozenset, itertools.combinations(common_subterm, 2)): + idx[common_pair][new_term] = bias + _remove_old(idx, old_term, common_pair) + + if len(new_term) > 2: + for new_pair in (frozenset((prod_var, v)) for v in common_subterm): + idx[new_pair][new_term] = bias + new_pairs.add(new_pair) + else: + reduced_terms.append((new_term, bias)) + + for new_pair in new_pairs: + que[len(idx[new_pair])].add(new_pair) + + return reduced_terms, constraints + + def make_quadratic(poly, strength, vartype=None, bqm=None): """Create a binary quadratic model from a higher order polynomial. + Args: + poly (dict): + Polynomial as a dict of form {term: bias, ...}, where `term` is a tuple of + variables and `bias` the associated bias. + + strength (float): + The energy penalty for violating the prodcut constraint. + Insufficient strength can result in the binary quadratic model not + having the same minimizations as the polynomial. + + vartype (:class:`.Vartype`/str/set, optional): + Variable type for the binary quadratic model. Accepted input values: + + * :class:`.Vartype.SPIN`, ``'SPIN'``, ``{-1, 1}`` + * :class:`.Vartype.BINARY`, ``'BINARY'``, ``{0, 1}`` + + If `bqm` is provided, `vartype` is not required. + + bqm (:class:`.BinaryQuadraticModel`, optional): + The terms of the reduced polynomial are added to this binary quadratic model. + If not provided, a new binary quadratic model is created. + + Returns: + :class:`.BinaryQuadraticModel` + + Examples: + + >>> poly = {(0,): -1, (1,): 1, (2,): 1.5, (0, 1): -1, (0, 1, 2): -2} + >>> bqm = dimod.make_quadratic(poly, 5.0, dimod.SPIN) + + """ + if vartype is None: + if bqm is None: + raise ValueError("one of vartype or bqm must be provided") + else: + vartype = bqm.vartype + else: + vartype = as_vartype(vartype) # handle other vartype inputs + if bqm is None: + bqm = BinaryQuadraticModel.empty(vartype) + else: + bqm = bqm.change_vartype(vartype, inplace=False) + + # for backwards compatibility, add an info field + if not hasattr(bqm, 'info'): + bqm.info = {} + bqm.info['reduction'] = {} + + if not isinstance(poly, BinaryPolynomial) or poly.vartype != vartype: + poly = BinaryPolynomial(poly, vartype=vartype) + + variables = set().union(*poly) + reduced_terms, constraints = reduce_terms(poly) + + for (u, v), p in constraints: + + # add a constraint enforcing the relationship between p == u*v + if vartype is Vartype.BINARY: + constraint = _binary_product([u, v, p]) + bqm.info['reduction'][(u, v)] = {'product': p} + elif vartype is Vartype.SPIN: + aux = _new_aux(variables, u, v) # need an aux in SPIN-space + constraint = _spin_product([u, v, p, aux]) + bqm.info['reduction'][(u, v)] = {'product': p, 'auxiliary': aux} + else: + raise RuntimeError("unknown vartype: {!r}".format(vartype)) + + # scale constraint and update the polynomial with it + constraint.scale(strength) + for v, bias in constraint.linear.items(): + bqm.add_variable(v, bias) + for uv, bias in constraint.quadratic.items(): + bqm.add_interaction(*uv, bias) + bqm.offset += constraint.offset + + for term, bias in reduced_terms: + if len(term) == 2: + bqm.add_interaction(*term , bias) + elif len(term) == 1: + bqm.add_variable(*term, bias) + elif len(term) == 0: + bqm.offset += bias + else: + # still has higher order terms, this shouldn't happen + msg = ('Internal error: not all higher-order terms were reduced. ' + 'Please file a bug report.') + raise RuntimeError(msg) + + return bqm + + +def make_quadratic_old(poly, strength, vartype=None, bqm=None): + """Create a binary quadratic model from a higher order polynomial. + Args: poly (dict): Polynomial as a dict of form {term: bias, ...}, where `term` is a tuple of diff --git a/polynomial-perf.ipynb b/polynomial-perf.ipynb new file mode 100644 index 000000000..549083485 --- /dev/null +++ b/polynomial-perf.ipynb @@ -0,0 +1,1979 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "182a16c4-4777-4ec3-99b1-476914c2ec1b", + "metadata": {}, + "source": [ + "# Current" + ] + }, + { + "cell_type": "markdown", + "id": "11b1cb71-4f1b-441f-a6bf-93d430ac5356", + "metadata": { + "tags": [] + }, + "source": [ + "## Create test example" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "61901771-5a93-4cc9-a180-0cc2cc580a53", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "b0d92f0d-3549-4619-a272-a324ef475104", + "metadata": {}, + "outputs": [], + "source": [ + "import string, random, toolz, pandas, importlib, sys, os" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "d2c51a56-7617-427e-8ec5-12e4a0fc0a08", + "metadata": {}, + "outputs": [], + "source": [ + "terms = [(term, 1) for term in str(random.choices(string.ascii_letters, k=10**7)).split('Z')]" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "1f8a40cc-df42-4f45-9220-afd1f212239f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "count 192160.000000\n", + "mean 259.199839\n", + "std 256.922932\n", + "min 4.000000\n", + "25% 74.000000\n", + "50% 179.000000\n", + "75% 359.000000\n", + "max 3174.000000\n", + "dtype: float64" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pandas.Series(len(term) for term, _ in terms).describe()" + ] + }, + { + "cell_type": "markdown", + "id": "ed7030e6-6d63-4f54-a8af-13e938191812", + "metadata": {}, + "source": [ + "## Run current version" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "bc701097-6aa9-44a1-8673-b2777e84e929", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Saved working directory and index state WIP on binary-polynomial: bc4521f added symbolic arithmetic refactored relabel_variables, to_binary, to_spin filter out 0 coefficient terms in polynomial construction\n", + "Switched to branch 'main'\n", + "Your branch is up to date with 'origin/main'.\n" + ] + } + ], + "source": [ + "!git stash\n", + "!git checkout main\n", + "#importlib.reload(dimod)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "0dff8f12-ff29-4991-ad7c-8bb9d6367f5e", + "metadata": {}, + "outputs": [], + "source": [ + "from dimod import BinaryPolynomial as BPold\n", + "import dimod" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "ec77f944-27b1-47ce-b141-2b8d6fc3f116", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\u001b[0;31mSignature:\u001b[0m \u001b[0mBPold\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__init__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpoly\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvartype\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mDocstring:\u001b[0m Initialize self. See help(type(self)) for accurate signature.\n", + "\u001b[0;31mSource:\u001b[0m \n", + " \u001b[0;34m@\u001b[0m\u001b[0mvartype_argument\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'vartype'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__init__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpoly\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvartype\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpoly\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mabc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mMapping\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0mpoly\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpoly\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mitems\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0;31m# we need to aggregate the repeated terms\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_terms\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mterms\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mterm\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbias\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mpoly\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0mfsterm\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0masfrozenset\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mterm\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0;31m# when SPIN-valued, s^2 == 1, so we need to handle that case\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0;31m# in BINARY, x^2 == x\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfsterm\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mterm\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mvartype\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0mVartype\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mSPIN\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0mnew\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mset\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0mterm\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtuple\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mterm\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# make sure it has .count\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mv\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mfsterm\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mterm\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcount\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mv\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0mnew\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mv\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0mfsterm\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfrozenset\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnew\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mfsterm\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mterms\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0mterms\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mfsterm\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0mbias\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0mterms\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mfsterm\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mbias\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvartype\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mvartype\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mFile:\u001b[0m ~/dimod/dimod/higherorder/polynomial.py\n", + "\u001b[0;31mType:\u001b[0m function\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "BPold.__init__??" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "e4cfa0c6-b7d4-4642-82fb-9eba71ab340b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " " + ] + }, + { + "data": { + "text/plain": [ + " 9711530 function calls (9711450 primitive calls) in 48.033 seconds\n", + "\n", + " Ordered by: cumulative time\n", + " List reduced from 47 to 20 due to restriction <20>\n", + "\n", + " ncalls tottime percall cumtime percall filename:lineno(function)\n", + " 1 0.000 0.000 48.033 48.033 {built-in method builtins.exec}\n", + " 1 0.000 0.000 48.033 48.033 :1()\n", + " 1 0.000 0.000 48.033 48.033 decorators.py:289(new_f)\n", + " 1 7.909 7.909 48.033 48.033 polynomial.py:89(__init__)\n", + " 5482062 38.220 0.000 38.220 0.000 {method 'count' of 'tuple' objects}\n", + " 192160 1.075 0.000 1.135 0.000 polynomial.py:32(asfrozenset)\n", + " 3460625 0.690 0.000 0.690 0.000 {method 'add' of 'set' objects}\n", + " 384322 0.079 0.000 0.079 0.000 {built-in method builtins.len}\n", + " 192170 0.060 0.000 0.060 0.000 {built-in method builtins.isinstance}\n", + " 1 0.000 0.000 0.000 0.000 abc.py:96(__instancecheck__)\n", + " 1 0.000 0.000 0.000 0.000 {built-in method _abc._abc_instancecheck}\n", + " 41/1 0.000 0.000 0.000 0.000 abc.py:100(__subclasscheck__)\n", + " 41/1 0.000 0.000 0.000 0.000 {built-in method _abc._abc_subclasscheck}\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:1340(getcallargs)\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:1102(getfullargspec)\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:2218(_signature_from_callable)\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:2124(_signature_from_function)\n", + " 3 0.000 0.000 0.000 0.000 inspect.py:2489(__init__)\n", + " 1 0.000 0.000 0.000 0.000 decorators.py:281(_enforce_single_arg)\n", + " 1 0.000 0.000 0.000 0.000 vartypes.py:127(as_vartype)" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%prun -s cumtime -l 20\n", + "bp = BPold(terms, 'SPIN')" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "a74eb4b1-a59a-49d7-8e36-95ea91a7a12b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
01
count181561.000000181561.000000
mean18.9317031.058377
std7.5522808.721284
min1.0000001.000000
25%13.0000001.000000
50%20.0000001.000000
75%25.0000001.000000
max42.0000003677.000000
\n", + "
" + ], + "text/plain": [ + " 0 1\n", + "count 181561.000000 181561.000000\n", + "mean 18.931703 1.058377\n", + "std 7.552280 8.721284\n", + "min 1.000000 1.000000\n", + "25% 13.000000 1.000000\n", + "50% 20.000000 1.000000\n", + "75% 25.000000 1.000000\n", + "max 42.000000 3677.000000" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pandas.DataFrame((len(term), bias) for term, bias in bp.items()).describe()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6f8463b3-a6fe-4841-918f-33743295181f", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "ce407274-b49c-4dc5-8fc0-69a5753029c7", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "term = string.ascii_letters[:12]" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "0834a2d8-5e01-4a40-9541-0a871f18ff2a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1.14 s ± 310 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" + ] + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%timeit BPold({term: 1}, 'SPIN').to_binary().to_spin() == BPold({term: 1}, 'SPIN')\n", + "BPold({term: 1}, 'SPIN').to_binary().to_spin() == BPold({term: 1}, 'SPIN')" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "a7e72459-4dce-458d-84d4-bf6ddf925e33", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1.22 s ± 265 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" + ] + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%timeit BPold({term: 1}, 'BINARY').to_spin().to_binary() == BPold({term: 1}, 'BINARY')\n", + "BPold({term: 1}, 'BINARY').to_spin().to_binary() == BPold({term: 1}, 'BINARY')" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "a8af1d2f-e9d4-4fe6-9129-173589c30d9b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4096" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(BPold({term: 1}, 'SPIN').to_binary().to_spin())" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "45b7c9d6-cc7a-475e-adaf-8fa4649119a6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4096" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(BPold({term: 1}, 'BINARY').to_spin().to_binary())" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "a4a0ea46-a6a5-47f7-8f4e-47fa480c492d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " " + ] + }, + { + "data": { + "text/plain": [ + " 19196037 function calls (19196032 primitive calls) in 21.734 seconds\n", + "\n", + " Ordered by: cumulative time\n", + " List reduced from 66 to 20 due to restriction <20>\n", + "\n", + " ncalls tottime percall cumtime percall filename:lineno(function)\n", + " 1 0.000 0.000 21.734 21.734 {built-in method builtins.exec}\n", + " 1 0.000 0.000 21.733 21.733 :1()\n", + " 2/1 15.297 7.648 21.733 21.733 polynomial.py:232(relabel_variables)\n", + " 7237640 2.147 0.000 2.887 0.000 polynomial.py:256()\n", + " 544686 1.648 0.000 2.116 0.000 _collections_abc.py:742(__iter__)\n", + " 6874522 0.740 0.000 0.740 0.000 {method 'get' of 'dict' objects}\n", + " 363120 0.462 0.000 0.608 0.000 polynomial.py:158(__setitem__)\n", + " 1 0.000 0.000 0.517 0.517 polynomial.py:177(copy)\n", + " 1 0.000 0.000 0.517 0.517 decorators.py:289(new_f)\n", + " 1 0.200 0.200 0.517 0.517 polynomial.py:89(__init__)\n", + " 1452484 0.347 0.000 0.479 0.000 polynomial.py:32(asfrozenset)\n", + " 544683 0.313 0.000 0.468 0.000 polynomial.py:149(__getitem__)\n", + " 363120 0.282 0.000 0.409 0.000 polynomial.py:120(__delitem__)\n", + " 1 0.012 0.012 0.134 0.134 polynomial.py:165(variables)\n", + " 1452493 0.132 0.000 0.132 0.000 {built-in method builtins.isinstance}\n", + " 1 0.122 0.122 0.122 0.122 {method 'union' of 'set' objects}\n", + "363133/363129 0.031 0.000 0.031 0.000 {built-in method builtins.len}\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:1340(getcallargs)\n", + " 3 0.000 0.000 0.000 0.000 utilities.py:351(iter_safe_relabels)\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:1102(getfullargspec)" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "prun -s cumtime -l 20 bp2 = bp.relabel_variables(dict(zip(string.ascii_letters, reversed(string.ascii_letters))), inplace=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "7eeadfa9-40e8-41c5-bcf5-39d1ca2fbd00", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " " + ] + }, + { + "data": { + "text/plain": [ + " 19196034 function calls (19196029 primitive calls) in 18.191 seconds\n", + "\n", + " Ordered by: cumulative time\n", + " List reduced from 63 to 20 due to restriction <20>\n", + "\n", + " ncalls tottime percall cumtime percall filename:lineno(function)\n", + " 1 0.000 0.000 18.191 18.191 {built-in method builtins.exec}\n", + " 1 0.000 0.000 18.191 18.191 :1()\n", + " 2/1 9.913 4.957 18.191 18.191 polynomial.py:232(relabel_variables)\n", + " 7237640 2.937 0.000 3.940 0.000 polynomial.py:256()\n", + " 544686 1.989 0.000 2.508 0.000 _collections_abc.py:742(__iter__)\n", + " 6874522 1.003 0.000 1.003 0.000 {method 'get' of 'dict' objects}\n", + " 363120 0.674 0.000 0.886 0.000 polynomial.py:158(__setitem__)\n", + " 1452484 0.430 0.000 0.592 0.000 polynomial.py:32(asfrozenset)\n", + " 363120 0.404 0.000 0.565 0.000 polynomial.py:120(__delitem__)\n", + " 544683 0.350 0.000 0.519 0.000 polynomial.py:149(__getitem__)\n", + " 1 0.000 0.000 0.477 0.477 polynomial.py:177(copy)\n", + " 1 0.000 0.000 0.477 0.477 decorators.py:289(new_f)\n", + " 1 0.178 0.178 0.477 0.477 polynomial.py:89(__init__)\n", + " 1452493 0.161 0.000 0.161 0.000 {built-in method builtins.isinstance}\n", + " 1 0.009 0.009 0.122 0.122 polynomial.py:165(variables)\n", + " 1 0.113 0.113 0.113 0.113 {method 'union' of 'set' objects}\n", + "363133/363129 0.030 0.000 0.030 0.000 {built-in method builtins.len}\n", + " 3 0.000 0.000 0.000 0.000 utilities.py:351(iter_safe_relabels)\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:1340(getcallargs)\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:1102(getfullargspec)" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "prun -s cumtime -l 20 bp3 = bp2.relabel_variables(dict(zip(string.ascii_letters, reversed(string.ascii_letters))), inplace=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "0791493b-2ded-4b56-84ea-accb50f0de3d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bp == bp2" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "3efb0d30-46a3-41f5-bebc-7d9a18d17e41", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bp == bp3" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "a81ab133-322d-4f93-a9d3-5abd8b49d6ab", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bp2 == bp3" + ] + }, + { + "cell_type": "markdown", + "id": "81473689-9ece-45a7-85a0-389d0418be3e", + "metadata": { + "tags": [] + }, + "source": [ + "# Exit interpreter\n", + "I just can't get module reloading to work properly here ..." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "673fe5b0-5934-4b40-a418-62122e867aa9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "BYE\n" + ] + }, + { + "ename": "SystemExit", + "evalue": "", + "output_type": "error", + "traceback": [ + "An exception has occurred, use %tb to see the full traceback.\n", + "\u001b[0;31mSystemExit\u001b[0m\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/daniel/anaconda3/lib/python3.8/site-packages/IPython/core/interactiveshell.py:3449: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D.\n", + " warn(\"To exit: use 'exit', 'quit', or Ctrl-D.\", stacklevel=1)\n" + ] + } + ], + "source": [ + "print('BYE')\n", + "exit()\n", + "raise SystemExit\n", + "print('HI')" + ] + }, + { + "cell_type": "markdown", + "id": "8d68e1c7-8d3c-40ae-acdd-360edccad297", + "metadata": {}, + "source": [ + "# Proposed" + ] + }, + { + "cell_type": "markdown", + "id": "c2041ccc-e502-4135-b067-159d85043378", + "metadata": { + "tags": [] + }, + "source": [ + "## Create test example" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "370178a2-f029-4e9b-b4f7-f4c051df686c", + "metadata": {}, + "outputs": [], + "source": [ + "import string, random, toolz, pandas, importlib, sys, os, cytoolz, toolz, dimod" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "47e01614-89da-426a-8f4d-a546fe454328", + "metadata": {}, + "outputs": [], + "source": [ + "import itertools as it" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "a2199fbe-fa29-4286-b93a-eadba3b739e3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 96.8 ms, sys: 9.77 ms, total: 107 ms\n", + "Wall time: 106 ms\n" + ] + } + ], + "source": [ + "%time terms = [(term, 1) for term in ''.join(random.choices(string.ascii_letters, k=10**6)).split('Z')]" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "5707eff9-710b-4799-87bc-99bed0eed866", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "count 18962.000000\n", + "mean 51.737106\n", + "std 52.324975\n", + "min 0.000000\n", + "25% 14.000000\n", + "50% 36.000000\n", + "75% 72.000000\n", + "max 535.000000\n", + "dtype: float64" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pandas.Series(len(term) for term, _ in terms).describe()" + ] + }, + { + "cell_type": "markdown", + "id": "75dbfea5-3022-4652-89f2-e41f0b822abd", + "metadata": {}, + "source": [ + "## Run proposed version" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "6f8b616f-1835-4723-83c3-dc189b891a94", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "D\tpolynomial-perf.ipynb\n", + "Already on 'binary-polynomial'\n", + "Your branch is ahead of 'origin/binary-polynomial' by 1 commit.\n", + " (use \"git push\" to publish your local commits)\n", + "No stash entries found.\n" + ] + } + ], + "source": [ + "!mv polynomial-perf.ipynb{,.bak}\n", + "!git checkout binary-polynomial\n", + "!git stash pop\n", + "#!touch -c ./dimod/higherorder/polynomial.py\n", + "#importlib.reload(dimod)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "6e5ac6a3-5a9a-4147-8909-0b09208d66c2", + "metadata": {}, + "outputs": [], + "source": [ + "from dimod import BinaryPolynomial as BPnew" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "b8472b21-b3e6-4c19-b860-d2631dd78065", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\u001b[0;31mSignature:\u001b[0m \u001b[0mBPnew\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__init__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpoly\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvartype\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mDocstring:\u001b[0m Initialize self. See help(type(self)) for accurate signature.\n", + "\u001b[0;31mSource:\u001b[0m \n", + " \u001b[0;34m@\u001b[0m\u001b[0mvartype_argument\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'vartype'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__init__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpoly\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvartype\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpoly\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mabc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mMapping\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0mpoly\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpoly\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mitems\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0;31m# we need to aggregate the repeated terms\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_terms\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mterms\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdefaultdict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mint\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mterm\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbias\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mpoly\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0mterms\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mfreeze_term\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mterm\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvartype\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0mbias\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvartype\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mvartype\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mFile:\u001b[0m ~/dimod/dimod/higherorder/polynomial.py\n", + "\u001b[0;31mType:\u001b[0m function\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "BPnew.__init__??" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "9065a62a-4c71-4f58-843b-65f611bc4848", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " " + ] + }, + { + "data": { + "text/plain": [ + " 399010 function calls (398930 primitive calls) in 0.179 seconds\n", + "\n", + " Ordered by: cumulative time\n", + " List reduced from 46 to 20 due to restriction <20>\n", + "\n", + " ncalls tottime percall cumtime percall filename:lineno(function)\n", + " 1 0.000 0.000 0.179 0.179 {built-in method builtins.exec}\n", + " 1 0.000 0.000 0.179 0.179 :1()\n", + " 1 0.000 0.000 0.178 0.178 decorators.py:289(new_f)\n", + " 1 0.013 0.013 0.178 0.178 polynomial.py:108(__init__)\n", + " 18962 0.123 0.000 0.165 0.000 polynomial.py:40(freeze_term)\n", + " 341921 0.039 0.000 0.039 0.000 polynomial.py:47()\n", + " 18972 0.001 0.000 0.002 0.000 {built-in method builtins.isinstance}\n", + " 18963 0.001 0.000 0.001 0.000 {method 'items' of 'dict' objects}\n", + " 1 0.000 0.000 0.000 0.000 abc.py:96(__instancecheck__)\n", + " 1 0.000 0.000 0.000 0.000 {built-in method _abc._abc_instancecheck}\n", + " 41/1 0.000 0.000 0.000 0.000 abc.py:100(__subclasscheck__)\n", + " 41/1 0.000 0.000 0.000 0.000 {built-in method _abc._abc_subclasscheck}\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:1340(getcallargs)\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:1102(getfullargspec)\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:2218(_signature_from_callable)\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:2124(_signature_from_function)\n", + " 1 0.000 0.000 0.000 0.000 decorators.py:281(_enforce_single_arg)\n", + " 3 0.000 0.000 0.000 0.000 inspect.py:2489(__init__)\n", + " 1 0.000 0.000 0.000 0.000 vartypes.py:127(as_vartype)\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:2772(__init__)" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%prun -s cumtime -l 20 \n", + "bp = BPnew(terms, 'SPIN')" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "b9f0d049-5b6f-4521-a6c9-f6d0f529b8a8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
01
count18203.00000018203.000000
mean17.7188381.041696
std7.6908282.906779
min0.0000001.000000
25%12.0000001.000000
50%19.0000001.000000
75%24.0000001.000000
max39.000000390.000000
\n", + "
" + ], + "text/plain": [ + " 0 1\n", + "count 18203.000000 18203.000000\n", + "mean 17.718838 1.041696\n", + "std 7.690828 2.906779\n", + "min 0.000000 1.000000\n", + "25% 12.000000 1.000000\n", + "50% 19.000000 1.000000\n", + "75% 24.000000 1.000000\n", + "max 39.000000 390.000000" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pandas.DataFrame((len(term), bias) for term, bias in bp.items()).describe()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "e396116b-8b48-4e80-b780-63e6918d75e3", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "term = string.ascii_letters[:12]" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "251c2cf3-d1e0-4f81-8b2d-0bfe3b809afc", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "528 ms ± 55.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" + ] + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%timeit BPnew({term: 1}, 'SPIN').to_binary().to_spin() == BPnew({term: 1}, 'SPIN')\n", + "BPnew({term: 1}, 'SPIN').to_binary().to_spin() == BPnew({term: 1}, 'SPIN')" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "1b734eee-3346-4ccf-a46b-b7f1062d7146", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "793 ms ± 77.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" + ] + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%timeit BPnew({term: 1}, 'BINARY').to_spin().to_binary() == BPnew({term: 1}, 'BINARY')\n", + "BPnew({term: 1}, 'BINARY').to_spin().to_binary() == BPnew({term: 1}, 'BINARY')" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "cd914370-6d26-4549-8ac1-409b9cfb0d42", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4096" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(BPnew({term: 1}, 'BINARY').to_spin().to_binary())" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "9b8ea924-76fe-4dfc-9b0f-1e526c38f0ce", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4096" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(BPnew({term: 1}, 'SPIN').to_binary().to_spin())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3cec6003-377c-4ce2-aaff-195413a5d7f0", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "5855d98a-3560-4ff4-8717-c71e7a5b9322", + "metadata": {}, + "outputs": [], + "source": [ + "#len(BPnew({term: 1}, 'BINARY').to_spin() * BPnew({term: 1}, 'BINARY').to_spin())" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "8f1025ab-14a5-4ab2-b636-aae76d82b1cb", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " " + ] + }, + { + "data": { + "text/plain": [ + " 1799999 function calls (1799994 primitive calls) in 0.717 seconds\n", + "\n", + " Ordered by: cumulative time\n", + " List reduced from 67 to 20 due to restriction <20>\n", + "\n", + " ncalls tottime percall cumtime percall filename:lineno(function)\n", + " 1 0.000 0.000 0.717 0.717 {built-in method builtins.exec}\n", + " 1 0.000 0.000 0.717 0.717 :1()\n", + " 2/1 0.370 0.185 0.717 0.717 polynomial.py:236(relabel_variables)\n", + " 681478 0.127 0.000 0.169 0.000 polynomial.py:260()\n", + " 54612 0.036 0.000 0.074 0.000 _collections_abc.py:742(__iter__)\n", + " 1 0.000 0.000 0.046 0.046 polynomial.py:181(copy)\n", + " 1 0.000 0.000 0.046 0.046 decorators.py:289(new_f)\n", + " 1 0.017 0.017 0.046 0.046 polynomial.py:108(__init__)\n", + " 645076 0.042 0.000 0.042 0.000 {method 'get' of 'dict' objects}\n", + " 36404 0.031 0.000 0.040 0.000 polynomial.py:162(__setitem__)\n", + " 54609 0.027 0.000 0.038 0.000 polynomial.py:153(__getitem__)\n", + " 127417 0.020 0.000 0.028 0.000 polynomial.py:35(asfrozenset)\n", + " 36404 0.018 0.000 0.025 0.000 polynomial.py:124(__delitem__)\n", + " 1 0.001 0.001 0.018 0.018 polynomial.py:169(variables)\n", + " 1 0.017 0.017 0.017 0.017 {method 'union' of 'set' objects}\n", + " 145629 0.009 0.000 0.009 0.000 {built-in method builtins.isinstance}\n", + " 18203 0.003 0.000 0.004 0.000 polynomial.py:40(freeze_term)\n", + " 3 0.000 0.000 0.000 0.000 utilities.py:351(iter_safe_relabels)\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:1340(getcallargs)\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:1102(getfullargspec)" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "prun -s cumtime -l 20 bp2 = bp.relabel_variables(dict(zip(string.ascii_letters, reversed(string.ascii_letters))), inplace=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "f28b9d31-00f6-4d19-a799-4aebd8dcdf77", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " " + ] + }, + { + "data": { + "text/plain": [ + " 1799996 function calls (1799991 primitive calls) in 0.425 seconds\n", + "\n", + " Ordered by: cumulative time\n", + " List reduced from 64 to 20 due to restriction <20>\n", + "\n", + " ncalls tottime percall cumtime percall filename:lineno(function)\n", + " 1 0.000 0.000 0.425 0.425 {built-in method builtins.exec}\n", + " 1 0.000 0.000 0.425 0.425 :1()\n", + " 2/1 0.165 0.082 0.425 0.425 polynomial.py:236(relabel_variables)\n", + " 681478 0.106 0.000 0.141 0.000 polynomial.py:260()\n", + " 54612 0.025 0.000 0.053 0.000 _collections_abc.py:742(__iter__)\n", + " 645076 0.036 0.000 0.036 0.000 {method 'get' of 'dict' objects}\n", + " 1 0.000 0.000 0.029 0.029 polynomial.py:181(copy)\n", + " 1 0.000 0.000 0.029 0.029 decorators.py:289(new_f)\n", + " 1 0.008 0.008 0.029 0.029 polynomial.py:108(__init__)\n", + " 54609 0.019 0.000 0.028 0.000 polynomial.py:153(__getitem__)\n", + " 36404 0.017 0.000 0.024 0.000 polynomial.py:162(__setitem__)\n", + " 127417 0.017 0.000 0.024 0.000 polynomial.py:35(asfrozenset)\n", + " 36404 0.011 0.000 0.018 0.000 polynomial.py:124(__delitem__)\n", + " 1 0.002 0.002 0.012 0.012 polynomial.py:169(variables)\n", + " 1 0.010 0.010 0.010 0.010 {method 'union' of 'set' objects}\n", + " 145629 0.007 0.000 0.007 0.000 {built-in method builtins.isinstance}\n", + " 18203 0.002 0.000 0.003 0.000 polynomial.py:40(freeze_term)\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:1340(getcallargs)\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:1102(getfullargspec)\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:2218(_signature_from_callable)" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "prun -s cumtime -l 20 bp3 = bp2.relabel_variables(dict(zip(string.ascii_letters, reversed(string.ascii_letters))), inplace=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "1feeafa7-7b82-4936-8907-1d9e2cb2f09f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bp == bp2" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "2b68eedb-625d-4b55-913e-eca731039285", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bp == bp3" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "f26be75b-8a2f-4825-9c5d-61cb22cb23da", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bp2 == bp3" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "7ac90b1e-af50-42e1-89f5-7c3274d9bff0", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "%load_ext line_profiler" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "3ff64574-290e-4e1d-ba85-5dc597c31258", + "metadata": {}, + "outputs": [], + "source": [ + "#%lprun -fdimod.make_quadratic bqm = dimod.make_quadratic(bp, vartype = 'BINARY', strength = 2**6)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "7ac382c2-abc7-43e2-b599-8320b48d89f4", + "metadata": {}, + "outputs": [], + "source": [ + "import functools as ft\n", + "import itertools as it\n", + "import cytoolz as tl\n", + "from dimod.higherorder.utils import _new_product, as_vartype\n", + "from collections import defaultdict" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "cbb733a7-ea7a-44f8-87d5-2b53c5ea28a7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 11.4 s, sys: 571 ms, total: 12 s\n", + "Wall time: 12 s\n" + ] + } + ], + "source": [ + "%%time\n", + "idx = defaultdict(\n", + " dict,\n", + " tl.valmap(\n", + " tl.compose(dict, ft.partial(map, tl.second)),\n", + " tl.groupby(\n", + " tl.first,\n", + " (\n", + " (frozenset(pair), item)\n", + " for item in bp.items()\n", + " if len(term := tl.first(item)) >= 3\n", + " for pair in it.combinations(term, 2) ))))" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "fb73bc93-03de-477b-9157-faf63ea0736a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1275" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(idx)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "b2b90337-0e71-4fec-939e-0999b9e9e3cc", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "#idx" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "21d519e4-d50e-46de-8dd6-3b38a495f75e", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "#bp" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "a522c29b-62b8-4019-b096-cd03e6bc67c4", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "#terms" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "e6a2909a-6752-46de-a52f-7c5754837c21", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2679" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "que = tl.valmap(tl.compose(set, ft.partial(map, tl.first)), tl.groupby(tl.second, tl.valmap(len, idx).items()))\n", + "most = max(que)\n", + "most" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "8b50b60f-64f1-4f8a-ace0-af13fe2e5dbd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "frozenset({'K', 'u'})" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "que[most].pop()" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "f8dbcabd-74d7-43c2-b6a0-d30628e6e5e1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "set()" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "que[most]" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "52a46763-7cd9-491c-8608-88982806650b", + "metadata": {}, + "outputs": [], + "source": [ + "constraints = []\n", + "reduced_terms = [item for item in bp.items() if len(tl.first(item)) <= 2]\n", + "pair, terms = tl.topk(1, idx.items(), tl.compose(len,tl.second))[0]\n", + "p = _new_product(bp.variables, *pair)\n", + "constraints.append((pair, p))\n", + "del idx[pair]\n", + "pset = {p}" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "365b65f0-41c1-4dbb-8bab-aea72369c98a", + "metadata": {}, + "outputs": [], + "source": [ + "for term, bias in terms.items():\n", + " for pair2 in map(frozenset, (it.combinations(term, 2))):\n", + " if pair2 != pair:\n", + " del idx[pair2][term]\n", + " base_term = term - pair\n", + " new_term = base_term | pset\n", + " if len(new_term) <= 3:\n", + " reduced_terms.append((new_term, bias))\n", + " else:\n", + " for pair3 in map(frozenset, it.combinations(new_term, 2)):\n", + " idx[pair3][new_term] = bias" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "6999b196-287e-4454-981d-4217a0135b1c", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "#reduced_terms" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "33266725-1494-4ffb-9855-cba3e8f1d36c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[(frozenset({'K', 'u'}), 'u*K')]" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "constraints" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "186eb239-28d8-4f49-953c-ef168d371060", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "#terms" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "42cb3775-6408-48e7-adc4-e612c314b0ad", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "((frozenset({'V', 's'}), 2668),\n", + " (frozenset({'d', 't'}), 2658),\n", + " (frozenset({'U', 'V'}), 2656),\n", + " (frozenset({'M', 'V'}), 2655),\n", + " (frozenset({'C', 'V'}), 2649))" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tl.topk(5, tl.valmap(len, idx).items(), tl.second)" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "faee8bfe-222d-447d-8e10-3e03e9dbb9fb", + "metadata": {}, + "outputs": [], + "source": [ + "#%prun -s cumtime -l 30 dimod.reduced_terms, constraints = reduce_terms(bp)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "0b9b2c67-05fa-4a86-8c3a-acc15119e861", + "metadata": {}, + "outputs": [], + "source": [ + "#len(reduced_terms), len(constraints)" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "179f7b4b-7895-4a12-824b-0f42c855727e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " " + ] + }, + { + "data": { + "text/plain": [ + " 67534938 function calls (67534930 primitive calls) in 45.651 seconds\n", + "\n", + " Ordered by: cumulative time\n", + " List reduced from 104 to 30 due to restriction <30>\n", + "\n", + " ncalls tottime percall cumtime percall filename:lineno(function)\n", + " 1 0.000 0.000 45.651 45.651 {built-in method builtins.exec}\n", + " 1 0.023 0.023 45.651 45.651 :1()\n", + " 1 0.624 0.624 45.628 45.628 utils.py:176(make_quadratic)\n", + " 1 22.136 22.136 40.487 40.487 utils.py:120(reduce_terms)\n", + " 25594299 8.849 0.000 8.849 0.000 utils.py:113(_remove_old)\n", + " 5860386 4.291 0.000 6.749 0.000 utils.py:103(_decrement_count)\n", + " 3180742 2.057 0.000 2.057 0.000 utils.py:164()\n", + " 58153 0.083 0.000 1.989 0.000 utils.py:62(_binary_product)\n", + " 58154 0.087 0.000 1.906 0.000 binary_quadratic_model.py:93(__init__)\n", + " 58153 0.270 0.000 1.799 0.000 binary_quadratic_model.py:136(_init_components)\n", + " 5860386 1.356 0.000 1.356 0.000 {method 'remove' of 'set' objects}\n", + " 8889068 1.190 0.000 1.190 0.000 {method 'add' of 'set' objects}\n", + " 367069 0.642 0.000 1.022 0.000 {method 'add_quadratic' of 'dimod.binary.cybqm.cybqm_float64.cyBQM_template' objects}\n", + " 269020 0.140 0.000 0.972 0.000 _collections_abc.py:742(__iter__)\n", + " 2805949 0.374 0.000 0.740 0.000 abc.py:96(__instancecheck__)\n", + " 174461 0.210 0.000 0.590 0.000 decorators.py:474(wrapper)\n", + " 192610 0.046 0.000 0.588 0.000 binary_quadratic_model.py:709(add_interaction)\n", + " 232612 0.080 0.000 0.514 0.000 quadratic.py:136(__iter__)\n", + " 58153 0.154 0.000 0.474 0.000 binary_quadratic_model.py:654(add_linear_from)\n", + " 6951364 0.434 0.000 0.434 0.000 {built-in method builtins.len}\n", + " 232612 0.422 0.000 0.422 0.000 _collections_abc.py:870(__iter__)\n", + " 174510 0.278 0.000 0.413 0.000 {method 'add_variable' of 'dimod.binary.cybqm.cybqm_float64.cyBQM_template' objects}\n", + " 2805949 0.366 0.000 0.366 0.000 {built-in method _abc._abc_instancecheck}\n", + " 174459 0.065 0.000 0.295 0.000 quadratic.py:130(__getitem__)\n", + " 232612 0.078 0.000 0.236 0.000 quadratic.py:176(__iter__)\n", + " 174459 0.115 0.000 0.202 0.000 {method 'add_linear' of 'dimod.binary.cybqm.cybqm_float64.cyBQM_template' objects}\n", + " 345387 0.086 0.000 0.173 0.000 {built-in method builtins.isinstance}\n", + " 58154 0.136 0.000 0.170 0.000 binary_quadratic_model.py:187(_init_empty)\n", + " 232612 0.143 0.000 0.158 0.000 binary_quadratic_model.py:1252(iter_quadratic)\n", + " 174459 0.095 0.000 0.147 0.000 {method 'get_linear' of 'dimod.binary.cybqm.cybqm_float64.cyBQM_template' objects}" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%prun -s cumtime -l 30 bqm = dimod.make_quadratic(bp, 1000, 'BINARY')" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "9ca15f52-6ab1-4743-9c3f-3293512dc758", + "metadata": {}, + "outputs": [], + "source": [ + "zz = set(range(4))" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "24d32eb7-61af-4c89-80bf-87583d1d9a65", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Timer unit: 1e-06 s\n", + "\n", + "Total time: 0.006932 s\n", + "File: /home/daniel/dimod/dimod/higherorder/utils.py\n", + "Function: reduce_terms at line 120\n", + "\n", + "Line # Hits Time Per Hit % Time Line Contents\n", + "==============================================================\n", + " 120 def reduce_terms(bp):\n", + " 121 1 4.0 4.0 0.1 variables = bp.variables\n", + " 122 1 1.0 1.0 0.0 constraints = []\n", + " 123 \n", + " 124 1 0.0 0.0 0.0 reduced_terms = []\n", + " 125 1 1.0 1.0 0.0 idx = defaultdict(dict)\n", + " 126 2 11.0 5.5 0.2 for item in bp.items():\n", + " 127 1 0.0 0.0 0.0 term, bias = item\n", + " 128 1 1.0 1.0 0.0 if len(term) <= 2:\n", + " 129 reduced_terms.append(item)\n", + " 130 else:\n", + " 131 232 106.0 0.5 1.5 for pair in itertools.combinations(term, 2):\n", + " 132 231 298.0 1.3 4.3 idx[frozenset(pair)][term] = bias\n", + " 133 \n", + " 134 1 1.0 1.0 0.0 que = defaultdict(set)\n", + " 135 232 127.0 0.5 1.8 for pair, terms in idx.items():\n", + " 136 231 151.0 0.7 2.2 que[len(terms)].add(pair)\n", + " 137 \n", + " 138 21 15.0 0.7 0.2 while idx:\n", + " 139 20 19.0 0.9 0.3 new_pairs = set()\n", + " 140 20 22.0 1.1 0.3 most = max(que)\n", + " 141 20 14.0 0.7 0.2 que_most = que[most]\n", + " 142 20 19.0 0.9 0.3 pair = que_most.pop()\n", + " 143 20 15.0 0.8 0.2 if not que_most:\n", + " 144 del que[most]\n", + " 145 20 20.0 1.0 0.3 terms = idx.pop(pair)\n", + " 146 \n", + " 147 20 134.0 6.7 1.9 prod_var = _new_product(variables, *pair)\n", + " 148 20 12.0 0.6 0.2 constraints.append((pair, prod_var))\n", + " 149 20 11.0 0.6 0.2 prod_var_set = {prod_var}\n", + " 150 \n", + " 151 40 48.0 1.2 0.7 for old_term, bias in terms.items():\n", + " 152 20 32.0 1.6 0.5 common_subterm = (old_term - pair)\n", + " 153 20 20.0 1.0 0.3 new_term = common_subterm | prod_var_set\n", + " 154 \n", + " 155 440 386.0 0.9 5.6 for old_pair in map(frozenset, itertools.product(pair, common_subterm)):\n", + " 156 420 707.0 1.7 10.2 _decrement_count(idx, que, old_pair)\n", + " 157 420 560.0 1.3 8.1 _remove_old(idx, old_term, old_pair)\n", + " 158 \n", + " 159 1350 886.0 0.7 12.8 for common_pair in map(frozenset, itertools.combinations(common_subterm, 2)):\n", + " 160 1330 965.0 0.7 13.9 idx[common_pair][new_term] = bias\n", + " 161 1330 1264.0 1.0 18.2 _remove_old(idx, old_term, common_pair)\n", + " 162 \n", + " 163 20 19.0 0.9 0.3 if len(new_term) > 2:\n", + " 164 228 253.0 1.1 3.6 for new_pair in (frozenset((prod_var, v)) for v in common_subterm):\n", + " 165 209 174.0 0.8 2.5 idx[new_pair][new_term] = bias\n", + " 166 209 305.0 1.5 4.4 new_pairs.add(new_pair)\n", + " 167 else:\n", + " 168 1 4.0 4.0 0.1 reduced_terms.append((new_term, bias))\n", + " 169 \n", + " 170 229 137.0 0.6 2.0 for new_pair in new_pairs:\n", + " 171 209 190.0 0.9 2.7 que[len(idx[new_pair])].add(new_pair)\n", + " 172 \n", + " 173 1 0.0 0.0 0.0 return reduced_terms, constraints" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%lprun -fdimod.higherorder.utils.reduce_terms bqm = dimod.make_quadratic(BPnew({term: 1}, 'SPIN'), strength=5, vartype='SPIN')" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "1934c5e7-5e31-4939-aae5-e23f8ede4ea0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Timer unit: 1e-06 s\n", + "\n", + "Total time: 101.475 s\n", + "File: /home/daniel/dimod/dimod/higherorder/utils.py\n", + "Function: reduce_terms at line 120\n", + "\n", + "Line # Hits Time Per Hit % Time Line Contents\n", + "==============================================================\n", + " 120 def reduce_terms(bp):\n", + " 121 1 8869.0 8869.0 0.0 variables = bp.variables\n", + " 122 1 3.0 3.0 0.0 constraints = []\n", + " 123 \n", + " 124 1 1.0 1.0 0.0 reduced_terms = []\n", + " 125 1 29.0 29.0 0.0 idx = defaultdict(dict)\n", + " 126 18204 52791.0 2.9 0.1 for item in bp.items():\n", + " 127 18203 9428.0 0.5 0.0 term, bias = item\n", + " 128 18203 12144.0 0.7 0.0 if len(term) <= 2:\n", + " 129 386 823.0 2.1 0.0 reduced_terms.append(item)\n", + " 130 else:\n", + " 131 3252010 1518548.0 0.5 1.5 for pair in itertools.combinations(term, 2):\n", + " 132 3234193 3075564.0 1.0 3.0 idx[frozenset(pair)][term] = bias\n", + " 133 \n", + " 134 1 11.0 11.0 0.0 que = defaultdict(set)\n", + " 135 1276 679.0 0.5 0.0 for pair, terms in idx.items():\n", + " 136 1275 10824.0 8.5 0.0 que[len(terms)].add(pair)\n", + " 137 \n", + " 138 58154 29577.0 0.5 0.0 while idx:\n", + " 139 58153 47937.0 0.8 0.0 new_pairs = set()\n", + " 140 58153 79341.0 1.4 0.1 most = max(que)\n", + " 141 58153 32205.0 0.6 0.0 que_most = que[most]\n", + " 142 58153 44334.0 0.8 0.0 pair = que_most.pop()\n", + " 143 58153 30567.0 0.5 0.0 if not que_most:\n", + " 144 316 191.0 0.6 0.0 del que[most]\n", + " 145 58153 235823.0 4.1 0.2 terms = idx.pop(pair)\n", + " 146 \n", + " 147 58153 176664.0 3.0 0.2 prod_var = _new_product(variables, *pair)\n", + " 148 58153 50434.0 0.9 0.0 constraints.append((pair, prod_var))\n", + " 149 58153 36876.0 0.6 0.0 prod_var_set = {prod_var}\n", + " 150 \n", + " 151 344336 359995.0 1.0 0.4 for old_term, bias in terms.items():\n", + " 152 286183 566357.0 2.0 0.6 common_subterm = (old_term - pair)\n", + " 153 286183 267784.0 0.9 0.3 new_term = common_subterm | prod_var_set\n", + " 154 \n", + " 155 6146569 5191902.0 0.8 5.1 for old_pair in map(frozenset, itertools.product(pair, common_subterm)):\n", + " 156 5860386 12781714.0 2.2 12.6 _decrement_count(idx, que, old_pair)\n", + " 157 5860386 7942377.0 1.4 7.8 _remove_old(idx, old_term, old_pair)\n", + " 158 \n", + " 159 20020096 12707113.0 0.6 12.5 for common_pair in map(frozenset, itertools.combinations(common_subterm, 2)):\n", + " 160 19733913 22539962.0 1.1 22.2 idx[common_pair][new_term] = bias\n", + " 161 19733913 22912153.0 1.2 22.6 _remove_old(idx, old_term, common_pair)\n", + " 162 \n", + " 163 286183 229066.0 0.8 0.2 if len(new_term) > 2:\n", + " 164 3180742 5189832.0 1.6 5.1 for new_pair in (frozenset((prod_var, v)) for v in common_subterm):\n", + " 165 2912376 2771588.0 1.0 2.7 idx[new_pair][new_term] = bias\n", + " 166 2912376 1802737.0 0.6 1.8 new_pairs.add(new_pair)\n", + " 167 else:\n", + " 168 17817 14797.0 0.8 0.0 reduced_terms.append((new_term, bias))\n", + " 169 \n", + " 170 534444 288154.0 0.5 0.3 for new_pair in new_pairs:\n", + " 171 476291 455596.0 1.0 0.4 que[len(idx[new_pair])].add(new_pair)\n", + " 172 \n", + " 173 1 0.0 0.0 0.0 return reduced_terms, constraints" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%lprun -fdimod.higherorder.utils.reduce_terms bqm = dimod.make_quadratic(bp, strength=5, vartype=bp.vartype)" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "1f1a5a0c-5a2f-4227-9f4b-2b3f4f696ce2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 2.84 ms, sys: 13 µs, total: 2.85 ms\n", + "Wall time: 2.86 ms\n" + ] + }, + { + "data": { + "text/plain": [ + "62" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%time len(dimod.make_quadratic(BPnew({term: 1}, 'SPIN'), strength=5, vartype='SPIN'))" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "1963c838-558b-4257-81d2-968c9648ea14", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Object `make_quadratic` not found.\n" + ] + } + ], + "source": [ + "make_quadratic??" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "ed0769ec-6d1b-40d2-b110-989f2f068c86", + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (3330683553.py, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"/tmp/ipykernel_7808/3330683553.py\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m BinaryPolynomial.\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "BinaryPolynomial." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4d4d5183-1bb3-4b7f-a8ab-4af55b2c55e7", + "metadata": {}, + "outputs": [], + "source": [ + "dimod.BQM" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7fdb1794-06f7-4fdf-a346-2533dc78ca63", + "metadata": {}, + "outputs": [], + "source": [ + "itertools" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fac7547a-db9e-4e35-8a5d-99e2aa72d137", + "metadata": {}, + "outputs": [], + "source": [ + "%prun -s cumtime -l 20 dimod.make_quadratic(bp, 100, vartype='BINARY')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78014140-af4d-426f-8969-687e2750cfab", + "metadata": {}, + "outputs": [], + "source": [ + "from dimod.higherorder import utils" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b806c9a1-3690-4eab-8c6b-f200026cbfb9", + "metadata": {}, + "outputs": [], + "source": [ + "%pwd" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bdb58284-1a2d-4880-93ff-b8dd31134d83", + "metadata": {}, + "outputs": [], + "source": [ + "bool(set())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "629eea9c-0ccd-464c-afa5-de6d6ea071b2", + "metadata": {}, + "outputs": [], + "source": [ + "bool" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/requirements.txt b/requirements.txt index 67bdf45cb..bb4c30b22 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,7 @@ numpy==1.19.4 cython==0.29.21 dwave-preprocessing==0.3.0 +cytoolz==0.11.0 reno==3.3.0 # for changelog