import json
from io import BytesIO

import shap
import numpy as np
import pandas as pd
from PIL import Image
from sklearn import metrics
import matplotlib.pyplot as plt

from cardio.utils import FEATURE_TRANSLATION, ALL_FEATURES
from benchmark import load_split, TRAIN_SPLIT, TEST_SPLIT, OUTPUT_PATH

from confusion_matrix_pretty_print import plot_confusion_matrix_from_data

def save_figure(fig, filename, dpi=1000, **kwargs):
    png_1 = BytesIO()
    fig.savefig(png_1, dpi=dpi, format="png", **kwargs)
    png_2 = Image.open(png_1)
    png_2.save(filename)
    png_1.close()

def get_thresholds(model_results):
    if "holdout" in model_results:
        roc_thresh = model_results["holdout"]["roc"]["threshold"]
        pr_thresh = model_results["holdout"]["pr"]["threshold"]
    else:
        roc_thresh = model_results["roc"]["threshold"]
        pr_thresh = model_results["pr"]["threshold"]
    return roc_thresh, pr_thresh

def plot_curve(labels, results, model_list, metric_name, ax=None):
    if ax is None:
        f, ax = plt.subplots()
    if metric_name == "pr":
        ax.set_xlabel("Recall")
        ax.set_ylabel("Precision")
    elif metric_name == "roc":
        ax.set_xlabel("1 - Specificity")
        ax.set_ylabel("Sensitivity")
    else:
        raise ValueError(f"Metric {metric_name} is not supported.")
    for model_name in model_list:
        preds = np.array(results[model_name]["outputs"])
        if metric_name == "pr":
            if model_name == "isolation_forest":
                y_axis = results[model_name]["holdout"]["pr"]["precision"]
                x_axis = results[model_name]["holdout"]["pr"]["recall"]
            else:
                precision, recall, _ = metrics.precision_recall_curve(labels, preds)
                y_axis = precision[:-1]
                x_axis = recall[:-1]
        elif metric_name == "roc":
            if model_name == "isolation_forest":
                y_axis = results[model_name]["holdout"]["roc"]["tpr"]
                x_axis = results[model_name]["holdout"]["roc"]["fpr"]
            else:
                fpr, tpr, thresh_array = metrics.roc_curve(labels, preds, pos_label=1)
                y_axis = tpr  # Sensitivity
                x_axis = fpr  # 1 - Specificity
        if model_name == "euroscore":
            alpha = 1
            lw = 1.5
            c = "b"
        elif "gradient_boosting" in model_name:
            alpha = 1
            lw = 1.5
            c = "r"
        else:
            alpha = 0.6
            lw = 1
            c = None
        if model_name in ["euroscore", "isolation_forest", "naive_bayes"]:
            model_name += "*"
        format_name = model_name.replace("_balanced", "")
        format_name = " ".join([word.capitalize() for word in format_name.split("_")])
        if format_name == "Euroscore*":
            format_name = "Euroscore II*"
        ax.plot(x_axis, y_axis, label=format_name, linewidth=lw, alpha=alpha, c=c)
    ax.axis("equal")

if __name__ == "__main__":

    with open(OUTPUT_PATH, "r") as f:
        results = json.load(f)

    train_data = load_split(TRAIN_SPLIT)
    test_data = load_split(TEST_SPLIT, euroscore=True)
    test_labels = test_data["labels"]

    # ROC and PR Curves
    _ = results.pop("isolation_forest", None)
    model_names = results.keys()
    balanced_models = [name for name in model_names if "balanced" in name]
    balanced_models = sorted(balanced_models)
    imbalanced_models = [name.replace("_balanced", "") for name in balanced_models]
    assert len(imbalanced_models) == len(
        list(set(imbalanced_models) & set(model_names))
    ), "Not all balanced models have an 'imbalanced' counterpart"
    remaining_models = list(
        set(model_names) - (set(imbalanced_models) | set(balanced_models))
    )
    remaining_models = sorted(remaining_models)
    balanced_models = remaining_models + balanced_models
    imbalanced_models = remaining_models + imbalanced_models

    # Plot ROC balanced and imbalanced
    f_imb, axs_imb = plt.subplots(1, 2)
    plot_curve(
        labels=test_labels,
        results=results,
        model_list=imbalanced_models,
        metric_name="roc",
        ax=axs_imb[0],
    )
    axs_imb[0].grid()
    axs_imb[0].set_title("ROC")
    plot_curve(
        labels=test_labels,
        results=results,
        model_list=imbalanced_models,
        metric_name="pr",
        ax=axs_imb[1],
    )
    axs_imb[1].grid()
    axs_imb[1].set_title("PR")
    title = f_imb.suptitle("Imbalanced")
    handles, labels = axs_imb[0].get_legend_handles_labels()
    f_imb.set_size_inches(7.3, 3.5)
    lgd = f_imb.legend(
        handles,
        labels,
        loc="lower center",
        ncol=3,
        bbox_to_anchor=(0, -0.3, 1, 1),
        bbox_transform=f_imb.transFigure,
        fancybox=True,
    )
    save_figure(
        f_imb,
        "figures/imbalanced_curves.tiff",
        bbox_extra_artists=(lgd, title),
        bbox_inches="tight",
    )
    # Plot ROC balanced and imbalanced
    f_bal, axs_bal = plt.subplots(1, 2)
    plot_curve(
        labels=test_labels,
        results=results,
        model_list=balanced_models,
        metric_name="roc",
        ax=axs_bal[0],
    )
    axs_bal[0].grid()
    axs_bal[0].set_title("ROC")
    plot_curve(
        labels=test_labels,
        results=results,
        model_list=balanced_models,
        metric_name="pr",
        ax=axs_bal[1],
    )
    axs_bal[1].grid()
    axs_bal[1].set_title("PR")
    title = f_bal.suptitle("Balanced")
    handles, labels = axs_bal[0].get_legend_handles_labels()
    f_bal.set_size_inches(7.3, 3.5)
    lgd = f_bal.legend(
        handles,
        labels,
        loc="lower center",
        ncol=3,
        bbox_to_anchor=(0, -0.3, 1, 1),
        bbox_transform=f_bal.transFigure,
        fancybox=True,
    )
    save_figure(
        f_bal,
        "figures/balanced_curves.tiff",
        bbox_extra_artists=(lgd, title),
        bbox_inches="tight",
    )

    plt.close("all")

    # Feature importance

    feature_importance = results["gradient_boosting"]["feature_importance"]
    indexes = list(feature_importance.keys())
    feat_names = [int(idx.replace("f", "")) for idx in indexes]
    feat_names = [test_data["features"][name] for name in feat_names]
    feat_names = [FEATURE_TRANSLATION[name] for name in feat_names]
    feat_values = [feature_importance[idx] for idx in indexes]
    ordered = np.argsort(feat_values)[::-1]

    feat_names = [feat_names[i] for i in ordered]
    feat_values = [feat_values[i] for i in ordered]

    f_imp, ax = plt.subplots(figsize=(7.3, 3.5))
    y_pos = np.arange(len(feat_names))
    ax.barh(y_pos, feat_values)
    ax.set_yticks(y_pos)
    ax.set_yticklabels(feat_names)
    ax.invert_yaxis()  # labels read top-to-bottom
    ax.set_xlabel("Importance (Split Gain)")

    save_figure(f_imp, "figures/feature_importance.tiff", bbox_inches="tight")

    plt.close("all")

    # SHAP values

    shap_values = results["gradient_boosting"]["shap_values"]
    shap_values = np.abs(np.array(shap_values)).mean(axis=0)
    ordered = np.argsort(shap_values)[::-1]

    feat_names = [test_data["features"][i] for i in ordered]
    shap_values = [shap_values[i] for i in ordered]

    useful = np.argwhere(np.array(shap_values) > 0)[:, 0].tolist()

    feat_names = [FEATURE_TRANSLATION[feat_names[i]] for i in useful]
    shap_values = [shap_values[i] for i in useful]

    f_shap, ax = plt.subplots(figsize=(7.3, 3.5))
    y_pos = np.arange(len(feat_names))
    ax.barh(y_pos, shap_values)
    ax.set_yticks(y_pos)
    ax.set_yticklabels(feat_names)
    ax.invert_yaxis()  # labels read top-to-bottom
    ax.set_xlabel("Importance (SHAP)")

    save_figure(f_shap, "figures/shap_values.tiff", bbox_inches="tight")

    plt.close("all")

    shap_values = np.array(results["gradient_boosting"]["shap_values"])
    shap.summary_plot(
        shap_values,
        features=train_data["data"],
        feature_names=[FEATURE_TRANSLATION[name] for name in train_data["features"]],
        show=False,
    )

    ax = plt.gca()
    f_summary = ax.figure

    save_figure(f_summary, "figures/shap_summary.tiff", dpi=300, bbox_inches="tight")

    # Create Confusion Matrices

    euroscore = np.array(results["euroscore"]["outputs"])
    euroscore_roc_thresh, euroscore_pr_thresh = get_thresholds(results["euroscore"])
    gradient_boosting = np.array(results["gradient_boosting"]["outputs"])
    gradient_boosting_roc_thresh, gradient_boosting_pr_thresh = get_thresholds(
        results["gradient_boosting"]
    )

    fontsize = 8

    euroscore_roc, ax = plot_confusion_matrix_from_data(
        y_test=test_labels,
        predictions=euroscore >= euroscore_roc_thresh,
        figsize=[3.5, 3.5],
        fz=fontsize,
        columns=["Alive", "Dead"],
    )
    title = ax.set_title(
        f"Euroscore II  ROC (Youden's J)\nThreshold: {euroscore_roc_thresh * 100 :.02f}%",
        fontsize=fontsize + 1,
    )
    save_figure(
        euroscore_roc,
        "figures/euroscore_roc.tiff",
        bbox_extra_artists=(title,),
        bbox_inches="tight",
    )

    euroscore_pr, ax = plot_confusion_matrix_from_data(
        y_test=test_labels,
        predictions=euroscore >= euroscore_pr_thresh,
        figsize=[3.5, 3.5],
        fz=fontsize,
        columns=["Alive", "Dead"],
    )
    title = ax.set_title(
        f"Euroscore II  PR (F1)\nThreshold: {euroscore_pr_thresh * 100 :.02f}%",
        fontsize=fontsize + 1,
    )
    save_figure(
        euroscore_pr,
        "figures/euroscore_pr.tiff",
        bbox_extra_artists=(title,),
        bbox_inches="tight",
    )

    gradient_boosting_roc, ax = plot_confusion_matrix_from_data(
        y_test=test_labels,
        predictions=gradient_boosting >= gradient_boosting_roc_thresh,
        figsize=[3.5, 3.5],
        fz=fontsize,
        columns=["Alive", "Dead"],
    )
    title = ax.set_title(
        f"Gradient Boosting  ROC (Youden's J)\nThreshold: {gradient_boosting_roc_thresh * 100 :.02f}%",
        fontsize=fontsize + 1,
    )
    save_figure(
        gradient_boosting_roc,
        "figures/gradient_boosting_roc.tiff",
        bbox_extra_artists=(title,),
        bbox_inches="tight",
    )

    gradient_boosting_pr, ax = plot_confusion_matrix_from_data(
        y_test=test_labels,
        predictions=gradient_boosting >= gradient_boosting_pr_thresh,
        figsize=[3.5, 3.5],
        fz=fontsize,
        columns=["Alive", "Dead"],
    )
    title = ax.set_title(
        f"Gradient Boosting  PR (F1)\nThreshold: {gradient_boosting_pr_thresh * 100 :.02f}%",
        fontsize=fontsize + 1,
    )
    save_figure(
        gradient_boosting_pr,
        "figures/gradient_boosting_pr.tiff",
        bbox_extra_artists=(title,),
        bbox_inches="tight",
    )

    plt.close("all")


