import strawberryfields as sf
from strawberryfields import ops
from strawberryfields.utils import random_interferometer
from strawberryfields.apps import data, sample, subgraph, plot
import plotly
import networkx as nx
import numpy as np

class GBS:
    def __init__(self, samples =[], min_pho = 16, max_pho = 30, subgraph_size = 8, max_count = 2000):
        self.samples = samples
        self.min_pho = min_pho
        self.max_pho = max_pho
        self.subgraph_size = subgraph_size
        self.max_count = max_count

    def graphDensity(self, samples, min_pho, max_pho, subgraph_size, max_count):
        dense = subgraph.search(samples, pl_graph, subgraph_size, min_pho, max_count=max_count)
        dense_freq = []
        for k in range(subgraph_size, min_pho+1):
            dense_freq.append([k,len(dense[k])])
        return dense, dense_freq

    def graphFreqScore(self, d_freqs, max_freq):
        x,y = [], []
        for i in range(len(d_freqs)):
            for j in range(len(d_freqs[i])):
                n,f = d_freqs[i][j][0],d_freqs[i][j][1]
                x.append(n*f)
            N = len(d_freq[i])
            y.append((1/max_freq)*(np.sum(x)/N))
            x = []
        min_y = np.min(y)
        y = [min_y/x for x in y]

        return y, y.index(max(y))

    def runJob(self, eng):
        num_subsystem = 8
        prog = sf.Program(num_subsystem, name="remote_job")
        U = random_interferometer(4)
        with prog.context as q:
            # Initial squeezed states
            # Allowed values are r=1.0 or r=0.0
            ops.S2gate(1.0) | (q[0], q[4])
            ops.S2gate(1.0) | (q[1], q[5])
            ops.S2gate(1.0) | (q[3], q[7])

            # Interferometer on the signal modes (0-3)
            ops.Interferometer(U) | (q[0], q[1], q[2], q[3])
            ops.BSgate(0.543, 0.123) | (q[2], q[0])
            ops.Rgate(0.453) | q[1]
            ops.MZgate(0.65, -0.54) | (q[2], q[3])

            # *Same* interferometer on the idler modes (4-7)
            ops.Interferometer(U) | (q[4], q[5], q[6], q[7])
            ops.BSgate(0.543, 0.123) | (q[6], q[4])
            ops.Rgate(0.453) | q[5]
            ops.MZgate(0.65, -0.54) | (q[6], q[7])

            ops.MeasureFock() | q


        eng = eng
        results =eng.run(prog, shots=10)
        # state = results.state
        # measurements = results.samples
        return results.samples

[((18, 16, 18, 95), 'strawberryfields.apps.subgraph.search', 'subgraph.search', (), '', False, 'from strawberryfields.apps import data, sample, subgraph, plot\n'), ((33, 16, 33, 25), 'numpy.min', 'np.min', ({(33, 23, 33, 24): 'y'}, {}), '(y)', True, 'import numpy as np\n'), ((40, 15, 40, 59), 'strawberryfields.Program', 'sf.Program', (), '', True, 'import strawberryfields as sf\n'), ((41, 12, 41, 36), 'strawberryfields.utils.random_interferometer', 'random_interferometer', ({(41, 34, 41, 35): '4'}, {}), '(4)', False, 'from strawberryfields.utils import random_interferometer\n'), ((45, 12, 45, 27), 'strawberryfields.ops.S2gate', 'ops.S2gate', ({(45, 23, 45, 26): '(1.0)'}, {}), '(1.0)', False, 'from strawberryfields import ops\n'), ((46, 12, 46, 27), 'strawberryfields.ops.S2gate', 'ops.S2gate', ({(46, 23, 46, 26): '(1.0)'}, {}), '(1.0)', False, 'from strawberryfields import ops\n'), ((47, 12, 47, 27), 'strawberryfields.ops.S2gate', 'ops.S2gate', ({(47, 23, 47, 26): '(1.0)'}, {}), '(1.0)', False, 'from strawberryfields import ops\n'), ((50, 12, 50, 33), 'strawberryfields.ops.Interferometer', 'ops.Interferometer', ({(50, 31, 50, 32): 'U'}, {}), '(U)', False, 'from strawberryfields import ops\n'), ((51, 12, 51, 36), 'strawberryfields.ops.BSgate', 'ops.BSgate', ({(51, 23, 51, 28): '(0.543)', (51, 30, 51, 35): '(0.123)'}, {}), '(0.543, 0.123)', False, 'from strawberryfields import ops\n'), ((52, 12, 52, 28), 'strawberryfields.ops.Rgate', 'ops.Rgate', ({(52, 22, 52, 27): '(0.453)'}, {}), '(0.453)', False, 'from strawberryfields import ops\n'), ((53, 12, 53, 35), 'strawberryfields.ops.MZgate', 'ops.MZgate', ({(53, 23, 53, 27): '(0.65)', (53, 29, 53, 34): '(-0.54)'}, {}), '(0.65, -0.54)', False, 'from strawberryfields import ops\n'), ((56, 12, 56, 33), 'strawberryfields.ops.Interferometer', 'ops.Interferometer', ({(56, 31, 56, 32): 'U'}, {}), '(U)', False, 'from strawberryfields import ops\n'), ((57, 12, 57, 36), 'strawberryfields.ops.BSgate', 'ops.BSgate', ({(57, 23, 57, 28): '(0.543)', (57, 30, 57, 35): '(0.123)'}, {}), '(0.543, 0.123)', False, 'from strawberryfields import ops\n'), ((58, 12, 58, 28), 'strawberryfields.ops.Rgate', 'ops.Rgate', ({(58, 22, 58, 27): '(0.453)'}, {}), '(0.453)', False, 'from strawberryfields import ops\n'), ((59, 12, 59, 35), 'strawberryfields.ops.MZgate', 'ops.MZgate', ({(59, 23, 59, 27): '(0.65)', (59, 29, 59, 34): '(-0.54)'}, {}), '(0.65, -0.54)', False, 'from strawberryfields import ops\n'), ((61, 12, 61, 29), 'strawberryfields.ops.MeasureFock', 'ops.MeasureFock', ({}, {}), '()', False, 'from strawberryfields import ops\n'), ((31, 35, 31, 44), 'numpy.sum', 'np.sum', ({(31, 42, 31, 43): 'x'}, {}), '(x)', True, 'import numpy as np\n')]