import xarray
import geo
import defopt
import numpy
import re
from horizgrid import HorizGrid
import mint
# to read the target points from file
from latlonreader import LatLonReader
import timeobj

EARTH_RADIUS = 6371000.0

class Field(object):

    def __init__(self, tFile, uFile, vFile, lonLatZPoints, sverdrup=False):

        self.sverdrup = sverdrup

        # read the cell bounds
        with xarray.open_dataset(tFile) as nc:
            bounds_lat = nc['bounds_lat'][:]
            bounds_lon = nc['bounds_lon'][:]
            self.bounds_depth = nc['deptht_bounds'][:]

        self.lonmin = bounds_lon.min()
        self.lonmax = bounds_lon.max()
        self.latmin = bounds_lat.min()
        self.latmax = bounds_lat.max()
        print(f'lon-lat box: {self.lonmin}, {self.latmin} -> {self.lonmax}, {self.latmax}')

        self.timeIndex = 0
        self.ncU = xarray.open_dataset(uFile)
        self.ncV = xarray.open_dataset(vFile)

        # read the time values
        self.timeObj = timeobj.TimeObj(self.ncU)

        self.nt, self.nz, self.ny, self.nx = self.getSizes()

        self.gr = HorizGrid(tFile)
        self.plis = []
        for i in range(len(lonLatZPoints)):
            pli = mint.PolylineIntegral()
            pli.setGrid(self.gr.getMintGrid())
            pli.buildLocator(numCellsPerBucket=128, periodX=360., enableFolding=False)
            pli.computeWeights(numpy.array(lonLatZPoints[i]), counterclock=False)
            self.plis.append(pli)

        self.thickness = self.bounds_depth[:, 1] - self.bounds_depth[:, 0]

        numCells = self.ny * self.nx
        self.dx = min((self.lonmax - self.lonmin)/float(self.nx), (self.latmax - self.latmin)/float(self.ny))
        self.arcLengths = numpy.zeros((numCells, 4), numpy.float64)
        self.computeArcLengths()

        # compute the edge fluxes from the vector fields
        self.edgeFluxesUArray = numpy.zeros((numCells,), numpy.float64)
        self.edgeFluxesVArray = numpy.zeros((numCells,), numpy.float64)
        self.integratedVelocity = numpy.zeros((numCells, 4), numpy.float64)
        self.maxAbsFlux = 0.

        # read/get the staggered field integrated over the depth
        uVerticallyIntegrated, vVerticallyIntegrated = self.getUV()
        self.computeIntegratedFlux(uVerticallyIntegrated, vVerticallyIntegrated)
        print(f'max vertically integrated edge |flux|: {self.maxAbsFlux}')

        self.buildEdgeUVGrids(bounds_lon, bounds_lat)

        # create a polyline grid along the target points and place vectors on them
        vectorPoints = []
        self.uVectors = []
        for lonlatpts in lonLatZPoints:
            for i in range(len(lonlatpts) - 1):
                begPoint = numpy.array(lonlatpts[i])
                endPoint = numpy.array(lonlatpts[i + 1])
                u = endPoint - begPoint
                distance = numpy.sqrt(u.dot(u))
                # normalize
                u /= distance
                nvpts = max(2, int(distance / self.dx))
                vdx = distance / float(nvpts - 1)
                for j in range(nvpts):
                    vectorPoints.append(begPoint + u*j*vdx)
                    self.uVectors.append(u)
            self.vectorPoints = numpy.array(vectorPoints)

        # compute the vector at the target line
        self.vinterp = mint.VectorInterp()
        self.vinterp.setGrid(self.gr.getMintGrid())
        self.vinterp.buildLocator(numCellsPerBucket=128, periodX=360.)
        self.vinterp.findPoints(self.vectorPoints, tol2=1.e-12)
        self.vectorValues = self.vinterp.getFaceVectors(
               self.integratedVelocity, placement=0)

    def getFluxText(self):

        txt = ""
        for pli in self.plis:
            totalFlux = pli.getIntegral(self.integratedVelocity, mint.CELL_BY_CELL_DATA)
            txt += f"{totalFlux:4.3g}, "
        if self.sverdrup:
            txt += "(Sv) "
        else:
            txt += "(A m^2/s) "
        txt = re.sub(r',\s*\(', ' (', txt)
        return txt

    def update(self):

        # update the data
        uVerticallyIntegrated, vVerticallyIntegrated = self.getUV()
        # this will update self.integratedVelocity
        self.computeIntegratedFlux(uVerticallyIntegrated, vVerticallyIntegrated)

        self.vectorValues[:] = self.vinterp.getFaceVectors(
               self.integratedVelocity, placement=0)

    def getSizes(self):
        # get the sizes
        nt, nz, ny, nx = 1, 1, 0, 0
        shapeU = self.ncU['uo'].shape
        try:
            nt, nz, ny, nx = shapeU
        except:
            try:
                nz, ny, nx = shapeU
            except:
                try:
                    ny, nx = shapeU
                except:
                    raise RuntimeError("ERROR: uo's shape does not match (t, z, y, x), (z, y, x) or (y, x)")
        return nt, nz, ny, nx

    def buildEdgeUVGrids(self, bounds_lon, bounds_lat):

        # points, 4 points per cell, 3D
        self.lonlat = numpy.zeros((self.ny, self.nx, 4, 3), numpy.float64)
        self.lonlat[..., 0] = bounds_lon
        self.lonlat[..., 1] = bounds_lat

    def readField(self, nc, fieldName):

        # read fieldName
        try:
            field = nc[fieldName][self.timeIndex, :, :, :]
        except:
            try:
                field = nc[fieldName][...]
            except:
                raise RuntimeError(f'ERROR: could not read {fieldName} field')

        # set to zero where missing
        field = field.fillna(0.0)

        # integrate vertically, multiplying by the thickness of the layers,
        # this is the sum of multiplying axis 0 of thickness with axis 0 of field...
        fieldVerticallyIntegrated = numpy.tensordot(self.thickness, field, axes=(0, 0))

        return fieldVerticallyIntegrated

    def getUV(self):
        uVerticallyIntegrated = self.readField(self.ncU, 'uo')
        vVerticallyIntegrated = self.readField(self.ncV, 'vo')
        return uVerticallyIntegrated, vVerticallyIntegrated

    def computeArcLengths(self):

        # lon, lat, elev coords
        points = self.gr.getPoints() # array of size (numCells, 4, 3)

        # convert to Cartesian
        xyz = geo.lonLat2XYZArray(points, radius=geo.EARTH_RADIUS) # array of size (numCells, 4, 3)

        # compute the arc lengths
        for i0 in range(4):
            i1 = (i0 + 1) % 4
            self.arcLengths[:, i0] = geo.getArcLengthArray(xyz[:, i0, :], xyz[:, i1, :], radius=geo.EARTH_RADIUS)

    def computeIntegratedFlux(self, uVerticallyIntegrated, vVerticallyIntegrated):

        numCells = self.ny * self.nx
        #        ^
        #        |
        #  3-----V-----2
        #  |           |
        #  |     T     U-->
        #  |           |
        #  0-----------1

        # cross product means that the flux in V points to the negative y
        self.edgeFluxesUArray[:] = + uVerticallyIntegrated.reshape((numCells,)) * self.arcLengths[:, 1]
        self.edgeFluxesVArray[:] = - vVerticallyIntegrated.reshape((numCells,)) * self.arcLengths[:, 2]

        #        2
        #        ^
        #        |
        #  3-----V-----2
        #  |           |
        #  |->3  0     U->1
        #  |     ^     |
        #  |     |     |
        #  0-----------1

        # east
        self.integratedVelocity[:, 1] = self.edgeFluxesUArray
        # north
        self.integratedVelocity[:, 2] = self.edgeFluxesVArray

        # these should provide a different view to the array, NOT A COPY
        eU = self.edgeFluxesUArray.reshape((self.ny, self.nx))
        eV = self.edgeFluxesVArray.reshape((self.ny, self.nx))
        iV = self.integratedVelocity.reshape((self.ny, self.nx, 4))

        # south, (ny, nx, 4)
        iV[1:, :, 0] = eV[:-1, :] # will set self.integratedVelocity on the south side
        # west
        iV[:, 1:, 3] = eU[:, :-1]
        # periodic BCs
        iV[:, 0, 3] = eU[:, -1]

        if self.sverdrup:
            eU *= EARTH_RADIUS / 1.e6
            eV *= EARTH_RADIUS / 1.e6
            iV *= EARTH_RADIUS / 1.e6

        # from now on, edge fluxes are abs values!
        self.edgeFluxesUArray[:] = numpy.fabs(self.edgeFluxesUArray)
        self.edgeFluxesVArray[:] = numpy.fabs(self.edgeFluxesVArray)

        self.maxAbsFlux = max(self.maxAbsFlux, self.edgeFluxesUArray.max(), self.edgeFluxesVArray.max())

def __del__(self):
    self.ncU.close()
    self.ncV.close()

def main(*, tFile: str, uFile: str, vFile: str, lonLatPoints: str='', iFile: str='', sverdrup: bool=False):
    """Visualize fluxes
    :param tFile: netcdf file holding the T-grid
    :param uFile: netcdf file holding u data
    :param vFile: netcdf file holding v data
    :param lonLatPoints: target points "(lon0, lat0), (lon1, lat1),..."
    :param iFile: alternatively read target points from text file
    """
    if lonLatPoints:
        xyVals = numpy.array(eval(lonLatPoints))
    elif iFile:
        llreader = LatLonReader(iFile)
        xyVals = llreader.getLonLats()
    else:
        raise RuntimeError('ERROR must provide either iFile or lonLatPoints!')
    print(f'target points:\n {xyVals}')
    numTargetPoints = xyVals.shape[0]
    lonLatZPoints = numpy.zeros((numTargetPoints, 3), numpy.float64)
    lonLatZPoints[:, :2] = xyVals
    field = Field(tFile, uFile, vFile, lonLatZPoints, sverdrup)

if __name__ == '__main__':
    defopt.run(main)


import os
import sys

from PIL import Image

def main():
    verbose = 1 if sys.argv[1] == '-v' else 0
    for i in range(1 + verbose, len(sys.argv)):
        analyze(sys.argv[i], verbose)
    return 0

def analyze(filepath, verbose):
    img = Image.open(filepath)
    print ('Name:\t{0}'.format(os.path.basename(filepath)))
    print ('Mode:\t{0}'.format(img.mode))
    print ('Size:\t{0}'.format(img.size))
    print ('Bands:\t{0}'.format(img.getbands()))
    if verbose:
        img.load()
        width = img.size[0]
        for band_name, band in zip(img.getbands(), img.split()):
            band_data = list(band.getdata())
            print('\nBand {0}:'.format(band_name))
            start_index = 0
            while start_index < len(band_data):
                end_index = start_index + width
                part = str(band_data[start_index:end_index])
                print('{0},'.format(part.strip('[').strip(']')))
                start_index = end_index

if __name__ == '__main__':
    exit(main())


import utils, configs
import argparse
import seaborn as sns
import pandas as pd
import numpy as np

# import plotly as py
# import plotly.graph_objs as go
import matplotlib.pyplot as plt

from tqdm.auto import tqdm

# from skimage import draw
from sklearn.metrics import roc_curve
from sklearn.metrics import average_precision_score
from sklearn.metrics import roc_auc_score, precision_recall_curve, auc
from sklearn.neighbors import NearestNeighbors, KernelDensity
from sklearn import svm

from sklearn.model_selection import GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.decomposition import FastICA, PCA

def multi_df_stats(df, index):
    stats = pd.DataFrame(index=index, columns=["median", "mean", "std"], dtype=np.float32)
    stats["median"] = df.median(axis=1)
    stats["mean"] = df.mean(axis=1)
    stats["std"] = df.std(axis=1)

    return stats

def result_dict(train_score, test_score, ood_scores, metrics):
    return {
        "train_scores": train_score,
        "test_scores": test_score,
        "ood_scores": ood_scores,
        "metrics": metrics,
    }

def get_metrics(test_score, ood_scores, labels, **kwargs):
    metrics = {}
    for idx, _score in enumerate(ood_scores):
        ood_name = labels[idx + 2]
        metrics[ood_name] = ood_metrics(test_score, _score, names=(labels[1], ood_name))
    metrics_df = pd.DataFrame(metrics).T * 100  # Percentages
    return metrics_df