import sqlite3

db_path = '/scraper/database/catalogue.db'

def create_connection():
    """
    Creates connection with the SQLite database
    :return: Connection and Cursor object
    """
    try:
        conn = sqlite3.connect(db_path)
        cur = conn.cursor()
        return conn, cur
    except Exception as err:
        print(f'Error in establishing connection with SQLite database {err}')

def create_table():
    """
    Creates the required tables for the given SQLite database
    """
    try:
        conn, cur = create_connection()

        # Create manufacturer table
        cur.execute('''CREATE TABLE IF NOT EXISTS tbl_manufacturer(
                 manufacturer text,
                 category_id integer,
                 model_id integer,
                 part text,
                 part_category_id integer
                )''')

        # Create model table
        cur.execute('''CREATE TABLE IF NOT EXISTS tbl_model(
                 id integer,
                 model text
                )''')

        # Create category table
        cur.execute('''CREATE TABLE IF NOT EXISTS tbl_category(
                 id integer,
                 category text
                )''')

        # Create part_category table
        cur.execute('''CREATE TABLE IF NOT EXISTS tbl_part_category(
                 id integer,
                 part_category text
                )''')

        close_connection(conn)
    except Exception as err:
        print(f'Error in creating tables in the SQLite database {err}')

def close_connection(conn):
    """
    Closes the connection with the SQLite database
    :param conn: Connection object for the database
    """
    try:
        conn.close()
    except Exception as err:
        print(f'Error in closing connection with the SQLite database {err}')


import argparse
import json
import os
import shutil
import subprocess
import sys

import sbol3
import labop
from labop.data import serialize_sample_format
from labop.strings import Strings
import xarray as xr
from tyto import OM
import tyto

from labop_convert.pylabrobot.pylabrobot_specialization import (
    PylabrobotSpecialization,
)

filename = "".join(__file__.split(".py")[0].split("/")[-1:])
OUT_DIR = os.path.join(os.path.dirname(__file__), "artifacts")
if not os.path.exists(OUT_DIR):
    os.mkdir(OUT_DIR)

def generate_initialize_subprotocol(doc):
    protocol = labop.Protocol("initialize")
    doc.add(protocol)

    # create the materials to be provisioned
    PLASMID = sbol3.Component(
        "ddH2O", "https://identifiers.org/pubchem.substance:24901740"
    )
    PLASMID.name = "DNA TO BE PURIFIEd"

    doc.add(PLASMID)

    PROTOCOL_NAME = "initialize_simple_transfer"
    PROTOCOL_LONG_NAME = "initialize_simple_transfer"
    protocol = labop.Protocol(PROTOCOL_NAME)
    protocol.name = PROTOCOL_LONG_NAME
    protocol.version = "1.2"
    protocol.description = """
 protocol to initialize transfer to a MPE container
    """

    doc.add(protocol)

    load_Tiprack_on_deck = protocol.primitive_step(
        "LoadRackOnInstrument",
        rack=labop.ContainerSpec("tiprack", queryString="cont:HTF_L"),
        coordinates="(x=100, y=100, z=100)",
    )

    PLASMID_plate = protocol.primitive_step(
        "LoadContainerOnInstrument",
        specification=labop.ContainerSpec(
            "PLASMID_plate",
            name="PLASMID_plate",
            queryString="cont:Cos_96_PCR",
            prefixMap={
                "cont": "https://github.com/PyLabRobot/pylabrobot/blob/main/pylabrobot/resources/corning_costar/plates.py"
            },
        ),
        slots="(x=200, y=100, z=100)",
    )

    MPE_plate = protocol.primitive_step(
        "LoadContainerOnInstrument",
        specification=labop.ContainerSpec(
            "MPE_plate",
            name="MPE_plate",
            queryString="cont:Cos_96_EZWash",
            prefixMap={
                "cont": "https://github.com/PyLabRobot/pylabrobot/blob/main/pylabrobot/resources/corning_costar/plates.py"
            },
        ),
        slots="(x=400, y=100, z=100)",
    )

    provision = protocol.primitive_step(
        "Provision",
        resource=PLASMID,
        destination=PLASMID_plate.output_pin("samples"),
        amount=sbol3.Measure(30, OM.microliter),
    )

    output1 = protocol.designate_output(
        "PLASMID_plate",
        "http://bioprotocols.org/labop#SampleArray",
        source=PLASMID_plate.output_pin("samples"),
    )

    output2 = protocol.designate_output(
        "MPE_plate",
        "http://bioprotocols.org/labop#SampleArray",
        source=MPE_plate.output_pin("samples"),
    )

    ### the provision step creates the reagents as objects and attaches them to the containers where they'll be located

    return protocol

def generate_protocol():
    import labop
    from labop_convert import DefaultBehaviorSpecialization

    doc = sbol3.Document()
    sbol3.set_namespace("http://labop.io/")

    #############################################
    # Import the primitive libraries
    # print("Importing libraries")
    labop.import_library("liquid_handling")
    # print("... Imported liquid handling")
    labop.import_library("plate_handling")
    # print("... Imported plate handling")
    labop.import_library("sample_arrays")
    # print("... Imported sample arrays")

    PROTOCOL_NAME = "simple_transfer"
    PROTOCOL_LONG_NAME = "simple_transfer"
    protocol = labop.Protocol(PROTOCOL_NAME)
    protocol.name = PROTOCOL_LONG_NAME
    protocol.version = "1.2"
    protocol.description = """
 protocol to transfer plasmid and ethanol to a MPE container
    """
    doc.add(protocol)

    initialize_subprotocol = generate_initialize_subprotocol(doc)

    initialization = protocol.primitive_step(initialize_subprotocol)

    plan_mapping = serialize_sample_format(
        xr.DataArray(
            [
                [
                    [
                        [
                            (20.0 if source_aliquot == target_aliquot else 0.0)
                            for target_aliquot in ["A1", "A2", "A3"]
                        ]
                    ]
                    for source_aliquot in ["A1", "A2", "A3"]
                ]
            ],
            dims=(
                f"source_{Strings.CONTAINER}",
                f"source_{Strings.LOCATION}",
                f"target_{Strings.CONTAINER}",
                f"target_{Strings.LOCATION}",
            ),
            coords={
                f"source_{Strings.CONTAINER}": [
                    initialization.output_pin("PLASMID_plate").name
                ],
                f"source_{Strings.LOCATION}": ["A1", "A2", "A3"],
                f"target_{Strings.CONTAINER}": [
                    initialization.output_pin("MPE_plate").name
                ],
                f"target_{Strings.LOCATION}": ["A1", "A2", "A3"],
            },
        )
    )

    # The SampleMap specifies the sources and targets, along with the mappings.
    plan = labop.SampleMap(
        sources=[initialization.output_pin("PLASMID_plate")],
        targets=[initialization.output_pin("MPE_plate")],
        values=plan_mapping,
    )

    # The outputs of the create_source and create_target calls will be identical
    # to the source_array and target_array.  They will not be on the output pin
    # until execution, but the SampleMap needs to reference them.
    transfer_by_map = protocol.primitive_step(
        "TransferByMap",
        source=initialization.output_pin("PLASMID_plate"),
        destination=initialization.output_pin("MPE_plate"),
        plan=plan,
        amount=sbol3.Measure(20, tyto.OM.milliliter),
        temperature=sbol3.Measure(30, tyto.OM.degree_Celsius),
    )

    protocol.to_dot().render(
        os.path.join(OUT_DIR, f"{filename}-protocol-graph")
    )

    protocol_file = os.path.join(OUT_DIR, f"{filename}-protocol.nt")
    with open(protocol_file, "w") as f:
        print(f"Saving protocol [{protocol_file}].")
        f.write(doc.write_string(sbol3.SORTED_NTRIPLES).strip())

    ee = labop.ExecutionEngine(
        out_dir=OUT_DIR,
        failsafe=False,
        specializations=[
            PylabrobotSpecialization(
                filename=os.path.join(OUT_DIR, f"{filename}-pylabrobot.py")
            )
        ],
        sample_format="xarray",
    )

    execution = ee.execute(
        protocol,
        sbol3.Agent("test_agent"),
        id="test_execution",
        parameter_values=[],
    )
    # ee.prov_observer.to_dot().render(os.path.join(OUT_DIR, f"{filename}-sample-graph"))

