from flask import current_app, g, Flask, flash, jsonify, redirect, render_template, request, session, Response
import logging
import sqlite3
import json
import requests
from db import DB, KeyNotFound, BadRequest
import datetime

# Configure application
app = Flask(__name__)

app.config['JSON_SORT_KEYS'] = False

# Ensure templates are auto-reloaded
app.config["TEMPLATES_AUTO_RELOAD"] = True

# Needed to flash messages
app.secret_key = b'mEw6%7APK'

# path to database
DATABASE = 'splatDB.sqlite3'

# default path
@app.route('/')
def home():
    return render_template("home.html")

# hello world
@app.route('/hello')
def hello_world():
    data = {"message": "Hello, World!"}
    return jsonify(data)

# -----------------
# Create/Read Endpoints
# These JSON/REST api endpoints are used to add new records
# and return lookups based on Ids
# -------------------

# creates required table for application.
# note having a web endpoint for this is not a standard approach, but used for quick testing
@app.route('/create', methods=["GET"])
def create_tables():
    """
    Drops existing tables and creates new tables
    """
    db = DB(get_db_conn())
    return db.create_db('schema/create.sql')

@app.route('/artist', methods=["POST"])
def add_artist():
    """
    Loads a new appearance of song
    (and possibly a new song) into the database.
    """
    post_body = request.json
    if not post_body:
        logging.error("No post body")
        return Response(status=400)

    # get DB class with new connection
    db = DB(get_db_conn())

    try:
        db.add_artist(post_body)
    except BadRequest as e:
        raise InvalidUsage(e.message, status_code=e.error_code)
    except sqlite3.Error as e:
        print(e)
        raise InvalidUsage(str(e))
    return Response(status=201)

@app.route('/album', methods=["POST"])
def add_album():
    """
    Loads a new appearance of song
    (and possibly a new song) into the database.
    """
    post_body = request.json
    if not post_body:
        logging.error("No post body")
        return Response(status=400)

    # get DB class with new connection
    db = DB(get_db_conn())

    try:
        db.add_album(post_body)
    except BadRequest as e:
        raise InvalidUsage(e.message, status_code=e.error_code)
    except sqlite3.Error as e:
        print(e)
        raise InvalidUsage(str(e))
    return Response(status=201)

@app.route('/songs', methods=["POST"])
def add_song():
    """
    Loads a new appearance of song
    (and possibly a new song) into the database.
    """
    post_body = request.json
    if not post_body:
        logging.error("No post body")
        return Response(status=400)

    # get DB class with new connection
    db = DB(get_db_conn())

    try:
        db.add_song_ms2(post_body)
    except BadRequest as e:
        raise InvalidUsage(e.message, status_code=e.error_code)
    except sqlite3.Error as e:
        print(e)
        raise InvalidUsage(str(e))
    return Response(status=201)

@app.route('/playlists', methods=["POST"])
def add_playlist():
    """
    Adds a new playlist, with a list of ordered songs
    """
    post_body = request.json
    if not post_body:
        logging.error("No post body")
        return Response(status=400)

    # get DB class with new connection
    db = DB(get_db_conn())

    try:
        db.add_playlist(post_body)
    except BadRequest as e:
        raise InvalidUsage(e.message, status_code=e.error_code)
    except sqlite3.Error as e:
        print(e)
        raise InvalidUsage(str(e))
    return Response(status=201)

@app.route("/playcount", methods=["POST"])
def add_play():
    """
    Aad a play count detail
    Must have"play_count","song_id","date"
    May have a source as either a "playlist_id" OR "album_id" OR NEITHER (indicates a direct play)
    NOTE: Can have multiple calls for the same song, date, and source (playlist,album,or none)
    """
    post_body = request.json
    if not post_body:
        logging.error("No post body")
        return Response(status=400)

    # get DB class with new connection
    db = DB(get_db_conn())

    try:
        db.add_play(post_body)
    except BadRequest as e:
        raise InvalidUsage(e.message, status_code=e.error_code)
    except sqlite3.Error as e:
        print(e)
        raise InvalidUsage(str(e))
    return Response(status=201)

@app.route('/songs/<song_id>', methods=["GET"])
def find_song(song_id):
    """
    Returns a song's info
    (song_id, name, length, artist name, album name) based on song_id
    """
    # get DB class with new connection
    db = DB(get_db_conn())

    try:
        res = db.find_song(song_id)
        return jsonify(res)
    except KeyNotFound as e:
        print(e)
        raise InvalidUsage(e.message, status_code=404)
    except sqlite3.Error as e:
        print(e)
        raise InvalidUsage(str(e))
    return Response(status=400)

@app.route('/songs/by_album/<album_id>', methods=["GET"])
def find_songs_by_album(album_id):
    """
    Returns all an album's songs
    (song_id, name, length, artist name, album name) based on album_id
    """
    # get DB class with new connection
    db = DB(get_db_conn())

    try:
        res = db.find_songs_by_album(album_id)
        return jsonify(res)
    except KeyNotFound as e:
        print(e)
        raise InvalidUsage(e.message, status_code=404)
    except sqlite3.Error as e:
        print(e)
        raise InvalidUsage(str(e))
    return Response(status=400)

@app.route('/songs/by_artist/<artist_id>', methods=["GET"])
def find_songs_by_artist(artist_id):
    """
    Returns all an artists' songs
    (song_id, name, length, artist name, album name) based on artist_id
    """
    # get DB class with new connection
    db = DB(get_db_conn())

    try:
        res = db.find_songs_by_artist(artist_id)
        return jsonify(res)
    except KeyNotFound as e:
        print(e)
        raise InvalidUsage(e.message, status_code=404)
    except sqlite3.Error as e:
        print(e)
        raise InvalidUsage(str(e))
    return Response(status=400)

@app.route('/albums/<album_id>', methods=["GET"])
def find_album(album_id):
    """
    Returns a album's info
    (album_id, album_name, release_year).
    """
    # get DB class with new connection
    db = DB(get_db_conn())

    try:
        res = db.find_album(album_id)
        return jsonify(res)
    except KeyNotFound as e:
        print(e)
        raise InvalidUsage(e.message, status_code=404)
    except sqlite3.Error as e:
        print(e)
        raise InvalidUsage(str(e))
    return Response(status=400)

@app.route('/albums/by_artist/<artist_id>', methods=["GET"])
def find_album_by_artist(artist_id):
    """
    Returns a album's info
    (album_id, album_name, release_year).
    """
    # get DB class with new connection
    db = DB(get_db_conn())

    try:
        res = db.find_album_by_artist(artist_id)
        return jsonify(res)
    except KeyNotFound as e:
        print(e)
        raise InvalidUsage(e.message, status_code=404)
    except sqlite3.Error as e:
        print(e)
        raise InvalidUsage(str(e))
    return Response(status=400)

@app.route('/artists/<artist_id>', methods=["GET"])
def find_artist(artist_id):
    """
    Returns a artist's info
    (artist_id, artist_name, country).
    """
    # get DB class with new connection
    db = DB(get_db_conn())

    try:
        res = db.find_artist(artist_id)
        return jsonify(res)
    except KeyNotFound as e:
        print(e)
        raise InvalidUsage(e.message, status_code=404)
    except sqlite3.Error as e:
        print(e)
        raise InvalidUsage(str(e))
    return Response(status=400)

# -----------------
# Analytics Endpoints
# These JSON/REST api endpoints are used to run analysis
# over the dataset and calculate an aggregated answer
# -------------------

@app.route('/analytics/artists/avg_song_length/<artist_id>', methods=["GET"])
def avg_song_length(artist_id):
    """
    Returns the average length of an artist's songs (artist_id, avg_length)
    """
    # get DB class with new connection
    db = DB(get_db_conn())

    try:
        res = db.avg_song_length(artist_id)
        return jsonify(res)
    except KeyNotFound as e:
        print(e)
        raise InvalidUsage(e.message, status_code=404)
    except sqlite3.Error as e:
        print(e)
        raise InvalidUsage(str(e))
    return Response(status=400)

@app.route('/analytics/artists/cnt_singles/<artist_id>', methods=["GET"])
def cnt_singles(artist_id):
    """
    Returns the number of singles an artist has (artist_id, cnt_single)
    """
    # get DB class with new connection
    db = DB(get_db_conn())

    try:
        res = db.cnt_singles(artist_id)
        return jsonify(res)
    except KeyNotFound as e:
        print(e)
        raise InvalidUsage(e.message, status_code=404)
    except sqlite3.Error as e:
        print(e)
        raise InvalidUsage(str(e))
    return Response(status=400)

@app.route('/analytics/artists/top_length/<num_artists>', methods=["GET"])
def top_length(num_artists):
    """
    Returns top (n=num_artists) artists based on total length of songs
    (artist_id, total_length).
    """
    # get DB class with new connection
    db = DB(get_db_conn())

    try:
        res = db.top_length(num_artists)
        return jsonify(res)
    except KeyNotFound as e:
        print(e)
        raise InvalidUsage(e.message, status_code=404)
    except sqlite3.Error as e:
        print(e)
        raise InvalidUsage(str(e))
    return Response(status=400)

@app.route('/analytics/solo_albums', methods=["GET"])
def solo_albums():
    """
    Returns an array/list of album_ids where the album
    and all songs are by the same single artist_id
    """
    # get DB class with new connection
    db = DB(get_db_conn())
    try:
        res = db.solo_albums()
        return jsonify(res)
    except BadRequest as e:
        print(e)
        raise InvalidUsage(e.message, status_code=404)
    except sqlite3.Error as e:
        print(e)
        raise InvalidUsage(str(e))
    return Response(status=400)

# Convert a YYYY-MM-DD string to a datetime.date. Raises BadRequest if not in the right format
# or if not a valid date.
# From https://stackoverflow.com/questions/53460391/passing-a-date-as-a-url-parameter-to-a-flask-route
# Better function exists in 3.7+ adding this to support 3.6+
def to_date(date_string):
    try:
        return datetime.datetime.strptime(date_string, "%Y-%m-%d").date()
    except ValueError:
        raise BadRequest('{} is not valid date in the format YYYY-MM-DD'.format(date_string))

@app.route('/analytics/playcount/top_song/<date_string>', methods=["GET"])
def top_song(date_string):
    """
    Get the top song played on a given date
    The test data does not account for ties/ have ties. if you want to break them use song_id ascending.
    """
    # get DB class with new connection
    db = DB(get_db_conn())
    try:
        check_date = to_date(date_string)
        res = db.top_song(check_date)
        return jsonify(res)
    except BadRequest as e:
        raise InvalidUsage(e.message, status_code=400)
    except KeyNotFound as e:
        print(e)
        raise InvalidUsage(e.message, status_code=404)
    except sqlite3.Error as e:
        print(e)
        raise InvalidUsage(str(e))
    return Response(status=400)

@app.route('/analytics/playcount/top_source/<song_id>/<date_string>', methods=["GET"])
def top_source(song_id, date_string):
    """
    For a given song and date, return the source that contributed to the most plays
    This could be a given playlist_id, a given album_id, or None (a direct play)
    The test data does not account for ties.
    If you want to want to account for ties, give all sources that have the same (top) play_count
    """
    # get DB class with new connection
    db = DB(get_db_conn())
    try:
        check_date = to_date(date_string)
        res = db.top_source(song_id, check_date)
        return jsonify(res)
    except BadRequest as e:
        raise InvalidUsage(e.message, status_code=400)
    except KeyNotFound as e:
        print(e)
        raise InvalidUsage(e.message, status_code=404)
    except sqlite3.Error as e:
        print(e)
        raise InvalidUsage(str(e))
    return Response(status=400)

