def test_failover_offline(self, MockClient):
        if sys.version_info.major <= 2 or sys.version_info.minor < 6:
            raise unittest.SkipTest(
                "need mock features only available in 3.6+")

        sampler = DWaveSampler(failover=True)

        mocksolver = sampler.solver
        edgelist = sampler.edgelist

        # call once
        ss = sampler.sample_ising({}, {})

        self.assertIs(mocksolver, sampler.solver)  # still same solver

        # one of the sample methods was called
        self.assertEqual(
            sampler.solver.sample_ising.call_count +
            sampler.solver.sample_qubo.call_count, 1)

        # add a side-effect
        sampler.solver.sample_ising.side_effect = SolverOfflineError
        sampler.solver.sample_qubo.side_effect = SolverOfflineError

        # and make sure get_solver makes a new mock solver
        sampler.client.get_solver.reset_mock(return_value=True)

        ss = sampler.sample_ising({}, {})

        self.assertIsNot(mocksolver, sampler.solver)  # new solver
        self.assertIsNot(edgelist, sampler.edgelist)  # also should be new
    def test_failover_false(self, MockClient):
        sampler = DWaveSampler(failover=False)

        sampler.solver.sample_ising.side_effect = SolverOfflineError
        sampler.solver.sample_qubo.side_effect = SolverOfflineError

        with self.assertRaises(SolverOfflineError):
            sampler.sample_ising({}, {})
    def test_failover_notfound_noretry(self, MockClient):

        sampler = DWaveSampler(failover=True, retry_interval=-1)

        mocksolver = sampler.solver

        # add a side-effect
        sampler.solver.sample_ising.side_effect = SolverOfflineError
        sampler.solver.sample_qubo.side_effect = SolverOfflineError

        # and make sure get_solver makes a new mock solver
        sampler.client.get_solver.side_effect = SolverNotFoundError

        with self.assertRaises(SolverNotFoundError):
            sampler.sample_ising({}, {})
Example #4
0
def solve_ising_dwave(hii, Jij):
    config_file = '/media/sf_QWorld/QWorld/QA_DeNovoAsb/dwcloud.conf'
    client = Client.from_config(config_file, profile='aritra')
    solver = client.get_solver(
    )  # Available QPUs: DW_2000Q_2_1 (2038 qubits), DW_2000Q_5 (2030 qubits)
    dwsampler = DWaveSampler(config_file=config_file)

    edgelist = solver.edges
    adjdict = edgelist_to_adjacency(edgelist)
    embed = minorminer.find_embedding(Jij.keys(), edgelist)
    [h_qpu, j_qpu] = embed_ising(hii, Jij, embed, adjdict)

    response_qpt = dwsampler.sample_ising(h_qpu,
                                          j_qpu,
                                          num_reads=solver.max_num_reads())
    client.close()

    bqm = dimod.BinaryQuadraticModel.from_ising(hii, Jij)
    unembedded = unembed_sampleset(response_qpt,
                                   embed,
                                   bqm,
                                   chain_break_method=majority_vote)
    print("Maximum Sampled Configurations from D-Wave\t===>")
    solnsMaxSample = sorted(unembedded.record, key=lambda x: -x[2])
    for i in range(0, 10):
        print(solnsMaxSample[i])
    print("Minimum Energy Configurations from D-Wave\t===>")
    solnsMinEnergy = sorted(unembedded.record, key=lambda x: +x[1])
    for i in range(0, 10):
        print(solnsMinEnergy[i])
Example #5
0
if (qubit_1 in qubits) and (qubit_2 in qubits) and (
        coupler in couplers):  # let's ensure both are available in our system
    print('Qubits {} and {} and their coupler {} are available'.format(
        qubit_1, qubit_2, coupler))

# Define a problem: Force the qubits to be spin-up by setting h_0 = h_4 = -1 and have a FM coupling between them. We expect to get samples with spin up (1) qubits and an energy of -1 + -1 + -1 = -3.

# H = h_1 * s_1 + h_2 * s_2 + J_{1,2} * s_1 * s_2
# h1 and h2 are biases on individual qubits and J_{1,2} is the coupling term