if __name__ == "__main__":
    generate_protocol()


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# =============================================================================
# Copyright (c) Ostap developpers.
# =============================================================================
## @file ostap/math/tests/test_math_linalgt.py
#  Test module for the file ostap/math/linalgt.py
# =============================================================================
""" Test module for ostap/math/linalgt.py
"""
# =============================================================================
from __future__             import print_function
from   sys                  import version_info as python_version
from   ostap.math.base      import typename
from   ostap.math.linalg    import checkops
from   ostap.core.core      import Ostap
from   ostap.core.meta_info import root_version_int
import ostap.logger.table   as     T
import ROOT, array, random
# =============================================================================
# logging
# =============================================================================
from ostap.logger.logger import getLogger
if '__main__' ==  __name__ : logger = getLogger ( 'tests_math_linalgt'  )
else                       : logger = getLogger ( __name__              )
# =============================================================================
try :
    import numpy as np
except ImportError :
    np = None

# =============================================================================
def test_linalgt_vct () :

    logger = getLogger ( "test_linalgt_vct" )

    logger.info ( 'Basic operations with vectors' )

    LA3 = Ostap.Vector(3)

    l1  = LA3 ( 0 , 1 , 2 )
    l2  = LA3 ( 3 , 4 , 5 )

    t1  = ROOT.TVectorD(3)
    t2  = ROOT.TVectorD(3)

    t1 [ 0 ] , t1 [ 1 ] , t1 [ 2]  = 0 , 1 , 2
    t2 [ 0 ] , t2 [ 1 ] , t2 [ 2 ] = 3 , 4 , 5

    logger.info ( 'l1 ,  l2    : %s ,  %s      '    % ( l1 , l2  ) )
    logger.info ( 't1 ,  t2    : %s ,  %s      '    % ( t1 , t2  ) )

    logger.info ( 'l1 +  l2    : %s +  %s = %s '    % ( l1 , l2 , l1 + l2  ) )
    logger.info ( 'l1 +  t2    : %s +  %s = %s '    % ( l1 , t2 , l1 + t2  ) )
    logger.info ( 't1 +  l2    : %s +  %s = %s '    % ( t1 , l2 , t1 + l2  ) )
    logger.info ( 't1 +  t2    : %s +  %s = %s '    % ( t1 , t2 , t1 + t2  ) )

    logger.info ( 'l1 -  l2    : %s -  %s = %s '    % ( l1 , l2 , l1 - l2  ) )
    logger.info ( 'l1 -  t2    : %s -  %s = %s '    % ( l1 , t2 , l1 - t2  ) )
    logger.info ( 't1 -  l2    : %s -  %s = %s '    % ( t1 , l2 , t1 - l2  ) )
    logger.info ( 't1 -  t2    : %s -  %s = %s '    % ( t1 , t2 , t1 - t2  ) )

    logger.info ( 'l1 *   2    : %s *  %s = %s '    % ( l1 ,  2 , l1 *  2  ) )
    logger.info ( 't1 *   2    : %s *  %s = %s '    % ( t1 ,  2 , t1 *  2  ) )

    logger.info ( 'l1 /   3    : %s /  %s = %s '    % ( l1 ,  3 , l1 *  3  ) )
    logger.info ( 't1 /   3    : %s /  %s = %s '    % ( t1 ,  3 , t1 *  3  ) )

    logger.info ( ' 2 *  l1    : %s *  %s = %s '    % (  2 , l1 ,  2 *  l1 ) )
    logger.info ( ' 2 *  t1    : %s *  %s = %s '    % (  2 , t1 ,  2 *  t1 ) )

    logger.info ( 'l1 *  l2    : %s *  %s = %s '    % ( l1 , l2 , l1 * l2  ) )
    logger.info ( 'l1 *  t2    : %s *  %s = %s '    % ( l1 , t2 , l1 * t2  ) )
    logger.info ( 't1 *  l2    : %s *  %s = %s '    % ( t1 , l2 , t1 * l2  ) )
    logger.info ( 't1 *  t2    : %s *  %s = %s '    % ( t1 , t2 , t1 * t2  ) )

    logger.info ( 'l1 x  l2    : %s x  %s = \n%s '  % ( l1 , l2 , l1.cross ( l2 ) ) )
    logger.info ( 'l1 x  t2    : %s x  %s = \n%s '  % ( l1 , t2 , l1.cross ( t2 ) ) )
    logger.info ( 't1 x  l2    : %s x  %s = \n%s '  % ( t1 , l2 , t1.cross ( l2 ) ) )
    logger.info ( 't1 x  t2    : %s x  %s = \n%s '  % ( t1 , t2 , t1.cross ( t2 ) ) )

    logger.info ( 'l1 == l2    : %s == %s = %s '    % ( l1 , l2 , l1 == l2  ) )
    logger.info ( 'l1 == t2    : %s == %s = %s '    % ( l1 , t2 , l1 == t2  ) )
    logger.info ( 't1 == l2    : %s == %s = %s '    % ( t1 , l2 , t1 == l2  ) )
    logger.info ( 't1 == t2    : %s == %s = %s '    % ( t1 , t2 , t1 == t2  ) )

    logger.info ( 'l1 != l2    : %s != %s = %s '    % ( l1 , l2 , l1 != l2  ) )
    logger.info ( 'l1 != t2    : %s != %s = %s '    % ( l1 , t2 , l1 != t2  ) )
    logger.info ( 't1 != l2    : %s != %s = %s '    % ( t1 , l2 , t1 != l2  ) )
    logger.info ( 't1 != t2    : %s != %s = %s '    % ( t1 , t2 , t1 != t2  ) )

    v1 = ( 0 , 1 , 2 )
    logger.info ( 'l1 == tuple : %s == %s = %s '    % (  l1 , v1 , l1 == v1 ) )
    logger.info ( 't1 == tuple : %s == %s = %s '    % (  t1 , v1 , t1 == v1 ) )
    logger.info ( 'tuple == l1 : %s == %s = %s '    % (  v1 , l1 , v1 == l1 ) )
    logger.info ( 'tuple == t1 : %s == %s = %s '    % (  v1 , t1 , v1 == t1 ) )

    v1 = [ 0 , 1 , 2 ]
    logger.info ( 'l1 == list  : %s == %s = %s '    % (  l1 , v1 , l1 == v1 ) )
    logger.info ( 't1 == list  : %s == %s = %s '    % (  t1 , v1 , t1 == v1 ) )
    logger.info ( 'list == l1  : %s == %s = %s '    % (  v1 , l1 , v1 == l1 ) )
    logger.info ( 'list == t1  : %s == %s = %s '    % (  v1 , t1 , v1 == t1 ) )

    l1 *= 2
    t1 *= 2
    logger.info ( 'l1 *= 2     : %s '  % l1 )
    logger.info ( 't1 *= 2     : %s '  % t1 )

    l1 /= 2
    t1 /= 2
    logger.info ( 'l1 /= 2     : %s '  % l1 )
    logger.info ( 't1 /= 2     : %s '  % t1 )

    ## if ( 3 , 5 ) <= python_version :

    ##     logger.info ( 'l1 @ l2 : %s    '  % ( l1 @ l2  ) )
    ##     logger.info ( 'l1 @  2 : %s    '  % ( l1 @  2  ) )
    ##     logger.info ( ' 2 @ l2 : %s    '  % ( 2  @ l2  ) )

    ##summary table for allowed  binary operations
    checkops ( l1 , l2 , logger = logger )
    checkops ( l1 , t2 , logger = logger )
    checkops ( t1 , l2 , logger = logger )
    checkops ( t1 , t2 , logger = logger )