def auxiliary_model_analysis(
    X_train,
    X_test,
    outliers,
    labels,
    components_range=range(2, 21, 2),
    ica_range=range(2, 8, 2),
    flow_epochs=1000,
    verbose=True,
    pca_gmm=False,
    kde=False
):
    if verbose: print("=====" * 5 + " Training GMM " + "=====" * 5)
    best_gmm_clf = train_gmm(
        X_train, components_range=components_range, ica_range=ica_range, verbose=verbose
    )
    if verbose:
        print("---Likelihoods---")
        print("Training: {:.3f}".format(np.median(best_gmm_clf.score_samples(X_train))))
        print("{}: {:.3f}".format(labels[1], np.median(best_gmm_clf.score_samples(X_test))))

        for name, ood in zip(labels[2:], outliers):
            print("{}: {:.3f}".format(name, np.median(best_gmm_clf.score_samples(ood))))

    gmm_train_score = best_gmm_clf.score_samples(X_train)
    gmm_test_score = best_gmm_clf.score_samples(X_test)
    gmm_ood_scores = np.array([best_gmm_clf.score_samples(ood) for ood in outliers])
    gmm_metrics = get_metrics(-gmm_test_score, -gmm_ood_scores, labels)
    gmm_results = result_dict(
        gmm_train_score, gmm_test_score, gmm_ood_scores, gmm_metrics
    )

    pca_gmm_results=None
    if pca_gmm:
        best_gmm_clf = train_gmm(
            X_train, components_range=components_range, ica_range=ica_range, verbose=verbose, pca=True
        )

        gmm_train_score = best_gmm_clf.score_samples(X_train)
        gmm_test_score = best_gmm_clf.score_samples(X_test)
        gmm_ood_scores = np.array([best_gmm_clf.score_samples(ood) for ood in outliers])
        gmm_metrics = get_metrics(-gmm_test_score, -gmm_ood_scores, labels)
        pca_gmm_results = result_dict(
            gmm_train_score, gmm_test_score, gmm_ood_scores, gmm_metrics
        )

    kde_results=None
    if kde:
        if verbose: print("=====" * 5 + " Training KDE Model " + "=====" * 5)
        kde_model = train_kde(X_train, bandwidth_range=[0.5, 1.0, 1.5, 2.0, 2.5, 3.0], verbose=verbose)

        kde_train_score = kde_model.score_samples(X_train) ## Likelihoods
        kde_test_score  =  kde_model.score_samples(X_test)
        kde_ood_scores = np.array([kde_model.score_samples(ood) for ood in outliers])
        kde_metrics = get_metrics(-kde_test_score, -kde_ood_scores, labels)
        kde_results = result_dict(
            kde_train_score, kde_test_score, kde_ood_scores, kde_metrics
        )

    # if verbose: print("=====" * 5 + " Training OCSVM Model " + "=====" * 5)
    # ocsvm_model = svm.OneClassSVM(kernel="rbf",verbose=False, max_iter=10000,
    #                   tol=1e-6, nu=0.01, gamma="scale", shrinking=True).fit(X_train) #(kernel='exponential', bandwidth=0.5,

    # ocsvm_train_score = -ocsvm_model.decision_function(X_train) ## Likelihoods
    # ocsvm_test_score  =  -ocsvm_model.decision_function(X_test)
    # ocsvm_ood_scores = np.array([-ocsvm_model.decision_function(ood) for ood in outliers])
    # ocsvm_metrics = get_metrics(ocsvm_test_score, ocsvm_ood_scores, labels)
    # ocsvm_results = result_dict(
    #     ocsvm_train_score, ocsvm_test_score, ocsvm_ood_scores, ocsvm_metrics
    # )

    if verbose: print("=====" * 5 + " Training KD Tree " + "=====" * 5)
    kd_results = None
    N_NEIGHBOURS = 2
    nbrs = NearestNeighbors(n_neighbors=N_NEIGHBOURS, algorithm="kd_tree").fit(X_train)

    kd_train_score, indices = nbrs.kneighbors(X_train)
    kd_train_score = kd_train_score[..., -1]  # Distances to the kth neighbour
    kd_test_score, _ = nbrs.kneighbors(X_test)
    kd_test_score = kd_test_score[..., -1]
    kd_ood_scores = []
    for ood in outliers:
        dists, _ = nbrs.kneighbors(ood)
        kd_ood_scores.append(dists[..., -1])
    kd_metrics = get_metrics(kd_test_score, kd_ood_scores, labels)

    kd_results = result_dict(kd_train_score, kd_test_score, kd_ood_scores, kd_metrics)

    return {
        "PCA-GMM":pca_gmm_results,
        "GMM":gmm_results,
            "KDE":kde_results,
            "KD Tree":kd_results
           }

def train_gmm(
    X_train, components_range=range(2, 21, 2), ica_range=[2, 4, 8],
    verbose=False, pca=False
):
    from sklearn.mixture import GaussianMixture
    from sklearn.model_selection import GridSearchCV
    from sklearn.preprocessing import StandardScaler, MinMaxScaler
    from sklearn.pipeline import Pipeline
    from sklearn.decomposition import FastICA, PCA

    def scorer(gmm, X, y=None):
        return np.quantile(gmm.score_samples(X), 0.1)

#     def bic_scorer(model, X, y=None):
#         return -model["GMM"].bic(model["scaler"].transform(X))

#         return -model["GMM"].bic(model["ICA"].transform(X))

    gmm_clf = Pipeline(
        [
            # ("ICA", FastICA(n_components=10)),
            ("PCA", PCA(n_components=5)) if pca else ("scaler", StandardScaler()),
            ("GMM", GaussianMixture(
                init_params="kmeans",
                covariance_type="full",
                max_iter=100000)),
        ]
    )

    param_grid = dict(
#         ICA__n_components=ica_range,
        # ICA__max_iter=[10000],
#         ICA__tol=[1e-2],

        GMM__n_components=components_range,
#         GMM__covariance_type=["full"],
    )  # Full always performs best

    grid = GridSearchCV(
        estimator=gmm_clf,
        param_grid=param_grid,
        cv=5,
        n_jobs=1,
        verbose=verbose,
        scoring=scorer,
    )

    grid_result = grid.fit(X_train)

    if verbose:
        print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
        print("-----" * 15)
        means = grid_result.cv_results_["mean_test_score"]
        stds = grid_result.cv_results_["std_test_score"]
        params = grid_result.cv_results_["params"]
        for mean, stdev, param in zip(means, stds, params):
            print("%f (%f) with: %r" % (mean, stdev, param))

        plt.plot([p["GMM__n_components"] for p in params], means)
        plt.show()

    # best_gmm_clf = gmm_clf.set_params(**grid.best_params_)
    # best_gmm_clf.fit(X_train)
#     print(grid.best_estimator_["GMM"])
    return grid.best_estimator_

def train_kde(
    X_train, bandwidth_range=[1.0, 1.5, 2.0],
    verbose=False, pca=False
):

    def scorer(kde, X, y=None):
        return np.sum(kde.score_samples(X))
        # return np.quantile(kde.score_samples(X), 0.1)

    kde_clf = Pipeline(
        [
            # ("scaler", StandardScaler()),
            ("KDE", KernelDensity())
        ]
    )

    param_grid = dict(

        KDE__bandwidth=bandwidth_range,
        KDE__kernel=['gaussian','exponential'],
    )
    grid = GridSearchCV(
        estimator=kde_clf,
        param_grid=param_grid,
        cv=5,
        n_jobs=1,
        verbose=verbose,
        scoring=scorer,
    )

    grid_result = grid.fit(X_train)

    if verbose:
        print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
        print("-----" * 15)
        means = grid_result.cv_results_["mean_test_score"]
        stds = grid_result.cv_results_["std_test_score"]
        params = grid_result.cv_results_["params"]
        for mean, stdev, param in zip(means, stds, params):
            print("%f (%f) with: %r" % (mean, stdev, param))

        plt.plot([p["KDE__bandwidth"] for p in params], means)
        plt.show()

    return grid.best_estimator_

def plot_curves(inlier_score, outlier_score, label, axs=()):

    if len(axs) == 0:
        fig, axs = plt.subplots(1, 2, figsize=(16, 4))

    y_true = np.concatenate((np.zeros(len(inlier_score)), np.ones(len(outlier_score))))
    y_scores = np.concatenate((inlier_score, outlier_score))

    fpr, tpr, thresholds = roc_curve(y_true, y_scores, drop_intermediate=True)
    roc_auc = roc_auc = roc_auc_score(y_true, y_scores)

    prec_in, rec_in, _ = precision_recall_curve(y_true, y_scores)
    prec_out, rec_out, _ = precision_recall_curve((y_true == 0), -y_scores)
    pr_auc = auc(rec_in, prec_in)

    ticks = np.arange(0.0, 1.1, step=0.1)
    axs[0].plot(fpr, tpr, label="{}: {:.3f}".format(label, roc_auc))
    axs[0].set(
        xlabel="FPR",
        ylabel="TPR",
        title="ROC",
        ylim=(-0.05, 1.05),
        xticks=ticks,
        yticks=ticks,
    )

    axs[1].plot(rec_in, prec_in, label="{}: {:.3f}".format(label, pr_auc))
    # axs[1].plot(rec_out, prec_out, label="PR-Out")
    axs[1].set(
        xlabel="Recall",
        ylabel="Precision",
        title="Precision-Recall",
        ylim=(-0.05, 1.05),
        xticks=ticks,
        yticks=ticks,
    )

    axs[0].legend()
    axs[1].legend()

    if len(axs) == 0:
        fig.suptitle("{} vs {}".format(*labels), fontsize=20)
        plt.show()
        plt.close()

    return axs

def ood_metrics(
    inlier_score, outlier_score, plot=False, verbose=False, names=["Inlier", "Outlier"]
):
    import numpy as np
    import seaborn as sns

    y_true = np.concatenate((np.zeros(len(inlier_score)), np.ones(len(outlier_score))))
    y_scores = np.concatenate((inlier_score, outlier_score))

    prec_in, rec_in, _ = precision_recall_curve(y_true, y_scores)

    # Outliers are treated as "positive" class
    # i.e label 1 is now label 0
    prec_out, rec_out, _ = precision_recall_curve((y_true == 0), -y_scores)

    fpr, tpr, thresholds = roc_curve(y_true, y_scores, drop_intermediate=False)

    # rtol=1e-3 implies range of [0.949, 0.951]
    find_fpr = np.isclose(tpr, 0.95, rtol=1e-3, atol=1e-4).any()

    if find_fpr:
        tpr99_idx = np.where(np.isclose(tpr, 0.99, rtol=-1e-3, atol=1e-4))[0][0]
        tpr95_idx = np.where(np.isclose(tpr, 0.95, rtol=1e-3, atol=1e-4))[0][0]
        tpr80_idx = np.where(np.isclose(tpr, 0.8, rtol=1e-2, atol=1e-3))[0][0]
    else:
        # This is becasuse numpy bugs out when the scores are fully separable
        # OR fully unseparable :D
        tpr99_idx = np.where(np.isclose(tpr, 0.99, rtol=1e-2, atol=1e-2))[0][0]
        # print("Clipping 99 TPR to:", tpr[tpr99_idx])
        if np.isclose(tpr, 0.95, rtol=-1e-2, atol=3e-2).any():
            tpr95_idx = np.where(np.isclose(tpr, 0.95, rtol=-1e-2, atol=3e-2))[0][0]
        else:
            tpr95_idx = np.where(np.isclose(tpr, 0.95, rtol=2e-2, atol=3e-2))[0][0]
            print("Clipping 95 TPR to:", tpr[tpr95_idx])
#         tpr80_idx = np.where(np.isclose(tpr, 0.8, rtol=-5e-2, atol=5e-2))[0][0]
    #         tpr95_idx, tpr80_idx = 0,0 #tpr95_idx