@app.route('/analytics/playcount/top_country/<date_string>', methods=["GET"])
def top_country(date_string):
    """
    This is an extra credit MS that for a given date , it gives the country
    with the most play
    """
    # get DB class with new connection
    db = DB(get_db_conn())
    try:
        check_date = to_date(date_string)
        res = db.top_country(check_date)
        return jsonify(res)
    except BadRequest as e:
        raise InvalidUsage(e.message, status_code=400)
    except KeyNotFound as e:
        print(e)
        raise InvalidUsage(e.message, status_code=404)
    except sqlite3.Error as e:
        print(e)
        raise InvalidUsage(str(e))
    return Response(status=400)

# -----------------
# Web APIs
# These simply wrap requests from the website/browser and
# invoke the underlying REST / JSON API.
# -------------------

# paste in a query
@app.route('/web/query', methods=["GET", "POST"])
def query():
    """
    runs pasted in query
    """

    data = None
    if request.method == "POST":
        qry = request.form.get("query")
        # Ensure query was submitted

        # get DB class with new connection
        db = DB(get_db_conn())

        # note DO NOT EVER DO THIS NORMALLY (run SQL from a client/web directly)
        # https://xkcd.com/327/
        try:
            res = db.run_query(str(qry))
        except sqlite3.Error as e:
            print(e)
            return render_template("error.html", errmsg=str(e), errcode=400)

        data = res
    return render_template("query.html", data=data)

# paste in a query
@app.route('/web/post_data', methods=["GET", "POST"])
def post_song_web():
    """
    runs simple post song json
    """

    data = None
    if request.method == "POST":
        parameter = request.form.get("path")
        if parameter is None or parameter.strip() == "":
            flash("Must set key")
            return render_template("post_data.html", data=data)

        get_url = "http://127.0.0.1:5000/%s" % parameter
        print("Making request to %s" % get_url)
        # grab the response

        j = json.loads(request.form.get("json_data").strip())
        print("Json from form: %s" % j)
        r = requests.post(get_url, json=j)
        if r.status_code >= 400:
            print("Error.  %s  Body: %s" % (r, r.content))
            return render_template("error.html", errmsg=r.json(), errcode=r.status_code)

        else:
            flash("Ran post command")
        return render_template("post_data.html", data=None)
    return render_template("post_data.html", data=None)

@app.route('/web/create', methods=["GET"])
def create_web():
    get_url = "http://127.0.0.1:5000/create"
    print("Making request to %s" % get_url)
    # grab the response
    r = requests.get(get_url)
    if r.status_code >= 400:
        print("Error.  %s  Body: %s" % (r, r.content))
        return render_template("error.html", errmsg=r.json(), errcode=r.status_code)

    else:
        flash("Ran create command")
        data = r.json()
    return render_template("home.html", data=data)

@app.route('/web/songs', methods=["GET", "POST"])
def song_landing():
    data = None
    if request.method == "POST":
        path = request.form.get("path")

        parameter = request.form.get("parameter")
        if parameter is None or parameter.strip() == "":
            flash("Must set key")
            return render_template("songs.html", data=data)

        get_url = "http://127.0.0.1:5000/songs/" + path + parameter
        print("Making request to %s" % get_url)
        # grab the response
        r = requests.get(get_url)
        if r.status_code >= 400:
            print("Error.  %s  Body: %s" % (r, r.content))
            return render_template("error.html", errmsg=r.json(), errcode=r.status_code)

        else:
            data = r.json()
    return render_template("songs.html", data=data)

@app.route('/web/artists', methods=["GET", "POST"])
def artists_landing():
    data = None
    if request.method == "POST":
        path = request.form.get("path")
        # Ensure path was submitted

        parameter = request.form.get("parameter")
        if parameter is None or parameter.strip() == "":
            flash("Must set key")
            return render_template("artists.html", data=data)

        get_url = "http://127.0.0.1:5000/artists/" + path + parameter
        # grab the response
        r = requests.get(get_url)
        if r.status_code >= 400:
            print("Error.  %s  Body: %s" % (r, r.content))
            return render_template("error.html", errmsg=r.json(), errcode=r.status_code)

        else:
            data = r.json()
    return render_template("artists.html", data=data)

@app.route('/web/albums', methods=["GET", "POST"])
def albums_landing():
    data = None
    if request.method == "POST":
        path = request.form.get("path")
        # Ensure path was submitted

        parameter = request.form.get("parameter")
        if parameter is None or parameter.strip() == "":
            flash("Must set key")
            return render_template("albums.html", data=data)

        get_url = "http://127.0.0.1:5000/albums/" + path + parameter
        # grab the response
        r = requests.get(get_url)
        if r.status_code >= 400:
            print("Error.  %s  Body: %s" % (r, r.content))
            return render_template("error.html", errmsg=r.json(), errcode=r.status_code)
        else:
            data = r.json()
    return render_template("albums.html", data=data)

@app.route('/web/analytics', methods=["GET", "POST"])
def analytics_landing():
    data = None
    if request.method == "POST":
        path = request.form.get("path")
        # Ensure path was submitted

        if path == "solo_albums":
            get_url = "http://127.0.0.1:5000/analytics/" + path
        elif path == "playcount/top_song/" or path == "playcount/top_country/":
            date = request.form.get("date")
            if date is None or date.strip() == "":
                flash("Must set key")
                return render_template("analytics.html", data=data)

            get_url = "http://127.0.0.1:5000/analytics/" + path + date
        elif path == "playcount/top_source/":
            parameter = request.form.get("parameter")
            if parameter is None or parameter.strip() == "":
                flash("Must set key")
                return render_template("analytics.html", data=data)
            parameter2 = request.form.get("parameter2")
            if parameter2 is None or parameter2.strip() == "":
                flash("Must set key")
                return render_template("analytics.html", data=data)
            get_url = "http://127.0.0.1:5000/analytics/" + path + parameter + '/' + parameter2
        else:
            parameter = request.form.get("parameter")
            if parameter is None or parameter.strip() == "":
                flash("Must set key")
                return render_template("analytics.html", data=data)

            get_url = "http://127.0.0.1:5000/analytics/" + path + parameter

        # grab the response
        print(get_url)
        r = requests.get(get_url)
        if r.status_code >= 400:
            print("Error.  %s  Body: %s" % (r, r.content))
            return render_template("error.html", errmsg=r.json(), errcode=r.status_code)

        else:
            data = r.json()
    return render_template("analytics.html", data=data)

# -----------------
# Utilities / Errors
# -------------------

# gets connection to database
def get_db_conn():
    db = getattr(g, '_database', None)
    if db is None:
        db = g._database = sqlite3.connect(DATABASE)

    return db

# Error Class for managing Errors
class InvalidUsage(Exception):
    status_code = 400

    def __init__(self, message, status_code=None, payload=None):
        Exception.__init__(self)
        self.message = message
        if status_code is not None:
            self.status_code = status_code
        self.payload = payload

    def to_dict(self):
        rv = dict(self.payload or ())
        rv['message'] = self.message
        return rv

@app.errorhandler(InvalidUsage)
def handle_invalid_usage(error):
    response = jsonify(error.to_dict())
    response.status_code = error.status_code
    return response

# called on close of response; closes db connection
@app.teardown_appcontext
def close_connection(exception):
    db = getattr(g, '_database', None)
    if db is not None:
        db.close()

# ########### post MS1 ############## #


from copy import deepcopy
from pandas import DataFrame as DF
from scipy.spatial.transform import Slerp
from scipy.spatial.transform import Rotation as R
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import os

id = 0
USE_SLERP = False
class Sample:
    def __init__(
        self,
        source: str,
        continuity_index: int,
        activity: str,
        gyro: DF,
        accelerometer: DF,
        orient: DF,
        gravity: DF,
    ):
        global id
        self.id = id
        id += 1

        self.source = source
        self.continuity_index = continuity_index
        self.activity = activity

        self.gyro = gyro
        self.accelerometer = accelerometer
        self.orient = orient
        self.gravity = gravity

    def __repr__(self):
        classname = self.__class__.__name__
        return f"{classname} {self.id}: {self.activity}"

    def plot_sensor_data(self, sensor_data, title, domain = (0, float("inf"))):
        """Helper function to plot a specific sensor's data."""
        df = sensor_data

        filtered = df[df["time"] < domain[1] * 1e10]
        filtered = filtered[filtered["time"] > domain[0] * 1e10]
        for col in df.columns:
            # if col != "time":
            if col not in ["time", "roll", "pitch", "yaw"]:
                plt.plot(filtered["time"], filtered[col], label=col)

        plt.title(title)
        plt.legend()

    def getLength(self):
        return self.gyro["time"].iloc[-1] * 1e-9 - self.gyro["time"].iloc[0]* 1e-9

    def graph(self, domain=(0, float("inf"))):
        """Plots the data for all sensors in separate subplots."""
        fig, axs = plt.subplots(4, 1, figsize=(10, 20))

        fig.suptitle(f"Data Source: {self.source}", fontsize=16, y=1.05)

        plt.subplot(4, 1, 1)
        self.plot_sensor_data(self.gyro, "Gyroscope Data", domain)

        plt.subplot(4, 1, 2)
        self.plot_sensor_data(self.accelerometer, "Accelerometer Data", domain)

        plt.subplot(4, 1, 3)
        self.plot_sensor_data(self.orient, "Orientation Data", domain)

        plt.subplot(4, 1, 4)
        self.plot_sensor_data(self.gravity, "Gravity Data", domain)

        plt.tight_layout()
        plt.show()

    def _plot_sensor_data_edges(self, subplot, sensor_data, title, margin_sec: int):
        """Helper function to plot a specific sensor's data."""
        df = sensor_data

        offset_nanosec = margin_sec * 1e9
        start_split = df[df["time"] > offset_nanosec].index[0]
        df_start = df.loc[: start_split - 1]

        maxtime = df["time"].iloc[-1]
        end_split = df[df["time"] > maxtime - offset_nanosec].index[0]
        df_end = df.loc[end_split:]

        plt.subplot(subplot)
        time_data = df_start["time"]
        for col in df_start.columns:
            if col != "time":
                plt.plot(time_data * 1e-9, df_start[col], label=col)

        plt.title(title)
        plt.legend()

        plt.subplot(subplot + 1)
        plt.title(title)
        # plt.legend() results in: No artists with labels found to put in legend.  Note that artists whose label start with an underscore are ignored when legend() is called with no argument.
        time_data = df_end["time"]
        for col in df_end.columns:
            if col != "time":
                plt.plot((time_data - maxtime) * 1e-9, df_end[col], label=col)

    def graph_edges(self, margin):
        """Plots the data for all sensors in separate subplots."""
        fig, axs = plt.subplots(4, 2, figsize=(10, 20))

        fig.suptitle(f"Data Source: {self.source}", fontsize=16, y=1.05)

        self._plot_sensor_data_edges(421, self.gyro, "Gyroscope Data", margin)
        self._plot_sensor_data_edges(
            423, self.accelerometer, "Accelerometer Data", margin
        )
        self._plot_sensor_data_edges(425, self.orient, "Orientation Data", margin)
        self._plot_sensor_data_edges(427, self.gravity, "Gravity Data", margin)

        plt.tight_layout()
        plt.show(block=True)

    def showAccPlot(self, window=128):
        acc_128 = self.accelerometer[0:window]
        print(acc_128.shape)

        x = acc_128['x']
        y = acc_128['y']
        z = acc_128['z']
        index = np.arange(0, window, 1)

        fig = plt.gcf()
        fig.set_size_inches(15, 8)
        plt.title(f"Accelerometer - {self.activity} - {window} samples")

        plt.plot(index, x, label="x")
        plt.plot(index, y, label="y")
        plt.plot(index, z, label="z")

        plt.legend()
        plt.show()

    def save_trim(self, start, end):
        with open(os.path.join(self.source, "trim.txt"), "w") as f:
            f.write(f"{start}|{end}")

    def resample(self, frequency_hz: float):
        interval_ms = 1 / frequency_hz
        self.gyro = resample_sensor(self.gyro, interval_ms)
        self.accelerometer = resample_sensor(self.accelerometer, interval_ms)
        if USE_SLERP:
            self.orient = resample_sensor_quaternion(self.orient, interval_ms)
        else:
            self.orient = resample_sensor(self.orient, interval_ms)
        self.gravity = resample_sensor(self.gravity, interval_ms)

    def synchronize(self):
        """Effect:
        All sensors are split into the same time windows
        e.g. if sample had gyro readings in seconds [1, 5]
        but accelerometer [3, 6], synchronized would have readings
        for both in time window [3, 5].
        Necessary for models taking multiple sensors as inputs
        """
        pass  # TODO