# =============================================================================
def test_linalgt_mtrx () :

    logger = getLogger ( "test_linalgt_mtrx" )

    logger.info ( 'Basic operations with matrices' )

    rows = [ ( 'Type1' , 'Op' , 'Type2' , 'Result' ) ]

    m22 = Ostap.Math.Matrix(2,2)  ()
    m23 = Ostap.Math.Matrix(2,3)  ()
    s22 = Ostap.Math.SymMatrix(2) ()

    t22 = ROOT.TMatrixD    ( 2 , 2 )
    t23 = ROOT.TMatrixD    ( 2 , 3 )
    r22 = ROOT.TMatrixDSym ( 2     )

    l2  = Ostap.Math.Vector(2)( 1 , 2 )
    l3  = Ostap.Math.Vector(3)( 1 , 2 , 3 )
    t2  = ROOT.TVectorD ( 2 )
    t3  = ROOT.TVectorD ( 3 )

    vectors2    = ( l2 , t2 )
    vectors3    = ( l3 , t3 )
    vectorsa    = vectors2  + vectors3
    matrices22  = s22 , m22 , r22 , t22
    matrices23  = m23 , t23
    symmatrices = s22 , r22

    t2 [ 0 ] , t2 [ 1 ]   = 1 , 2
    t3 [ 0 ] , t3 [ 1 ] , t3 [ 2 ] = 1 , 2 , 3

    logger.info ( 'initial    l2 , l3 : %s , %s '  % ( l2 , l3  ) )
    logger.info ( 'initial    t2 , t3 : %s , %s '  % ( t2 , t3  ) )

    m22 [ 0 , 0 ] = 1
    m22 [ 0 , 1 ] = 1
    m22 [ 1 , 1 ] = 1

    m23 [ 0 , 0 ] = 1
    m23 [ 1 , 1 ] = 1
    m23 [ 0 , 2 ] = 1

    s22 [ 0 , 0 ] = 2
    s22 [ 1 , 0 ] = 1
    s22 [ 1 , 1 ] = 3

    t22 [ 0 , 0 ] = 1
    t22 [ 0 , 1 ] = 1
    t22 [ 1 , 1 ] = 1

    t23 [ 0 , 0 ] = 1
    t23 [ 1 , 1 ] = 1
    t23 [ 0 , 2 ] = 1

    r22 [ 0 , 0 ] = 2
    r22 [ 1 , 0 ] = 1
    r22 [ 1 , 1 ] = 3

    logger.info ( 'initial    m22\n%s'    % m22     )
    logger.info ( 'initial    s22\n%s'    % s22     )
    logger.info ( 'initial    m23\n%s'    % m23     )

    logger.info ( 'initial    t22\n%s'    % t22     )
    logger.info ( 'initial    r22\n%s'    % r22     )
    logger.info ( 'initial    t23\n%s'    % t23     )

    logger.info ( 'scale      m22/3\n%s'  % (m22/3) )
    logger.info ( 'scale      m23*3\n%s'  % (m23*3) )
    logger.info ( 'scale      3*m23\n%s'  % (3*m23) )

    logger.info ( 'scale      t22/3\n%s'  % (t22/3) )
    logger.info ( 'scale      t23*3\n%s'  % (t23*3) )
    logger.info ( 'scale      3*t23\n%s'  % (3*t23) )

    s22 += 2
    logger.info ( 'iadd       s22+=2\n%s'   % (s22) )
    s22 -= 2
    logger.info ( 'isub       s22+=2\n%s'   % (s22) )

    m22 += 2
    logger.info ( 'iadd       m22+=2\n%s'   % (m22) )
    m22 -= 2
    logger.info ( 'isub       m22+=2\n%s'   % (m22) )

    t22 += 2
    logger.info ( 'iadd       t22+=2\n%s'   % (t22) )
    t22 -= 2
    logger.info ( 'isub       t22+=2\n%s'   % (t22) )

    r22 += 2
    logger.info ( 'iadd       r22+=2\n%s'   % (r22) )
    r22 -= 2
    logger.info ( 'isub       r22+=2\n%s'   % (r22) )

    m22 += s22
    logger.info ( 'iadd       m22+=s22\n%s' % (m22) )
    m22 -= s22
    logger.info ( 'isub       m22-=s22\n%s' % (m22) )

    m22 += r22
    logger.info ( 'iadd       m22+=r22\n%s' % (m22) )
    m22 -= r22
    logger.info ( 'isub       m22-=r22\n%s' % (m22) )

    m22 += t22
    logger.info ( 'iadd       m22+=t22\n%s' % (m22) )
    m22 -= t22
    logger.info ( 'isub       m22-=t22\n%s' % (m22) )

    t22 += r22
    logger.info ( 'iadd       t22+=r22\n%s' % (t22) )
    t22 -= r22
    logger.info ( 'isub       r22-=r22\n%s' % (t22) )

    t22 += s22
    logger.info ( 'iadd       t22+=s22\n%s' % (t22) )
    t22 -= s22
    logger.info ( 'isub       r22-=s22\n%s' % (t22) )

    t22 += m22
    logger.info ( 'iadd       t22+=m22\n%s' % (t22) )
    t22 -= m22
    logger.info ( 'isub       r22-=m22\n%s' % (t22) )

    ## the basic operations
    for v1 in vectors2 :
        n1 = typename ( v1 )
        for v2 in vectors2 :
            n2 = typename ( v1 )

            r = v1 + v2
            row     = n1 , '+' , n2 , typename ( r )
            rows.append ( row )

            r = v1 - v2
            row     = n1 , '-' , n2 , typename ( r )
            rows.append ( row )

            v1 += v2
            row     = n1 , '+=' , n2 , typename ( v1 )
            rows.append ( row )

            v1 -= v2
            row     = n1 , '-=' , n2 , typename ( v1 )
            rows.append ( row )

            r = v1 * v2
            row     = n1 , '*' , n2 , typename ( r )
            rows.append ( row )

    ## cross-product (tensor product)
    for v1 in vectorsa :
        n1 = typename ( v1 )
        for v2 in vectorsa :
            n2 = typename ( v2 )
            r = v1.cross  ( v1 )
            row     = n1 , 'x' , n2 , typename ( r )
            rows.append ( row )
            logger.info ( ' %-25s x   %25s \n%s' % ( n1 , n2 , r ) )

    ## matrix-vector multiplications
    for m in matrices22 :
        n1 = typename ( m )
        for v in vectors2 :
            n2 = typename ( v  )
            r   = m * v
            logger.info ( ' %-25s +   %25s = %s' % ( n1 , n2 , r ) )
            row = n1 , '*' , n2 , typename ( r )
            rows.append ( row )

    ## vector-matrix multiplications
    for v in vectors2 :
        n1 = typename ( v  )
        for m in matrices22 :
            n2 = typename ( m )
            r   = v * m
            logger.info ( ' %-25s +   %25s = %s' % ( n1 , n2 , r ) )
            row = n1 ,  '*' , n2 ,  typename ( r )
            rows.append ( row )

    ## matrix addition
    for m1 in matrices22 + ( 1.0 , ) :
        n1 = typename ( m1 )
        for m2 in matrices22 + ( 1.0 , ) :
            n2 = typename ( m2 )
            if isinstance ( m1 , float ) and isinstance ( m2 , float  ) : continue

            r   = m1 + m2
            logger.info ( ' %-25s +   %25s \n%s' % ( n1 , n2 , r ) )
            row = n1 , '+' , n2 , typename ( r )
            rows.append ( row )

    ## matrix subtraction
    for m1 in matrices22 + ( 1.0 , )  :
        n1 = typename ( m1 )
        for m2 in matrices22 + ( 1.0 , ) :
            n2 = typename ( m2 )
            if isinstance ( m1 , float ) and isinstance ( m2 , float  ) : continue

            r   = m1 - m2
            logger.info ( ' %-25s -  %25s \n%s' % ( n1 , n2 , r ) )
            row = n1 , '-' , n2 , typename ( r )
            rows.append ( row )

    ## matrix addtion/subtraction in place
    for m1 in matrices22 :
        n1 = typename ( m1 )
        for m2 in matrices22 + ( 1.0, ):
            n2 = typename ( m2 )

            m1 += m2
            logger.info ( ' %-25s +=  %25s \n%s' % ( n1 , n2 , m1 ) )
            row = n1 , '+=' , n2 , typename ( m1 )
            rows.append ( row )

            m1 -= m2
            logger.info ( ' %-25s -=  %25s \n%s' % ( n1 , n2 , m1 ) )
            row = n1 , '-=' , n2 , typename ( m1 )
            rows.append ( row )

    ## matrix-matrix multiplication
    for m1 in matrices22 :
        n1 = typename ( m1 )
        for m2 in matrices22 + matrices23 :
            n2 = typename ( m2 )

            r_mult   = m1 * m2
            logger.info ( ' %-25s *   %25s \n%s' % ( n1 , n2 , r_mult  ) )

            row3 = n1 , '*' , n2 , typename ( r_mult   )
            rows.append ( row3 )

    ## pow for matrices
    for m1 in matrices22 :

        n1 = typename ( m1 )
        n2 = typename ( 3  )

        print ( 'm1:' , m1 )

        r1 = m1 **  3
        row = n1 , '**' , n2,  typename ( r1 )
        rows.append ( row )

        mm = m1 + 1
        for d in range  ( 3 ) :

            logger.info ( 'power  M**%d\n%s'          % (  d , mm** d ) )
            logger.info ( 'power  M**%d\n%s'          % ( -d , mm**-d ) )
            logger.info ( 'power  (M**%d)*(M**%d)\n%s' % ( d , -d , (mm**d)*(mm**-d)) )

    ## sim for matrices
    for m1 in ( s22 , r22 ) :
        n1 = typename ( m1 )
        for m2 in matrices22 + ( l2 , t2 ) :
            n2 = typename ( m2 )
            r_sim   = m1 .sim (  m2 )
            logger.info ( ' %-25s sim %25s = \n%s' % ( n1 , n2 , r_sim  ) )
            row     = n1 , 'sim' , n2 , typename ( r_sim )
            rows.append ( row )

    ## simT for matrices
    for m1 in ( s22 , r22 ) :
        n1 = typename ( m1 )
        for m2 in matrices22 + matrices23 :
            n2 = typename ( m2 )
            r_sim   = m1 .simT (  m2 )
            logger.info ( ' %-25s simT %25s = \n%s' % ( n1 , n2 , r_sim  ) )
            row     = n1 , 'simT' , n2 , typename ( r_sim )
            rows.append ( row )

    title = 'Binary operations'
    table = T.table ( rows , title = title , prefix = '# ' , alignment = 'lcll' )
    logger.info ( '%s:\n%s' % ( title , table ) )