#     print("Clipping 95 TPR to:", tpr[tpr95_idx])
#     print("Clipping 99 TPR to:", tpr[tpr99_idx])

    # Detection Error
    de = np.min(0.5 - tpr / 2 + fpr / 2)

    metrics = dict(
        true_tpr95=tpr[tpr95_idx],
        fpr_tpr99=fpr[tpr99_idx],
        fpr_tpr95=fpr[tpr95_idx],
        de=de,
        roc_auc=roc_auc_score(y_true, y_scores),
        pr_auc_in=auc(rec_in, prec_in),
        pr_auc_out=auc(rec_out, prec_out),
#         fpr_tpr80=fpr[tpr80_idx],
        ap=average_precision_score(y_true, y_scores),
    )

    if plot:

        fig, axs = plt.subplots(1, 2, figsize=(16, 4))
        fpr, tpr, thresholds = roc_curve(y_true, y_scores, drop_intermediate=True)
        ticks = np.arange(0.0, 1.1, step=0.1)

        axs[0].plot(fpr, tpr)
        axs[0].set(
            xlabel="FPR",
            ylabel="TPR",
            title="ROC",
            ylim=(-0.05, 1.05),
            xticks=ticks,
            yticks=ticks,
        )

        axs[1].plot(rec_in, prec_in, label="PR-In")
        axs[1].plot(rec_out, prec_out, label="PR-Out")
        axs[1].set(
            xlabel="Recall",
            ylabel="Precision",
            title="Precision-Recall",
            ylim=(-0.05, 1.05),
            xticks=ticks,
            yticks=ticks,
        )
        axs[1].legend()
        fig.suptitle("{} vs {}".format(*names), fontsize=20)
    #         plt.show()
    #         plt.close()

    if verbose:
        print("{} vs {}".format(*names))
        print("----------------")
        print("ROC-AUC: {:.4f}".format(metrics["roc_auc"] * 100))
        print(
            "PR-AUC (In/Out): {:.4f} / {:.4f}".format(
                metrics["pr_auc_in"] * 100, metrics["pr_auc_out"] * 100
            )
        )
        print("FPR (95% TPR): {:.2f}%".format(metrics["fpr_tpr95"] * 100))
        print("Detection Error: {:.2f}%".format(de * 100))
        print("FPR (99% TPR): {:.2f}%".format(metrics["fpr_tpr99"] * 100))

    return metrics

def evaluate_model(
    train_score, inlier_score, outlier_scores, labels, ylim=None, xlim=None, **kwargs
):
    rows = 1 + int(np.ceil(len(outlier_scores) / 2))
    fig, axs = plt.subplots(rows, 1, figsize=(12, rows * 4))
    axs = np.array(axs).reshape(-1)  # Makes axs into list even if row num is 1
    colors = sns.color_palette("bright") + sns.color_palette("dark")

    sns.histplot(train_score, color=colors[0], label=labels[0], ax=axs[0], **kwargs)
    sns.histplot(inlier_score, color=colors[1], label=labels[1], ax=axs[0], **kwargs)

    offset = 2
    for idx, _score in enumerate(outlier_scores):
        idx += offset
        sns.histplot(_score, color=colors[idx], label=labels[idx], ax=axs[0], **kwargs)

    # Plot in pairs
    if len(outlier_scores) > 0:
        offset = 0
        for row in range(1, axs.shape[0]):
            sns.histplot(
                inlier_score, color=colors[1], label=labels[1], ax=axs[row], **kwargs
            )

            #         for idx in range(offset, min(len(outlier_sc)offset+2)):
            for idx, _score in enumerate(outlier_scores[offset : offset + 2]):
                idx += offset + 2
                sns.histplot(
                    _score, color=colors[idx], label=labels[idx], ax=axs[row], **kwargs
                )
            offset = 2 * row

    for ax in axs:
        ax.legend()
        ax.set_ylim(top=ylim)
        ax.set_xlim(left=xlim, right=10 if xlim else None)

    #     plt.show()

    return axs


from azure.kusto.data import KustoClient, KustoConnectionStringBuilder
from azure.kusto.data.exceptions import KustoServiceError
from azure.kusto.data.helpers import dataframe_from_result_table
import pandas as pd
import json
from kusto import get_data2
from flask import Flask, jsonify
import threading
import time
import datetime

app = Flask(__name__)

AAD_TENANT_ID = "f0e7e7ca-b83f-4893-94b4-6f982b62bbc8"
KUSTO_CLUSTER = "https://restarteddataexplorer1.southcentralus.kusto.windows.net"
KUSTO_DATABASE = "restarted-gym-rat"
KCSB = KustoConnectionStringBuilder.with_aad_device_authentication(
    KUSTO_CLUSTER)
KCSB.authority_id = AAD_TENANT_ID
KUSTO_CLIENT = KustoClient(KCSB)
KUSTO_QUERY = "Raspberrypi | sort by reptime, repcount | take 1"
RESPONSE = KUSTO_CLIENT.execute(KUSTO_DATABASE, KUSTO_QUERY)

def get_data2():
    df = dataframe_from_result_table(RESPONSE.primary_results[0])
    df2 = pd.DataFrame.to_json(df, orient="records")
    data = json.loads(df2)
    df3 = json.dumps(data)
    current_time = datetime.datetime.now()
    print(df3)
    return df3

@app.route("/data")
def get_adx_data():
    return get_data2()

# Continuously update the data from ADX every 10 seconds
def update_adx_data():
    while True:
        app.config['ADX_DATA'] = get_data2()
        time.sleep(10)

if __name__ == "__main__":
    # Start the thread to continuously update the data from ADX
    update_thread = threading.Thread(target=update_adx_data)
    update_thread.start()

    # Start the Flask app
    app.run()


# author: HuYong
#coding=utf-8
from django.conf.urls import url
from service import views

urlpatterns = [
   url(r'^checkStudent',views.checkStudent),
   url(r'^charge',views.charge),
   url(r'^AmmeterControl',views.AmmeterControl),

]


import logging

import numpy

from sourced.ml.models import Id2Vec

def id2vec_project(args):
    MAX_TOKENS = 10000  # hardcoded in Tensorflow Projector

    log = logging.getLogger("id2vec_project")
    id2vec = Id2Vec(log_level=args.log_level).load(source=args.input)
    if args.docfreq_in:
        log.info("Loading docfreq model from %s", args.docfreq_in)
        from sourced.ml.models import DocumentFrequencies
        df = DocumentFrequencies(log_level=args.log_level).load(source=args.docfreq_in)
    else:
        df = None
    if len(id2vec) < MAX_TOKENS:
        tokens = numpy.arange(len(id2vec), dtype=int)
        if df is not None:
            freqs = [df.get(id2vec.tokens[i], 0) for i in tokens]
        else:
            freqs = None
    else:
        if df is not None:
            log.info("Filtering tokens through docfreq")
            items = []
            for token, idx in id2vec.items():
                try:
                    items.append((df[token], idx))
                except KeyError:
                    continue
            log.info("Sorting")
            items.sort(reverse=True)
            tokens = [i[1] for i in items[:MAX_TOKENS]]
            freqs = [i[0] for i in items[:MAX_TOKENS]]
        else:
            log.warning("You have not specified --df => picking random %d tokens", MAX_TOKENS)
            numpy.random.seed(777)
            tokens = numpy.random.choice(
                numpy.arange(len(id2vec), dtype=int), MAX_TOKENS, replace=False)
            freqs = None
    log.info("Gathering the embeddings")
    embeddings = numpy.vstack([id2vec.embeddings[i] for i in tokens])
    tokens = [id2vec.tokens[i] for i in tokens]
    labels = ["subtoken"]
    if freqs is not None:
        labels.append("docfreq")
        tokens = list(zip(tokens, (str(i) for i in freqs)))
    import sourced.ml.utils.projector as projector
    projector.present_embeddings(args.output, not args.no_browser, labels, tokens, embeddings)
    if not args.no_browser:
        projector.wait()


import sys
from argparse import ArgumentParser, Namespace

from lib.environments import get_environments
from lib.logger import install_logger
from lib.parser_defaults import parser_default_args, parser_default_funcs
from lib.providers.credentials import get_envs, get_info, parser_driver_arguments
from lib.run_func import run_func
from lib.settings import C_CMD, C_CODE, C_END, C_FILE, DEKICK_DOTENV_FILE, is_pytest

def parser_help() -> str:
    """Set description for this command, used in arguments parser"""
    return (
        "Get credentials from credentials provider "
        + f"defined in {C_FILE}.dekickrc.yml{C_END} and save it to {C_FILE}.env{C_END} file"
    )

def arguments(parser: ArgumentParser):
    """Set arguments for this command."""
    parser.add_argument(
        "--env",
        required=False,
        default="",
        help="Set specific environment to get credentials for",
        choices=get_environments(),
    )
    parser.set_defaults(func=main)
    parser_default_args(parser)
    parser_driver_arguments(parser)

def main(parser: Namespace, args: list):  # pylint: disable=unused-argument
    """Main entry point for this command."""
    parser_default_funcs(parser)
    install_logger(parser.log_level, parser.log_filename)
    exit_code = ui_save_dotenv(**vars(parser))
    sys.exit(exit_code)

def ui_save_dotenv(**kwargs):
    """UI wrapper for docker_compose"""
    if is_pytest():
        return

    def wrapper(**kwargs):
        try:
            save_dotenv(**kwargs)
        except Exception as error:  # pylint: disable=broad-except
            return {"success": False, "text": error.args[0]}

    env = kwargs["env"]
    driver_info = get_info()

    return run_func(
        text=f"Saving credentials to {C_FILE}{DEKICK_DOTENV_FILE}{C_END} for "
        + f"{C_CMD}env {env}{C_END} using {C_CODE}{driver_info}{C_END}",
        func=wrapper,
        func_args=kwargs,
    )

def save_dotenv(*args, **kwargs) -> int:
    """Saves credentials to .env file."""
    envs = get_envs(*args, **kwargs)

    try:
        with open(DEKICK_DOTENV_FILE, "w", encoding="utf-8") as file:
            file.write(envs)
    except PermissionError as exception:
        raise PermissionError(
            f"Credentials: Permission denied while writing to file {DEKICK_DOTENV_FILE}"
        ) from exception

    return 0


import os

import bpy
from bpy.types import Operator
from bpy.props import StringProperty, BoolProperty, FloatProperty
from bpy_extras.io_utils import ImportHelper, ExportHelper

from ..utils import is_writable, write_to_file
from ..types import BFException

# Collections

bl_classes = list()

def subscribe(cls):
    """Subscribe class to related collection."""
    bl_classes.append(cls)
    return cls

# Import menu

@subscribe
class ImportFDS(Operator, ImportHelper):
    """Import FDS case file to a new Scene"""

    bl_idname = "import_scene.fds"
    bl_label = "Import FDS"
    bl_options = {"UNDO"}

    filename_ext = ".fds"
    filter_glob: StringProperty(default="*.fds", options={"HIDDEN"})

    @classmethod
    def poll(cls, context):
        return context.scene is not None

    def execute(self, context):
        return {"CANCELLED"}

def menu_func_import_FDS(self, context):
    self.layout.operator("import_scene.fds", text="NIST FDS (.fds)")

# Export menu

@subscribe
class ExportFDS(Operator, ExportHelper):
    """Export current Scene to FDS case file"""

    bl_idname = "export_scene.fds"
    bl_label = "Export FDS"
    bl_description = "Export current Blender Scene as an FDS case file"

    filename_ext = ".fds"
    filter_glob: StringProperty(default="*.fds", options={"HIDDEN"})

    @classmethod
    def poll(cls, context):
        return context.scene is not None

    def execute(self, context):
        # Init
        w = context.window_manager.windows[0]
        w.cursor_modal_set("WAIT")
        sc = context.scene
        # Prepare FDS filepath
        print(f"BFDS: Exporting Blender Scene <{sc.name}> to FDS file...")
        filepath = self.filepath
        if not filepath.lower().endswith(".fds"):
            filepath += ".fds"
        filepath = bpy.path.abspath(filepath)
        # Check FDS filepath writable
        if not is_writable(filepath):
            w.cursor_modal_restore()
            self.report({"ERROR"}, "FDS file not writable, cannot export")
            return {"CANCELLED"}
        # Prepare FDS file
        try:
            fds_file = sc.to_fds(context=context, full=True)
        except BFException as err:
            w.cursor_modal_restore()
            self.report({"ERROR"}, str(err))
            return {"CANCELLED"}
        # Add namelist index # TODO develop
        # Write FDS file
        if not write_to_file(filepath, fds_file):
            w.cursor_modal_restore()
            self.report({"ERROR"}, "FDS file not writable, cannot export")
            return {"CANCELLED"}
        print(f"BFDS: FDS file written.")
        # GE1 description file requested?
        if sc.bf_dump_render_file:
            print(
                f"BFDS: Warning: Exporting Blender Scene <{sc.name}> to GE1 file not implemented!"
            )  # FIXME
            # # Prepare GE1 filepath
            # print(f"BFDS: Exporting Blender Scene <{sc.name}> to GE1 file...")
            # filepath = filepath[:-4] + ".ge1"
            # if not is_writable(filepath):
            #     w.cursor_modal_restore()
            #     self.report({"ERROR"}, "GE1 file not writable, cannot export")
            #     return {"CANCELLED"}
            # # Prepare GE1 file
            # try:
            #     ge1_file = sc.to_ge1(context=context)
            # except BFException as err:
            #     w.cursor_modal_restore()
            #     self.report({"ERROR"}, str(err))
            #     return {"CANCELLED"}
            # # Write GE1 file
            # if not write_to_file(filepath, ge1_file):
            #     w.cursor_modal_restore()
            #     self.report({"ERROR"}, "GE1 file not writable, cannot export")
            #     return {"CANCELLED"}
            # print(f"BFDS: GE1 file written.")
        # End
        w.cursor_modal_restore()
        self.report({"INFO"}, "FDS case exported")
        return {"FINISHED"}

    def draw(self, context):
        pass