h = {qubit_1: -1, qubit_2: -1}  # force the qubits to be spin-up
J = {
    tuple(coupler): -1
}  # we expect to get samples with spin up (1) qubits and an energy of -1 + -1 + -1 = -3

solution = solver.sample_ising(
    h, J, num_reads=10)  # ask for a solution with 10 samples (reads):

print('Solution:', solution)

print('\nsamples in dict format\n' + str(list(solution.samples())))

# print('\nsamples in matrix format\n' + str(list(solution.samples_matrix))) # AttributeError: 'SampleSet' object has no attribute 'samples_matrix'

print('\nenergies of samples\n' + str(list(solution.data_vectors)))

print('\ntiming information\n' + str(list(solution.info)))

# Response = rec.array([([1, 1], -3., 10)]
Example #6
0
if not embedding:
    raise ValueError("no embedding found")


#Create a complete Ising model on a QPU 
target_h, target_J = embed_ising(h, J, embedding, target_adjacency)
# print('__________________')
# print('Linear coeff on QPU:', target_h)
# print('Quadratic coeff on QPU:', target_J)
# print('__________________')

# Set parameters for calculations. num_reas is a number of experiments
runs = 4
response = sampler.sample_ising(target_h,
							target_J, 
							num_reads=runs, 
							answer_mode='histogram',
							annealing_time = 1000)
#Get a SampleSet with spins and energies (WARNING: results are for the task, embedded on QPU)
# print('Resulting spins on QPU:')
# print(response)
# print('__________________')

#Return to the original spins:
unembedding = unembed_sampleset(response, embedding, dimod.BinaryQuadraticModel.from_ising({}, J))
# print('Resulting spins in terms of original task:')
# print(unembedding)
# print('__________________')
# plt.hist(unembedding.record.energy,rwidth=1,align='left')
# plt.show()
print(unembedding)
Example #7
0
File: 02.py Project: USP/D-Wave
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# https://docs.ocean.dwavesys.com/en/latest/overview/dwavesys.html#querying-available-solvers

from dwave.system.samplers import DWaveSampler
sampler = DWaveSampler()

print('\nsampler.parameters', sampler.parameters, sep='\n')

print('\nsampler.properties.keys()', sampler.properties.keys(), sep='\n')

print('\nresp1', sampler.sample_ising({0: 0.0}, {}, num_reads=1), sep='\n')

print('\nresp2', sampler.sample_ising({0: 2.0}, {}), sep='\n')
Example #8
0
from dwave.system.samplers import DWaveSampler
#sampler = DWaveSampler(solver={'qpu': True})

solver = DWaveSampler()
print("Connected to sampler", solver.solver.id)

qubits = solver.properties['qubits']
couplers = solver.properties['couplers']

qubit_1 = 0
qubit_2 = 4
coupler = [qubit_1, qubit_2]

if (qubit_1 in qubits) and \
   (qubit_2 in qubits) and \
   (coupler in couplers):
    print('Qubits {} and {} and their coupler {} are available'.format(
        qubit_1, qubit_2, coupler))
h = {qubit_1: -1, qubit_2: -1}
J = {tuple(coupler): -1}
solution = solver.sample_ising(h, J, num_reads=10)
solution
# To see exactly how often each chain is breaking in a standard run on the QPU, we will first run our Ising problem on the QPU using the basic `embed_ising` method.
# We will use the optional parameter `chain_strength` within `embed_ising`, and will set this value to $2.0$ for our comparison.

# To use this tool, we provide the graph minor embedding discovered above to create and embedded version.
# Then send this embedded ising problem over to the QPU using `sample_ising`.

from dwave.embedding import embed_ising
embedded_h, embedded_J = embed_ising(h,
                                     J,
                                     embedding,
                                     dwave_sampler.adjacency,
                                     chain_strength=2.0)
reads = 1000
fixed_response = dwave_sampler.sample_ising(embedded_h,
                                            embedded_J,
                                            num_reads=reads)
energies = fixed_response.record.energy
print("QPU call complete using",
      fixed_response.info['timing']['qpu_access_time'] / 1000000.0,
      "seconds of QPU time.\n")

# Next we will look at the frequency that chains broke in our samples.
# This will be our metric to explore the advantages of `VirtualGraphComposite`.