# =============================================================================
## The main function to test linear algebra
def test_linalgt_old () :
    """The main function to test linear algebra
    """

    logger = getLogger( 'test_linangt_old')

    logger.info('Test Linear Algebra: ')

    logger.info('TEST vectors: ')

    l1 = Ostap.TVector(3)
    l2 = Ostap.TVector(3)

    l1[0],l1[1],l1[2] = 0,1,2
    l2[0],l2[1],l2[2] = 3,4,5

    logger.info ( 'l1 , l2 : %s %s '  % ( l1 , l2  ) )
    logger.info ( 'l1 + l2 : %s    '  % ( l1 + l2  ) )

    logger.info ( 'l1 - l2 : %s    '  % ( l1 - l2  ) )
    logger.info ( 'l1 * l2 : %s    '  % ( l1 * l2  ) )
    logger.info ( 'l1 *  2 : %s    '  % ( l1 *  2  ) )
    logger.info ( ' 2 * l2 : %s    '  % ( 2  * l2  ) )
    logger.info ( 'l1 /  2 : %s    '  % ( l1 /  2  ) )

    l1 /= 2
    logger.info ( 'l1 /= 2 : %s    '  % l1 )
    l1 *= 2
    logger.info ( 'l1 *= 2 : %s    '  % l1 )

    ## if ( 3 , 5 ) <= python_version :

    ##     logger.info ( 'l1 @ l2 : %s    '  % ( l1 @ l2  ) )
    ##     logger.info ( 'l1 @  2 : %s    '  % ( l1 @  2  ) )
    ##     logger.info ( ' 2 @ l2 : %s    '  % ( 2  @ l2  ) )

    logger.info('TEST matrices: ')

    m22 = Ostap.Math.TMatrix(2,2)
    m23 = Ostap.Math.TMatrix(2,3)
    s22 = Ostap.Math.TMatrixSym(2)

    l2  = Ostap.TVector(2)
    l3  = Ostap.TVector(3)

    l2[0]    = 1
    l2[1]    = 2

    l3[0]    = 1
    l3[1]    = 2
    l3[1]    = 3

    logger.info ( 'l2 , l3 : %s %s '  % ( l2 , l3  ) )

    ## if ( 3 , 5 ) <= python_version :

    ##     logger.info ( 'm23 @ 3   :\n%s' % ( m23 @ 3   ) )
    ##     logger.info ( 'm22 @ m23 :\n%s' % ( m22 @ m23 ) )
    ##     logger.info ( 'm22 @  l2 : %s ' % ( m22 @ l2  ) )
    ##     logger.info ( 'm23 @  l3 : %s ' % ( m23 @ l3  ) )

    m22[0,0] = 1
    m22[0,1] = 1
    m22[1,1] = 1

    m23[0,0] = 1
    m23[1,1] = 1
    m23[0,2] = 1

    s22[0,0] = 2
    s22[1,0] = 1
    s22[1,1] = 3

    logger.info ( 'm22\n%s'   % m22     )
    logger.info ( 's22\n%s'   % s22     )
    logger.info ( 'm23\n%s'   % m23     )
    logger.info ( 'm22/3\n%s' % (m22/3) )
    logger.info ( 'm23*3\n%s' % (m23*3) )

    logger.info ( 'm22**3\n%s' % m22**3  )
    logger.info ( 's22**4\n%s' % s22**4  )

    logger.info ( 'm22 * m23 :\n%s' % ( m22 * m23 ) )
    logger.info ( 'm22 *  l2 : %s ' % ( m22 * l2  ) )
    logger.info ( 'l2  * m22 : %s ' % ( l2  * m22 ) )
    logger.info ( 'm23 *  l3 : %s ' % ( m23 * l3  ) )
    logger.info ( 'l2  * m23 : %s ' % ( l2  * m23 ) )

    logger.info ( 'm22 * s22 + 2 * m22 :\n%s ' %  ( m22*s22 + 2*m22  ) )
    logger.info ( 'm22 == m22*1.0 : %s ' % (  m22 == m22 * 1.0 ) )
    logger.info ( 'm22 != m22*1.1 : %s ' % (  m22 != m22 * 1.1 ) )
    logger.info ( 'm23 == m23*1.0 : %s ' % (  m23 == m23 * 1.0 ) )
    logger.info ( 'm23 != m23*1.1 : %s ' % (  m23 != m23 * 1.1 ) )
    logger.info ( 'l1  == l1 *1.0 : %s ' % (  l1  == l1  * 1.0 ) )
    logger.info ( 'l1  != l1 *1.1 : %s ' % (  l1  != l1  * 1.1 ) )
    logger.info ( 's22 == s22*1.0 : %s ' % (  s22 == s22 * 1.0 ) )
    logger.info ( 's22 != s22*1.1 : %s ' % (  s22 != s22 * 1.1 ) )

    logger.info ( ' l1 == (0,1,2) : %s ' % (  l1 == ( 0 , 1 , 2 ) ) )
    logger.info ( ' l1 == [0,1,2] : %s ' % (  l1 == [ 0 , 1 , 2 ] ) )

    m22[0,0] = 1
    m22[0,1] = 2
    m22[1,0] = 2
    m22[1,1] = 3

    s22[0,0] = 1
    s22[0,1] = 2
    s22[1,1] = 3

    logger.info ( ' m22 == s22     : %s ' % ( m22 == s22       ) )
    logger.info ( ' m22 == s22*1.0 : %s ' % ( m22 == s22 * 1.0 ) )
    logger.info ( ' m22 != s22*1.1 : %s ' % ( m22 != s22 * 1.1 ) )

    m22 += m22*2
    m22 -= m22*1

    m22 += s22*2
    m22 -= s22*1

    s22 += s22*2
    s22 -= s22*1

    ## DISABLE!!!
    if np : ## and False :

        logger.info ( 'Operations with numpy objects')

        v2 = np.array ( [1.0,2.0]      )
        v3 = np.array ( [1.0,2.0,3.0 ] )

        logger.info ( 'v2  * l2  : %s' % ( v2  * l2  ) )
        logger.info ( 'l3  * v3  : %s' % ( l3  * v3  ) )
        logger.info ( 's22 * v2  : %s' % ( s22 * v2  ) )
        logger.info ( 'm22 * v2  : %s' % ( m22 * v2  ) )
        logger.info ( 'm23 * v3  : %s' % ( m23 * v3  ) )

        n22_m = m22.to_numpy ()
        n22_s = s22.to_numpy ()
        n23   = m23.to_numpy ()

        if 62006 <= root_version_int :
            logger.warning ("Tests with numpy are broken for ROOT %s" %  root_version_int )
        else :
            logger.info ( 'm22  * m22(np) :\n%s' % ( m22 * m22.to_numpy() ) )
            logger.info ( 's22  * s22(np) :\n%s' % ( s22 * s22.to_numpy() ) )
            logger.info ( 's22  * m23(np) :\n%s' % ( s22 * m23.to_numpy() ) )
            logger.info ( 'l2   * m22(np) :\n%s' % ( l2  * m22.to_numpy() ) )

# ==============================================================================
## test to check TMatrix <-> array interplay
def test_linalgt_arr () :
    """Test to check TMatrix <-> array interplay"""

    logger = getLogger( 'test_linangt_2')

    M = ROOT.TMatrixD

    for k in range ( 1 , 11  ) :
        for n in range ( 1 , 11  ) :

            m = M ( k , n )

            for r in range ( m.GetNrows() ) :
                for c in range ( m.GetNcols () ) :
                    m [ r , c ] = random.uniform ( -10 , 10 )

            ## create the array from matrix
            a = array.array ( 'd' , m )
            assert len(a) == m.GetNoElements() , \
                   'Invalid array is created!'

            ## recteare it from the array
            m2 = M ( k , n , a )

            assert m == m2 , 'Matrix is nor recreated!'

            logger.info ('Test with TMatrixD(%2d,%2d) is %s' % ( k , n , m == m2 ) )

    MS = ROOT.TMatrixDSym

    for k in range ( 1 , 11  ) :

        m = MS ( k)

        for r in range ( m.GetNrows() ) :
            for c in range ( m.GetNcols () ) :
                m [ r , c ] = random.uniform ( -10 , 10 )

        ## create the array from matrix
        a = array.array ( 'd' , m )
        assert len ( a ) == m.GetNoElements () , 'Invalid array is created!'

        ## recreate it from the array
        m2 = MS ( k , a )

        assert m == m2 , 'Matrix is nor recreated!'

        logger.info ('Test with TMatrixDSym(%2d) is %s' % ( k , m == m2 ) )

# =============================================================================
if '__main__' == __name__ :

    test_linalgt_vct  ()
    test_linalgt_mtrx ()
    test_linalgt_old  ()
    test_linalgt_arr  ()

# =============================================================================
##                                                                      The END
# =============================================================================


#!/usr/bin/env python

import math
import numpy as np

def square_diff(A,B):
    "a and b are n-dimensional vectors"
    return sum([(a-b)**2 for a,b in zip(A,B)])

def distance(A,B):
    "a and b are n-dimensional vectors"
    return math.sqrt(square_diff(A,B))

def angle(A,B,C):
    "3D space, A in CENTER"
    d12 = distance(A,B)
    d13 = distance(A,C)
    d23 = distance(B,C)
    #round. To avoid things like 1.000000001
    ang_in_rad = math.acos(round((d12**2 + d13**2 - d23**2)/(2*d12*d13), 7))
    return np.degrees(ang_in_rad)

def dihedral(A,B,C,D):
    """Calculate dihedral considering A in the beggining"""
    A, B, C, D = [np.array(x) for x in (A,B,C,D)]
    b1 = B - A
    b2 = C - B
    b3 = D - C
    temp = np.linalg.norm(b2) * b1
    y = np.dot(temp, np.cross(b2, b3))
    x = np.dot(np.cross(b1, b2), np.cross(b2, b3))
    return np.degrees(math.atan2(y, x))

def anymetric(TUPLIST):
    """TUPLIST can have 2,3 or 4 tuples of x,y,z values"""
    if len(TUPLIST) == 2:
        A,B = TUPLIST
        return distance(A,B)
    elif len(TUPLIST) == 3:
        A,B,C = TUPLIST
        return angle(B,A,C) # NOTE CONSISTENT WITH GAUSSIAN MODREDUNDANT
    elif len(TUPLIST) == 4:
        A,B,C,D = TUPLIST
        return dihedral(A,B,C,D)
    else:
        raise RuntimeError('len(TUPLIST) must be 2,3 or 4')

def difang(a, b):
    """min RADIANs difference either clock or counter-clock-wise"""
    alldifs = [abs(a-b+(i*math.pi)) for i in [-4, -2, 0, 2, 4]]
    return min(alldifs)

def rot3D(pt, ax, rad):
    """
Rotate point:
pt = (x,y,z) coordinates to be rotated
ax = vector around wich rotation is performed
rad = rotate by "rad" radians
"""
    # Make sure ax has unitary length
    len_ax = distance(ax, (0,0,0))
    u, v, w = [i/len_ax for i in ax]
    x, y, z = pt
    ux, uy, uz = u*x, u*y, u*z
    vx, vy, vz = v*x, v*y, v*z
    wx, wy, wz = w*x, w*y, w*z
    sa=math.sin(rad)
    ca=math.cos(rad)
    #pt[0]=(u*(ux+vy+wz)+(x*(v*v+w*w)-u*(vy+wz))*ca+(-wy+vz)*sa)+ m[0]
    #pt[1]=(v*(ux+vy+wz)+(y*(u*u+w*w)-v*(ux+wz))*ca+(wx-uz)*sa)+ m[1]
    #pt[2]=(w*(ux+vy+wz)+(z*(u*u+v*v)-w*(ux+vy))*ca+(-vx+uy)*sa)+ m[2]
    p0 =(u*(ux+vy+wz)+(x*(v*v+w*w)-u*(vy+wz))*ca+(-wy+vz)*sa)
    p1=(v*(ux+vy+wz)+(y*(u*u+w*w)-v*(ux+wz))*ca+(wx-uz)*sa)
    p2=(w*(ux+vy+wz)+(z*(u*u+v*v)-w*(ux+vy))*ca+(-vx+uy)*sa)
    #b = [pt, m, ax]
    return (p0, p1, p2)