def menu_func_export_FDS(self, context):
    # Prepare default filepath
    filepath = "{0}.fds".format(os.path.splitext(bpy.data.filepath)[0])
    directory = os.path.dirname(filepath)
    basename = os.path.basename(filepath)
    # If the context scene contains path and basename, use them
    sc = context.scene
    if sc.bf_head_directory:
        directory = sc.bf_head_directory
    if sc.name:
        basename = "{0}.fds".format(bpy.path.clean_name(sc.name))
    # Call the exporter operator
    filepath = f"{directory}/{basename}"
    self.layout.operator("export_scene.fds", text="Scene to NIST FDS (.fds)")

# Register

def register():
    from bpy.utils import register_class

    for cls in bl_classes:
        register_class(cls)
    #    bpy.types.TOPBAR_MT_file_import.append(menu_func_import_FDS)  # FIXME implement
    bpy.types.TOPBAR_MT_file_export.append(menu_func_export_FDS)

def unregister():
    from bpy.utils import unregister_class

    for cls in reversed(bl_classes):
        unregister_class(cls)
    #    bpy.types.TOPBAR_MT_file_import.remove(menu_func_import_FDS)  # FIXME implement
    bpy.types.TOPBAR_MT_file_export.remove(menu_func_export_FDS)


import json
import math

from datetime                  import datetime,timedelta
from django.db.models          import Sum
from django.http               import JsonResponse
from rest_framework            import status
from rest_framework.response   import Response
from rest_framework.decorators import api_view

from ads.serializers import AdSerializer
from ads.models      import Ad, Result
from ads.serializers import AdSerializer

@api_view(['GET'])
def get_result(request):
    """
    류성훈
    """
    # 광고주의 id 받아오기
    advertiser_id = request.GET.get('advertiser', None)

    try:
        start_date = request.GET.get('start_date', None)
        end_date   = request.GET.get('end_date', None)
    except TypeError:
        return Response("타입이 잘못되었습니다.", status=404)

    # 광고주의 광고들을 불러옵니다.
    advertiser = Ad.objects.filter(advertiser=advertiser_id, is_delete=False)
    if not advertiser:
        return Response("존재하지 않는 광고주 id입니다.", status=404)

    advertiser_uid = advertiser.values('uid')

    media_list = ['naver', 'facebook', 'google', 'kekeo']

    answer = {}
    for media in media_list:
        objs = Result.objects.filter(uid__in=advertiser_uid, date__gte=start_date, date__lte=end_date, media=media)
        if objs:
            total = objs.aggregate(
                total_click      =Sum('click'),
                total_impression = Sum('impression'),
                total_cost       = Sum('cost'),
                total_conversion = Sum('conversion'),
                total_cv = Sum('cv'),
            )

            val = {
                'ctr' : 0 if total['total_impression']==0 else math.trunc((total['total_click'] * 10000 / total['total_impression']))/100,
                'roas': 0 if total['total_cost']==0 else math.trunc(total['total_cv'] * 10000 / total['total_cost'])/100,
                'cpc' : 0 if total['total_click']==0 else math.trunc(total['total_cost'] * 100 / total['total_click'])/100,
                'cvr' : 0 if total['total_click']==0 else math.trunc(total['total_conversion'] * 10000 / total['total_click'])/100,
                'cpa' : 0 if total['total_conversion']==0 else math.trunc(total['total_cost'] * 100 / total['total_conversion'])/100,
            }

            answer[media] = val

    return Response(answer, status=200)

@api_view(['POST'])
def post_create_ad(request):
    """
    김석재
    """
    # 필수 입력값 4개(ad) + 1개 (result) 입력시 ad를 하나(캠페인)생성 , 기간에 따라 하루마다 하나씩 result를 생성
    if request.method == 'POST':

        start_date    = request.data['start_date']
        end_date      = request.data['end_date']
        advertiser_id = request.data['advertiser_id']
        media         = request.data['media']
        uid           = request.data['uid']

        if not start_date or not end_date or not advertiser_id or not media or not uid:
            return Response({'MESSAGE' : 'MISSING_VALUE'}, status = 400)

        #end-start day로 차이나는 값 만큼 result를 생성 (최소1)
        start = datetime.strptime(start_date, '%Y-%m-%d')
        end   = datetime.strptime(end_date, '%Y-%m-%d')
        day   = end - start

        if start < datetime.now():
            return Response({'MESSAGE' : 'INVALID_DATE'}, status = 400)
        if start >= end:
            return Response({'MESSAGE' : 'INVALID_DATE'}, status = 400)

        new_ad = Ad.objects.create(
            start_date    = start_date,
            end_date      = end_date,
            advertiser_id = advertiser_id,
            uid           = uid
        )

        #필수 데이터 외에 추가데이터
        if 'budget' in request.data:
            new_ad.budget = request.data['budget']
            if float(request.data['budget']) < 0:
                return Response({'MESSAGE' : 'INVALID_VALUE'}, status = 400)

        if 'estimated_spend' in request.data:
            new_ad.estimated_spend = request.data['estimated_spend']
            if float(request.data['estimated_spend']) < 0:
                return Response({'MESSAGE' : 'INVALID_VALUE'}, status = 400)

        for day in range(day.days+1):
            date = start + timedelta(days=day)
            Result.objects.create(
                uid   = new_ad,
                media = media,
                date  = date
            )

        serializer = AdSerializer(new_ad)
        return Response(serializer.data)

@api_view(['PATCH', 'DELETE'])
def update_delete_ad(request, advertiser, uid):
    """
    권상현 / 정미정
    """
    if request.method == 'PATCH':
        """
        권상현
        """
        try:
            data = json.loads(request.body)
            ad = Ad.objects.get(advertiser = advertiser, uid = uid)

            if ad.is_delete == True:
                raise Ad.DoesNotExist

            serializer = AdSerializer(ad, data, partial=True)

            if serializer.is_valid(raise_exception=True):
                serializer.save()
                return Response({'MESSAGE' : 'SUCCESS'}, status = status.HTTP_200_OK)

            return Response({'MESSAGE' : 'KEY_ERROR'}, status = status.HTTP_400_BAD_REQUEST)

        except Ad.DoesNotExist:
            return Response({'MESSAGE':'AD_DOES_NOT_EXIST'}, status = status.HTTP_404_NOT_FOUND)

    elif request.method == 'DELETE':
        """
        정미정 (soft delete로 구현)
        """
        try:
            ad = Ad.objects.get(uid=uid)
            if ad.is_delete == True:
                raise Ad.DoesNotExist
            serializer = AdSerializer(ad)
            ad.delete_at = datetime.now()
            ad.is_delete = True
            ad.save()
            return JsonResponse({'MESSAGE' : 'SUCCESS'}, status=status.HTTP_200_OK)

        except Ad.DoesNotExist:
            return JsonResponse({'MESSAGE' : 'AD_DOES_NOT_EXIST'}, status=status.HTTP_404_NOT_FOUND)

    else:
        return JsonResponse({'MESSAGE' : 'METHOD_NOT_ALLOWED'}, status = status.HTTP_405_METHOD_NOT_ALLOWED)


import tkinter as tk
import serial
from tkinter import ttk
from ttkthemes import ThemedTk
import cv2
import time
import os
from tkinter import filedialog

ser = serial.Serial('COM5', 9600)

def on_daq():
    global daq_name_var
    global picture_number_var
    global daq_path_var
    global daq_window

    def take_global_params():
        global daq_name
        daq_name='\\' + daq_name_var.get()
        global picture_number
        picture_number=picture_number_var.get()
        global daq_path
        daq_path=daq_path_var.get()
        daq_window.destroy()
        print("Im Working",daq_path+daq_name+picture_number )
    daq_window = tk.Toplevel(root)
    daq_window.title("DAQ Settings")
    daq_window.geometry("330x140")

    # Create label and entry for daq_name
    daq_name_label = tk.Label(daq_window, text="DAQ Name:")
    daq_name_label.grid(row=0, column=0, padx=5, pady=5)

    daq_name_var = tk.StringVar()
    daq_name_entry = tk.Entry(daq_window, textvariable=daq_name_var)
    daq_name_entry.grid(row=0, column=1, padx=5, pady=5)
    daq_name_var.set("Default Name")

    daq_path_label = tk.Label(daq_window, text="Choose path")
    daq_path_label.grid(row=1, column=0, padx=5, pady=5)

    daq_path = tk.Button(daq_window, text = "Select Path", command = lambda: daq_path_var.set(filedialog.askdirectory()))
    daq_path.config(width=10, height=1)
    daq_path.grid(row=1, column=2, padx=5, pady=5)

    daq_path_var = tk.StringVar()
    daq_path_entry = tk.Entry(daq_window, textvariable=daq_path_var)
    daq_path_entry.grid(row=1, column=1, padx=5, pady=5)

    # Create label and entry for picture_number
    picture_number_label = tk.Label(daq_window, text="Picture Number:")
    picture_number_label.grid(row=2, column=0, padx=5, pady=5)

    picture_number_var = tk.StringVar()
    picture_number_entry = tk.Entry(daq_window, textvariable=picture_number_var)
    picture_number_entry.grid(row=2, column=1, padx=5, pady=5)
    picture_number_var.set("200")

    # Create start button
    start_button = tk.Button(daq_window, text="Start DAQ", command=take_global_params)
    start_button.config(width=10, height=1)
    start_button.grid(row=3, column=0, columnspan=2, padx=5, pady=5)

def take_point_by_point():
    ser.write(f'L 1'.encode())
    on_daq()
    daq_window.wait_window()
    cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
    print("camera init done")
    steps_=0
    step_increment=1
    if int(picture_number)>35: numer_of_steps=35
    else: number_of_steps=picture_number
    for i in range(number_of_steps):
        ret, frame = cap.read()
        frame=cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        cv2.imshow('frame',frame)
        cv2.waitKey(1)
        cv2.imwrite(daq_path+daq_name+str(i)+".jpg", frame, [cv2.IMWRITE_JPEG_QUALITY, 100])
        steps_=steps_+step_increment
        ser.write(f'M {steps_}'.encode())
        print('Current step =',ser.readline().decode('utf-8').strip()," Set Step = ",steps_*80*8/3)
    cap.release()
    cv2.destroyAllWindows()
    print("Snapshot Taken!")
    on_home()
    ser.write(f'L 0'.encode())

def take_continously():
    ser.write(f'L 1'.encode())
    on_daq()
    daq_window.wait_window()
    cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
    print("camera init done")
    ser.write(f'S 50'.encode())
    time.sleep(0.05)
    ser.write(f'M 35'.encode())
    time.sleep(1)
    for i in range(int(picture_number)):
        ret, frame = cap.read()
        frame=cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        cv2.imshow('frame',frame)
        cv2.waitKey(1)
        cv2.imwrite(daq_path+daq_name+str(i)+".jpg", frame, [cv2.IMWRITE_JPEG_QUALITY, 100])
        print("Picture", i, "from", picture_number )
    cap.release()
    cv2.destroyAllWindows()
    print("Snapshot Taken!")
    on_home()
    ser.write(f'L 0'.encode())

def on_home():
    ser.write(b'H')
    #time.sleep(0.05)
    print(ser.readline().decode('utf-8').strip())

def on_speed():
    speed = speed_var.get()
    ser.write(f'S {speed}'.encode())
    #time.sleep(0.05)
    print(ser.readline().decode('utf-8').strip())

def on_move():
    steps = steps_var.get()
    ser.write(f'M {steps}'.encode())
    #time.sleep(0.05)
    print('Current step =',ser.readline().decode('utf-8').strip()," Set Step = ",float(steps)*80*8/3)

def on_led():
    state = led_var.get()
    ser.write(f'L {state}'.encode())
    print(ser.readline().decode('utf-8').strip())

def on_exit():
    ser.close()
    root.destroy()

#root = tk.Tk()
root = ThemedTk(theme='blue')
print(root.get_themes())
root.title("Micro Mirror Test Software")
root.geometry("350x150")

max_length = max(len("RPM Value"), len("Abs Value mm"))