from dwave.embedding import chain_break_frequency
chain_break_frequency = chain_break_frequency(fixed_response, embedding)
for key, val in chain_break_frequency.items():
    print("Chain", key, "broke in", val * 100, "percent of samples.")

# Let's visualize these results by plotting each chain against the percentage of samples in which it broke.
Example #10
0
def find_loop(unit_size=8, i0=0, j0=0, use_qpu=True):
    '''
    dwaveの各セルを頂点として、頂点をつなげるループを
    見つけようとするモデルを実行する。 

    結果は、エネルギー最小値にならないため
    期待した結果にはならない。 

    今後のマシンの精度向上に期待。 
    または、どうにかして頑健なグラフ構造にすべきか。 

    ※注意:マシンは個体ごとにところどころ壊れているので、使用するセルを以下の引数で指定する。 

    Args:
        unit_size:
            セルの正方形の辺の長さ
        i0:
            セルの縦方向のオフセット
        j0:
            セルの横方向のオフセット
        use_qpu:
            qpuを使うか指定する
    '''
    qpu_unit_size = 16
    C16 = dnx.chimera_graph(qpu_unit_size)

    h, J = V(unit_size=unit_size, i0=i0, j0=j0)
    #print(h)
    #print(J)
    if use_qpu:
        sampler = DWaveSampler()
        samples = sampler.sample_ising(h, J, num_reads=10, annealing_time=20)

        if 0:
            count = 0
            for s,e,o in samples.data(['sample', 'energy', 'num_occurrences']):     
                print(e, o)
                print_chimera_simple(s)


                samples = sampler.sample_ising(h, J, 
                        num_reads=100,
                        anneal_schedule = [[0.0,1.0],[20.0,0.0],[30.0,0.3],[35.0,0.3],[40.0,1.0]],
                        reinitialize_state=False,
                        initial_state=s)

                count += 1
                if count >= 1 :
                    break

    else:
        classical_sampler = neal.SimulatedAnnealingSampler()
        sampler = dimod.StructureComposite(classical_sampler, C16.nodes, C16.edges)    
        samples = sampler.sample_ising(h, J, num_reads=10)

    count = 0
    for s,e,o in samples.data(['sample', 'energy', 'num_occurrences']):     
        print(e, o)
        print_chimera_simple(s)
        count += 1
        if count >= 10 :
            break