import maya.cmds as cmds
from functools import partial
import re

widgets = {}
typeList = cmds.allNodeTypes() # get all current node types in the scene

def typeFinderUI(*args):
	if cmds.window("typeFinderWin", exists=True):
		cmds.deleteUI("typeFinderWin")

	widgets["win"] = cmds.window("typeFinderWin", w=400, h=400, t="zbw_typeFinder")
	widgets["mainCLO"] = cmds.columnLayout(w=400, h=400, bgc=(.2, .2,.2))

#---------------- right click on an item and get option to replace with parent or go down to shape

	cmds.text(l="Note: Rt-click on the below field to get suggestions from your sub-string")
	cmds.separator(h=10)

	widgets["typeTFBG"] = cmds.textFieldButtonGrp(l="Node Type", bl="Find", cal=[(1,"left"),(2,"left"),(3,"left")], cw=[(1, 75), (2,250), (3, 50)], bc=getObjectList)
	widgets["searchPUM"] = cmds.popupMenu(postMenuCommand=populateMenuItems)

	widgets["searchSelCB"] = cmds.checkBox(l="Only search current selection?", v=0)
	widgets["shpsToXformCB"] = cmds.checkBox(l="List transforms of found shapes (mesh, etc)?", v=1)

	widgets["stringMatchCB"] = cmds.checkBox(l="Additional name/string search?", v=0, changeCommand=toggleStringSearchEnable)
	widgets["stringSearchTFG"] = cmds.textFieldGrp(l="String:", en=False, cal=[(1,"left"),(2,"left")], cw=[(1, 75), (2,250)], changeCommand=getObjectList)

	cmds.separator(h=10)

	widgets["resultsTSL"] = cmds.textScrollList(w=400, h=200, bgc=(0,0,0), allowMultiSelection=True)
#---------------- checkbox here to expand selection? for sets (true-select objects in set, false - just seletc the set)

	widgets["selectAllBut"] = cmds.button(l="Select All in List", h= 30)
	widgets["selectSelBut"] = cmds.button(l="Select Selected in List", h= 30)
	widgets["selectParOfSelBut"] = cmds.button(l="Select Parent/Transform of Selected in List", h= 30)
	widgets["deleteAllBut"] = cmds.button(l="Delete All in List", h= 30)
	widgets["deleteSelBut"] = cmds.button(l="Delete Selected in List", h= 30)
	widgets["clearListBut"] = cmds.button(l="Clear List", h= 30, c=clearScrollList)
	#widgets["connectDecompBut"] = cmds.button(l="Clear List", h= 30, c=clearList)
#---------------- button to promote all shape to transforms?
#---------------- button to select shapes of all in list

	cmds.showWindow(widgets["win"])

#---------------- FUNCTIONS:
#---------------- get current selection (to filter our list)
#---------------- filter our list based on another list
#---------------- promote shapes: given an obj, is it a shape node? if it is, return it's parent
#---------------- stop the process if the list count is more than 100? or 1000?
#---------------- create a confirm dialog func (in zbw_rig?), args = message, buttons?
#---------------- populate the buttons and related functions

def getTypeText(*args):
	"""
	gets text
	"""
	txt = cmds.textFieldButtonGrp(widgets["typeTFBG"], q=True, tx=True)
	if not txt: # if no entry
		cmds.warning("node type: Nothing entered!")
		return(None)
	if re.match('^[a-zA-Z0-9_]+$',txt): # if we have valid text
		return(txt)
	else: # if we have bad text
		cmds.warning("Some bad characters in there. Please use numbers, letters, or underscores!")
		return(None)

def getSearchText(*args):
	"""
	gets text
	"""
	txt = cmds.textFieldGrp(widgets["stringSearchTFG"], q=True, tx=True)
	if not txt: # if no entry
		cmds.warning("string search: Nothing entered!")
		return(None)
	if re.match('^[a-zA-Z0-9_]+$',txt): # if we have valid text
		return(txt)
	else: # if we have bad text
		cmds.warning("Some bad characters in there. Please use numbers, letters, or underscores!")
		return(None)

def getObjectList(*args):
	"""gets the list of object of type txt"""

	objs = []
	objText = getTypeText()

	if objText in typeList:
		objs = cmds.ls(type=objText)
	else:
		cmds.warning("This instance of Maya doesn't recognize that type of object: {0}!".format(objText))
		return()

	if objs:
#---------------- check if we're promoting shapes
#---------------- if yes, send out list to see which elements are shapes and promote them, return a new list into obj ie. objs = promoteList(objs), this will return either the same list or an ammended list
		addObjectsToScrollList(objs)
	else:
		cmds.warning("No objects found of type: {0}".format(objText))

def toggleStringSearchEnable(*args):
	enabled = cmds.textFieldGrp(widgets["stringSearchTFG"], q=True, en=True)
	toggle = 1

	if enabled==1:
		toggle = 0

	cmds.textFieldGrp(widgets["stringSearchTFG"], e=True, en=toggle)
	return(toggle)

def addObjectsToScrollList(objs):
	"""puts the list of things in the textScrollList"""

	clearScrollList()
	stringSearch = cmds.checkBox(widgets["stringMatchCB"], q=True, v=True)
	searchText = ""
	checkedObjs = []

	if stringSearch:
		searchText = getSearchText()

	if stringSearch and searchText:
		for obj in objs:
			# check if the string is in the name of obj
			if searchText.lower() in obj.lower():
				checkedObjs.append(obj)

	else:
		checkedObjs = objs

	for x in checkedObjs:
#---------------- here add rt click functions to select all shapes or select transform (if shape)
		cmds.textScrollList(widgets["resultsTSL"], e=True, a=x, doubleClickCommand=selectItemInList)

def clearScrollList(*args):
	"""just empties the scroll list"""

	cmds.textScrollList(widgets["resultsTSL"], e=True, removeAll=True)

def queryListSelection(*args):
	"""gets a list of selected items from the textScrollList"""

	sel = cmds.textScrollList(widgets["resultsTSL"], q=True, si=True)
	return(sel)

def selectItemInList(*args):
	"""selects (in your scene) given list of items"""

	sel = queryListSelection()

	if sel:
		print("selecting: {0}".format(sel))
		# check whether the noExpand should be there (for sets: do we want to select the set or expand to select it's elements?)
		cmds.select(sel, r=True, noExpand=False)
	else:
		cmds.warning("Nothing selected!")

def returnMatches(currText, theList, *args):
	myMatches = []
	if currText and len(currText)>2:
		myMatches = [x for x in theList if currText.lower() in x.lower()]

	return(myMatches)

def populateMenuItems(*args):
	cmds.popupMenu(widgets["searchPUM"], e=True, deleteAllItems=True) # clear popup menu
	t = getTypeText()

	matches = []

	if t:
		matches = returnMatches(t, typeList)

	if matches:
		for item in matches:
			cmds.menuItem(p=widgets["searchPUM"], l=item, c=partial(fillMenuText, item))

def fillMenuText(text, *args):
	cmds.textFieldButtonGrp(widgets["typeTFBG"], e=True, tx=text)

def typeFinder(*args):
	typeFinderUI()


def tb26():
    n=int(input())
    for a in range(n):
        line1=input().split(' ')
        N,K=int(line1[0]),int(line1[1])
        arr=[int(x) for x in input().split(' ')]
        res=""
        for i in range(0,N-K+1):
            set=[]
            for j in range(i,i+K):
                set.append(arr[j])
            res+=str(max(set))+" "
        print(res)
    return

tb26()


from scripts.yolo_v3.models import (YoloV3, YoloV3Tiny)
from scripts.yolo_v3.dataset import transform_images
from scripts.yolo_v3.utils import draw_outputs

import numpy as np
import tensorflow as tf

import argparse
import time
import cv2
import os

def parse_args():
    desc = "Object Detection"
    parser = argparse.ArgumentParser(description=desc)
    parser.add_argument('--classes', type=str, default='./models/coco.names', help='Path To Classes File')
    parser.add_argument('--weights', type=str, default='./checkpoints/yolov3.tf', help='Path To Weights File')
    parser.add_argument('--tiny', type=bool, default=False, help='YOLO v3 or YOLO-Tiny v3')
    parser.add_argument('--num_classes', type=int, default=80, help='Number Of Classes In The Model')
    parser.add_argument('--size', type=int, default=416, help='Resize Images To')
    parser.add_argument('--image', type=str, default='./data/sample.jpg', help='Path To Input Image')
    parser.add_argument('--save', type=bool, default=False, help='Save Output File ?')

    return parser.parse_args()

def main():
    args = parse_args()
    if args is None:
        exit()

    physical_devices = tf.config.experimental.list_physical_devices('GPU')
    for physical_device in physical_devices:
        tf.config.experimental.set_memory_growth(physical_device, True)

    if args.tiny:
        yolo = YoloV3Tiny(classes=args.num_classes)
    else:
        yolo = YoloV3(classes=args.num_classes)

    yolo.load_weights(args.weights).expect_partial()
    class_names = [c.strip() for c in open(args.classes).readlines()]
    img_raw = tf.image.decode_image(open(args.image, 'rb').read(), channels=3)

    img = tf.expand_dims(img_raw, 0)
    img = transform_images(img, args.size)

    start_time = time.time()
    boxes, scores, classes, nums = yolo(img)
    end_time = time.time()

    for i in range(nums[0]):
        print('\t{}, {}'.format(class_names[int(classes[0][i])], np.array(scores[0][i])))

    if args.save:
        file_parts = os.path.abspath(args.image).split(".")
        img = cv2.cvtColor(img_raw.numpy(), cv2.COLOR_RGB2BGR)
        img = draw_outputs(img, (boxes, scores, classes, nums), class_names)
        file_name = f'{file_parts[0]}_output.{file_parts[-1]}'
        cv2.imwrite(file_name, img)