menubar = tk.Menu(root)
filemenu = tk.Menu(menubar, tearoff=0)
#filemenu.add_command(label="Set COM Port", command=set_com_port)
filemenu.add_separator()
filemenu.add_command(label="Home", command=on_home)
filemenu.add_separator()
filemenu.add_command(label="DAQ point by point", command=take_point_by_point)
filemenu.add_separator()
filemenu.add_command(label="DAQ continuously", command=take_continously)
#filemenu.add_separator()
#filemenu.add_command(label="Function to be tested", command=on_daq)
menubar.add_cascade(label="Functions", menu=filemenu)

filemenu = tk.Menu(menubar, tearoff=0)
filemenu.add_command(label="Exit", command=on_exit)
menubar.add_cascade(label="Exit", menu=filemenu)
root.config(menu=menubar)

speed_frame = tk.Frame(root)
speed_frame.grid(row=1, column=0, padx=5, pady=5)

speed_label = tk.Label(speed_frame, text="RPM Value")
speed_label.config(width=max_length)
speed_label.grid(row=0, column=0, padx=5, pady=5)

speed_var = tk.StringVar()
speed_entry = tk.Entry(speed_frame, textvariable=speed_var)
speed_entry.grid(row=0, column=1, padx=5, pady=5)

speed_button = tk.Button(speed_frame, text="Set Speed", command=on_speed)
speed_button.config(width=10, height=1)
speed_button.grid(row=0, column=2,   padx=5, pady=5)

steps_frame = tk.Frame(root)
steps_frame.grid(row=2, column=0, padx=5, pady=5)

steps_label = tk.Label(steps_frame, text="Abs Value mm")
steps_label.config(width=max_length)
steps_label.grid(row=0, column=0, padx=5, pady=5)

steps_var = tk.StringVar()
steps_entry = tk.Entry(steps_frame, textvariable=steps_var)
steps_entry.grid(row=0, column=1, padx=5, pady=5)

steps_button = tk.Button(steps_frame, text="MoveTo", command=on_move)
steps_button.config(width=10, height=1)
steps_button.grid(row=0, column=2,  padx=5, pady=5)

led_frame = tk.Frame(root)
led_frame.grid(row=3, column=0, padx=5, pady=5)

led_var = tk.IntVar()
led_var.set(0)
led_on_button = tk.Radiobutton(led_frame, text='Laser On', variable=led_var, value=1, command=on_led)
led_on_button.grid(row=0, column=0, padx=5, pady=5)
led_off_button = tk.Radiobutton(led_frame, text='Laser Off', variable=led_var, value=0, command=on_led)
led_off_button.grid(row=0, column=1, padx=5, pady=5)

root.mainloop()


from clifford.g3 import *  # Import 3D geometric algebra functions
import numpy as np

# Spin-1/2 particle properties
mu = 1.0  # Magnetic moment (arbitrary units)
B = e3  # Magnetic field along the z-axis

# Initial state of the spin particle (aligned with the x-axis)
psi = e1

# Time evolution
t_values = np.linspace(0, 10, 100)
spin_evolution = []

for t in t_values:
    # Compute the evolution operator
    U = np.exp(-0.5 * mu * B * t)

    # Apply the evolution operator to the initial state
    psi_t = U * psi * ~U
    spin_evolution.append([float(psi_t[e1]), float(psi_t[e2]), float(psi_t[e3])])

# Visualization
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

spin_evolution = np.array(spin_evolution)
ax.quiver(0, 0, 0, spin_evolution[:, 0], spin_evolution[:, 1], spin_evolution[:, 2], length=0.1, normalize=True, color='g', linewidth=2.5)

ax.set_xlim([-1, 1])
ax.set_ylim([-1, 1])
ax.set_zlim([-1, 1])
ax.set_title("Evolution of Spin-1/2 Particle in Magnetic Field")
plt.show()


from dotenv import load_dotenv
from os import environ
from http import HTTPStatus

from errors.application_error import ApplicationError

class EnvironmentUtility:

    @classmethod
    def initialize_environment_utility(cls):
        load_dotenv()

    @classmethod
    def get_environment_variable_value(cls, key: str):
        # fetch value from environment
        value = environ.get(key)
        if value is None:
            # raise exception if value is not available
            raise ApplicationError(HTTPStatus.INTERNAL_SERVER_ERROR,
                                    f"invalid environment variable: {key}")
        else:
            # return environment variable value
            return value


from flask import Flask, request, jsonify
from application import app
from spam_classifer import calc_spam
spam_class = calc_spam()

@app.route('/hello_user', methods=['POST'])
def hello_user():
    data = request.json
    user = data['user']
    number = data['num']
    number = int(number)+1
    return f'{number}'

@app.route('/hello')
def hello():

    return f'Привет!'

@app.route('/classify_text', methods=['POST'])
def classify_text():
    data = request.json
    text = data['text']

    result = spam_class.classify(text)
    return jsonify({'result': result})


"""
1090. 受标签影响的最大值

我们有一个 n 项的集合。给出两个整数数组 values 和 labels ，第 i 个元素的值和标签分别是 values[i] 和 labels[i]。
还会给出两个整数 numWanted 和 useLimit 。
从 n 个元素中选择一个子集 s :
子集 s 的大小 小于或等于 numWanted 。
s 中 最多 有相同标签的 useLimit 项。
一个子集的 分数 是该子集的值之和。
返回子集 s 的最大 分数 。
"""
import collections
from typing import List

class Solution:
    def largestValsFromLabels(self, values: List[int], labels: List[int], numWanted: int, useLimit: int) -> int:
        label_dict = collections.defaultdict(list)
        for label, value in zip(labels, values):
            label_dict[label].append(value)
        for k, v in label_dict.items():
            label_dict[k] = list(sorted(v, reverse=True))
        candidates = []
        for k, v in label_dict.items():
            candidates.extend(v[:useLimit])
        return sum(list(sorted(candidates, reverse=True))[:numWanted])

1090. 受标签影响的最大值.py


from qiskit.tools.visualization import plot_histogram
import Qconfig
import qiskit as qk
from qiskit.providers.ibmq import least_busy
qr = qk.QuantumRegister(4)  # Allocate two quantum registers - 4 qubits
cr = qk.ClassicalRegister(4)  # Allocate two classical registers - 4 bits
qc = qk.QuantumCircuit(qr, cr)  # Create a Quantum Circuit acting on qr and cr

# Now, we can make operations on those.
qc.h(qr[0])
qc.h(qr[1])
# control not-gate, this in a real QComputer will entangle both qubits.
qc.cx(qr[0], qr[2])
# control not-gate, this in a real QComputer will entangle both qubits.
qc.cx(qr[1], qr[3])

measure_Z = qk.QuantumCircuit(qr, cr)

measure_Z.h(qr[2])
measure_Z.h(qr[3])
# measure_Z.cx(qr[1],qr[3])
# measure_Z.cx(qr[2],qr[0])
measure_Z.measure(qr, cr)

measure_X = qk.QuantumCircuit(qr, cr)

measure_X.h(qr)
measure_X.measure(qr, cr)

test_Z = qc + measure_Z

test_X = qc + measure_X

backend = qk.BasicAer.get_backend('qasm_simulator')
job_1 = qk.execute(test_Z, backend, shots=1000)

result_1 = job_1.result()

print(result_1.get_counts(test_Z))

plot_histogram(result_1.get_counts(test_Z)).savefig("test_Z.png")

job_1 = qk.execute(test_X, backend, shots=1000)

result_1 = job_1.result()

print(result_1.get_counts(test_X))

plot_histogram(result_1.get_counts(test_X)).savefig("test_X.png")

qk.IBMQ.load_accounts(hub=None)

backend = least_busy(qk.IBMQ.backends(
    filters=lambda x: not x.configuration().simulator))

job_2 = qk.execute(test_Z, backend, shots=1000)

print(job_2.status)

result_2 = job_2.result()

print(result_2.get_counts(test_Z))

plot_histogram(result_2.get_counts(test_Z)).savefig("IBM_test_Z.png")

backend = least_busy(qk.IBMQ.backends(
    filters=lambda x: not x.configuration().simulator))

job_2 = qk.execute(test_X, backend, shots=1000)

result_2 = job_2.result()

print(result_2.get_counts(test_X))

plot_histogram(result_2.get_counts(test_X)).savefig("IBM_test_X.png")


import os
import sys
import time
import numpy as np
import tensorflow as tf
#from tensorflow.keras.layers import Conv2D, Flatten, MaxPooling2D, Dense
import matplotlib.pyplot as plt
import datetime
import tensorflow_probability as tfp
tfd = tfp.distributions
import gym
import config_multi_sac
from model import *
from utils import *
from sac_train import *
from actor import *

class sac(object):
  def __init__(self, env, config):
    self.env = env
    self.config = config
    if self.config.use_replay_buffer:
      self.replay_buffer = []
    self.obs_len = len(self.env.reset())
    self.loss_ = []
    self.build()

  def build(self):
    ep = self.config.num_val_epochs
    ol = self.obs_len
    self.model = polinet(self.env, ol, len(self.env.action_space.sample()), continuity = self.config.continuity).model
    if self.config.on_policy:
      self.valuenet = valuenet(self.env, ep)
    else:
      self.qnet, self.qnet2, self.tar_qnet, self.tar_qnet2 = valuenet(self.env, ep),valuenet(self.env, ep), valuenet(self.env, ep), valuenet(self.env, ep)
    self.lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(self.config.learning_rate, decay_steps = 100000, decay_rate = 0.96)
    self.opts = tf.keras.optimizers.Adam(self.lr_schedule, clipvalue = 5)
    #self.ckpt = tf.train.Checkpoint(step = tf.Variable(1), optimizers = self.opts, net = )
    checkpoint_path = "./checkpoints"
    self.ckpt = tf.train.Checkpoint(step = tf.Variable(1),
                                    model = self.model,
                                    qnet_model = self.qnet.model,
                                    qnet2_model = self.qnet2.model,
                                    tar_qnet_model = self.tar_qnet.model,
                                    tar_qnet2_model = self.tar_qnet2.model,
                                    opts = self.opts,
                                    qnet_opt = self.qnet.opt,
                                    qnet2_opt = self.qnet2.opt,
                                    tar_qnet_opt = self.tar_qnet.opt,
                                    tar_qnet2_opt = self.tar_qnet2.opt)
    self.ckpt_manager = tf.train.CheckpointManager(self.ckpt, checkpoint_path, max_to_keep=10)
    self.sampling(100)

  def sampling(self, num_episode = None):
    paths = sample_path(self.env, self.model, self.config.batch_size, self.config.max_ep_len, self.config.continuity, num_episodes = num_episode)
    if self.config.use_replay_buffer:
      self.replay_buffer.extend(paths)
      crit = len(self.replay_buffer) - self.config.replay_buffer_size
      if crit > 0:
        self.replay_buffer = self.replay_buffer[crit:]
    return paths

  def sample_action(self, obs):
    try:
        mu, log_sig = self.model(tf.expand_dims(obs, axis = 0))
    except:
        mu, log_sig = self.model(obs)
    action, _ = action_log_pi(mu, tf.math.exp(log_sig))
    return action

  def train_step2(self):
    self.paths = self.sampling(self.config.batch_total)
    mask = np.random.choice(len(self.replay_buffer), self.config.batchnumber)
    batch = np.take(self.replay_buffer, mask, axis = 0)
    _ = train_critic(batch, self.model, self.qnet, self.qnet2, self.tar_qnet, self.tar_qnet2)
    obs, _, _, _, _ = path_reshape(batch)

    shape = [self.config.batchnumber, self.config.action_space_dims]

    dist = tfd.MultivariateNormalDiag(loc = np.zeros(shape), scale_diag = np.ones(shape))
    noise = dist.sample()
    prob = dist.log_prob(noise)
    log_prob = tf.cast(prob, tf.float32)
    noise = tf.cast(noise, tf.float32)

    pt = policy_train()
    shape = [self.config.batchnumber, self.config.action_space_dims]
    loss_, mean_q, mean_entropy = pt(tf.cast(obs, tf.float32), self.model, self.qnet, self.opts, noise, log_prob)
    update_network_weights(self.config.update_rate, self.qnet.model, self.tar_qnet.model)
    update_network_weights(self.config.update_rate, self.qnet2.model, self.tar_qnet2.model)
    return loss_, mean_q, mean_entropy

  def train_step(self):
    self.paths = self.sampling(self.config.batch_total)
    mask = np.random.choice(len(self.replay_buffer), self.config.batchnumber)
    batch = np.take(self.replay_buffer, mask, axis = 0)
    _ = train_value(batch, self.model, self.qnet, self.qnet2, self.tar_qnet, self.tar_qnet2)
    mask = np.random.choice(len(self.replay_buffer), self.config.batchnumber)
    batch = np.take(self.replay_buffer, mask, axis = 0)
    obs, _, _, _, _ = path_reshape(batch)

    #dist = tfd.MultivariateNormalDiag(loc = np.zeros(shape), scale_diag = np.ones(shape))
    #noise = dist.sample()
    #prob = dist.log_prob(noise)
    #log_prob = tf.cast(prob, tf.float32)
    #noise = tf.cast(noise, tf.float32)

    noise = sampler(self.config.batchnumber, self.config.action_space_dims)
    noise = tf.cast(noise, tf.float32)

    pt = policy_training()
    shape = [self.config.batchnumber, self.config.action_space_dims]
    loss_, mean_q, mean_entropy = pt(tf.cast(obs, tf.float32), self.model, self.qnet, self.opts, noise)#, log_prob)
    update_network_weights(self.config.update_rate, self.qnet.model, self.tar_qnet.model)
    update_network_weights(self.config.update_rate, self.qnet2.model, self.tar_qnet2.model)
    return loss_, mean_q, mean_entropy

  def train(self, n):
    if self.config.use_checkpoint:
        self.ckpt.restore(self.ckpt_manager.latest_checkpoint)
        if self.ckpt_manager.latest_checkpoint:
            print('\nRestored checkpoint of step : {}'.format(int(self.ckpt.step)))

    for i in range(n):
      print('\n')
      print(i,'th iteration ...')
      loss_, mean_q, mean_entropy = self.train_step()
      print('Loss is :', loss_)
      print('Mean q is :', mean_q)
      print('Mean entropy is :', mean_entropy)
      print(len(self.replay_buffer))
      returns = self.estimator()
      if i/10 == i//10 :
        pass
      if self.config.use_checkpoint:

          if i % 1 == 0:
              self.ckpt_manager.save()
          self.ckpt.step.assign_add(1)
          print('Checkpoint step is :', int(self.ckpt.step))
          self.loss_.append([int(self.ckpt.step), returns])
      else:
          self.loss_append([i, returns])
    print('done!')

  def estimator(self):
    rwd = 0
    for i in range(len(self.paths)):
      rwd += self.paths[i][2]
    returns = rwd/(self.config.batch_total*5)
    print('Current return is :', rwd/(self.config.batch_total*5))
    return returns

