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

[((621, 700), 'strawberryfields.apps.subgraph.search', 'subgraph.search', (['samples', 'pl_graph', 'subgraph_size', 'min_pho'], {'max_count': 'max_count'}), '(samples, pl_graph, subgraph_size, min_pho, max_count=max_count)\n', (636, 700), False, 'from strawberryfields.apps import data, sample, subgraph, plot\n'), ((1212, 1221), 'numpy.min', 'np.min', (['y'], {}), '(y)\n', (1218, 1221), True, 'import numpy as np\n'), ((1359, 1403), 'strawberryfields.Program', 'sf.Program', (['num_subsystem'], {'name': '"""remote_job"""'}), "(num_subsystem, name='remote_job')\n", (1369, 1403), True, 'import strawberryfields as sf\n'), ((1416, 1440), 'strawberryfields.utils.random_interferometer', 'random_interferometer', (['(4)'], {}), '(4)\n', (1437, 1440), False, 'from strawberryfields.utils import random_interferometer\n'), ((1571, 1586), 'strawberryfields.ops.S2gate', 'ops.S2gate', (['(1.0)'], {}), '(1.0)\n', (1581, 1586), False, 'from strawberryfields import ops\n'), ((1614, 1629), 'strawberryfields.ops.S2gate', 'ops.S2gate', (['(1.0)'], {}), '(1.0)\n', (1624, 1629), False, 'from strawberryfields import ops\n'), ((1657, 1672), 'strawberryfields.ops.S2gate', 'ops.S2gate', (['(1.0)'], {}), '(1.0)\n', (1667, 1672), False, 'from strawberryfields import ops\n'), ((1756, 1777), 'strawberryfields.ops.Interferometer', 'ops.Interferometer', (['U'], {}), '(U)\n', (1774, 1777), False, 'from strawberryfields import ops\n'), ((1817, 1841), 'strawberryfields.ops.BSgate', 'ops.BSgate', (['(0.543)', '(0.123)'], {}), '(0.543, 0.123)\n', (1827, 1841), False, 'from strawberryfields import ops\n'), ((1869, 1885), 'strawberryfields.ops.Rgate', 'ops.Rgate', (['(0.453)'], {}), '(0.453)\n', (1878, 1885), False, 'from strawberryfields import ops\n'), ((1905, 1928), 'strawberryfields.ops.MZgate', 'ops.MZgate', (['(0.65)', '(-0.54)'], {}), '(0.65, -0.54)\n', (1915, 1928), False, 'from strawberryfields import ops\n'), ((2018, 2039), 'strawberryfields.ops.Interferometer', 'ops.Interferometer', (['U'], {}), '(U)\n', (2036, 2039), False, 'from strawberryfields import ops\n'), ((2079, 2103), 'strawberryfields.ops.BSgate', 'ops.BSgate', (['(0.543)', '(0.123)'], {}), '(0.543, 0.123)\n', (2089, 2103), False, 'from strawberryfields import ops\n'), ((2131, 2147), 'strawberryfields.ops.Rgate', 'ops.Rgate', (['(0.453)'], {}), '(0.453)\n', (2140, 2147), False, 'from strawberryfields import ops\n'), ((2167, 2190), 'strawberryfields.ops.MZgate', 'ops.MZgate', (['(0.65)', '(-0.54)'], {}), '(0.65, -0.54)\n', (2177, 2190), False, 'from strawberryfields import ops\n'), ((2219, 2236), 'strawberryfields.ops.MeasureFock', 'ops.MeasureFock', ([], {}), '()\n', (2234, 2236), False, 'from strawberryfields import ops\n'), ((1163, 1172), 'numpy.sum', 'np.sum', (['x'], {}), '(x)\n', (1169, 1172), True, 'import numpy as np\n')]