if __name__ == '__main__':
    main()


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# =============================================================================
## @file ostap/parallel/tests/test_parallel_kisa.py
#  Test for parallel data processing
#  @author Vanya BELYAEV Ivan.Belyaeve@itep.ru
#  @date 2015-05-17
# =============================================================================
"""Test for parallel data processing
"""
# =============================================================================
__version__ = "$Revision:"
__author__  = "Vanya BELYAEV Ivan.Belyaev@itep.ru"
__date__    = "2014-06-08"
__all__     = ()  ## nothing to be imported
# =============================================================================
from   builtins                import range
import ostap.core.pyrouts
from   ostap.utils.timing      import timing
from   ostap.trees.data        import Data
import ostap.parallel.parallel as     Parallel
##
import ostap.parallel.kisa              ## ATTENTION!
import ostap.parallel.parallel_project  ## ATTENTION!
import ostap.parallel.parallel_fill     ## ATTENTION!
##
import ROOT,os,  random
##
# =============================================================================
# logging
# =============================================================================
from ostap.logger.logger import getLogger
if '__main__' == __name__ or '__builtin__' == __name__ :
    logger = getLogger( 'test_parallel_kisa' )
else :
    logger = getLogger( __name__ )
# =============================================================================
## create a file with tree
def create_tree ( jobid , item ) :
    """Create a file with a tree
    >>> create_tree ( ('1.root' ,  1000 ) )
    """

    fname , nentries = item

    import ROOT, random
    import ostap.io.root_file

    from array import array
    var1 = array ( 'd', [0])
    var2 = array ( 'd', [0])
    var3 = array ( 'd', [0])

    with ROOT.TFile.Open( fname , 'new' ) as root_file:

        tree = ROOT.TTree ( 'S','tree' )
        tree.SetDirectory ( root_file  )
        tree.Branch ( 'mass'  , var1 , 'mass/D'  )
        tree.Branch ( 'c2dtf' , var2 , 'c2dtf/D' )
        tree.Branch ( 'pt'    , var3 , 'pt/D'    )

        for i in range ( nentries ) :

            m  = random.gauss        ( 3.1 ,  0.015 )
            c2 = random.gammavariate ( 2.5 , 0.5    ) / 5
            pt = random.uniform      ( 0   , 10     )

            var1[0] = m
            var2[0] = c2
            var3[0] = pt

            tree.Fill()

        root_file.Write()

    return  fname,

# ==============================================================================================
def prepare_data ( tmpdir , nfiles =  100 ,  nentries = 100 , ppservers = () , silent = True ) :

    ## Use generic Task from Kisa
    from ostap.parallel.parallel import GenericTask as Task
    task  = Task ( processor = create_tree )

    ## task  = PrepareTask ()
    wmgr  = Parallel.WorkManager( ppservers = ppservers , silent = silent )

    from ostap.utils.cleanup import CleanUp
    tmpfile = CleanUp.tempfile ( prefix = 'ostap-test-kisa-' , suffix = '.root' , dir = tmpdir )

    fname = '%s/test_kisa_%d.root'

    files = [ CleanUp.tempfile ( prefix = 'ostap-test-kisa-' , suffix = '.root' , dir = tmpdir ) for i in range(nfiles) ]

    wmgr.process (  task , [  ( f , nentries ) for f in files  ] )

    the_files = set()
    for f in task.results () :
        if os.path.exists ( f ) :
            the_files.add ( f )

    from ostap.trees.data   import Data
    the_files = list( the_files )
    the_files.sort()
    return Data ( 'S' , list ( the_files ) )

with timing('Prepare data') :

    logger.info('Prepare data, it could take some time')
    from ostap.utils.cleanup import CleanUp
    tmpdir  = CleanUp().tmpdir

    ## data = prepare_data ( tmpdir , nfiles = 250 , nentries = 200000 , silent = False )
    ## data = prepare_data ( tmpdir , nfiles = 100 , nentries = 50000  , silent = False )
    ## data = prepare_data ( tmpdir , nfiles = 500  , nentries = 1000    , silent = False )
    ## data = prepare_data ( tmpdir , nfiles = 50  , nentries = 50000  , silent = False )
    data = prepare_data ( tmpdir , nfiles = 20  , nentries = 2000  , silent = False )

    logger.info    ( 'DATA %s' % data  )

# =============================================================================
def test_kisa () :

    logger = getLogger ( 'test_parallel_kisa' )

    if 62400 <= ROOT.gROOT.GetVersionInt() < 62406 :
        logger.warning ('Test can fail for %s' % ROOT.gROOT.GetVersion() )

    h1 = ROOT.TH1D( 'h1' , '' , 200 , 3 , 3.2 )
    h2 = h1.clone()

    chain = data.chain

    with timing('SEQUENTIAL(%s):' % len(chain) , logger ) :
        chain. project ( h1 , 'mass' , '3<=mass && mass<=3.2 && 0<=c2dtf && c2dtf<5' )

    logger.info ( h1.dump(100,30) )

    with timing('PARALLEL(%s):' % len(chain) , logger ) :
        chain.pproject ( h2 , 'mass' , '3<=mass && mass<=3.2 && 0<=c2dtf && c2dtf<5' , silent = False )

    logger.info ( h2.dump(100,30) )

class MASS (object):
    def __call__ (  self , s ) :
        return s.mass
def MASS1  ( s ) : return s.mass

# =============================================================================
def test_kisa2 () :

    logger = getLogger ( 'test_parallel_kisa2' )

    if 62400 <= ROOT.gROOT.GetVersionInt() < 62406 :
        logger.warning ('Test can fail for %s' % ROOT.gROOT.GetVersion() )

    from ostap.fitting.pyselectors import SelectorWithVars, Variable
    variables = [
        Variable   ( 'mass'  , 'mass(mu+mu-)' ,  3.09 , 3.11 ) ,
        Variable   ( 'c2dtf' , 'chi2(dtf)'    , -1    , 10   ) ,
        Variable   ( 'mass2' , 'mass(mu+mu-)' , 1 , 5 , MASS()  ) ,
        Variable   ( 'mass3' , 'mass(mu+mu-)' , 1 , 5 , 'mass'  )
        ]

    from sys import version_info  as python_version
    if  python_version.major < 3 :
        variables.append ( Variable ( 'mass1' , 'mass(mu+mu-)' , 2 , 4 , lambda s : s.mass ) )

    ppservers = () ## 'lxplus051' , )
    ## ppservers = 'auto'

    nf   = len ( data.files )
    nf //= 40
    nf  += 1
    nf   = min ( nf , 25 )

    with timing('%d files in sequence %s' % ( nf , len( data.chain )  ) ) :
        selector = SelectorWithVars  (
            variables = variables ,
            selection = '2<=mass && mass<4 && 0<=c2dtf && c2dtf<5' ,
            silence   = False
            )
        chain =  data.chain[:nf]
        st = chain.process ( selector , silent = False , shortcut = True )
        ds = selector.data
        del selector
    logger.info ( 'Dataset (sequential):\n%s' % ds.table()  )

    with timing('%s files in parallel %s' % ( len ( data.files ) , len( data.chain ) ) ) :
        selector = SelectorWithVars  (
            variables = variables ,
            selection = '2<=mass && mass<4 && 0<=c2dtf && c2dtf<5' ,
            silence   = True
            )
        st = data.chain.parallel_fill ( selector               ,
                                        silent     = False     ,
                                        chunk_size = -1        ,
                                        max_files  =  1        ,
                                        ppservers  = ppservers )
        ds = selector.data
        del selector
    logger.info ( 'Dataset (paralell):\n%s' % ds.table ( prefix = '# ' ) )

# =============================================================================
def test_kisa3 () :

    logger = getLogger ( 'test_parallel_kisa3' )

    if 62400 <= ROOT.gROOT.GetVersionInt() < 62406 :
        logger.warning ('Test can fail for %s' % ROOT.gROOT.GetVersion() )

    h1  = ROOT.TH1D('h1','',100,0,20)
    h1 += lambda x : x

    ## from  ostap.trees.funcs import H1DFunc
    ## xh1 = H1DFunc ( histo = h1 , xvar = 'pt' )
    ## from  ostap.trees.funcs import FuncTH1
    ## xh1 = FuncTH1 ( histo = h1 , xvar = 'pt' )

    from ostap.fitting.pyselectors import SelectorWithVars, Variable
    variables = [
        ## Variable ( 'mass1' , 'mass(mu+mu-)' , 2 , 4 , lambda s : s.mass ) ,
        Variable ( 'mass'  , 'mass(mu+mu-)' ,  3.09 , 3.11 ) ,
        Variable ( 'c2dtf' , 'chi2(dtf)'    , -1    , 10   ) ,
        ## Variable ( 'xpt'   , 'xpt'          , -1    , 30   , xh1 ) ,
        Variable ( 'mass2' , 'mass(mu+mu-)' , 1 , 5 , MASS()  ) ,
        Variable ( 'mass3' , 'mass(mu+mu-)' , 1 , 5 , 'mass'  )
        ]

    with timing('fill it!' ) :
        selector = SelectorWithVars  (
            variables = variables ,
            selection =  '2<=mass && mass<4 && 0<=c2dtf && c2dtf<5' ,
            silence   = True
            )
        chain =  data.chain
        st = chain.parallel_fill ( selector , silent = False , shortcut = True )
        ds = selector.data
        del selector
    logger.info ( 'Dataset (paralell):\n%s' % ds.table ( prefix = '# ' ) )

# =============================================================================
if '__main__' == __name__ :

    test_kisa  ()
    test_kisa2 ()
    test_kisa3 ()

# =============================================================================
##                                                                      The END
# =============================================================================


"""
This is a simple backtracking algorithm which uses recursion to plot hotel reservations on a simple calendar.
The reservations are instances of a Python class and the calendar is just a list of lists.
Some of the guests are already checked in and can't be moved. All rooms are of the same type.
"""

from tabulate import tabulate

guest_list = []
empty_cell = " ______ "

week_overview = [[empty_cell for day in range(7)] for room in range(10)]