if __name__ == "__main__":
  env = gym.make('Hopper-v2')
  config = config_multi_sac.config_multi_sac(False)
  sa = sac(env, config)
  sa.train(2000)
  save_results(sa.loss_, 'results')
  #rendering(sa)


import pygame
import main
import sys
from Helpers.button import Button

import settings

def options(screen_width, screen_height):
    buttons_posX = screen_width / 2
    y_start = screen_height / 2
    buttons_posY = [y_start - 300 ,y_start - 200, y_start - 100, y_start , y_start + 150 ,y_start + 300]

    Music_On = True
    Music_label = "Mute Music"
    while True:
        OPTIONS_MOUSE_POS = pygame.mouse.get_pos()

        main.SCREEN.fill("white")

        main.SCREEN.blit(main.BG, (0, 0))

        info = Button(image=None, pos=(buttons_posX, 50),
                            text_input="Left Click to increase - Right Click to decrease",
                            font=main.get_font(20), base_color="White", hovering_color="White")

        Maze_rows = Button(image=None, pos=(buttons_posX, buttons_posY[0]),
                            text_input=f"Number of Maze Rows\t {settings.Number_of_rows}",
                            font=main.get_font(40), base_color="White", hovering_color="#7400b8")

        Maze_Cols = Button(image=None, pos=(buttons_posX, buttons_posY[1]),
                            text_input=f"Number of Maze Columns\t {settings.Number_of_cols}",
                            font=main.get_font(40), base_color="White", hovering_color="#6930c3")

        Kids = Button(image=None, pos=(buttons_posX, buttons_posY[2]),
                        text_input=f"Number of Kids\t {settings.Num_of_kids}",
                        font=main.get_font(40), base_color="White", hovering_color="#5e60ce")

        Time = Button(image=None, pos=(buttons_posX, buttons_posY[3]),
                        text_input=f"Bomb Time :\t {settings.Level_time}",
                        font=main.get_font(40), base_color="White", hovering_color="#5390d9")

        SOUND_BUTTON_MUTE = Button(image=None, pos=(buttons_posX, buttons_posY[4]),
                                   text_input=Music_label, font=main.get_font(60), base_color="White",
                                   hovering_color="#4cc9f0")

        OPTIONS_BACK = Button(image=None, pos=(buttons_posX, buttons_posY[5]),
                              text_input="BACK", font=main.get_font(75), base_color="White",
                              hovering_color="#ff006e")

        for button in [OPTIONS_BACK, SOUND_BUTTON_MUTE, Kids, Maze_rows, Maze_Cols, Time, info]:
            button.changeColor(OPTIONS_MOUSE_POS)
            button.update(main.SCREEN)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                if OPTIONS_BACK.checkForInput(OPTIONS_MOUSE_POS):
                    main.main_menu()
                if SOUND_BUTTON_MUTE.checkForInput(OPTIONS_MOUSE_POS):
                    if Music_On:
                        main.mixer.music.stop()
                        Music_label = "UnMute Music"
                        Music_On = False
                    else:
                        main.mixer.music.play()
                        Music_label = "Mute Music"
                        Music_On = True

                if Time.checkForInput(OPTIONS_MOUSE_POS):
                    if event.button == 1:
                        if settings.Level_time == "default":
                            settings.Level_time = 10
                        else:
                            settings.Level_time += 5
                    elif event.button == 3:
                        if settings.Level_time != "default":
                            settings.Level_time -=5
                        if settings.Level_time == 'default' or settings.Level_time <= 0:
                            settings.Level_time = "default"

                if Kids.checkForInput(OPTIONS_MOUSE_POS):
                    if event.button == 1:
                        if settings.Num_of_kids < 100:
                            settings.Num_of_kids +=1
                    elif event.button == 3:
                        if settings.Num_of_kids > 1:
                            settings.Num_of_kids -= 1

                if Maze_Cols.checkForInput(OPTIONS_MOUSE_POS):
                    if event.button == 1:
                        if settings.Number_of_cols < 100:
                            settings.Number_of_cols += 5
                    elif event.button == 3:
                        if settings.Number_of_cols > 5:
                            settings.Number_of_cols -= 5

                if Maze_rows.checkForInput(OPTIONS_MOUSE_POS):
                    if event.button == 1:
                        if settings.Number_of_rows < 100:
                            settings.Number_of_rows += 5
                    elif event.button == 3:
                        if settings.Number_of_rows > 5:
                            settings.Number_of_rows -= 5

        pygame.display.update()


from io import BytesIO

from vkbottle import AudioUploader, Bot, DocUploader, Message, PhotoUploader

from gtts import gTTS
from PIL import Image

bot = Bot("token")

photo_uploader = PhotoUploader(bot.api, generate_attachment_strings=True)
doc_uploader = DocUploader(bot.api, generate_attachment_strings=True)
audio_uploader = AudioUploader(bot.api, generate_attachment_strings=True)

@bot.on.message_handler(text="photo_from_bytes", lower=True)
async def photo_from_bytes(ans: Message):
    image = Image.new("RGB", (320, 320), (0, 0, 0))
    fp = BytesIO()
    image.save(fp, "PNG")
    setattr(fp, "name", "image.png")
    photo = await photo_uploader.upload_message_photo(fp)
    await ans(attachment=photo)

@bot.on.message_handler(text="doc_from_file", lower=True)
async def doc_from_file(ans: Message):
    doc = Image.new("RGB", (320, 320), (0, 0, 0))
    doc.save("doc.png", "RGB")
    doc_output = await doc_uploader.upload_doc_to_message("doc.png", ans.peer_id)
    await ans(attachment=doc_output)

@bot.on.message_handler(text="audio_message", lower=True)
async def audio(ans: Message):
    tts = gTTS(text="бокале монада", lang="ru")
    fp = BytesIO()
    tts.write_to_fp(fp)
    audio_message = await audio_uploader.upload_audio_message(fp, ans.peer_id)
    await ans(attachment=audio_message)

if __name__ == "__main__":
    bot.run_polling()


from time import time

import numpy as np

from settings import TILE_SIZE
from utils import find_unite_pos, find_animal_pos

neighbours = [(x, y) for x in range(-1, 2) for y in range(-1, 2)]
neighbours.remove((0, 0))

class Animal:
    def __init__(self, nom, pos, pos_depart, health, speed, ressource):
        self.name = nom
        self.pos = pos
        self.posDepart = pos_depart
        self.health = health
        self.speed = speed
        self.xpixel, self.ypixel = 0, 0
        self.path = ()
        self.vie = True
        self.ressource = ressource
        self.reviens = False
        self.time_depla = 0
        self.next_depla = 0
        # self.attack = attack
        # self.range_attack = range_attack
        # self.vitesse_attack = vitesse_attack
        # self.tick_attaque = -1
        # self.attackB = False
        # self.cible = None

    def updatepos(self, grid_length_x, grid_length_y, world, buildings, unites, animaux):
        if self.path or self.xpixel or self.ypixel:
            if self.path:
                if self.path == self.pos:
                    self.path = ()
                    return

                taille = TILE_SIZE / 2
                for neighbour in neighbours:
                    x, y = self.pos[0] + neighbour[0], self.pos[1] + neighbour[1]

                    if self.path[0] == x and self.path[1] == y:
                        deplacement = False
                        self.xpixel += neighbour[0]
                        self.ypixel += neighbour[1]
                        if self.xpixel < -taille:
                            self.xpixel = taille
                            deplacement = True
                        elif self.xpixel > taille:
                            self.xpixel = -taille
                            deplacement = True

                        if self.ypixel < -taille:
                            self.ypixel = taille
                            deplacement = True
                        elif self.ypixel > taille:
                            self.ypixel = -taille
                            deplacement = True

                        if deplacement:
                            self.pos = self.path
                            self.path = ()
                        break

            elif self.xpixel != 0 or self.ypixel != 0:
                self.xpixel = self.xpixel - 1 if self.xpixel > 0 else self.xpixel + 1
                self.ypixel = self.ypixel - 1 if self.ypixel > 0 else self.ypixel + 1

        # calcul du prochain path
        else:
            if time() - self.time_depla > self.next_depla:
                for x in range(-2, 3):
                    for y in range(-2, 3):
                        if find_unite_pos(x + self.pos[0], y + self.pos[1], unites):
                            x = -1 if self.pos[0] < self.posDepart[0] else (1 if self.pos[0] > self.posDepart[0] else 0)
                            y = -1 if self.pos[1] < self.posDepart[1] else (1 if self.pos[1] > self.posDepart[1] else 0)
                            if x == 0 and y == 0:
                                return
                            pos, pos1, pos2 = self.find_3_pos(x, y)

                            poss = []
                            if self.is_good_pos(pos, grid_length_x, grid_length_y, world, buildings, unites, animaux):
                                poss.append(pos)
                            if self.is_good_pos(pos1, grid_length_x, grid_length_y, world, buildings, unites, animaux):
                                poss.append(pos1)
                            if self.is_good_pos(pos2, grid_length_x, grid_length_y, world, buildings, unites, animaux):
                                poss.append(pos2)

                            if len(poss) > 0:
                                self.path = poss[np.random.randint(0, len(poss))]

                            self.time_depla = time()
                            self.next_depla = np.random.randint(1, 5)
                            return

                if self.reviens:
                    if abs(self.pos[0] - self.posDepart[0]) < 2 and abs(self.pos[1] - self.posDepart[1]) < 2:
                        self.reviens = False
                        return
                    else:
                        x = 1 if self.pos[0] < self.posDepart[0] else (-1 if self.pos[0] > self.posDepart[0] else 0)
                        y = 1 if self.pos[1] < self.posDepart[1] else (-1 if self.pos[1] > self.posDepart[1] else 0)
                        pos, pos1, pos2 = self.find_3_pos(x, y)

                        poss = []
                        if self.is_good_pos(pos, grid_length_x, grid_length_y, world, buildings, unites, animaux):
                            poss.append(pos)
                        if self.is_good_pos(pos1, grid_length_x, grid_length_y, world, buildings, unites, animaux):
                            poss.append(pos1)
                        if self.is_good_pos(pos2, grid_length_x, grid_length_y, world, buildings, unites, animaux):
                            poss.append(pos2)
                        if len(poss) == 0 and (find_animal_pos(pos[0], pos[1], animaux) or
                                               find_animal_pos(pos1[0], pos1[1], animaux)
                                               or find_animal_pos(pos2[0], pos2[1], animaux)):
                            self.time_depla = time()
                            self.next_depla = np.random.randint(1, 5)
                            return
                        elif len(poss) == 0:
                            # l'animal est bloqué
                            return

                        self.path = poss[np.random.randint(0, len(poss))]

                elif abs(self.pos[0] - self.posDepart[0]) < 4 and abs(self.pos[1] - self.posDepart[1]) < 4:
                    n = neighbours.copy()
                    coo = n.pop(np.random.randint(0, len(n)))
                    pos = (self.pos[0] + coo[0], self.pos[1] + coo[1])
                    while len(n) > 0 and not self.is_good_pos(pos, grid_length_x, grid_length_y, world, buildings,
                                                              unites, animaux):
                        coo = n.pop(np.random.randint(0, len(n)))
                        pos = (self.pos[0] + coo[0], self.pos[1] + coo[1])
                    if len(n) > 0 or self.is_good_pos(pos, grid_length_x, grid_length_y, world, buildings, unites,
                                                      animaux):
                        self.path = pos
                else:
                    self.reviens = True
                self.time_depla = time()
                self.next_depla = np.random.randint(1, 5)

    def is_good_pos(self, pos, grid_length_x, grid_length_y, world, buildings, unites, animaux):
        x, y = pos
        return grid_length_x > x >= 0 and grid_length_y > y >= 0 and (world[x][y]["tile"] == "" or
                                                                      world[x][y]["tile"] == "sable") and \
               buildings[x][y] is None and find_unite_pos(x, y, unites) is None and \
               find_animal_pos(x, y, animaux) is None

    def find_3_pos(self, x, y):
        index = neighbours.index((x, y))
        if (x, y) in [(1, -1), (0, -1), (-1, 1), (0, 1)]:
            if (x, y) == (1, -1):
                xy1 = neighbours[index - 2]
                xy2 = neighbours[index + 1]
            elif (x, y) == (-1, 1):
                xy1 = neighbours[index - 1]
                xy2 = neighbours[index + 2]
            elif (x, y) == (0, -1):
                xy1 = neighbours[index - 3]
                xy2 = neighbours[index + 2]
            else:  # elif (x, y) == (0, 1)
                xy1 = neighbours[index - 2]
                xy2 = neighbours[index + 3]
        else:
            xy1 = neighbours[index - 1]
            xy2 = neighbours[(index + 1) % len(neighbours)]

        pos = (self.pos[0] + x, self.pos[1] + y)
        pos1 = (self.pos[0] + xy1[0], self.pos[1] + xy1[1])
        pos2 = (self.pos[0] + xy2[0], self.pos[1] + xy2[1])
        return pos, pos1, pos2