Example #11
0
class DictRep(ProbRep):
    """
    A concrete class that represents problems
    on the D-Wave as a dictionary of values.
    """
    def __init__(self, H, qpu, vartype, encoding):
        """
        Class that takes a dictionary representation of an ising-hamiltonian and submits problem to a quantum annealer

        qpu: string
            specifies quantum processing unit to be used during calculation--referring to name specifying this information in dwave config file

        vartype: string
            QUBO or Ising (all case variants acceptable)

        encoding: string
            logical or direct. If logical, embeds onto chip under the hood. If direct, assumes manual embedding and tries to put directly onto chip as is.

        H: dict
            The hamiltonian represented as a dict of the form {(0, 0): h0, (0, 1): J01, ...} OR {(0, 0): 'h0', (0, 1): 'J0', (1, 1): 'h1', ...}
        """
        # poplate run information
        super().__init__(qpu, vartype, encoding)

        # create a set of regex rules to parse h/J string keys in H
        # also creates a "rules" dictionary to relate qubit weights to relevant factor
        self.hvrule = re.compile('h[0-9]*')
        self.Jvrule = re.compile('J[0-9]*')
        self.weight_rules = {}

        # create list of qubits/ couplers and
        # dicts that map indepndent params to
        # all qubits/ couplers that have that value
        self.H = H
        self.qubits = []
        self.params_to_qubits = {}
        self.couplers = []
        self.params_to_couplers = {}
        for key, value in H.items():
            if key[0] == key[1]:
                self.qubits.append(key[0])
                if type(value) != str:
                    div_idx = -1
                else:
                    div_idx = value.find('/')
                if div_idx == -1:
                    self.weight_rules[key[0]] = 1
                else:
                    self.weight_rules[key[0]] = float(value[div_idx + 1:])
                    value = value[:div_idx]
                self.params_to_qubits.setdefault(value, []).append(key[0])
            else:
                self.couplers.append(key)
                if type(value) != str:
                    div_idx = -1
                else:
                    div_idx = value.find('/')
                if div_idx == -1:
                    self.weight_rules[key] = 1
                else:
                    self.weight_rules[key] = float(value[div_idx + 1:])
                    value = value[:div_idx]
                self.params_to_couplers.setdefault(value, []).append(key)

        self.nqubits = len(self.qubits)
        self.Hsize = 2**(self.nqubits)

        if qpu == 'dwave':
            try:
                # let OCEAN handle embedding
                if encoding == "logical":
                    # encode several times on graph
                    # based on qubits encoded
                    if len(self.qubits) <= 4:
                        self.sampler = EmbeddingComposite(
                            TilingComposite(DWaveSampler(), 1, 1, 4))
                    else:
                        self.sampler = EmbeddingComposite(DWaveSampler())

                # otherwise, assume 1-1
                else:
                    self.sampler = DWaveSampler()

            except:
                raise ConnectionError(
                    "Cannot connect to DWave sampler. Have you created a DWave config file using 'dwave config create'?"
                )

        elif qpu == 'test':
            self.sampler = dimod.SimulatedAnnealingSampler()

        elif qpu == 'numerical':
            self.processordata = loadAandB()
            self.graph = nx.Graph()
            self.graph.add_edges_from(self.couplers)
            self.data = pd.DataFrame()

        # save values/ metadata
        self.H = copy.deepcopy(H)
        if encoding == 'direct':
            self.wqubits = self.sampler.properties['qubits']
            self.wcouplers = self.sampler.properties['couplers']

    def save_config(self, fname, config_data={}):
        """
        Saves Hamiltonian configuration for future use
        """
        # if config data not supplied, at least dump Hamiltonian
        if config_data == {}:
            config_data = {'H': self.H}

        with open(fname + ".yml", 'w') as yamloutput:
            yaml.dump(config_data, yamloutput)

    def tile_H(self):
        pqubits = self.qubits
        pcouplers = self.couplers
        wqubits = self.wqubits
        wcouplers = self.wcouplers
        H = copy.deepcopy(self.H)

        for unitcell in range(1, 16 * 16):
            # create list of qubits/couplers that should be working in this unit cell
            unit_qubits = [q for q in range(8 * unitcell, 8 * (unitcell + 1))]
            unit_couplers = [[q, q + (4 - q % 4) + i] for q in unit_qubits[:4]
                             for i in range(4)]

            # ensure that all qubits and couplers are working
            if all(q in wqubits
                   for q in unit_qubits) and all(c in wcouplers
                                                 for c in unit_couplers):
                # init_state.extend(init_state[:])
                # copy the initial state
                # if so, create copies of H on other unit cells
                for q in unit_qubits:
                    if (q % 8) in pqubits:
                        H[(q, q)] = H[(q % 8, q % 8)]

                for c in unit_couplers:
                    if (c[0] % 8, c[1] % 8) in pcouplers:
                        H[tuple(c)] = H[(c[0] % 8, c[1] % 8)]

            # else:
            #init_state.extend([3 for q in range(len(unit_qubits))])

        #self.init_state = init_state
        self.H = H
        self.qubits = []
        self.params_to_qubits = {}
        self.couplers = []
        self.params_to_couplers = {}
        for key, value in H.items():
            if key[0] == key[1]:
                self.qubits.append(key[0])
                self.params_to_qubits.setdefault(value, []).append(key[0])
            else:
                self.couplers.append(key)
                self.params_to_couplers.setdefault(value, []).append(key)

    def populate_parameters(self, parameters):
        # generate all independent combinations of parameters
        self.params = []
        self.values = []
        for key, value in parameters.items():
            self.params.append(key)
            self.values.append(value)
        self.combos = list(itertools.product(*self.values))

        # format pandas DataFrame
        # columns = self.params[:]
        # columns.extend(['energy', 'state'])
        self.data = pd.DataFrame()
        self.data.H = str(self.H)
        self.data.vartype = self.vartype
        self.data.encoding = self.encoding

        return

    def call_annealer(self, **kwargs):
        """
        Calls qpu on problem encoded by H.
        cull: bool
            if true, only outputs lowest energy states,
            otherwise shows all results
        """

        # parse the input data
        # cull = kwargs.get('cull', False)  # only takes lowest energy data
        s_to_hx = kwargs.get('s_to_hx',
                             '')  # relates s to transverse-field bias
        spoint = kwargs.get(
            'spoint',
            0)  # can start sampling data midway through if interuptted

        # if H.values() only contains floats,
        # run sinlge problem as is
        if all(
                type(value) == int or type(value) == float
                for value in self.H.values()):

            if self.vartype == 'ising':
                h, J = get_dwaveH(self.H, 'ising')
                response = self.sampler.sample_ising(h, J)
                return response

            elif self.vartype == 'qubo':
                H = get_dwaveH(self.H, 'vartype')
                response = self.sampler.sample_ising(H)
                return response

        # otherwise, run a parameter sweep
        for combo in self.combos[spoint::]:
            # init single run's data/inputs
            rundata = {}
            runh = {}
            runJ = {}
            optional_args = {}
            count = 0
            # map params to values in combo
            for param in self.params:
                rundata[param] = combo[count]
                # if param is qubit param
                if self.hvrule.match(param):
                    for qubit in self.params_to_qubits[param]:
                        runh[qubit] = combo[count] / self.weight_rules[qubit]

                elif self.Jvrule.match(param):
                    for coupler in self.params_to_couplers[param]:
                        runJ[coupler] = combo[count] / self.weight_rules[
                            coupler]

                elif param == 'anneal_schedule':
                    anneal_schedule = combo[count]
                    optional_args['anneal_schedule'] = anneal_schedule
                    # if transverse field terms, get hx
                    if s_to_hx:
                        hx = s_to_hx[anneal_schedule[1][1]]
                        rundata['hx'] = hx

                elif param == 'num_reads':
                    num_reads = combo[count]
                    optional_args['num_reads'] = num_reads

                elif param == 'initial_state':
                    initial_state = combo[count]
                    optional_args['initial_state'] = initial_state

                elif param == 'reinitialize_state':
                    reinitialize_state = combo[count]
                    optional_args['reinitialize_state'] = reinitialize_state

                count += 1

            # run the sim and collect data
            if self.qpu == 'dwave':

                response = self.sampler.sample_ising(h=runh,
                                                     J=runJ,
                                                     **optional_args)

                for energy, state, num in response.data(
                        fields=['energy', 'sample', 'num_occurrences']):
                    rundata['energy'] = energy
                    rundata['state'] = tuple(state[key]
                                             for key in sorted(state.keys()))
                    for n in range(num):
                        self.data = self.data.append(rundata,
                                                     ignore_index=True)

            elif self.qpu == 'test':
                bqm = dimod.BinaryQuadraticModel.from_ising(h=runh, J=runJ)
                response = self.sampler.sample(bqm, num_reads=num_reads)
                for energy, state in response.data(
                        fields=['energy', 'sample']):
                    rundata['energy'] = energy
                    rundata['state'] = tuple(state[key]
                                             for key in sorted(state.keys()))
                    self.data = self.data.append(rundata, ignore_index=True)

            elif self.qpu == 'numerical':
                continue

        return self.data

    def visualize_graph(self):
        G = nx.Graph()
        G.add_edges_from(self.couplers)
        nx.draw_networkx(G)
        return G

    def save_data(self, filename):
        self.data.to_csv(filename, index=False)

    def get_state_plot(self,
                       figsize=(12, 8),
                       filename=None,
                       title='Distribution of Final States'):
        data = self.data
        ncount = len(data)

        plt.figure(figsize=figsize)
        ax = sns.countplot(x="state", data=data)
        plt.title(title)
        plt.xlabel('State')

        # Make twin axis
        ax2 = ax.twinx()

        # Switch so count axis is on right, frequency on left
        ax2.yaxis.tick_left()
        ax.yaxis.tick_right()

        # Also switch the labels over
        ax.yaxis.set_label_position('right')
        ax2.yaxis.set_label_position('left')

        ax2.set_ylabel('Frequency [%]')

        for p in ax.patches:
            x = p.get_bbox().get_points()[:, 0]
            y = p.get_bbox().get_points()[1, 1]
            ax.annotate('{:.1f}%'.format(100. * y / ncount), (x.mean(), y),
                        ha='center',
                        va='bottom')  # set the alignment of the text

        # Use a LinearLocator to ensure the correct number of ticks
        ax.yaxis.set_major_locator(ticker.LinearLocator(11))

        # Fix the frequency range to 0-100
        ax2.set_ylim(0, 100)
        ax.set_ylim(0, ncount)

        # And use a MultipleLocator to ensure a tick spacing of 10
        ax2.yaxis.set_major_locator(ticker.MultipleLocator(10))

        # Need to turn the grid on ax2 off, otherwise the gridlines end up on top of the bars
        # ax2.grid(None)

        if filename:
            plt.savefig(filename, dpi=300)

        return plt

    def get_ferro_diagram(self, xparam, yparam, divideby=None, title=''):
        """
        Plot the probability that output states are ferromagnetic on a contour plot
        with xaxis as xparam/divdeby and yaxis as yparam/divideby.
        """
        df = self.data
        # obtain denominator of expression (if constant value is used across-the-board)
        if divideby:
            denom = abs(df[divideby].unique()[0])
            xlabel = xparam + '/|' + divideby + '|'
            ylabel = yparam + '/|' + divideby + '|'
        else:
            denom = 1
            xlabel = xparam
            ylabel = yparam

        xs = df[xparam].unique()
        ys = df[yparam].unique()

        pfm_meshgrid = []
        # iterate over trials and obtain pFM for given xparam and yparam
        for y in ys:
            pfms = []
            for x in xs:
                # get length of unique elements in state bitstrings
                lubs = [
                    len(set(state))
                    for state in df.loc[(df[yparam] == y)
                                        & (df[xparam] == x)]['state']
                ]
                pfms.append(lubs.count(1) / len(lubs))
            pfm_meshgrid.append(pfms)

        X, Y = np.meshgrid(xs / denom, ys / denom)

        # plot the figure
        plt.figure()
        plt.title(title)
        plt.contourf(X,
                     Y,
                     pfm_meshgrid,
                     np.arange(0, 1.2, .2),
                     cmap='viridis',
                     extent=(-4, 4, 0, 4))
        cbar = plt.colorbar(ticks=np.arange(0, 1.2, .2))
        cbar.ax.set_title('$P_{FM}$')
        plt.clim(0, 1)
        plt.xlabel(xlabel)
        plt.ylabel(ylabel)

        return plt

    def diag_H(self):
        """
        Returns probability of each state.
        """
        numericH = get_numeric_H(self)
        HZ = numericH['HZ']
        gs = gs_calculator(HZ)
        num_qubits = len(self.qubits)
        Hsize = 2**(num_qubits)
        probs = np.array([abs(gs[i].flatten()[0])**2 for i in range(Hsize)])

        return probs

    def nf_anneal(self, schedule):
        """
        Performs a numeric forward anneal on H using QuTip.

        inputs:
        ---------
        schedule - a numeric anneal schedule defined with anneal length

        outputs:
        ---------
        probs - probability of each output state as a list ordered in canconically w.r.t. tensor product
        """
        times, svals = schedule

        # create a numeric representation of H
        ABfuncs = time_interpolation(schedule, self.processordata)
        numericH = get_numeric_H(self)
        A = ABfuncs['A(t)']
        B = ABfuncs['B(t)']
        HX = numericH['HX']
        HZ = numericH['HZ']
        # "Analytic" or function H(t)
        analH = lambda t: A(t) * HX + B(t) * HZ
        # Define list_H for QuTiP
        listH = [[HX, A], [HZ, B]]

        # perform a numerical forward anneal on H
        results = qt.sesolve(listH, gs_calculator(analH(0)), times)
        probs = np.array([
            abs(results.states[-1][i].flatten()[0])**2
            for i in range(self.Hsize)
        ])

        return probs

    def nr_anneal(self, schedule, init_state):
        """
        Performs a numeric reverse anneal on H using QuTip.

        inputs:
        ---------
        schedule - a numeric anneal schedule
        init_state - the starting state for the reverse anneal listed as string or list
        e.g. '111' or [010]

        outputs:
        ---------
        probs - probability of each output state as a list ordered in canconically w.r.t. tensor product
        """
        times, svals = schedule

        # create a numeric representation of H
        ABfuncs = time_interpolation(schedule, self.processordata)
        numericH = get_numeric_H(self)
        A = ABfuncs['A(t)']
        B = ABfuncs['B(t)']
        HX = numericH['HX']
        HZ = numericH['HZ']
        # Define list_H for QuTiP
        listH = [[HX, A], [HZ, B]]

        # create a valid QuTip initial state
        qubit_states = [qts.ket([int(i)]) for i in init_state]
        QuTip_init_state = qt.tensor(*qubit_states)

        # perform a numerical reverse anneal on H
        results = qt.sesolve(listH, QuTip_init_state, times)
        probs = np.array([
            abs(results.states[-1][i].flatten()[0])**2
            for i in range(self.Hsize)
        ])

        return probs

    def frem_anneal(self, schedules, partition, HR_init_state):
        """
        Performs a numeric FREM anneal on H using QuTip.

        inputs:
        ---------
        schedules - a numeric annealing schedules [reverse, forward]
        partition - a parition of H in the form [HR, HF]
        init_state - the starting state for the reverse anneal listed as string or list
        e.g. '111' or [010]

        outputs:
        ---------
        probs - probability of each output state as a list ordered in canconically w.r.t. tensor product
        """

        # retrieve useful quantities from input data
        f_sch, r_sch = schedules
        times = f_sch[0]
        HR = DictRep(H=partition['HR'],
                     qpu='numerical',
                     vartype='ising',
                     encoding='logical')
        HF = DictRep(H=partition['HF'],
                     qpu='numerical',
                     vartype='ising',
                     encoding='logical')
        Rqubits = partition['Rqubits']

        # prepare the initial state
        statelist = []
        fidx = 0
        ridx = 0
        for qubit in self.qubits:
            # if part of HR, give assigned value by user
            if qubit in Rqubits:
                statelist.append(qts.ket(HR_init_state[ridx]))
                ridx += 1
            # otherwise, put in equal superposition (i.e. gs of x-basis)
            else:
                xstate = (qts.ket('0') - qts.ket('1')).unit()
                statelist.append(xstate)
                fidx += 1
        init_state = qto.tensor(*statelist)

        # Create the numeric Hamiltonian for HR
        ABfuncs = time_interpolation(r_sch, self.processordata)
        numericH = get_numeric_H(HR)
        A = ABfuncs['A(t)']
        B = ABfuncs['B(t)']
        HX = numericH['HX']
        HZ = numericH['HZ']
        # Define list_H for QuTiP
        listHR = [[HX, A], [HZ, B]]

        # create the numeric Hamiltonian for HF
        ABfuncs = time_interpolation(f_sch, self.processordata)
        numericH = get_numeric_H(HF)
        A = ABfuncs['A(t)']
        B = ABfuncs['B(t)']
        HX = numericH['HX']
        HZ = numericH['HZ']
        # "Analytic" or function H(t)
        analHF = lambda t: A(t) * HX + B(t) * HZ
        # Define list_H for QuTiP
        listHF = [[HX, A], [HZ, B]]

        # create the total Hamitlontian of HF + HR
        list_totH = listHR + listHF

        # run the numerical simulation and find probabilities of each state
        frem_results = qt.sesolve(list_totH, init_state, times)
        probs = np.array([
            abs(frem_results.states[-1][i].flatten()[0])**2
            for i in range(self.Hsize)
        ])

        return probs

    def frem_comparison(self, T, sval, ftr):
        """
        Performs FREM algorithm and compares it to direct forward annealing.

        inputs:
        ---------
        T: total anneal time
        sval: svalue to go to in reverse annealing/ frem anneal
        ftr: the ratio of time spent in reverse and forward in frem

        outputs:
        ---------
        KL_div - the KL divergence of forward and FREM annealing w.r.t. diagonalization
        """
        f_sch = make_numeric_schedule(.1, **{'direction': 'forward', 'ta': T})
        r_sch = make_numeric_schedule(
            .1, **{
                'direction': 'reverse',
                'ta': ftr * T,
                'sa': sval,
                'tq': (1 - ftr) * T
            })

        # first, do direct diag on H
        # then extract non-zero entires ("gs" entries)
        dprobs = self.diag_H()
        nonzeroidxs = np.nonzero(dprobs)
        gs_dprobs = dprobs[nonzeroidxs]

        # perform forward anneal
        fprobs = self.nf_anneal(f_sch)
        gs_fprobs = fprobs[nonzeroidxs]

        # next, find a random partition of H into HR/HF
        partition = random_partition(self)
        # get qubits that belong to HR
        Rqubits = partition['Rqubits']
        # find the most probable state of Rqubits from forward anneal
        init_state = ml_measurement(fprobs, self.nqubits)

        # perform reverse anneal using initial state guess
        rprobs = self.nr_anneal(r_sch, init_state)
        gs_rprobs = rprobs[nonzeroidxs]

        # find initial state of sub-system (i.e. Rqubits)
        sub_system_state = []
        for (idx, qs) in enumerate(init_state):
            if idx in Rqubits:
                sub_system_state.append(qs)
        sub_init_state = ''.join([str(i) for i in sub_system_state])

        # perform FREM anneal
        fremprobs = self.frem_anneal([f_sch, r_sch], partition, sub_init_state)
        gs_fremprobs = fremprobs[nonzeroidxs]

        # save data in a pandas dataframe
        fdata = {
            'method': 'forward',
            'T': T,
            's': sval,
            'ftr': ftr,
            'part_size': self.nqubits,
            'probs': fprobs,
            'KL_div': entropy(dprobs, fprobs),
            'gs_KL_div': entropy(gs_dprobs, gs_fprobs),
            'gs_prob': sum(gs_fprobs)
        }

        rdata = {
            'method': 'reverse',
            'T': T,
            's': sval,
            'ftr': ftr,
            'part_size': self.nqubits,
            'probs': rprobs,
            'KL_div': entropy(dprobs, rprobs),
            'gs_KL_div': entropy(gs_dprobs, gs_rprobs),
            'gs_prob': sum(gs_rprobs)
        }

        fremdata = {
            'method': 'frem',
            'T': T,
            's': sval,
            'ftr': ftr,
            'part_size': len(Rqubits),
            'probs': fremprobs,
            'KL_div': entropy(dprobs, fremprobs),
            'gs_KL_div': entropy(gs_dprobs, gs_fremprobs),
            'gs_prob': sum(gs_fremprobs)
        }

        self.data = self.data.append(fdata, ignore_index=True)
        self.data = self.data.append(rdata, ignore_index=True)
        self.data = self.data.append(fremdata, ignore_index=True)

        return {'fdata': fdata, 'rdata': rdata, 'fremdata': fremdata}

    def sudden_anneal_test(self):
        pass

    def get_QUBO_rep(self):
        pass

    def get_Ising_rep(self):
        pass
    raise ValueError("no embedding found")

#Create a complete Ising model on a QPU
target_h, target_J = embed_ising(h, J, embedding, target_adjacency)

# print('__________________')
# print('Linear coeff on QPU:', target_h)
# print('Quadratic coeff on QPU:', target_J)
# print('__________________')

# Set parameters for calculations. num_reas is a number of experiments
runs = 30
schedule = [[0.0, 0.0], [10.1, 0.1], [10.3, 0.3], [100.0, 1.0]]
response = sampler.sample_ising(target_h,
                                target_J,
                                num_reads=runs,
                                answer_mode='histogram',
                                anneal_schedule=schedule)
#Get a SampleSet with spins and energies (WARNING: results are for the task, embedded on QPU)
# print('Resulting spins on QPU:')
# print(response)
# print('__________________')

#Return to the original spins:
unembedding = unembed_sampleset(response, embedding,
                                dimod.BinaryQuadraticModel.from_ising({}, J))
# print('Resulting spins in terms of original task:')
# print(unembedding)
# print('__________________')
# plt.hist(unembedding.record.energy,rwidth=1,align='left')
# plt.show()