class Booking:

	def __init__ (self, name, check_in, check_out, fix, room):
		self.name = name
		self.check_in = check_in
		self.check_out = check_out
		self.fix = fix
		self.room = room
		self.assigned = False

		guest_list.append(self)

		if self.check_in >= self.check_out:
			print (f"The check-in date for guest {self} is the same as or later than the check-out date. Please revise.")

	def __repr__(self):
		return self.name[:8]

	def populate_week_overview(self, room_number, reverse):
		date_counter = self.check_in
		# Because a backtracking algorithm requires that the object erase itself if its next recursion doesn't
		# satisfy the conditions, I add a parameter "reverse". If it returns True, the object erases itself.
		if reverse:
			while date_counter <= self.check_out:
				week_overview [room_number][date_counter] = empty_cell
				date_counter += 1
		while date_counter <= self.check_out:
			week_overview [room_number][date_counter] = self
			date_counter += 1

# Creating some guests:
guest1 = Booking("Tom", 1, 4, True, 1)
guest2 = Booking("Ron", 0, 1, True, 3)
guest3 = Booking("Leslie", 1, 5, False, None)
guest4 = Booking("April", 4, 6, False, None)
guest5 = Booking("Andy", 0, 3, False, None)
guest6 = Booking("Ben", 5, 6, False, None)
guest7 = Booking("Dona", 3, 4, True, 9)
guest8 = Booking("Li'l Sebastian", 1, 4, False, None)
guest9 = Booking("Jerry", 2, 4, False, None)
guest10 = Booking("Chris", 1, 2, False, None)
guest11 = Booking("Ann", 0, 6, False, None)
guest12 = Booking("Perd", 0, 6, False, None)
guest13 = Booking("Mark", 1, 6, False, None)
guest14 = Booking("Tammy2", 0, 4, False, None)

# Uncomment this guest to overbook
#guest15 = Booking("Tammy1", 4, 6, False, None)

# Arrange by check-in
guest_list.sort(key=lambda x: x.check_in)

def plot_fixed():
	for guest in guest_list:
		if guest.fix == True:
			guest.populate_week_overview(guest.room, reverse=False)
			guest.assigned = True

# This function checks if all fields from check-in to check-out are free so the guest can be given a room
def is_possible(guest, room):
	for cell in room[guest.check_in:guest.check_out]:
		if isinstance (cell, Booking):
			return False
	return True

def optimal_arrangement():
	for guest in guest_list:
		# "assigned" is a class variable which returns True if the guest already has a room
		if guest.assigned == False:
			# Now for each guest we go through every room to see if there is space for them
			for index, room in enumerate(week_overview):
				if is_possible(guest, room):
					# If there is space, we plot the guest and run the function again
					guest.populate_week_overview(index, reverse=False)
					guest.assigned = True
					optimal_arrangement()
					"""
					Our function runs recursively and every time it finds a spot for a guest it will change their
					"assigned" variable to True so eventually there weill be none left and the function will
					print out the solution. For this to make sense there has to be a meaningful relationship between
					the objects we iterate over in our guest list so that a step back could enable an efficient
					second attempt in the future. If the guests are randomly arranged in the guest list
					maybe the function will have to go back hundreds of times to a very early instance of its
					recursion which is inefficient. So the guest list is ordered by check-in and we go
					from left to right.
					"""
					guest.populate_week_overview(index, reverse=True)
					guest.assigned = False
			return
	print(tabulate(week_overview))
	input("Satisfactory? ")

plot_fixed()

optimal_arrangement()

# If there are solutions we will remain in the recursive function. Otherwise we print out the error message:
print("Overbooked")


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Jul 17 16:52:50 2018

@author: doorleyr
"""

from google.cloud import bigquery

def query_US_census():
    client = bigquery.Client()
    query_job = client.query("""
        SELECT
            source_year AS year,
            COUNT(is_male) AS birth_count
        FROM `bigquery-public-data.samples.natality`
        GROUP BY year
        ORDER BY year DESC
        LIMIT 15""")

    results = query_job.result()  # Waits for job to complete.
    for row in results:
        print(row)

def query_yellow_trips():
    client = bigquery.Client()
    query_job = client.query("""
        SELECT
            pickup_datetime AS pickupT,
            dropoff_datetime AS dropoffT,
            trip_distance as dist
        FROM `bigquery-public-data.new_york_taxi_trips.tlc_yellow_trips_2017`
        ORDER BY dist DESC
        LIMIT 15""")

    results = query_job.result()  # Waits for job to complete.
    for row in results:
        print(row)

if __name__ == '__main__':
    query_yellow_trips()


#!/usr/bin/env python
from caffe_config_template import caffe_cross_val_config

# General comment: Here you can define as many instancies of the "caffe_config" as you want. Each instance should be imported and then used separately in the run.py file. In this example, there is only one instance, called "test_caffe_config"

test_caffe_cross_val_config = caffe_cross_val_config._replace(path_to_caffe =  '/root/caffe-segnet-cudnn5/build/tools/caffe',
                                                    path_to_model='/disk2/nik/Analyzer/test/model_segnet_final',
                                                    caffe_work_area=['pocwisc1/caffe','pocwisc2/caffe','pocwisc3/caffe','pocwisc4/caffe','pocwisc5/caffe', 'pocwisc6/caffe',
								     'pocwisc7/caffe'],
  # 'pocwisc8/caffe', 'pocwisc9/caffe'], #'pocwisc10/caffe'],
                                                                    # 'output11/caffe',
                                                                    # 'output12/caffe'],
								    # 'output4/caffe',
								     #'output5/caffe',
								     #'output6/caffe', 'output7/caffe', 'output8/caffe', 'output9/caffe', 'output10/caffe'],
                                                    output_work_area=['pocwisc1/prediction','pocwisc2/prediction','pocwisc3/prediction','pocwisc4/prediction',
                                                                      'pocwisc5/prediction','pocwisc6/prediction',
                                                                      'pocwisc7/prediction'], #'pocwisc8/prediction', 'pocwisc9/prediction' ],
								     # 'pocwisc9/prediction', 'pocwisc10/prediction'],
                                                                     # 'output11/prediction',
                                                                     # 'output12/prediction'],
    #'output4/prediction', 'output5/prediction', 'output6/prediction',
#								      'output7/prediction', 'output8/prediction', 'output9/prediction', 'output10/prediction'],
                                                    test_initialization = 'false',
                                                    test_iter=1,
                                                    test_interval=10000000,
                                                    base_lr=0.001,
                                                    lr_policy='step',
                                                    gamma=1.0,
                                                    stepsize=10000000,
                                                    display=20,
                                                    max_iter='5000',
                                                    momentum=0.9,
                                                    weight_decay=0.0005,
                                                    snapshot_prefix=['pocwisc1/training','pocwisc2/training','pocwisc3/training','pocwisc4/training',
                                                                     'pocwisc5/training','pocwisc6/training', 'pocwisc7/training'], # 'pocwisc8/training','pocwisc9/training'],
                                                                   #   'pocwisc7/training', 'pocwisc8/training',
 								   #   'pocwisc9/training', 'pocwisc10/training'],
                                                                   #  'output11/training',
                                                                   #  'output12/training'],
#'output4/training','output5/training', 'output6/training',
#						                     'output7/training','output8/training', 'output9/training', 'output10/training'],
                                                    snapshot=5000,
                                                    solver_mode='GPU',
						    train_batch_size = 4,
                                                    trained_weights = '/disk2/nik/Analyzer/test/training_iter_5000.caffemodel', #'/disk2/nik/Analyzer/test/FaliuModels/v10/test_weights.caffemodel',
                                                    pretrained_weights = '/disk1/model_zoo/segNet/v2/segnet_pascal.caffemodel',
                                                    caffe_log ='caffe_log.txt'
                                                    )


"""
给定一个num, 返回这个数字的每一个digit的乘积：product 和 每一位digit的和：sum 的差值
"""

import functools

def solution(num):
    tmp = [int(d) for d in list(str(num))]

    product = functools.reduce(lambda x, y: x*y, tmp)
    return abs(product - sum(tmp))

print(solution(111))


from django.db import models

# Create your models here.

PRODUCT_TYPE_PODS = [
    ('Coffee Pod Large', 'Coffee Pod Large'),
    ('Coffee Pod Small', 'Coffee Pod Small'),
    ('Espresso Pod', 'Espresso Pod'),
]

COFFEE_FLAVOR = [
    ('Coffee Flavor Vanilla', 'Coffee Flavor Vanilla'),
    ('Coffee Flavor Caramel', 'Coffee Flavor Caramel'),
    ('Coffee Flavor Psl', 'Coffee Flavor Psl'),
    ('Coffee Flavor Mocha', 'Coffee Flavor Mocha'),
    ('Coffee Flavor Hazelunt', 'Coffee Flavor Hazelunt'),
]
PACKAGE_SIZE = [
    ('1 dozen (12)','1 dozen (12)'),
    ('3 dozen (36)','3 dozen (36)'),
    ('5 dozen (60)','5 dozen (60)'),
    ('7 dozen (84)','7 dozen (84)')
]

class CoffeePods(models.Model):
    pods_title                      = models.CharField(max_length = 50)
    pods_type                       = models.CharField(max_length = 50, choices=PRODUCT_TYPE_PODS, blank=True)
    coffee_flavor                   = models.CharField(max_length = 50, choices=COFFEE_FLAVOR, blank=True)
    Package_size                    = models.CharField(max_length = 50, choices=PACKAGE_SIZE, blank=True)
#    model_category                  = models.ForeignKey('Category', on_delete=models.CASCADE) # One to Many

    def __str__(self):
        return self.pods_title

#class Category(models.Model):  # Many to One
#    name = models.CharField(max_length = 25)

#    def __str__(self):
#        return self.name


'''WAPP to calculate the area of a Triangle

Area = (base * height) / 2

where "base" represents the length of the base of the triangle,
and "height" represents the perpendicular distance from the base to the opposite vertex.
'''

#Solution1
base = float(input("Enter the base of the triangle: "))
height = float(input("Enter the height of the triangle: "))

area = (base * height)/2

print(f"The area of a Triangle is {area}")