class Gazelle(Animal):
    def __init__(self, pos, pos_depart):
        super().__init__("gazelle", pos, pos_depart, 8, 1, 150)


import tensorflow as tf
from tensorflow.keras import layers
import numpy as np
import random
from tensorflow.distributions import Normal
import time
from utils import save_tiled_imgs, print_params

from flow_training import train, evaluate, load_data, iterbatches
from flows import (
    Flow, Compose, Inverse, ImgProc, Sigmoid, AffineCoupling, MixLogisticAttnCoupling,
    TupleFlip, CheckerboardSplit, ChannelSplit, SpaceToDepth, Norm, Pointwise, ElemwiseAffine,
    conv2d, gated_conv, nin, gate, layernorm, VarConfig, get_var, gaussian_sample_logp, sumflat
)

def construct(*, filters, dequant_filters, posterior_filters, blocks, posterior_blocks, components, extra_dims=0, x_dims=3, x_max_val=256):
    coupling_kwargs = dict(filters=filters, blocks=blocks, components=components)
    posterior_coupling_kwargs = dict(filters=posterior_filters, blocks=posterior_blocks, components=components)
    dequant_coupling_kwargs = dict(filters=filters, blocks=2, components=components)

    class PosteriorLatent(Flow):
        def __init__(self):
            class NormalPosterior:
                def forward(self, x, *, vcfg, dropout_p=0., verbose=True, context=None):
                    z, logq_z = gaussian_sample_logp(x.shape.as_list()[:-1] + [extra_dims])
                    return z, logq_z

            class FlowPosterior:
                def __init__(self):
                    self.inited = False
                    def shallow_processor(x, *, dropout_p, vcfg):
                        context = {}

                        (this, that), _ = CheckerboardSplit().forward(x)
                        x = conv2d(tf.concat([this, that], 3), name='proj_q', num_units=32, vcfg=vcfg)
                        for i in range(3):
                            x = gated_conv(x, name=f'q_c{i}', vcfg=vcfg, dropout_p=dropout_p, use_nin=False, a=None)
                        context[f'{x.shape.as_list()[1]}_{x.shape.as_list()[2]}'] = x

                        return context

                    self.context_proc = tf.make_template("context_proc", shallow_processor)

                    self.q_flow = Compose([
                        CheckerboardSplit(),
                        Norm(), Pointwise(), MixLogisticAttnCoupling(**posterior_coupling_kwargs), TupleFlip(),
                        Norm(), Pointwise(), MixLogisticAttnCoupling(**posterior_coupling_kwargs), TupleFlip(),
                        Norm(), Pointwise(), MixLogisticAttnCoupling(**posterior_coupling_kwargs), TupleFlip(),
                        Norm(), Pointwise(), MixLogisticAttnCoupling(**posterior_coupling_kwargs), TupleFlip(),
                        Inverse(CheckerboardSplit()),
                        Sigmoid(),
                    ])

                def forward(self, x, *, vcfg, dropout_p=0., verbose=True, context=None):
                    '''
                    z = f(u)
                    u = f^{-1}(z)
                    p(u) = p(z) * |det(J_f^{-1}^{-1}(u))| = p(z) * |det(J_f(u))|
                    '''
                    assert context is None
                    eps, eps_logp = gaussian_sample_logp(x.shape.as_list()[:-1] + [extra_dims])
                    xd, logd = self.q_flow.forward(
                        eps,
                        context=self.context_proc(x, dropout_p=dropout_p, vcfg=vcfg),
                        dropout_p=dropout_p, verbose=verbose, vcfg=vcfg
                    )
                    return xd, eps_logp - logd

            # self.posterior_flow = NormalPosterior()
            self.posterior_flow = FlowPosterior()

        def forward(self, x, **flow_kwargs):
            """
            return: z, shape (1, batch_size, h, w, extra_dims)
                    logq_z, shape (batch_size)
            """
            z, logq_z = self.posterior_flow.forward(x, **flow_kwargs)
            return tf.reshape(z, [1,] + x.shape.as_list()[:-1] + [extra_dims]), tf.reshape(logq_z, [-1])

    class UnifDequant(Flow):
        def forward(self, x, **kwargs):
            x = x + tf.random_uniform(x.shape.as_list())
            x, logd = ImgProc(max_val=x_max_val).forward(x)
            return x, logd

    class Dequant(Flow):
        def __init__(self):
            def shallow_processor(x, *, dropout_p, vcfg):
                x = x / (x_max_val * 1.0) - 0.5
                context = {}

                (this, that), _ = CheckerboardSplit().forward(x)
                x = conv2d(tf.concat([this, that], 3), name='proj', num_units=32, vcfg=vcfg)
                for i in range(3):
                    x = gated_conv(x, name=f'c{i}', vcfg=vcfg, dropout_p=dropout_p, use_nin=False, a=None)
                context[f'{x.shape.as_list()[1]}_{x.shape.as_list()[2]}'] = x

                return context

            self.context_proc = tf.make_template("context_proc", shallow_processor)

            self.dequant_flow = Compose([
                CheckerboardSplit(),
                Norm(), Pointwise(), MixLogisticAttnCoupling(**dequant_coupling_kwargs), TupleFlip(),
                Norm(), Pointwise(), MixLogisticAttnCoupling(**dequant_coupling_kwargs), TupleFlip(),
                Norm(), Pointwise(), MixLogisticAttnCoupling(**dequant_coupling_kwargs), TupleFlip(),
                Norm(), Pointwise(), MixLogisticAttnCoupling(**dequant_coupling_kwargs), TupleFlip(),
                Inverse(CheckerboardSplit()),
                Sigmoid(),
            ])

        def forward(self, x, *, vcfg, dropout_p=0., verbose=True, context=None):
            assert context is None
            eps, eps_logp = gaussian_sample_logp(x.shape.as_list())
            xd, logd = self.dequant_flow.forward(
                eps,
                context=self.context_proc(x, dropout_p=dropout_p, vcfg=vcfg),
                dropout_p=dropout_p, verbose=verbose, vcfg=vcfg
            )
            assert eps.shape == x.shape and logd.shape == eps_logp.shape == [x.shape[0]]
            x = x + xd
            dequant_logd = logd - eps_logp
            x, logd = ImgProc(max_val=x_max_val).forward(x)
            return x, dequant_logd + logd

    class SpecialAffine(Flow):
        def __init__(self, init_scale=1., blocks=3):
            self.inited = False
            def f(x, *, vcfg:VarConfig, dropout_p=0., verbose=True, context=None):
                assert context is None
                vcfg = VarConfig(init=(vcfg.init and not self.inited), ema=vcfg.ema, dtype=vcfg.dtype)
                if vcfg.init and verbose:
                    self.inited = True
                    # debug stuff
                    xmean, xvar = tf.nn.moments(x, axes=list(range(len(x.shape))))
                    x = tf.Print(
                        x, [tf.shape(x), xmean, tf.sqrt(xvar), tf.reduce_min(x), tf.reduce_max(x)],
                        message='{} (shape/mean/std/min/max) '.format(self.generative_net.variable_scope.name), summarize=10
                    )
                B, H, W, C = x.shape.as_list()
                x = conv2d(x, name='p_proj_in', num_units=filters, vcfg=vcfg)
                for i in range(blocks):
                    with tf.variable_scope(f'p_block{i}'):
                        x = gated_conv(x, name='p_conv', a=context, use_nin=True, dropout_p=dropout_p, vcfg=vcfg)
                        x = layernorm(x, name='p_ln', vcfg=vcfg)
                x = conv2d(x, name='p_proj_out', num_units=x_dims*2, init_scale=init_scale, vcfg=vcfg)
                x = tf.reshape(x, [B, H, W, x_dims*2])
                return x

            self.generative_net = tf.make_template(self.__class__.__name__, f)

        def decode(self, z, flow_kwargs):
            mean, logstd = tf.split(self.generative_net(z, **flow_kwargs), num_or_size_splits=2, axis=3)
            std = tf.exp(logstd) + 1e-6
            return mean, logstd, std

        def forward(self, xz, flow_kwargs):
            '''
            (x, z) -> (epsilon_x, epsilon_z)
            '''
            x = xz[:,:,:,:x_dims]
            z = xz[:,:,:,x_dims:]
            mean, logstd, std = self.decode(z, flow_kwargs)
            epsilon_x = (x - mean) / std
            epsilon_z = z
            logd = -sumflat(logstd)
            return tf.concat([epsilon_x, epsilon_z], axis=-1), logd

        def inverse(self, xz, flow_kwargs):
            epsilon_x = xz[:,:,:,:x_dims]
            z = xz[:,:,:,x_dims:]
            mean, logstd, std = self.decode(z, flow_kwargs)
            x = epsilon_x * std + mean
            logd = sumflat(logstd)
            return tf.concat([x, z], axis=-1), logd

    class SpecialAffineNULL(Flow):
        def forward(self, xz, flow_kwargs):
            return xz, tf.constant(0.)

        def inverse(self, xz, flow_kwargs):
            return xz, tf.constant(0.)

    class Generative(Flow):
        def __init__(self):
            self.vaeflow = SpecialAffineNULL()
            self.flow = Compose([
                # 32x32x6 (3+3)
                CheckerboardSplit(),
                Norm(), Pointwise(), MixLogisticAttnCoupling(**coupling_kwargs), TupleFlip(),
                Norm(), Pointwise(), MixLogisticAttnCoupling(**coupling_kwargs), TupleFlip(),
                Inverse(CheckerboardSplit()),

                ChannelSplit(),
                Norm(), Pointwise(), MixLogisticAttnCoupling(**coupling_kwargs), TupleFlip(),
                Norm(), Pointwise(), MixLogisticAttnCoupling(**coupling_kwargs), TupleFlip(),
                Inverse(ChannelSplit()),

                # 16x16x24
                SpaceToDepth(),

                CheckerboardSplit(),
                Norm(), Pointwise(), MixLogisticAttnCoupling(**coupling_kwargs), TupleFlip(),
                Norm(), Pointwise(), MixLogisticAttnCoupling(**coupling_kwargs), TupleFlip(),
                Inverse(CheckerboardSplit()),

                ChannelSplit(),
                Norm(), Pointwise(), MixLogisticAttnCoupling(**coupling_kwargs), TupleFlip(),
                Norm(), Pointwise(), MixLogisticAttnCoupling(**coupling_kwargs), TupleFlip(),
                Norm(), Pointwise(), MixLogisticAttnCoupling(**coupling_kwargs), TupleFlip(),
                Inverse(ChannelSplit()),
            ])

        def forward(self, x, z, flow_kwargs):
            '''
            y = f(xz)
            xz = f^{-1}(y)
            p(xz) = p(y) * |det(J_f^{-1}^{-1}(xz))| = p(y) * |det(J_f(xz))|
            '''
            H, W, Cx = x.shape.as_list()[-3:]
            x = tf.reshape(x, [-1, H, W, Cx])
            z = tf.reshape(z, [-1, H, W, extra_dims])

            xz = tf.concat([x, z], axis=-1)
            y, logd_flow = self.vaeflow.forward(xz, flow_kwargs)
            y, ld = self.flow.forward(y, **flow_kwargs)
            logd_flow += ld
            logpy = sumflat(Normal(0., 1.).log_prob(y))
            return y, logpy + logd_flow

        def inverse(self, y, flow_kwargs):
            '''
            g = f^{-1}
            y = g^{-1}(xz)
            p(y) = p(xz) * |det(J_g^{-1}^{-1}(y))| = p(xz) * |det(J_g(y))|
            '''
            y = tf.reshape(y, [-1] + y.shape.as_list()[-3:])
            logpy = sumflat(Normal(0., 1.).log_prob(y))

            xz = y
            xz = tf.reshape(xz, [-1, 16, 16, 4*(x_dims+extra_dims)])
            xz, ld = self.flow.inverse(xz, **flow_kwargs)
            xz, logd_flow = self.vaeflow.inverse(xz, flow_kwargs)
            logd_flow += ld
            return xz, logpy + logd_flow

        def sample(self, num_samples, flow_kwargs):
            y = tf.random_normal([num_samples, 32, 32, x_dims + extra_dims])
            xz, logp_xz = self.inverse(y, flow_kwargs)
            x = xz[:,:,:,:x_dims]
            x, logd = ImgProc(max_val=x_max_val).inverse(x)
            return x, logp_xz + logd

    dequant_flow = Dequant()
    # dequant_flow = UnifDequant()
    posterior_flow = PosteriorLatent()

    flow = Generative()

    return dequant_flow, flow, posterior_flow