def resample_sensor(sensor: DF, interval_ms: float):
    df = deepcopy(sensor) # for immutability, if performance gets too bad, remove and pray nothing breaks
    mi = np.min(df['time'])
    ma = np.max(df['time'])
    # print(mi, ma)
    df['time'] = pd.to_datetime(df['time'])
    df.set_index('time', inplace=True)
    resampled_df = df.resample(f'{interval_ms}L').mean()
    resampled_df_interpolated = resampled_df.interpolate(method='linear')
    df_reset = resampled_df_interpolated.reset_index()
    df_reset['time'] = df_reset['time'].astype('int64')
    df_reset.rename(columns={'index': 'time'}, inplace=True)
    # return df_reset
    return df_reset[(df_reset['time'] >= mi) & (df_reset['time'] <= ma)]

def resample_sensor_quaternion(df: DF, interval_ms: float):
    if df.empty:
        return df

    times = pd.to_timedelta(df['time'] / 1e9, unit="seconds").dt.total_seconds()

    if df[['qx', 'qy', 'qz', 'qw']].isnull().values.any():
        raise ValueError("NaN values found in quaternion data.")

    quaternions = df[['qx', 'qy', 'qz', 'qw']].to_numpy()
    if quaternions.shape[1] != 4:
        raise ValueError(f"Quaternion data has invalid shape: {quaternions.shape}")

    df = resample_sensor(df[['time', 'roll', 'pitch', 'yaw']], interval_ms)
    rotations = R.from_quat(quaternions)
    slerp = Slerp(times, rotations)
    new_rotations = slerp(df.time / 1e9)
    new_quats = new_rotations.as_quat()
    quaternion_df = pd.DataFrame(new_quats, columns=['qx', 'qy', 'qz', 'qw'])
    final_df = pd.concat([df, quaternion_df], axis=1)

    return final_df