def main():
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument('--eval_checkpoint', type=str, default=None)
    args = parser.parse_args()

    batch_size = 64
    max_lr = 0.0012
    min_lr = 3e-4
    warmup_steps = 2000
    lr_decay = 0.99999

    def lr_schedule(step):
        global curr_lr
        if step < warmup_steps:
            return max_lr * step / warmup_steps
        elif step >= warmup_steps and step <= (25 * warmup_steps):
            curr_lr =  max_lr
            return max_lr
        elif step > (25 * warmup_steps) and curr_lr > min_lr:
            curr_lr *= lr_decay
            return curr_lr
        return curr_lr

    dropout_p = 0.2
    blocks = 10
    posterior_blocks = 3
    filters = dequant_filters = 96
    posterior_filters = 96
    components = 32  # logistic mixture components
    ema_decay = 0.999

    extra_dims = 3

    def flow_constructor():
        return construct(filters=filters, dequant_filters=dequant_filters, posterior_filters=posterior_filters, blocks=blocks, posterior_blocks=posterior_blocks, components=components, extra_dims=extra_dims)

    if args.eval_checkpoint:
        evaluate(flow_constructor=flow_constructor, seed=0, restore_checkpoint=args.eval_checkpoint, total_bs=1024)
        return

    train(
        flow_constructor=flow_constructor,
        logdir=f'~/logs/vflow_fbdq{dequant_filters}_blocks{blocks}_f{filters}_lr{max_lr}_drop{dropout_p}_extra_dims{extra_dims}_posterior_blocks{posterior_blocks}_batchsize{batch_size}',
        lr_schedule=lr_schedule,
        dropout_p=dropout_p,
        seed=0,
        init_bs=batch_size,
        total_bs=batch_size,
        val_total_bs=batch_size,
        ema_decay=ema_decay,
        steps_per_log=100,
        epochs_per_val=1,
        max_grad_norm=1.,
    )
    return

if __name__ == '__main__':
    main()


import logging
import unittest
from decimal import Decimal
from typing import List

import pandas as pd

from hummingbot.client.config.client_config_map import ClientConfigMap
from hummingbot.client.config.config_helpers import ClientConfigAdapter
from hummingbot.connector.exchange.paper_trade.paper_trade_exchange import QuantizationParams
from hummingbot.connector.test_support.mock_paper_exchange import MockPaperExchange
from hummingbot.core.clock import Clock, ClockMode
from hummingbot.core.data_type.common import TradeType
from hummingbot.core.data_type.order_book import OrderBook
from hummingbot.core.data_type.order_book_row import OrderBookRow
from hummingbot.core.event.event_logger import EventLogger
from hummingbot.core.event.events import MarketEvent, OrderBookTradeEvent
from hummingbot.strategy.market_trading_pair_tuple import MarketTradingPairTuple
from hummingbot.strategy.order_book_asset_price_delegate import OrderBookAssetPriceDelegate
from hummingbot.strategy.pure_market_making.pure_market_making import PureMarketMakingStrategy

logging.basicConfig(level=logging.ERROR)

# Update the orderbook so that the top bids and asks are lower than actual for a wider bid ask spread
# this basially removes the orderbook entries above top bid and below top ask
def simulate_order_book_widening(order_book: OrderBook, top_bid: float, top_ask: float):
    bid_diffs: List[OrderBookRow] = []
    ask_diffs: List[OrderBookRow] = []
    update_id: int = order_book.last_diff_uid + 1
    for row in order_book.bid_entries():
        if row.price > top_bid:
            bid_diffs.append(OrderBookRow(row.price, 0, update_id))
        else:
            break
    for row in order_book.ask_entries():
        if row.price < top_ask:
            ask_diffs.append(OrderBookRow(row.price, 0, update_id))
        else:
            break
    order_book.apply_diffs(bid_diffs, ask_diffs, update_id)

class PureMMTakeIfCrossUnitTest(unittest.TestCase):
    start: pd.Timestamp = pd.Timestamp("2019-01-01", tz="UTC")
    end: pd.Timestamp = pd.Timestamp("2019-01-01 01:00:00", tz="UTC")
    start_timestamp: float = start.timestamp()
    end_timestamp: float = end.timestamp()
    trading_pair = "HBOT-ETH"
    base_asset = trading_pair.split("-")[0]
    quote_asset = trading_pair.split("-")[1]

    def setUp(self):
        self.clock_tick_size = 1
        self.clock: Clock = Clock(ClockMode.BACKTEST, self.clock_tick_size, self.start_timestamp, self.end_timestamp)
        self.market: MockPaperExchange = MockPaperExchange(
            client_config_map=ClientConfigAdapter(ClientConfigMap())
        )
        self.mid_price = 100
        self.bid_spread = 0.01
        self.ask_spread = 0.01
        self.order_refresh_time = 30
        self.market.set_balanced_order_book(trading_pair=self.trading_pair,
                                            mid_price=self.mid_price,
                                            min_price=1,
                                            max_price=200,
                                            price_step_size=1,
                                            volume_step_size=10)
        self.market.set_balance("HBOT", 500)
        self.market.set_balance("ETH", 5000)
        self.market.set_quantization_param(
            QuantizationParams(
                self.trading_pair, 6, 6, 6, 6
            )
        )
        self.market_info = MarketTradingPairTuple(self.market, self.trading_pair,
                                                  self.base_asset, self.quote_asset)
        self.clock.add_iterator(self.market)
        self.order_fill_logger: EventLogger = EventLogger()
        self.cancel_order_logger: EventLogger = EventLogger()
        self.market.add_listener(MarketEvent.OrderFilled, self.order_fill_logger)
        self.market.add_listener(MarketEvent.OrderCancelled, self.cancel_order_logger)

        self.ext_market: MockPaperExchange = MockPaperExchange(
            client_config_map=ClientConfigAdapter(ClientConfigMap())
        )
        self.ext_market_info: MarketTradingPairTuple = MarketTradingPairTuple(
            self.ext_market, self.trading_pair, self.base_asset, self.quote_asset
        )
        self.ext_market.set_balanced_order_book(trading_pair=self.trading_pair,
                                                mid_price=100, min_price=1, max_price=400, price_step_size=1,
                                                volume_step_size=100)
        self.order_book_asset_del = OrderBookAssetPriceDelegate(self.ext_market, self.trading_pair)

        self.one_level_strategy = PureMarketMakingStrategy()
        self.one_level_strategy.init_params(
            self.market_info,
            bid_spread=Decimal("0.01"),
            ask_spread=Decimal("0.01"),
            order_amount=Decimal("1"),
            order_refresh_time=3.0,
            filled_order_delay=3.0,
            order_refresh_tolerance_pct=-1,
            minimum_spread=-1,
            asset_price_delegate=self.order_book_asset_del,
            take_if_crossed=True
        )

    def simulate_maker_market_trade(self, is_buy: bool, quantity: Decimal, price: Decimal):
        order_book = self.market.get_order_book(self.trading_pair)
        trade_event = OrderBookTradeEvent(
            self.trading_pair,
            self.clock.current_timestamp,
            TradeType.BUY if is_buy else TradeType.SELL,
            price,
            quantity
        )
        order_book.apply_trade(trade_event)

    def test_strategy_take_if_crossed_bid_order(self):
        simulate_order_book_widening(self.ext_market.get_order_book(self.trading_pair), 120.0, 130.0)
        self.strategy = self.one_level_strategy
        self.clock.add_iterator(self.strategy)
        self.clock.backtest_til(self.start_timestamp + self.clock_tick_size)
        self.assertEqual(0, len(self.order_fill_logger.event_log))
        self.assertEqual(1, len(self.strategy.active_buys))
        self.assertEqual(1, len(self.strategy.active_sells))

        self.clock.backtest_til(
            self.start_timestamp + 2 * self.clock_tick_size
        )
        self.assertEqual(1, len(self.order_fill_logger.event_log))
        self.assertEqual(0, len(self.strategy.active_buys))
        self.assertEqual(1, len(self.strategy.active_sells))

        self.clock.backtest_til(
            self.start_timestamp + 7 * self.clock_tick_size
        )
        self.assertEqual(2, len(self.order_fill_logger.event_log))
        self.assertEqual(0, len(self.strategy.active_buys))
        self.assertEqual(1, len(self.strategy.active_sells))

        self.clock.backtest_til(
            self.start_timestamp + 10 * self.clock_tick_size
        )
        self.assertEqual(3, len(self.order_fill_logger.event_log))
        self.assertEqual(0, len(self.strategy.active_buys))
        self.assertEqual(1, len(self.strategy.active_sells))
        self.order_fill_logger.clear()

    def test_strategy_take_if_crossed_ask_order(self):
        simulate_order_book_widening(self.ext_market.get_order_book(self.trading_pair), 80.0, 90.0)
        self.strategy = self.one_level_strategy
        self.clock.add_iterator(self.strategy)

        self.clock.backtest_til(self.start_timestamp + self.clock_tick_size)
        self.assertEqual(0, len(self.order_fill_logger.event_log))
        self.assertEqual(1, len(self.strategy.active_buys))
        self.assertEqual(1, len(self.strategy.active_sells))

        self.clock.backtest_til(
            self.start_timestamp + 2 * self.clock_tick_size
        )
        self.assertEqual(1, len(self.order_fill_logger.event_log))
        self.assertEqual(1, len(self.strategy.active_buys))
        self.assertEqual(0, len(self.strategy.active_sells))

        self.clock.backtest_til(
            self.start_timestamp + 6 * self.clock_tick_size
        )
        self.assertEqual(2, len(self.order_fill_logger.event_log))
        self.assertEqual(1, len(self.strategy.active_buys))
        self.assertEqual(0, len(self.strategy.active_sells))

        self.clock.backtest_til(
            self.start_timestamp + 10 * self.clock_tick_size
        )
        self.assertEqual(3, len(self.order_fill_logger.event_log))
        self.assertEqual(1, len(self.strategy.active_buys))
        self.assertEqual(0, len(self.strategy.active_sells))
        self.order_fill_logger.clear()