def bubble_up_max(node, heap):
    heap.append(node)
    i = len(heap) - 1

    while (heap[i // 2] < node) :
        new_i = i // 2
        heap[new_i], heap[i] = heap[i],  heap[new_i]
        i = new_i

def bubble_up_min(node, heap):
    heap.append(node)
    i = len(heap) - 1

    while (heap[i // 2] > node) :
        new_i = i // 2
        heap[new_i], heap[i] = heap[i],  heap[new_i]
        i = new_i

def sift_down_max(node, heap):
    i = 0
    while True:
        if (heap[i] < heap[2 * i + 1]):
            new_i = i * 2 + 1
            heap[new_i], heap[i] = heap[i],  heap[new_i]
            i = new_i

        elif (heap[i] < heap[2 * i + 1]):
             new_i = i * 2 + 2
             heap[new_i], heap[i] = heap[i],  heap[new_i]
             i = new_i
        else:
            break

def sift_down_min(node, heap):
    i = 0
    while True:
        if (heap[i] > heap[2 * i + 1]):
            new_i = i * 2 + 1
            heap[new_i], heap[i] = heap[i],  heap[new_i]
            i = new_i

        elif (heap[i] > heap[2 * i + 1]):
             new_i = i * 2 + 2
             heap[new_i], heap[i] = heap[i],  heap[new_i]
             i = new_i
        else:
            break

def heapify(initial, param):
    heap = []
    for node in (initial):
        if param == "max":
             bubble_up_max(node, heap)
        elif param == "min":
            bubble_up_min(node, heap)

    return heap

def print_tree(heap):
    for index, node in enumerate(heap):
        if index * 2 + 2 < len(heap):
             print(node, "-> (", heap[index * 2 + 1], ",", heap[index * 2 + 2], ")")

if __name__ == "__main__":
    size = int(input("size of the array?"))
    initial_array = [int(input("enter an element:")) for i in range(size)]

    param = input("min heap or max heap? ")
    heap = (heapify(initial_array, param=param))
    print(heap)
    print_tree(heap)


load("@gapid//tools/build:cc_toolchain.bzl", "cc_configure")
load("@gapid//tools/build/rules:android.bzl", "android_native_app_glue", "ndk_vk_validation_layer", "ndk_version_check")
load("@gapid//tools/build/rules:repository.bzl", "github_repository", "maybe_repository")
load("@gapid//tools/build/third_party:breakpad.bzl", "breakpad")
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository", "new_git_repository")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

# Defines the repositories for GAPID's dependencies, excluding the
# go dependencies, which require @io_bazel_rules_go to be setup.
#  android - if false, the Android NDK/SDK are not initialized.
#  mingw - if false, our cc toolchain, which uses MinGW on Windows is not initialized.
#  locals - can be used to provide local path overrides for repos:
#     {"foo": "/path/to/foo"} would cause @foo to be a local repo based on /path/to/foo.
def gapid_dependencies(android = True, mingw = True, locals = {}):
    #####################################################
    # Get repositories with workspace rules we need first

    maybe_repository(
        github_repository,
        name = "io_bazel_rules_go",
        locals = locals,
        organization = "bazelbuild",
        project = "rules_go",
        commit = "efc3212592320c1ab7f986c9a7882770ee06ad3b",  # 0.34.0
        sha256 = "eb10f4436ddc732127afedf78636637d0cc9b256aba9f643a452914289266e6b",
    )

    maybe_repository(
        github_repository,
        name = "rules_python",
        locals = locals,
        organization = "bazelbuild",
        project = "rules_python",
        commit = "9bf7c49ea1920e497f857ccc1e9c2d1189c8a1c9",
        sha256 = "ebeae40415e1ac0ab4e4323f91d6213ec799ad8fcacecd4c499009e1d8d2eb51",
    )

    maybe_repository(
        github_repository,
        name = "bazel_gazelle",
        locals = locals,
        organization = "bazelbuild",
        project = "bazel-gazelle",
        commit = "e9091445339de2ba7c01c3561f751b64a7fab4a5",  # 0.23.0
        sha256 = "03e266ed67fd21f6fbede975773a569d397312daae71980d34ff7f7e087b7b14",
    )

    maybe_repository(github_repository,
        name = "net_zlib", # name used by rules_go
        locals = locals,
        organization = "madler",
        project = "zlib",
        commit = "21767c654d31d2dccdde4330529775c6c5fd5389",  # 1.2.12
        build_file = "@gapid//tools/build/third_party:zlib.BUILD",
        sha256 = "b860a877983100f28c7bcf2f3bb7abbca8833e7ce3af79edfda21358441435d3",
    )

    maybe_repository(
        github_repository,
        name = "com_google_protobuf",
        locals = locals,
        organization = "google",
        project = "protobuf",
        commit = "ab840345966d0fa8e7100d771c92a73bfbadd25c",  # 3.21.5
        sha256 = "0025119f5c97871436b4b271fee48bd6bfdc99956023e0d4fd653dd8eaaeff52",
        repo_mapping = {"@zlib": "@net_zlib"},
    )

    maybe_repository(
        github_repository,
        name = "com_github_grpc_grpc",
        locals = locals,
        organization = "grpc",
        project = "grpc",
        commit = "d2054ec6c6e8abcecf0e24b0b4ee75035d80c3cc",  # 1.48.0
        sha256 = "ea0da456d849eafa5287dc1e9d53c065896dca2cd896a984101ebe0708979dca",
        repo_mapping = {"@zlib": "@net_zlib"},
        patches = [
            # Remove calling the go dependencies, since we do that ourselves.
            "@gapid//tools/build/third_party:com_github_grpc_grpc.patch",
        ],
    )

    ###########################################
    # Now get all our other non-go dependencies

    maybe_repository(
        github_repository,
        name = "com_google_googletest",
        locals = locals,
        organization = "google",
        project = "googletest",
        commit = "58d77fa8070e8cec2dc1ed015d66b454c8d78850",  # 1.12.1
        sha256 = "ab78fa3f912d44d38b785ec011a25f26512aaedc5291f51f3807c592b506d33a",
    )

    maybe_repository(
        github_repository,
        name = "astc_encoder",
        locals = locals,
        organization = "ARM-software",
        project = "astc-encoder",
        commit = "f6236cf158a877b3279a2090dbea5e9a4c105d64",  # 4.0.0
        build_file = "@gapid//tools/build/third_party:astc-encoder.BUILD",
        sha256 = "28305281b0fe89b0e57c61f684ed7f6145a5079a3f4f03a4fd3fe0c27df0bb45",
    )

    maybe_repository(
        github_repository,
        name = "etc2comp",
        locals = locals,
        organization = "google",
        project = "etc2comp",
        commit = "9cd0f9cae0f32338943699bb418107db61bb66f2", # 2017/04/24
        build_file = "@gapid//tools/build/third_party:etc2comp.BUILD",
        sha256 = "0ddcf7484c0d55bc5a3cb92edb4812dc932ac9f73b4641ad2843fec82ae8cf90",
    )

    maybe_repository(
        breakpad,
        name = "breakpad",
        locals = locals,
        commit = "335e61656fa6034fabc3431a91e5800ba6fc3dc9",
        build_file = "@gapid//tools/build/third_party/breakpad:breakpad.BUILD",
    )

    maybe_repository(
        github_repository,
        name = "cityhash",
        locals = locals,
        organization = "google",
        project = "cityhash",
        commit = "f5dc54147fcce12cefd16548c8e760d68ac04226",
        build_file = "@gapid//tools/build/third_party:cityhash.BUILD",
        sha256 = "20ab6da9929826c7c81ea3b7348190538a23f823a8b749c2da9715ecb7a6b545",
    )

    # Override the gRPC abseil dependency, so we can patch it.
    maybe_repository(
        github_repository,
        name = "com_google_absl",
        locals = locals,
        organization = "abseil",
        project = "abseil-cpp",
        commit = "273292d1cfc0a94a65082ee350509af1d113344d",  # LTS 20220623, Patch 0
        sha256 = "6764f226bd6e2d8ab9fe2f3cab5f45fb1a4a15c04b58b87ba7fa87456054f98b",
        patches = [
            # Workaround for https://github.com/abseil/abseil-cpp/issues/326.
            "@gapid//tools/build/third_party:abseil_macos_fix.patch",
            # Pick up bcrypt library on Windows.
            "@gapid//tools/build/third_party:abseil_windows_fix.patch",
        ],
    )

    maybe_repository(
        github_repository,
        name = "glslang",
        locals = locals,
        organization = "KhronosGroup",
        project = "glslang",
        commit = "73c9630da979017b2f7e19c6549e2bdb93d9b238",  # 11.11.0
        sha256 = "9304cb73d86fc8e3f1cbcdbd157cd2750baad10cb9e3a798986bca3c3a1be1f0",
    )

    maybe_repository(
        github_repository,
        name = "stb",
        locals = locals,
        organization = "nothings",
        project = "stb",
        commit = "af1a5bc352164740c1cc1354942b1c6b72eacb8a",
        sha256 = "e3d0edbecd356506d3d69b87419de2f9d180a98099134c6343177885f6c2cbef",
        build_file = "@gapid//tools/build/third_party:stb.BUILD",
    )

    maybe_repository(
        new_git_repository,
        name = "lss",
        locals = locals,
        remote = "https://chromium.googlesource.com/linux-syscall-support",
        commit = "c0c9689369b4c5e46b440993807ce4b0a7c9af8a",
        build_file = "@gapid//tools/build/third_party:lss.BUILD",
        shallow_since = "1660655052 +0000",
    )

    maybe_repository(
        github_repository,
        name = "perfetto",
        locals = locals,
        organization = "google",
        project = "perfetto",
        commit = "0ff403688efce9d5de43d69cae3c835e993e4730",  # 29+
        sha256 = "e609a91a6d64caf9a4e4b64f1826d160eba8fd84f7e5e94025ba287374e78e30",
        patches = [
            # Fix a Windows MinGW build issue.
            "@gapid//tools/build/third_party:perfetto.patch",
        ]
    )

    maybe_repository(
        http_archive,
        name = "sqlite",
        locals = locals,
        url = "https://storage.googleapis.com/perfetto/sqlite-amalgamation-3350400.zip",
        sha256 = "f3bf0df69f5de0675196f4644e05d07dbc698d674dc563a12eff17d5b215cdf5",
        strip_prefix = "sqlite-amalgamation-3350400",
        build_file = "@perfetto//bazel:sqlite.BUILD",
    )

    maybe_repository(
        http_archive,
        name = "sqlite_src",
        locals = locals,
        url = "https://storage.googleapis.com/perfetto/sqlite-src-3320300.zip",
        sha256 = "9312f0865d3692384d466048f746d18f88e7ffd1758b77d4f07904e03ed5f5b9",
        strip_prefix = "sqlite-src-3320300",
        build_file = "@perfetto//bazel:sqlite.BUILD",
    )

    maybe_repository(
        native.new_local_repository,
        name = "perfetto_cfg",
        locals = locals,
        path = "tools/build/third_party/perfetto",
        build_file = "@gapid//tools/build/third_party/perfetto:BUILD.bazel",
    )

    maybe_repository(
        github_repository,
        name = "spirv_headers",
        locals = locals,
        organization = "KhronosGroup",
        project = "SPIRV-Headers",
        commit = "b2a156e1c0434bc8c99aaebba1c7be98be7ac580",  # 1.3.216.0
        sha256 = "fbb4e256c2e9385169067d3b6f2ed3800f042afac9fb44a348b619aa277bb1fd",
    )

    maybe_repository(
        github_repository,
        name = "spirv_cross",
        locals = locals,
        organization = "KhronosGroup",
        project = "SPIRV-Cross",
        commit = "0e2880ab990e79ce6cc8c79c219feda42d98b1e8",  # 2021-08-30
        build_file = "@gapid//tools/build/third_party:spirv-cross.BUILD",
        sha256 = "7ae1069c29f507730ffa5143ac23a5be87444d18262b3b327dfb00ca53ae07cd",
    )

    maybe_repository(
        github_repository,
        name = "spirv_tools",
        locals = locals,
        organization = "KhronosGroup",
        project = "SPIRV-Tools",
        commit = "b930e734ea198b7aabbbf04ee1562cf6f57962f0",  # 1.3.216.0
        sha256 = "2d956e7d49a8795335d13c3099c44aae4fe501eb3ec0dbf7e1bfa28df8029b43",
    )

    maybe_repository(
        github_repository,
        name = "spirv_reflect",
        locals = locals,
        organization = "KhronosGroup",
        project = "SPIRV-Reflect",
        commit = "0f142bbfe9bd7aeeae6b3c703bcaf837dba8df9d",  # 1.3.216.0
        sha256 = "8eae9dcd2f6954b452a9a53b02ce7507dd3dcd02bacb678c4316f336dab79d86",
    )

    maybe_repository(
        http_archive,
        name = "vscode-languageclient",
        locals = locals,
        url = "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-2.6.3.tgz",
        build_file = "@gapid//tools/build/third_party:vscode-languageclient.BUILD",
        sha256 = "42ad6dc73bbf24a067d1e21038d35deab975cb207ac2d63b81c37a977d431d8f",
    )

    maybe_repository(
        http_archive,
        name = "vscode-jsonrpc",
        locals = locals,
        url = "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-2.4.0.tgz",
        build_file = "@gapid//tools/build/third_party:vscode-jsonrpc.BUILD",
        sha256= "bed9b2facb7d179f14c8a710db8e613be56bd88b2a75443143778813048b5c89",
    )

    maybe_repository(
        http_archive,
        name = "vscode-languageserver-types",
        locals = locals,
        url = "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-1.0.4.tgz",
        build_file = "@gapid//tools/build/third_party:vscode-languageserver-types.BUILD",
        sha256 = "0cd219ac388c41a70c3ff4f72d25bd54fa351bc0850196c25c6c3361e799ac79",
    )

    maybe_repository(
        github_repository,
        name = "vulkan-headers",
        locals = locals,
        organization = "KhronosGroup",
        project = "Vulkan-Headers",
        commit = "3ef4c97fd6ea001d75a8e9da408ee473c180e456",  # 1.3.216
        build_file = "@gapid//tools/build/third_party:vulkan-headers.BUILD",
        sha256 = "64a7fc6994501b36811af47b21385251a56a136a3ed3cf92673465c9d62985a1",
    )

    if android:
        maybe_repository(
            native.android_sdk_repository,
            name = "androidsdk",
            locals = locals,
            api_level = 26, # This is the target API
            build_tools_version = "30.0.3",
        )

        maybe_repository(
            native.android_ndk_repository,
            name = "androidndk",
            locals = locals,
            api_level = 23, # This is the minimum API
        )

        maybe_repository(
            android_native_app_glue,
            name = "android_native_app_glue",
            locals = locals,
        )

        maybe_repository(
            ndk_vk_validation_layer,
            name = "ndk_vk_validation_layer",
            locals = locals,
        )

        maybe_repository(
            ndk_version_check,
            name = "ndk_version_check",
            locals = locals,
        )

    if mingw:
        cc_configure()


def solution(people, tshirts):
    answer = 0
    people.sort()
    tshirts.sort()

    for p in range(len(people)):
        if people[p] in tshirts:
            del tshirts[tshirts.index(people[p])]
            answer += 1
        elif people[p] not in tshirts:
            tshirts = [i for i in tshirts if i > people[p]]
            if len(tshirts) > 0:
                answer += 1
                del tshirts[0]
    return answer
print(solution([2, 3, 4], [1, 2, 3]))

프로그래머스/피어리뷰/1주차 중간고사_2.py

1주차 중간고사_2.py


# -*- coding: utf-8 -*-
"""
Created on Thu May 28 11:29:23 2020

@author: jampi
"""

"""BUG FIX NOTES:
    -needs functions change so intake array is not edited array
"""

import csv

#Function to cut eva
def cut_eva(EVA_width, cut_list_in, cut_pieces_in = [],EVA_consumption_length = 0, k = -1, main_cuts_in = []):
    #Recursion counter
    k+=1

    #Duplicate cut_pieces array
    cut_pieces = [i for i in cut_pieces_in]

    #duplicate cut_list array
    cut_list = [i for i in cut_list_in]

    #duplicate main_cuts entry for tracking the "ripper" cuts
    main_cuts = [i for i in main_cuts_in]

    if len(cut_list) > 0:

        #Get total area cut so far:
        total_cut_area = sum(i[2] for i in cut_pieces)

        #print(str(len(cut_pieces)+len(cut_list)) + '  |  ' + str(len(cut_pieces)) + '  |  ' + str(len(cut_list)))
        #Track order to cut pieces in
        first_cut_piece = cut_list[-1]
        first_cut_piece.append(k)
        cut_pieces.append(first_cut_piece)
        del(cut_list[-1])

        #Set effficiencies to negative in case one isn't used
        efficiency_1 = -1
        efficiency_2 = -1

        #Try first orientation:
        if first_cut_piece[1] <= EVA_width:
            EVA_consumption_1 = first_cut_piece[0]

            #Calculate remainder:
            remainder_1 = (EVA_width-first_cut_piece[1],first_cut_piece[0])
            #print('Remainder 1 is: ' + str(remainder_1))
            #Cut apart remainder:
            (cut_list_1,cut_pieces_1) = remainder_cut(cut_list, remainder_1, cut_pieces,k)

            #Calculate efficiency of new cuts
            efficiency_1 = (sum(i[2] for i in cut_pieces_1)-total_cut_area)/(EVA_width*EVA_consumption_1/144)
            #print('eff 1: ' + str(round(efficiency_1,2)))

        #Try first orientation:
        if first_cut_piece[0] <= EVA_width:
            EVA_consumption_2 = first_cut_piece[1]

            #Calculate remainder:
            remainder_2 = (EVA_width-first_cut_piece[0],first_cut_piece[1])
            #print('Remainder 2 is: ' + str(remainder_2))

            #Cut apart remainder:
            (cut_list_2,cut_pieces_2) = remainder_cut(cut_list, remainder_2, cut_pieces,k)

            #Calculate efficiency of new cuts
            efficiency_2 = (sum(i[2] for i in cut_pieces_2)-total_cut_area)/(EVA_width*EVA_consumption_2/144)
            #print('eff 2: ' + str(round(efficiency_2,2)))

        #use most efficient cut
        if efficiency_1 > efficiency_2:
            #print('1!')
            #Calculate EVA consumption
            EVA_consumption_length+=EVA_consumption_1

            #Append main cut length
            main_cuts.append(first_cut_piece[0])

            #Recurse with remaining uncut pieces using list 1
            return cut_eva(EVA_width,cut_list_1,cut_pieces_1,EVA_consumption_length,k,main_cuts)

        else:
            #print('2!')
            #Calculate EVA consumption
            EVA_consumption_length+=EVA_consumption_2

            #Append main cut length
            main_cuts.append(first_cut_piece[1])

            #Recurse with remaining uncut pieces using list 1
            return cut_eva(EVA_width,cut_list_2,cut_pieces_2,EVA_consumption_length,k,main_cuts)

    else:
        return (cut_pieces, EVA_consumption_length, main_cuts)

''' This function takes in a piece size and a list of pieces to be cut from it to return an efficient layout of cut pieces'''
#The cut_list is assumed to be ordered smallest to largest piece by width
#The cut_list should be an array of 3 dimension arrays with width, length, area
#The remainder is two-dimensional tuple
def remainder_cut(cut_list_in,remainder, cut_pieces_in = [], identifier = -1):
    #Create an empty array to track the pieces that can be cut from remainder
    potentials = []

    #Create new arrays for inputs to avoid changing data outside function
    cut_list = [i for i in cut_list_in]
    cut_pieces = [i for i in cut_pieces_in]

    #Find which pieces fit into remainder
    for x in range(len(cut_list)):
        if (cut_list[x][1] <= remainder[1] and cut_list[x][0] <= remainder[0]) or (cut_list[x][0] <= remainder[1] and cut_list[x][1] <= remainder[0]):
            potentials.append([cut_list[x][0], cut_list[x][1], cut_list[x][2], cut_list[x][3], x])
            #print('!')

    #If no pieces can be cut from the remainder, return the input data except remainder
    if potentials == []:
        return (cut_list, cut_pieces)

    #If there are potential cuts:
    else:
        #Cut the largest piece from the remainder and append identifier
        cut = max(potentials, key = lambda x: x[2])
        new_piece = cut[0:4]
        new_piece.append(identifier)
        cut_pieces.append(new_piece)
        #print('CUT!' +str(cut[0:3]))
        cut_index = cut[-1]

        del(cut_list[cut_index])

        #Set value of areas to -1 in case one option isn't ran
        area1 = -1
        area2 = -1

        #Determine possible orientations:
        if cut[0]<=remainder[0] and cut[1]<=remainder[1]:
            #print('ORIENTATION 1')
            #If orientation possible, determine which cut order results in larger remainder
            best_remainder_1 = best_cut_order((cut[0],cut[1]),(remainder[0],remainder[1]))
            #print('Orientation 1 remainder: ' + str(best_remainder_1))

            #get list of cuts from remainder
            new_cut_list_1, new_cut_pieces_1 = remainder_cut(cut_list,best_remainder_1,cut_pieces, identifier)

            #get area of cut cut pieces
            area1 = sum([i[2] for i in new_cut_pieces_1])
            #print(new_cut_pieces_1)
            #print('Already cut area 1 is: ' + str(area1))

        if cut[0]<=remainder[1] and cut[1]<=remainder[0]:
            #print('ORIENTATION 2')
            #If orientation possible, determine which cut order results in larger remainder
            best_remainder_2 = best_cut_order((cut[1],cut[0]),(remainder[0],remainder[1]))
            #print('Orientation 2 remainder: ' + str(best_remainder_2))
            #get list of cuts from remainder
            new_cut_list_2, new_cut_pieces_2 = remainder_cut(cut_list,best_remainder_2,cut_pieces, identifier)

            #get area of cut cut pieces
            area2 = sum([i[2] for i in new_cut_pieces_2])
            #print(new_cut_pieces_2)
            #print('Already cut area 2 is: ' + str(area2))

        #Get the max cut of orientation and return one with largest area
        if area1>area2:
            return (new_cut_list_1, new_cut_pieces_1)
        else:
            return (new_cut_list_2, new_cut_pieces_2)

'''This cut determines the best order to guillotine cut a piece from a remainder to result in the largest remaining piece'''
#This function assumes the inputs are ordered
def best_cut_order(cut,remainder):
     #Calculate two potential remainder areas
     cut_area_1 = (remainder[1]-cut[1])*remainder[0]
     cut_area_2 = (remainder[0]-cut[0])*remainder[1]

     #return dimensions of largest remainder piece
     if cut_area_1>cut_area_2:
         return (remainder[1]-cut[1],remainder[0])
     else:
         return (remainder[0]-cut[0],remainder[1])

"""This function grabs the data from the csv file"""
def get_data(filename = 'Glass Block Sizes.csv'):
    #Save out raw glass data in qty, size, size format. Assumes file collumns are qty, size, size
    with open(filename, newline = '') as glass_sizes_file:
        sizereader = csv.reader(glass_sizes_file ,dialect='excel',delimiter = ',', quotechar = '"')
        glass_data = []
        for x in sizereader:
            for y in range(len(x)):
                try:
                    if y == 0:
                        x[y]=int(x[y])
                    else:
                        x[y]=float(x[y])

                except:
                    pass
            if type(x[1]) == float:
                glass_data.append(x)

    return glass_data

"""This function deletes the quantity data fom the raw csv data"""
def clear_quantity(glass_data_in):
    #Create duplicate array to be edited
    glass_data = [i for i in glass_data_in]

    #Make a list with one block size on each line aand remove qty column
    glass_block_sizes = []
    k = 0
    for x in glass_data:
        k+=x[0]
        for y in range(x[0]):
            glass_block_sizes.append(x[1:])

    if k != len(glass_block_sizes):
        print('ERROR! Input count does not match output list length')

    print(len(glass_block_sizes*2))
    #sort glass sizes into short then long

    return glass_block_sizes

"""This function takes in data, orders the points smaller dim., larger dim., then
sorts based on the smaller dimension"""
def order_and_sort(glass_block_sizes):
    glass_block_sizes_ordered = []

    for x in glass_block_sizes:
        if x[0] < x[1]:
            glass_block_sizes_ordered.append(x)
        else:
            glass_block_sizes_ordered.append([x[1],x[0],x[2]])

    #Order points by width
    glass_block_sizes_sorted = sorted(glass_block_sizes_ordered, key=lambda x: x[0])

    return glass_block_sizes_sorted

"""This function eliminates points that are too large to be cut from the material
and returns two arrays with the eliminated points and points to cut"""
def point_eliminate(glass_block_sizes_sorted_in, EVA_width):

    #Duplicate sorted array for editing
    glass_block_sizes_sorted = [i for i in glass_block_sizes_sorted_in]

    initial_length = len(glass_block_sizes_sorted)

    #Eliminate points with dimensions greater than EVA width
    points_to_delete = []
    oversized_piece_sizes = []
    for x in range(len(glass_block_sizes_sorted)):
        if glass_block_sizes_sorted[x][1] > EVA_width and glass_block_sizes_sorted[x][0] > EVA_width:
            points_to_delete.append(x)
            oversized_piece_sizes.append(glass_block_sizes_sorted[x])

    for x in reversed(points_to_delete):
        del glass_block_sizes_sorted[x]

    #Double Check sizes of arrays to make sure the oversized pieces and glass_block_sizes arrays are same total length as before points are deleted
    if initial_length != len(glass_block_sizes_sorted)+len(oversized_piece_sizes):
        print('ERROR! Number of to-cut pieces and oversized pieces does not match total number of pieces!')

    return (glass_block_sizes_sorted,oversized_piece_sizes)

"""This function appends area to the size arrays
Assumes dims are in. and gives area in sq. ft."""
def append_area(glass_block_sizes_sorted_in):
    #Duplicate glass_block_sizes_sorted
    glass_block_sizes_sorted = [i for i in glass_block_sizes_sorted_in]

    #Add area to points
    for x in glass_block_sizes_sorted:
        x.insert(2, round(x[0]*x[1]/144,2))

    return glass_block_sizes_sorted

"""This function multiplies the number of gglass block size entries by the number
of layers required for each size"""
def layer_multiplier(glass_block_sizes_sorted, layer_count = 2):
    EVA_cut_list = []
    for x in glass_block_sizes_sorted:
        for y in range(layer_count):
            EVA_cut_list.append([i for i in x])

    return EVA_cut_list

"""This function calculates the theoretical minimum material requirement for the
cuts to be made, assuming areas are stored in the last array element """
def material_minimum(EVA_cut_list):
    return sum(i[2] for i in EVA_cut_list)

"""This function just calls all the above functions in order to output the cut list data"""
def eva_cut_from_csv(filename, EVA_width, layer_count, marks = True):

    #get data from csv file
    glass_data = get_data(filename)

    #Change dataset so every row represents only 1 panel
    glass_data = clear_quantity(glass_data)

    #order the list
    glass_data = order_and_sort(glass_data)

    #get rid of pieces too big to be cut from material
    glass_sizes, oversized_pieces = point_eliminate(glass_data, EVA_width)

    #append an area measurement to dimensions
    glass_sizes = append_area(glass_sizes)

    #multiply each entry by the number of layers
    to_cut_list = layer_multiplier(glass_sizes)

    #Run the cutting algorithm
    cut_pieces, EVA_consumption_length, main_cuts = cut_eva(EVA_width, to_cut_list)

    #Calculate the yield
    EVA_cut_yield = material_minimum(to_cut_list)/(EVA_consumption_length*EVA_width/144)

    return cut_pieces, EVA_consumption_length, main_cuts, EVA_cut_yield, oversized_pieces


from django import template
from apps.carts.models import *
from apps.products.models import Category

register = template.Library()

@register.simple_tag(takes_context=True)
def get_user_cart(context):
    request = context['request']
    user = request.user
    try:
        cart = Cart.objects.get(client=user, is_ordered=False)
    except:
        cart = []
    return cart

@register.simple_tag(takes_context=True)
def get_user_wishlist(context):
    request = context['request']
    user = request.user
    try:
        wl = Wishlist.objects.filter(user=user)
    except:
        wl = []
    wlist_products = [product.product.id for product in wl]
    return wlist_products

@register.simple_tag()
def categories():
    try:
        cat = Category.objects.all()
    except:
        cat = None
    return cat


import numpy as np
import pandas as pd

# 1:Male 0:Female
flag=['1','0','1','1','0','0','1','1','1','0']

# 1 Yes 0 No
datalist = [['1','0','0','0'],
            ['1','1','1','1'],
            ['0','0','0','0'],
            ['1','1','1','1'],
            ['1','0','1','0'],
            ['0','0','0','0'],
            ['1','1','1','1'],
            ['0','0','0','0'],
            ['1','0','0','0'],
            ['1','1','1','0']]
columns=['magazine','watch','insurance','creditcard']

data = pd.DataFrame(data = datalist,columns=columns)

data['flag']=flag
print(data)
flag = data['flag']

# np.unique(flag,return_counts=True)
# (array(['0', '1'], dtype=object), array([4, 6], dtype=int64))
c,ct= np.unique(flag,return_counts=True)

p=[i/sum(ct) for i in ct]
pc0=p[0]
pc1=p[1]

m = data['magazine']
magazine =  [np.unique(m[flag == i], return_counts=True) for i in c]
# [(array(['0', '1'], dtype=object), array([1, 3], dtype=int64)),
# (array(['0', '1'], dtype=object), array([2, 4], dtype=int64))]
m_c0=magazine[0][1]
pm_c0=[i/sum(m_c0) for i in m_c0]
pm0_c0=pm_c0[0]
pm1_c0=pm_c0[1]

m_c1=magazine[1][1]
pm_c1=[i/sum(m_c1) for i in m_c1]
pm0_c1=pm_c1[0]
pm1_c1=pm_c1[1]
print(pm0_c0,pm1_c0,pm0_c1,pm1_c1)
# =========================
w = data['watch']
watch =  [np.unique(w[flag == i], return_counts=True) for i in c]

w_c0=watch[0][1]
pw_c0=[i/sum(w_c0) for i in w_c0]
pw0_c0=pw_c0[0]
pw1_c0=pw_c0[1]

w_c1=watch[1][1]
pw_c1=[i/sum(w_c1) for i in w_c1]
pw0_c1=pw_c1[0]
pw1_c1=pw_c1[1]

print(pw0_c0,pw1_c0,pw0_c1,pw1_c1)

# =========================
ii = data['insurance']
insurance =  [np.unique(ii[flag == i], return_counts=True) for i in c]

i_c0=insurance[0][1]
pi_c0=[i/sum(i_c0) for i in i_c0]
pi0_c0=pi_c0[0]
pi1_c0=pi_c0[1]

i_c1=insurance[1][1]
pi_c1=[i/sum(i_c1) for i in i_c1]
pi0_c1=pi_c1[0]
pi1_c1=pi_c1[1]

print(pi0_c0,pi1_c0,pi0_c1,pi1_c1)

# =========================
cc = data['creditcard']
creditcard =  [np.unique(cc[flag == c], return_counts=True) for c in c]

c_c0=creditcard[0][1]
pc_c0=[c/sum(c_c0) for c in c_c0]
pc0_c0=pc_c0[0]
pc1_c0=pc_c0[1]

c_c1=creditcard[1][1]
pc_c1=[c/sum(c_c1) for c in c_c1]
pc0_c1=pc_c1[0]
pc1_c1=pc_c1[1]

print(pc0_c0,pc1_c0,pc0_c1,pc1_c1)

# m=1,w=1,i=0,c=0
pXc1=pm1_c1*pw1_c1*pi0_c1*pc0_c1*pc1
pXc0=pm1_c0*pw1_c0*pi0_c0*pc0_c1*pc0
print('pXc1:{} ,pXc0:{} , 所以性别是：{}'.format(pXc1,pXc0,'Male' if pXc1>pXc0 else 'Female'))


import pandas as pd
from sklearn.ensemble import RandomForestClassifier

def train_random_forest():
    # ****** Fit a random forest and extract predictions
    #
    forest = RandomForestClassifier(n_estimators = 100)

    # Fitting the forest may take a few minutes
    print("Fitting a random forest to labeled training data...")
    forest = forest.fit(train_centroids, train["sentiment"])
    result = forest.predict(test_centroids)

    # Write the test results
    output = pd.DataFrame(data={"id": test["id"], "sentiment":result})
    output.to_csv("BagOfCentroids.csv", index=False, quoting=3)
    print("Wrote BagOfCentroids.csv")


from math import pi
from collections import defaultdict

import numpy as np

from my_gpaw.kpt_descriptor import KPointDescriptor
from .kpts import RSKPoint, to_real_space

def create_symmetry_map(kd: KPointDescriptor):  # -> List[List[int]]
    sym = kd.symmetry
    U_scc = sym.op_scc
    nsym = len(U_scc)
    compconj_s = np.zeros(nsym, bool)
    if sym.time_reversal and not sym.has_inversion:
        U_scc = np.concatenate([U_scc, -U_scc])
        compconj_s = np.zeros(nsym * 2, bool)
        compconj_s[nsym:] = True
        nsym *= 2

    map_ss = np.zeros((nsym, nsym), int)
    for s1 in range(nsym):
        for s2 in range(nsym):
            diff_s = abs(U_scc[s1].dot(U_scc).transpose((1, 0, 2)) -
                         U_scc[s2]).sum(2).sum(1)
            indices = (diff_s == 0).nonzero()[0]
            assert len(indices) == 1
            s = indices[0]
            assert compconj_s[s1] ^ compconj_s[s2] == compconj_s[s]
            map_ss[s1, s2] = s

    return map_ss

class Symmetry:
    def __init__(self, kd: KPointDescriptor):
        self.kd = kd
        self.symmetry_map_ss = create_symmetry_map(kd)

        U_scc = kd.symmetry.op_scc
        is_identity_s = (U_scc == np.eye(3, dtype=int)).all(2).all(1)
        self.s0 = is_identity_s.nonzero()[0][0]
        self.inverse_s = self.symmetry_map_ss[:, self.s0]

    def symmetry_operation(self, s: int, wfs, inverse=False):
        if inverse:
            s = self.inverse_s[s]
        U_scc = self.kd.symmetry.op_scc
        nsym = len(U_scc)
        time_reversal = s >= nsym
        s %= nsym
        U_cc = U_scc[s]

        if (U_cc == np.eye(3, dtype=int)).all():
            def T0(a_R):
                return a_R
        else:
            N_c = wfs.gd.N_c
            i_cr = np.dot(U_cc.T, np.indices(N_c).reshape((3, -1)))
            i = np.ravel_multi_index(i_cr, N_c, 'wrap')

            def T0(a_R):
                return a_R.ravel()[i].reshape(N_c)

        if time_reversal:
            def T(a_R):
                return T0(a_R).conj()
        else:
            T = T0

        T_a = []
        for a, id in enumerate(wfs.setups.id_a):
            b = self.kd.symmetry.a_sa[s, a]
            S_c = np.dot(wfs.spos_ac[a], U_cc) - wfs.spos_ac[b]
            U_ii = wfs.setups[a].R_sii[s].T
            T_a.append((b, S_c, U_ii))

        return T, T_a, time_reversal

    def apply_symmetry(self, s: int, rsk, wfs, spos_ac):
        U_scc = self.kd.symmetry.op_scc
        nsym = len(U_scc)
        time_reversal = s >= nsym
        s %= nsym
        sign = 1 - 2 * int(time_reversal)
        U_cc = U_scc[s]

        if (U_cc == np.eye(3)).all() and not time_reversal:
            return rsk

        u1_nR = rsk.u_nR
        proj1 = rsk.proj
        f_n = rsk.f_n
        k1_c = rsk.k_c
        weight = rsk.weight

        u2_nR = np.empty_like(u1_nR)
        proj2 = proj1.new()

        k2_c = sign * U_cc.dot(k1_c)

        N_c = u1_nR.shape[1:]
        i_cr = np.dot(U_cc.T, np.indices(N_c).reshape((3, -1)))
        i = np.ravel_multi_index(i_cr, N_c, 'wrap')
        for u1_R, u2_R in zip(u1_nR, u2_nR):
            u2_R[:] = u1_R.ravel()[i].reshape(N_c)

        for a, id in enumerate(wfs.setups.id_a):
            b = self.kd.symmetry.a_sa[s, a]
            S_c = np.dot(spos_ac[a], U_cc) - spos_ac[b]
            x = np.exp(2j * pi * np.dot(k1_c, S_c))
            U_ii = wfs.setups[a].R_sii[s].T * x
            proj2[a][:] = proj1[b].dot(U_ii)

        if time_reversal:
            np.conj(u2_nR, out=u2_nR)
            np.conj(proj2.array, out=proj2.array)

        return RSKPoint(u2_nR, proj2, f_n, k2_c, weight)

    def pairs(self, kpts, wfs, spos_ac):
        kd = self.kd
        nsym = len(kd.symmetry.op_scc)

        assert len(kpts) == kd.nibzkpts

        symmetries_k = []
        for k in range(kd.nibzkpts):
            indices = np.where(kd.bz2ibz_k == k)[0]
            sindices = (kd.sym_k[indices] +
                        kd.time_reversal_k[indices] * nsym)
            symmetries_k.append(sindices)

        # pairs: Dict[Tuple[int, int, int], int]

        pairs1 = defaultdict(int)
        for i1 in range(kd.nibzkpts):
            for s1 in symmetries_k[i1]:
                for i2 in range(kd.nibzkpts):
                    for s2 in symmetries_k[i2]:
                        s3 = self.symmetry_map_ss[s1, s2]
                        # s3 = self.inverse_s[s3]
                        if 1:  # i1 < i2:
                            pairs1[(i1, i2, s3)] += 1
                        else:
                            s4 = self.inverse_s[s3]
                            if i1 == i2:
                                # pairs1[(i1, i1, min(s3, s4))] += 1
                                pairs1[(i1, i1, s3)] += 1
                            else:
                                pairs1[(i2, i1, s4)] += 1
        pairs = {}
        seen = {}
        for (i1, i2, s), count in pairs1.items():
            k2 = kd.bz2bz_ks[kd.ibz2bz_k[i2], s]
            if (i1, k2) in seen:
                pairs[seen[(i1, k2)]] += count
            else:
                pairs[(i1, i2, s)] = count
                # seen[(i1, k2)] = (i1, i2, s)

        comm = wfs.world
        lasti1 = -1
        lasti2 = -1
        for (i1, i2, s), count in sorted(pairs.items()):
            if i1 != lasti1:
                k1 = kpts[i1]
                u1_nR = to_real_space(k1.psit)
                rsk1 = RSKPoint(u1_nR, k1.proj.broadcast(),
                                k1.f_n, k1.k_c,
                                k1.weight, k1.dPdR_aniv)
                lasti1 = i1
            if i2 == i1:
                if s == self.s0:
                    rsk2 = rsk1
                else:
                    N = len(rsk1.u_nR)
                    S = comm.size
                    B = (N + S - 1) // S
                    na = min(B * comm.rank, N)
                    nb = min(na + B, N)
                    rsk2 = RSKPoint(rsk1.u_nR[na:nb],
                                    rsk1.proj.view(na, nb),
                                    rsk1.f_n[na:nb],
                                    rsk1.k_c,
                                    rsk1.weight)
                lasti2 = i2
            elif i2 != lasti2:
                k2 = kpts[i2]
                N = len(k2.psit.array)
                S = comm.size
                B = (N + S - 1) // S
                na = min(B * comm.rank, N)
                nb = min(na + B, N)
                u2_nR = to_real_space(k2.psit, na, nb)
                rsk2 = RSKPoint(u2_nR, k2.proj.broadcast().view(na, nb),
                                k2.f_n[na:nb], k2.k_c,
                                k2.weight)
                lasti2 = i2

            yield (i1, i2, s, rsk1,
                   self.apply_symmetry(s, rsk2, wfs, spos_ac),
                   count)


import os, sys
import logging
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from collections import defaultdict
import multiprocessing
from functools import partial
import gensim
from gensim import models, matutils
from gensim.corpora import MmCorpus, Dictionary
from scipy.stats import entropy
from scipy.spatial.distance import pdist, squareform
from scipy.linalg import svdvals
from nltk.corpus import stopwords
from tqdm import tqdm
#logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)

ignore_words = frozenset(stopwords.words('english'))

##############################################################################################################################
'''
    extract_data method is copied directly from gensim.py in the pyLDAvis library
    https://github.com/bmabey/pyLDAvis/blob/master/pyLDAvis/gensim.py
'''
##############################################################################################################################
def extract_data(topic_model, corpus, dictionary, doc_topic_dists=None):

    if not matutils.ismatrix(corpus):
          corpus_csc = matutils.corpus2csc(corpus, num_terms=len(dictionary))
    else:
          corpus_csc = corpus
          # Need corpus to be a streaming gensim list corpus for len and inference functions below:
          corpus = matutils.Sparse2Corpus(corpus_csc)

    # TODO: add the hyperparam to smooth it out? no beta in online LDA impl.. hmm..
    # for now, I'll just make sure we don't ever get zeros...
    fnames_argsort = np.asarray(list(dictionary.token2id.values()), dtype=np.int_)
    doc_lengths = corpus_csc.sum(axis=0).A.ravel()

    assert doc_lengths.shape[0] == len(corpus), 'Document lengths and corpus have different sizes {} != {}'.format(doc_lengths.shape[0], len(corpus))

    if hasattr(topic_model, 'lda_alpha'):
           num_topics = len(topic_model.lda_alpha)
    else:
           num_topics = topic_model.num_topics

    if doc_topic_dists is None:
          # If its an HDP model.
          if hasattr(topic_model, 'lda_beta'):
              gamma = topic_model.inference(corpus)
          else:
              gamma, _ = topic_model.inference(corpus)
          doc_topic_dists = gamma / gamma.sum(axis=1)[:, None]
    else:
          if isinstance(doc_topic_dists, list):
             doc_topic_dists = matutils.corpus2dense(doc_topic_dists, num_topics).T
          elif issparse(doc_topic_dists):
             doc_topic_dists = doc_topic_dists.T.todense()
          doc_topic_dists = doc_topic_dists / doc_topic_dists.sum(axis=1)

    assert doc_topic_dists.shape[1] == num_topics, 'Document topics and number of topics do not match {} != {}'.format(doc_topic_dists.shape[1], num_topics)

    # get the topic-term distribution straight from gensim without iterating over tuples
    if hasattr(topic_model, 'lda_beta'):
           topic = topic_model.lda_beta
    else:
           topic = topic_model.state.get_lambda()
    topic = topic / topic.sum(axis=1)[:, None]
    topic_term_dists = topic[:, fnames_argsort]

    assert topic_term_dists.shape[0] == doc_topic_dists.shape[1]

    coherence_model = models.CoherenceModel(model=topic_model, corpus=corpus, dictionary=dictionary, coherence='u_mass')

    return {'topic_term_dists': topic_term_dists, 'doc_topic_dists': doc_topic_dists,
            'doc_lengths': doc_lengths, 'num_topics': num_topics}

##############################################################################################################################

def cao_juan_2009(topic_term_dists, num_topics):
    cos_pdists = squareform(pdist(topic_term_dists, metric='cosine'))
    return np.sum(cos_pdists) / (num_topics*(num_topics - 1)/2)

def arun_2010(topic_term_dists, doc_topic_dists, doc_lengths, num_topics):
    P = svdvals(topic_term_dists)
    Q = np.matmul(doc_lengths, doc_topic_dists) / np.linalg.norm(doc_lengths)
    return entropy(P, Q)

def deveaud_2014(topic_term_dists, num_topics):
    jsd_pdists = squareform(pdist(topic_term_dists, metric=jensen_shannon))
    return np.sum(jsd_pdists) / (num_topics*(num_topics - 1))

def jensen_shannon(P, Q):
    M = 0.5 * (P + Q)
    return 0.5 * (entropy(P, M) + entropy(Q, M))

def preprocess_text(text):
    with open(text, 'r') as inp:
        text = ' '.join(line.rstrip('\n') for line in inp)
    return [word for word in gensim.utils.simple_preprocess(text, deacc=True, min_len=3) if word not in ignore_words]

def files_to_gen(directory):
    for path, dirs, files in os.walk(directory):
        for name in files:
            yield os.path.join(path, name)

class DocCorpus(gensim.corpora.TextCorpus):
    def get_texts(self):
        pool = multiprocessing.Pool(max(1, multiprocessing.cpu_count() - 1))
        for tokens in pool.map(preprocess_text, files_to_gen(self.input)):
            yield tokens
        pool.terminate()

def build_coherence_models(topic_model, **kwargs):
    u_mass = models.CoherenceModel(model=topic_model, corpus=kwargs['corpus'], dictionary=kwargs['dictionary'], coherence='u_mass')
    c_v = models.CoherenceModel(model=topic_model, texts=kwargs['texts'], corpus=kwargs['corpus'], dictionary=kwargs['dictionary'], coherence='c_v')
    c_uci = models.CoherenceModel(model=topic_model, texts=kwargs['texts'], corpus=kwargs['corpus'], dictionary=kwargs['dictionary'], coherence='c_uci')
    c_npmi = models.CoherenceModel(model=topic_model, texts=kwargs['texts'], corpus=kwargs['corpus'], dictionary=kwargs['dictionary'], coherence='c_npmi')
    return {'num_topics': topic_model.num_topics, 'u_mass': u_mass.get_coherence(), 'c_v': c_v.get_coherence(), 'c_uci': c_uci.get_coherence(), 'c_npmi': c_npmi.get_coherence()}

''' a poor attempt at implementing useless statistical measures, the result seems meaningless and is
    in the img folder of the github project. '''
def main(text_dir):
    topics = range(10, 101, 10) + range(120, 201, 20) + range(250, 451, 50)
    #topics = range(10, 21, 10)
    #corpus = DocCorpus(text_dir)
    #dictionary = corpus.dictionary
    corpus = MmCorpus('../twitter_LDA_topic_modeling/simple-wiki.mm')
    dictionary = Dictionary.load('../twitter_LDA_topic_modeling/simple-wiki.dict')
    print('Building LDA models')
    lda_models = [models.LdaMulticore(corpus=corpus, id2word=dictionary, num_topics=i, passes=5) for i in tqdm(topics)]
    print('Generating coherence models')
    texts = [[dictionary[word_id] for word_id, freq in doc] for doc in corpus]
    pool = multiprocessing.Pool(max(1, multiprocessing.cpu_count() - 1))
    func = partial(build_coherence_models,
                   corpus=corpus,
                   dictionary=dictionary,
                   texts=texts)
    coherence_models = pool.map(func, lda_models)
    pool.close()
#    print('Extracting data from models')
#    model_data = [extract_data(model, corpus, dictionary) for model in tqdm(lda_models)]
#    d = defaultdict(list)
#    print('Generating output data')
#    for i, data in tqdm(enumerate(model_data)):
#        d['num_topics'].append(data['num_topics'])
#        d['cao_juan_2009'].append(cao_juan_2009(data['topic_term_dists'], data['num_topics']))
#        d['arun_2010'].append(arun_2010(data['topic_term_dists'], data['doc_topic_dists'], data['doc_lengths'], data['num_topics']))
#        d['deveaud_2014'].append(deveaud_2014(data['topic_term_dists'], data['num_topics']))
#        d['u_mass_coherence'].append(data['u_mass_coherence'])
    d = defaultdict(list)
    print('Generating output data')
    for data in tqdm(coherence_models):
        d['num_topics'].append(data['num_topics'])
        d['u_mass'].append(data['u_mass'])
        d['c_v'].append(data['c_v'])
        d['c_uci'].append(data['c_uci'])
        d['c_npmi'].append(data['c_npmi'])
    df = pd.DataFrame(d)
    df = df.set_index('num_topics')
    df.to_csv('coherence_simple_wiki', sep='\t')
    df.plot(xticks=df.index, style=['bs-', 'yo-', 'r^-', 'gx-'])
    ax1 = df.plot(xticks=df.index, style='bs-', grid=True, y='u_mass')
    ax2 = df.plot(xticks=df.index, style='yo-', grid=True, y='c_v', ax=ax1)
    ax3 = df.plot(xticks=df.index, style='r^-', grid=True, y='c_npmi', ax=ax2)
    df.plot(xticks=df.index, style='gx-', grid=True, y='c_uci', ax=ax3)
    plt.legend(loc='upper center', bbox_to_anchor=(0.5, -0.17), fancybox=True, shadow=True, ncol=4, fontsize=9)
    plt.subplots_adjust(bottom=0.2)
    plt.xticks(df.index, rotation=45, ha='right', fontsize=8)
    plt.savefig('coherence_simple_wiki')
    plt.close()

if __name__ == '__main__':
    sys.exit(main(sys.argv[1]))


# coding: utf-8

"""
    Lightly API

    Lightly.ai enables you to do self-supervised learning in an easy and intuitive way. The lightly.ai OpenAPI spec defines how one can interact with our REST API to unleash the full potential of lightly.ai  # noqa: E501

    OpenAPI spec version: 1.0.0
    Contact: support@lightly.ai
    Generated by: https://github.com/swagger-api/swagger-codegen.git
"""

import pprint
import re  # noqa: F401

import six

from lightly.openapi_generated.swagger_client.configuration import Configuration

class TagArithmeticsRequest(object):
    """NOTE: This class is auto generated by the swagger code generator program.

    Do not edit the class manually.
    """

    """
    Attributes:
      swagger_types (dict): The key is attribute name
                            and the value is attribute type.
      attribute_map (dict): The key is attribute name
                            and the value is json key in definition.
    """
    swagger_types = {
        'tag_id1': 'MongoObjectID',
        'tag_id2': 'MongoObjectID',
        'operation': 'TagArithmeticsOperation',
        'new_tag_name': 'TagName',
        'creator': 'TagCreator'
    }

    attribute_map = {
        'tag_id1': 'tagId1',
        'tag_id2': 'tagId2',
        'operation': 'operation',
        'new_tag_name': 'newTagName',
        'creator': 'creator'
    }

    def __init__(self, tag_id1=None, tag_id2=None, operation=None, new_tag_name=None, creator=None, _configuration=None):  # noqa: E501
        """TagArithmeticsRequest - a model defined in Swagger"""  # noqa: E501
        if _configuration is None:
            _configuration = Configuration()
        self._configuration = _configuration

        self._tag_id1 = None
        self._tag_id2 = None
        self._operation = None
        self._new_tag_name = None
        self._creator = None
        self.discriminator = None

        self.tag_id1 = tag_id1
        self.tag_id2 = tag_id2
        self.operation = operation
        if new_tag_name is not None:
            self.new_tag_name = new_tag_name
        if creator is not None:
            self.creator = creator

    @property
    def tag_id1(self):
        """Gets the tag_id1 of this TagArithmeticsRequest.  # noqa: E501

        :return: The tag_id1 of this TagArithmeticsRequest.  # noqa: E501
        :rtype: MongoObjectID
        """
        return self._tag_id1

    @tag_id1.setter
    def tag_id1(self, tag_id1):
        """Sets the tag_id1 of this TagArithmeticsRequest.

        :param tag_id1: The tag_id1 of this TagArithmeticsRequest.  # noqa: E501
        :type: MongoObjectID
        """
        if self._configuration.client_side_validation and tag_id1 is None:
            raise ValueError("Invalid value for `tag_id1`, must not be `None`")  # noqa: E501

        self._tag_id1 = tag_id1

    @property
    def tag_id2(self):
        """Gets the tag_id2 of this TagArithmeticsRequest.  # noqa: E501

        :return: The tag_id2 of this TagArithmeticsRequest.  # noqa: E501
        :rtype: MongoObjectID
        """
        return self._tag_id2

    @tag_id2.setter
    def tag_id2(self, tag_id2):
        """Sets the tag_id2 of this TagArithmeticsRequest.

        :param tag_id2: The tag_id2 of this TagArithmeticsRequest.  # noqa: E501
        :type: MongoObjectID
        """
        if self._configuration.client_side_validation and tag_id2 is None:
            raise ValueError("Invalid value for `tag_id2`, must not be `None`")  # noqa: E501

        self._tag_id2 = tag_id2

    @property
    def operation(self):
        """Gets the operation of this TagArithmeticsRequest.  # noqa: E501

        :return: The operation of this TagArithmeticsRequest.  # noqa: E501
        :rtype: TagArithmeticsOperation
        """
        return self._operation

    @operation.setter
    def operation(self, operation):
        """Sets the operation of this TagArithmeticsRequest.

        :param operation: The operation of this TagArithmeticsRequest.  # noqa: E501
        :type: TagArithmeticsOperation
        """
        if self._configuration.client_side_validation and operation is None:
            raise ValueError("Invalid value for `operation`, must not be `None`")  # noqa: E501

        self._operation = operation

    @property
    def new_tag_name(self):
        """Gets the new_tag_name of this TagArithmeticsRequest.  # noqa: E501

        :return: The new_tag_name of this TagArithmeticsRequest.  # noqa: E501
        :rtype: TagName
        """
        return self._new_tag_name

    @new_tag_name.setter
    def new_tag_name(self, new_tag_name):
        """Sets the new_tag_name of this TagArithmeticsRequest.

        :param new_tag_name: The new_tag_name of this TagArithmeticsRequest.  # noqa: E501
        :type: TagName
        """

        self._new_tag_name = new_tag_name

    @property
    def creator(self):
        """Gets the creator of this TagArithmeticsRequest.  # noqa: E501

        :return: The creator of this TagArithmeticsRequest.  # noqa: E501
        :rtype: TagCreator
        """
        return self._creator

    @creator.setter
    def creator(self, creator):
        """Sets the creator of this TagArithmeticsRequest.

        :param creator: The creator of this TagArithmeticsRequest.  # noqa: E501
        :type: TagCreator
        """

        self._creator = creator

    def to_dict(self):
        """Returns the model properties as a dict"""
        result = {}

        for attr, _ in six.iteritems(self.swagger_types):
            value = getattr(self, attr)
            if isinstance(value, list):
                result[attr] = list(map(
                    lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
                    value
                ))
            elif hasattr(value, "to_dict"):
                result[attr] = value.to_dict()
            elif isinstance(value, dict):
                result[attr] = dict(map(
                    lambda item: (item[0], item[1].to_dict())
                    if hasattr(item[1], "to_dict") else item,
                    value.items()
                ))
            else:
                result[attr] = value
        if issubclass(TagArithmeticsRequest, dict):
            for key, value in self.items():
                result[key] = value

        return result

    def to_str(self):
        """Returns the string representation of the model"""
        return pprint.pformat(self.to_dict())

    def __repr__(self):
        """For `print` and `pprint`"""
        return self.to_str()

    def __eq__(self, other):
        """Returns true if both objects are equal"""
        if not isinstance(other, TagArithmeticsRequest):
            return False

        return self.to_dict() == other.to_dict()

    def __ne__(self, other):
        """Returns true if both objects are not equal"""
        if not isinstance(other, TagArithmeticsRequest):
            return True

        return self.to_dict() != other.to_dict()


import numpy as np
import cv2
import matplotlib.pyplot as plt

pt_1 = './pt_2D_1.txt'
pt_2 = './pt_2D_2.txt'

f1 = open(pt_1, 'r')
f2 = open(pt_2, 'r')

pt_1 = []
pt_2 = []

for line in f1.readlines():
    x = line.rstrip('\n').split(' ')
    pt_1.append(x)
for line in f2.readlines():
    x = line.rstrip('\n').split(' ')
    pt_2.append(x)

pt_1 = pt_1[1:]
pt_2 = pt_2[1:]

pt_1 = np.array(pt_1)
pt_2 = np.array(pt_2)

img1 = cv2.imread('./image1.jpg')
img2 = cv2.imread('./image2.jpg')

def LIS_eight(a, b):
    matrix = np.zeros((a.shape[0],9))

    for i in range(a.shape[0]):
        u = float(a[i][0])
        v = float(a[i][1])
        u_ = float(b[i][0])
        v_ = float(b[i][1])
        matrix[i] = np.array([u*u_, u_*v, u_, v_*u, v*v_, v_, u, v, 1])

    # Decompose ATA
    U, D, V  = np.linalg.svd(matrix,full_matrices=True)
    x = V.T[:, 8]
    F = np.reshape(x, (3,3))
    """
    Code above satisfied F = 1 requirement,
    We still need rank2 requirement
    """
    # compute rank2 f
    FU,FD,FV = np.linalg.svd(F,full_matrices=True)
    F = np.dot(FU, np.dot(np.diag([*FD[:2], 0]), FV))

    return F

# fundamental matrix
F = LIS_eight(pt_1, pt_2)

# normalized fundamental matrix
def normalized_points(m):
    uv = []
    for i in range(m.shape[0]):
        uv.append([float(m[i][0]), float(m[i][1])])
    uv = np.array(uv)

    # Center
    mean = np.mean(uv, axis=0)
    center = uv - mean

    # Scale
    scale = np.sqrt(2 * len(m) / np.sum(np.power(center, 2)))
    trans_matrix = np.array(
        [[scale, 0, -mean[0] * scale],
         [0, scale, -mean[1] * scale],
         [0,0,1]
        ],dtype=object
    )
    return uv, trans_matrix

uv1, trans_matrix1=normalized_points(pt_1)
uv2, trans_matrix2=normalized_points(pt_2)
uv1 = np.insert(uv1,uv1.shape[1],values=1, axis=1)
uv2 = np.insert(uv2,uv2.shape[1],values=1, axis=1)
# q = Tp
points1 = (trans_matrix1 @ (uv1.T)).T
# q = T'p'
points2 = (trans_matrix2 @ (uv2.T)).T
F_norm = LIS_eight(points1, points2)
# T'FT
F_norm = trans_matrix2.T @ (F_norm) @ (trans_matrix1)
#print(points_norm)

# pFp = [points2[i].dot(F_norm.dot(points1[i]))
#             for i in range(points1.shape[0])]
# print("p'^T F p =", np.abs(pFp).max())

def plot_(pt1, pt2, img1, img2, f):
    plt.subplot(1,2,1)
    # That is epipolar line associated with p.
    ln1 = f.T.dot(pt2.T)
    # Ax + By + C = 0
    A,B,C = ln1
    for i in range(ln1.shape[1]):
        # when y as 0，x = - (C/A)
        # when y = image.shape[0], x = -(Bw + C / A)
        # when x as image.shape[1], y = - (Aw + C / B)
        # when x as 0, y = - (C / B)
        #plt.plot([-C[i]/A[i], img1.shape[1]], [0, -(A[i]*img1.shape[1] + C[i])/B[i]], 'r')
        if ((-C[i]/B[i]) <0):
            plt.plot([-C[i]/A[i],img1.shape[1]],[0, -(C[i] + A[i]*img1.shape[1])/B[i]], 'r')
        elif ((-C[i]/B[i]) > img1.shape[0]):
            plt.plot([-(C[i] + B[i]*img1.shape[0])/A[i],img1.shape[1]],[img1.shape[0], -(C[i] + A[i]*img1.shape[1])/B[i]], 'r')
        else:
            plt.plot([0, img1.shape[1]], [-C[i]/B[i], -(C[i] + A[i]*img1.shape[1])/B[i]], 'r')
        plt.plot([pt1[i][0]], [pt1[i][1]], 'b*')
    plt.imshow(img1, cmap='gray')

    plt.subplot(1,2,2)
    # That is the epipolar line associated with p’.
    ln2 = f.dot(pt1.T)
    # Ax + By + C = 0
    A,B,C = ln2
    for i in range(ln2.shape[1]):
        # when y as 0，x = - (C/A)
        # when y = image.shape[0], x = -(Bw + C / A)
        # when x as image.shape[1], y = - (Aw + C / B)
        # when x as 0, y = - (C / B)
        #plt.plot([-C[i]/A[i], img1.shape[1]], [0, -(A[i]*img1.shape[1] + C[i])/B[i]], 'r')
        if ((-C[i]/B[i]) <0):
            plt.plot([-C[i]/A[i],img2.shape[1]],[0, -(C[i] + A[i]*img2.shape[1])/B[i]], 'r')
        elif ((-C[i]/B[i]) > img2.shape[0]):
            plt.plot([-(C[i] + B[i]*img2.shape[0])/A[i],img2.shape[1]],[img2.shape[0], -(C[i] + A[i]*img2.shape[1])/B[i]], 'r')
        else:
            plt.plot([0, img2.shape[1]], [-C[i]/B[i], -(C[i] + A[i]*img2.shape[1])/B[i]], 'r')
        plt.plot([pt1[i][0]], [pt1[i][1]], 'b*')
    plt.imshow(img2, cmap='gray')
    plt.show()

def plot_norm(pt1, pt2, img1, img2, f):
    plt.subplot(1,2,1)

    # That is epipolar line associated with p.
    ln1 = f.T.dot(pt2.T)
    # Ax + By + C = 0
    A,B,C = ln1
    for i in range(ln1.shape[1]):
        # when x as 0，y = - (C/B)
        # when x as 512(w), y = - (Aw + C / B)
        plt.plot([0, img1.shape[1]], [-C[i]/B[i], -(C[i] + A[i]*img1.shape[1])*1.0/B[i]], 'r')
        plt.plot([pt1[i][0]], [pt1[i][1]], 'b*')
    plt.imshow(img1, cmap='gray')

    plt.subplot(1,2,2)
    # That is the epipolar line associated with p’.
    ln2 = f.dot(pt1.T)
    # Ax + By + C = 0
    A,B,C = ln2
    for i in range(ln2.shape[1]):
        plt.plot([0, img2.shape[1]], [-C[i]*1.0/B[i], -(A[i]*img2.shape[1] + C[i])/B[i]], 'r')
        plt.plot([pt2[i][0]], [pt2[i][1]], 'b*')
    plt.imshow(img2, cmap='gray')
    plt.show()

plot_(uv1, uv2, img1, img2, F)
plot_norm(uv1, uv2, img1, img2, F_norm)

def calaulate_dist(pt1, pt2, f):
    ln1 = f.T.dot(pt2.T)
    pt_num = pt1.shape[0]
    a,b,c = ln1

    dist = 0.0
    for i in range(pt_num):
        dist += np.abs((a[i]*pt1[i][0] + b[i]*pt1[i][1] + c[i])) / np.sqrt(np.power(a[i],2) + np.power(b[i],2))
    acc = dist / pt_num
    return acc

# acc associated with point2
print('Accuracy of the fundamental matrices by point2:', calaulate_dist(uv1, uv2, F))
print('Accuracy of the normalized fundamental matrices by point2:', calaulate_dist(uv1, uv2, F_norm))
# acc associated with point1
print('Accuracy of the fundamental matrices by point1:', calaulate_dist(uv2, uv1, F.T))
print('Accuracy of the normalized fundamental matrices by point1:', calaulate_dist(uv2, uv1, F_norm.T))


import pyaudio
import numpy as np
from core.tools.buffer import AudioBuffer

class PyAudio():
    def __init__(self,verbose=True):
        """
        instantiate pyaudio client and buffer for input stream recording to plot
        """
        self.input_stream = None # on start will beinput stream from mic via pyaudio

        self.client=pyaudio.PyAudio()

        self.verbose=verbose

    def stream_read(self,chunk):
        """
        return values for a single chunk
        """
        data = np.frombuffer(self.input_stream.read(chunk),dtype=np.int16)
        return data

    def stream_start(self,rate,chunk):
        """
        start audio input stream
        """
        if self.verbose:
            print(" -- stream started")
        self.input_stream=self.client.open(format=pyaudio.paInt16,channels=1,
                                rate=rate,input=True,
                                frames_per_buffer=chunk)

    def stream_stop(self):
        """
        close the stream but keep the PyAudio instance alive.
        """
        self.input_stream.stop_stream()
        self.input_stream.close()
        if self.verbose:
            print("Programatically closing stream")


#!/usr/bin/python3
import requests
import subprocess  # to execute bash commands
import sys

try:
    check_for_package = subprocess.Popen(("dpkg", "-s", "html2text"), stdout=subprocess.PIPE)
    output = subprocess.check_output(("grep", "Status"), stdin=check_for_package.stdout)
    check_for_package.wait()
    opstr = str(output, 'utf-8')
    print(opstr)
    if opstr == "Status: install ok installed\n":
        print("Package installed")

except Exception as e:
    print("installing html2text..............................")
    install_pkg = subprocess.check_call("sudo apt install html2text", shell=True)

try:
    tracking_number = str(sys.argv[1])

except(IndexError, ValueError):
    print("please enter a tracking number of a valid format")
    sys.exit(2)

request_url = "http://ipsweb.ptcmysore.gov.in/ipswebtracking/IPSWeb_item_events.aspx?itemid=" + tracking_number
# print(request_url)
r = requests.get(request_url)
print(r.status_code)

f = open("raw_html", "w+")
f.write(r.text)
f.close()

view_html = subprocess.Popen(["html2text", "raw_html"])
output = view_html.communicate()
view_html.wait()
print(output)


#!/usr/bin/env python
# coding=utf-8

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

"""
给你一个链表，每 k 个节点一组进行翻转，请你返回翻转后的链表。

k 是一个正整数，它的值小于或等于链表的长度。

如果节点总数不是 k 的整数倍，那么请将最后剩余的节点保持原有顺序。

示例：

给你这个链表：1->2->3->4->5

当 k = 2 时，应当返回: 2->1->4->3->5

当 k = 3 时，应当返回: 3->2->1->4->5

说明：

你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值，而是需要实际进行节点交换。

链接：https://leetcode-cn.com/problems/reverse-nodes-in-klast_tail-group

# 单纯的模拟执行即可，需要注意的是需要保存上次的尾结点和下次的头结点。每k次需要翻转长度为k的链表，因此需要翻转 n/k 次
每次翻转的时间复杂度为k，因此总体时间复杂度是 o(n), 空间复杂度 o(1)
"""

class Solution(object):
    def reverse(self, start, end):
        tail = start
        last = None
        while start != end:
            next = start.next
            start.next = last
            last = start
            start = next
        return last, tail

    def reverseKGroup(self, head, k):
        """
        :type head: ListNode
        :type k: int
        :rtype: ListNode
        """
        new_head = None
        last_tail = None
        t = head
        while t:
            i = 0
            p = t
            while i < k and p:
                p = p.next
                i += 1

            if p:
                s, e = self.reverse(t, p)
            else:
                s, e = t, None

            t = p

            if not new_head:
                new_head = s

            if last_tail:
                last_tail.next = s
                last_tail = e

        return new_head


import unittest
import textwrap

from test.parse_helper import TransformTestCase

class TestSubscript(TransformTestCase):
	def test_list_indexing_valid(self):
		owl = textwrap.dedent(r"""
			bool[] b = [True, False]
			b[0]
			""")
		self.assertNoTransformError(owl)
	def test_list_indexing_var_valid(self):
		owl = textwrap.dedent(r"""
			bool[] b = [True, False]
			int i = 0
			b[i]
			""")
		self.assertNoTransformError(owl)

	# Invalid
	def test_list_indexing_invalid(self):
		owl = textwrap.dedent(r"""
			bool[] b = [True, False]
			float f = 1
			b[f]
			""")
		self.assertTransformError(owl)