import argparse
import time
import torch
from typing import *
from util import initialize_seq2seq_attention_params, build_seq2seq_attention_model, load_data
from time import time
from torch import optim
from core import Seq2SeqAttentionModel, encode_all
from math import exp
from core import SOS_token, EOS_token
from operator import itemgetter

def decode(prev_hidden: torch.tensor, source_hiddens: torch.tensor, prev_context: torch.tensor,
           input: int, model: Seq2SeqAttentionModel) -> (
        torch.tensor, torch.tensor, torch.tensor, torch.tensor):
    """ Run the decoder AND the output layer for a single step.

    :param: prev_hidden: tensor of shape [L, hidden_dim] - the decoder's previous hidden state, denoted H^{dec}_{t-1}
                          in the assignment
    :param: source_hiddens: tensor of shape [source sentence length, L, hidden_dim] - the encoder's hidden states,
                            denoted H^{enc}_1 ... H^{enc}_T in the assignment
    :param: prev_context: tensor of shape [hidden_dim], denoted c_{t-1} in the assignment
    :param input: int - the word being inputted to the decoder.
                            during log-likelihood computation, this is y_{t-1}
                            during greedy decoding, this is yhat_{t-1}
    :param model: a Seq2SeqAttention model
    :return: (1) a tensor `probs` of shape [target_vocab_size], denoted p(y_t | x_1 ... x_S, y_1 .. y_{t-1})
             (2) a tensor `hidden` of shape [L, hidden_size], denoted H^{dec}_t in the assignment
             (3) a tensor `context` of shape [hidden_size], denoted c_t in the assignment
             (4) a tensor `attention_weights` of shape [source_sentence_length], denoted \alpha in the assignment
    """

    composition_1=torch.cat((model.target_embedding_matrix[input],prev_context),dim=0)
    h=model.decoder_gru.forward(composition_1,prev_hidden)
    alpha=model.attention.forward(source_hiddens[:,-1,:],h[-1])
    c_t=torch.sum(torch.mm(torch.unsqueeze(alpha, 0), source_hiddens[:,-1,:]),0)
    composition_2=torch.cat((h[-1],c_t),dim=0)
    pd=model.output_layer.forward(composition_2)
    return pd,h,c_t,alpha

def log_likelihood(source_sentence: List[int],
                   target_sentence: List[int],
                   model: Seq2SeqAttentionModel) -> torch.Tensor:
    """ Compute the log-likelihood for a (source_sentence, target_sentence) pair.

    :param source_sentence: the source sentence, as a list of words
    :param target_sentence: the target sentence, as a list of words
    :return: log-likelihood of the (source_sentence, target_sentence) pair
    """
    res=0
    source_h=encode_all(source_sentence, model)
    prev_h=source_h[-1]
    c_0=torch.zeros((model.hidden_dim))
    for i in range(len(target_sentence)):
        if i==0:
            pd, prev_h,c_t,_=decode(prev_h,source_h,c_0,SOS_token,model)
            p=pd[target_sentence[i]]
        else:
            pd, prev_h,c_t,_=decode(prev_h,source_h,c_t,target_sentence[i-1],model)
            p=pd[target_sentence[i]]
        res+=torch.log(p)
    return res

def perplexity(sentences: List[Tuple[List[int], List[int]]], model: Seq2SeqAttentionModel) -> float:
    """ Compute the perplexity of an entire dataset under a seq2seq model.  Refer to the write-up for the
    definition of perplexity.

    :param sentences: list of (source_sentence, target_sentence) pairs
    :param model: seq2seq attention model
    :return: perplexity of the translation
    """
    LL=0
    T=0
    for i in range(len(sentences)):
        LL+=log_likelihood(sentences[i][0],sentences[i][1],model)
        T+=len(sentences[i][1])
    return torch.exp(-LL/T).detach()

def translate_greedy_search(source_sentence: List[int],
                            model: Seq2SeqAttentionModel, max_length=10) -> (List[int], torch.tensor):
    """ Translate a source sentence using greedy decoding.

    :param source_sentence: the source sentence, as a list of words
    :param model: a Seq2Seq model
    :param max_length: the maximum length that the target sentence could be
    :return: (1) the translated sentence as a list of ints
             (2) the attention matrix, a tensor of shape [target_sentence_length, source_sentence_length]

    """
    res=[]
    source_h=encode_all(source_sentence, model)
    prev_h=source_h[-1]
    c_0=torch.zeros((model.hidden_dim))
    for i in range(max_length):
        if i==0:
            pd, prev_h,c_t,alpha=decode(prev_h,source_h,c_0,SOS_token,model)
            y_hat=torch.argmax(pd)
            res.append(y_hat.item())
            atten=alpha
        else:
            pd, prev_h,c_t,alpha=decode(prev_h,source_h,c_t,y_hat,model)
            y_hat=torch.argmax(pd)
            res.append(y_hat.item())
            atten=torch.vstack((atten,alpha))
        if y_hat==EOS_token:
            break
    return res, torch.Tensor(atten)

def translate_beam_search(source_sentence: List[int], model: Seq2SeqAttentionModel,
                          beam_width: int, max_length=10) -> Tuple[List[int], float]:
    """ Translate a source sentence using beam search decoding.

    :param source_sentence: the source sentence, as a list of words
    :param model: a Seq2Seq model
    :param beam_width: the number of translation candidates to keep at each time step
    :param max_length: the maximum length that the target sentence could be
    :return: (1) the target sentence (translation),
             (2) sum of conditional log-likelihood of the translation, i.e., log p(target sentence|source sentence)
    """
    if beam_width==1:
        res=translate_greedy_search(source_sentence,model,max_length)[0]
        ll=log_likelihood(source_sentence,res,model)
        return res,ll
    count=0
    res_final=[]
    res=[]
    source_h=encode_all(source_sentence, model)
    prev_h=source_h[-1]
    c_0=torch.zeros((model.hidden_dim))
    while count < max_length:
        if beam_width==0:
            break
        if count==0:
            pd, prev_h,c_t,_=decode(prev_h,source_h,c_0,SOS_token,model)
            temp=torch.topk(pd,beam_width)
            for i in range(beam_width):
                res.append([[temp.indices[i].item()],prev_h,c_t,torch.log(temp.values[i]).item()])
        else:
            res_temp=[]
            for d in res:
                pd, prev_h,c_t,_=decode(d[1],source_h,d[2],d[0][-1],model)
                temp=torch.topk(pd,beam_width)
                for i in range(beam_width):
                    idx=d[0][:]
                    idx.append(temp.indices[i].item())
                    res_temp.append([idx,prev_h,c_t,((d[3]*count+torch.log(temp.values[i]))/(count+1)).item()])
            res_temp.sort(key=lambda x: x[3],reverse=True)
            res=res_temp[:beam_width]
        for d in res:
            if d[0][-1]==EOS_token:
                res_final.append(d)
                beam_width-=1
        count+=1
    #res_final+=res
    res=max(res_final, key=lambda x: x[3])
    return res[0], res[3]*len(res[0])

def train_epoch(sentences: List[Tuple[List[int], List[int]]], model: Seq2SeqAttentionModel,
                epoch: int, print_every: int = 100, learning_rate: float = 0.0001, gradient_clip=5):
    """ Train the model for an epoch.

    :param sentences: list of (source_sentence, target_sentence) pairs
    :param model: a Seq2Seq model
    :param epoch: which epoch we're at
    """
    print("epoch\titer\tavg loss\telapsed secs")
    total_loss = 0
    start_time = time()
    optimizer = optim.Adam(model_params.values(), lr=learning_rate)
    for i, (source_sentence, target_sentence) in enumerate(sentences):
        optimizer.zero_grad()
        theloss = -log_likelihood(source_sentence, target_sentence, model)
        total_loss += theloss
        theloss.backward()

        torch.nn.utils.clip_grad_norm_(model_params.values(), gradient_clip)

        optimizer.step()

        if i % print_every == 0:
            avg_loss = total_loss / print_every
            total_loss = 0
            elapsed_secs = time() - start_time
            print("{}\t{}\t{:.3f}\t{:.3f}".format(epoch, i, avg_loss, elapsed_secs))

    return model_params

def print_translations(sentences: List[Tuple[List[int], List[int]]], model: Seq2SeqAttentionModel,
                       source_vocab: Dict[int, str], target_vocab: Dict[int, str], beam_width):
    """ Iterate through a dataset, printing (1) the source sentence, (2) the actual target sentence, and (3)
    the translation according to our model.

    :param sentences: a list of (source sentence, target sentence) pairs
    :param model: a Seq2Seq model
    :param source_vocab: the mapping from word index to word string, in the source language
    :param target_vocab: the mapping from word index to word string, in the target language
    """
    for (source_sentence, target_sentence) in sentences:
        if beam_width > 0:
            translation, _ = translate_beam_search(source_sentence, model, beam_width)
        else:
            translation, _ = translate_greedy_search(source_sentence, model)

        print("source sentence:" + " ".join([source_vocab[word] for word in source_sentence]))
        print("target sentence:" + " ".join([target_vocab[word] for word in target_sentence]))
        print("translation:\t" + " ".join([target_vocab[word] for word in translation]))
        print("")

def beam_search_ll(sentences: List[Tuple[List[int], List[int]]], model: Seq2SeqAttentionModel,
                   beam_width: int) -> float:
    """ Computes the average of conditional log-likelihood of beam search translation.

    :param sentences: list of (source_sentence, target_sentence) pairs
    :param model: a Seq2Seq model
    :param beam_width: the number of translation candidates to keep at each time step
    :return: the average of the sum of conditional log-likelihood of the translations,
             i.e., sum_i (log p(target sentence i|source sentence i)) / len(sentences)
    """
    assert beam_width > 0, "beam_width must be set positive"

    ll_sum = 0.0
    total_cnt = 0
    for (source_sentence, target_sentence) in sentences:
        _, ll = translate_beam_search(source_sentence, model, beam_width)
        ll_sum += ll
        total_cnt += 1
    return ll_sum / total_cnt

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Seq2Seq Homework Assignment')
    parser.add_argument("action", type=str,
                        choices=["train", "finetune", "train_perplexity", "test_perplexity", "test_beam_search_ll",
                                 "print_train_translations", "print_test_translations", "visualize_attention"])
    parser.add_argument("--beam_width", type=int, default=-1,
                        help="number of translation candidates to keep at each time step. "
                             "this option is used for beam search translation (greedy search decoding is used by default).")
    parser.add_argument("--load_model", type=str,
                        help="path to saved model on disk.  if this arg is unset, the weights are initialized randomly")
    parser.add_argument("--save_model_prefix", type=str, help="prefix to save model with, if you're training")
    args = parser.parse_args()

    # load train/test data, and source/target vocabularies
    train_sentences, test_sentences, source_vocab, target_vocab = load_data()

    # load model weights (if path is specified) or else initialize weights randomly
    model_params = initialize_seq2seq_attention_params() if args.load_model is None \
        else torch.load(args.load_model)  # type: Dict[str, torch.Tensor]

    # build a Seq2SeqAttentionModel object
    model = build_seq2seq_attention_model(model_params)  # type: Seq2SeqAttentionModel

    if args.action == 'train':
        for epoch in range(10):
            train_epoch(train_sentences, model, epoch)
            torch.save(model_params, '{}_{}.pth'.format(args.save_model_prefix, epoch))
    elif args.action == 'finetune':
        train_epoch(train_sentences[:1000], model, 0, learning_rate=1e-5)
        torch.save(model_params, "{}.pth".format(args.save_model_prefix))
    elif args.action == "print_train_translations":
        print_translations(train_sentences, model, source_vocab, target_vocab, args.beam_width)
    elif args.action == "print_test_translations":
        print_translations(test_sentences, model, source_vocab, target_vocab, args.beam_width)
    elif args.action == "train_perplexity":
        print("perplexity: {}".format(perplexity(train_sentences[:1000], model)))
    elif args.action == "test_perplexity":
        print("perplexity: {}".format(perplexity(test_sentences, model)))
    elif args.action == "test_beam_search_ll":
        print("beam width: {} average LL: {}".format(args.beam_width,
                                                     beam_search_ll(test_sentences[:100], model, args.beam_width)))
    elif args.action == "visualize_attention":
        from plotting import visualize_attention

        # visualize the attention matrix for the first 5 test set sentences
        for i in range(5):
            source_sentence = test_sentences[i][0]
            predicted_sentence, attention_matrix = translate_greedy_search(source_sentence, model)
            source_sentence_str = [source_vocab[w] for w in source_sentence]
            predicted_sentence_str = [target_vocab[w] for w in predicted_sentence]
            visualize_attention(source_sentence_str, predicted_sentence_str,
                                attention_matrix.detach().numpy(), "images/{}.png".format(i))


def find_leader(array: list) -> int:
    counter = 0
    current_candidate = 0
    for el in array:
        if counter == 0:
            current_candidate = el
            counter = 1
        else:
            if el == current_candidate:
                counter += 1
            else:
                counter -= 1

    return current_candidate

def count_occurrences(element: int, array: list) -> int:
    count = 0
    for el in array:
        if el == element:
            count += 1

    return count

array = [1, 2, 5, 5, 7, 5, 5, 10, 5, 5]
majority = find_leader(array)
if count_occurrences(majority, array) >= len(array) / 2:
    print(f'Majority element is: {majority}')
else:
    print('There is no majority element in given list')


from os import listdir
import re
from skimage.io import imread
import numpy as np
import hashlib
def searchKey(name):
    number = int(re.search(r'[0-9]{1,10}',name).group(0))
    return number

def searchKeyM(line):
    number = int(re.search(r'[0-9]{1,10}',line[0]).group(0))
    return number

foldername = './test_b'
filenames = listdir(foldername)
bigDict = {}
for name in filenames:
    if name[len(name) - 3:len(name)] == 'png':
        histogram = [0] * 3 * 256
        im = imread(foldername+'/'+name)
        for i in range(im.shape[0]):
            for j in range(im.shape[1]):
                if (im[i,j] != np.array([255,255,255], dtype = np.uint8)).any():
                    histogram[int(im[i,j,0])] = histogram[int(im[i,j,0])] + 1
                    histogram[int(im[i,j,1]) + 256] = histogram[int(im[i,j,1]) + 256] + 1
                    histogram[int(im[i,j,2]) + 512] = histogram[int(im[i,j,2]) + 512] + 1
        keyTmp = ''.join(str(e) for e in histogram)
        bigDict.setdefault(keyTmp,[]).append(name)

result = []
tmp = list(bigDict.values())
for i in range(len(tmp)):
    result.append(sorted(tmp[i],key = searchKey))
result = sorted(result,key = searchKeyM)
for i in range(len(result)):
    result[i] = ' '.join(e for e in result[i])
result = '\n'.join(e for e in result)
result = result + '\n'
m = hashlib.sha256()
m.update(result.encode('utf-8'))
res = m.hexdigest()
print(res)


"""Code taken from original repository at https://github.com/BBVA/waf-brain
"""

import time
import string
import numpy as np

X_FEATURES = 5
BATCH_SIZE = 100000
EPOCHS = 200
TRAIN_PERC = 0.7
DEV_PERC = 0.25
TEST_PERC = 0.05
VOCABULARY = string.printable + '\xa0'

def row_parse(row):
    def char_parse(char):
        return VOCABULARY.index(char)

    return [char_parse(char) for char in row]

def reduce_dimension(row, x_features):
    def create_new_row(index, char):
        past_pos = x_features - 1
        new_row = [None for i in range(x_features + 1)]

        def fill_past():
            if index > past_pos:
                for i in range(past_pos * -1, 0, 1):
                    pos = index - i
                    if pos:
                        new_row[past_pos + i] = row[index + i]
            else:
                for i in range(x_features, 0, -1):
                    if (index - i) >= 0:
                        x = (index - i) + 1
                        new_row[past_pos - x] = row[index - x]

        def fill_future():
            if (index + 1) < len(row):
                new_row[-1] = row[index + 1]

        fill_past()
        new_row[past_pos] = char
        fill_future()
        return new_row

    return [create_new_row(index, char) for index, char in enumerate(row)]

def split_row(x, y, row):

    for t in row:
        x_zeros = np.zeros((X_FEATURES, 101))
        y_zeros = np.zeros((101))

        get_index = lambda index: 100 if index is None else index

        for i in range(X_FEATURES):
            x_zeros[i][get_index(t[i])] = 1

        x.append(x_zeros)
        y_zeros[get_index(t[-1])] = 1
        y.append(y_zeros)

def to_ascii(row):
    for i, elem in enumerate(row):
        if elem == 1:
            return VOCABULARY[i]

def transform_predict(y_predict):
    index = np.argmax(y_predict)
    if index == 100:
        return None
    return VOCABULARY[index]

def build_text(predict_char, predict_texts):
    if predict_char is None:
        predict_texts.append([])
    else:
        predict_texts[-1].append(predict_char)

def feature_vector(sample):
    elems = [reduce_dimension(row_parse(sample), X_FEATURES)]
    x_demo = []
    y_demo = []
    for elem in elems:
        split_row(x_demo, y_demo, elem)
    return x_demo, y_demo

def process_payload(model, param_name, payloads, check_weights=False):
    try:
        # Snapshot for time
        before_time = time.time()
        elems = [reduce_dimension(row_parse(payloads[0]), X_FEATURES)]
        x_demo = []
        y_demo = []

        # Passing a value
        for elem in elems:
            split_row(x_demo, y_demo, elem)

        nn_score = [model.evaluate(np.array(x_demo), np.array(y_demo), verbose=0)]
        nn_score = nn_score[0][1]

        # Inference time
        diff_time = time.time() - before_time

        # ---------------------------------------------------------------------
        # Check each letter influence
        # ---------------------------------------------------------------------
        weights = []
        if check_weights:

            predict_chars = [
                transform_predict(y_predict)
                for y_predict in model.predict(np.array(x_demo))
            ]
            predict_texts = [[]]

            for predict_char in predict_chars:
                build_text(predict_char, predict_texts)

            odor = [
                [
                    payloads[0][i],
                    model.evaluate(
                        np.expand_dims(x_demo[i], axis=0),
                        np.expand_dims(y_demo[i], axis=0),
                        batch_size=BATCH_SIZE,
                        verbose=0,
                    ),
                ]
                for i in range(len(payloads[0]))
            ]
            weights = [
                {"letter": o[0], "weight": o[1][0], "szie": o[1][1]} for o in odor
            ]

        return {
            "paramName": param_name,
            "score": nn_score,
            "time": diff_time,
            "weights": weights,
        }

        # with open('outputAttacks/sqlattacksOutput_feat_5_botneck-101_demo.txt', 'a') as file:
        #     file.write('{}\t{}\t{}\t{}\n'.format(nn_score[0][1], diff_time, payloads[0], odor))
    except Exception as e:
        print(e)
        # print("Exception here")

__all__ = ("process_payload",)


from django.core.management.base import NoArgsCommand
from skillstest.Subscription.tasks import make_payouts

class Command(NoArgsCommand):
    help = "Make payouts by reading objects from Payouts model."

    def handle_noargs(self, **options):
        make_payouts()
        self.stdout.write('Successfully completed.')

"""
Run this as follows:
python manage.py make_payouts <ENTER>
"""


from django.contrib.auth.models import User
from shared_models import models as shared_models

from . import models
import django_filters
from django import forms

chosen_js = {"class":"chosen-select-contains"}
# chosen_js = {"class":"chosen-select-contains", 'Select multiple': True}
# chosen_js = {"class":"chosen-select-contains"}

class InstrumentFilter(django_filters.FilterSet):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        YES_NO_CHOICES = [(True, "Yes"), (False, "No"), ]

        type_choices = models.Instrument.TYPE_CHOICES
        asset_choices = [(str(at.asset_tag), str(at.asset_tag)) for at in models.Instrument.objects.all()]

        self.filters["project_title"] = django_filters.CharFilter(field_name='project_title', lookup_expr='icontains')

        self.filters["instrument_type"] = django_filters.MultipleChoiceFilter(field_name='instrument_type', lookup_expr='exact',
                                                              choices=type_choices,
                                                              widget=forms.SelectMultiple(attrs=chosen_js))
        self.filters["location"] = django_filters.CharFilter(field_name='location', lookup_expr='icontains')
        self.filters["is_sensor"] = django_filters.ChoiceFilter(field_name='is_sensor', lookup_expr='exact',
                                                label="Is Sensor?", choices=YES_NO_CHOICES)
        self.filters["asset_tag"] = django_filters.MultipleChoiceFilter(field_name='asset_tag', lookup_expr='exact',
                                                        choices=asset_choices,
                                                        widget=forms.SelectMultiple(attrs=chosen_js))

class MooringFilter(django_filters.FilterSet):
    # FY_CHOICES = [(fy.id, str(fy)) for fy in shared_models.FiscalYear.objects.all()]
    # DIVISION_CHOICES = [(d.id, str(d)) for d in shared_models.Division.objects.filter(branch=1)]
    # SECTION_CHOICES = [(s.id, str(s)) for s in shared_models.Section.objects.filter(division__branch=1)]
    # TYPE_CHOICES = [('CTD', 'CTD'), ('ADCP', 'ADCP')]
    # LOC_CHOICES = models.Mooring.TYPE_CHOICES
    YES_NO_CHOICES = [(True, "Yes"), (False, "No"), ]

    mooring = django_filters.CharFilter(field_name='mooring', lookup_expr='icontains')
    mooring_number = django_filters.CharFilter(field_name='mooring_number', lookup_expr='exact')
    # mooring_number = django_filters.ChoiceFilter(field_name='mooring_number', lookup_expr='exact',
    #                                                   # label=_'mooring_number',
    #                                                   #    queryset=models.Mooring.objects.all(),
    #                                                      widget=forms.SelectMultiple(attrs=chosen_js))
    # mooring = django_filters.CharFilter(field_name='mooring', lookup_expr='icontains')
    # mooring_number = django_filters.ModelChoiceFilter(queryset=Deployment.objects.all)#, lookup_expr='exact')
    # fiscal_year = django_filters.ChoiceFilter(field_name='year', lookup_expr='exact', choices=FY_CHOICES)
    # division = django_filters.ChoiceFilter(field_name='section__division', lookup_expr='exact', label="Division", choices=DIVISION_CHOICES)
    # section = django_filters.ChoiceFilter(field_name='section', lookup_expr='exact', label="Section", choices=SECTION_CHOICES)
    # submitted = django_filters.ChoiceFilter(field_name='submitted', lookup_expr='exact',
    #                                         label="Submitted?", choices=YES_NO_CHOICES)
    # def get_queryset(self):
    #     return django_filters.MooringFilter(self.request.GET, queryset=models.Mooring.objects.exclude(mooring='HOME IOS'))


from typing import Optional

from mai_version.representation.TILDE_query import TILDEQuery, TILDEQueryHiddenLiteral
from mai_version.trees.leaf_strategy import LeafStrategy

class TreeNode:
    """A node in a First-Order Logical Decision Tree.

    There are two kinds of nodes: decision nodes and leaf nodes"""
    left_subtree = None  # type: Optional[TreeNode]
    right_subtree = None  # type: Optional[TreeNode]
    nb_of_examples_with_label = None  # type: Optional[int]
    nb_of_examples_in_this_node = None  # type: Optional[int]

    strategy = None  # type: Optional[LeafStrategy]

    query = None  # type: Optional[TILDEQuery]

    def get_left_child_node(self) -> 'TreeNode':
        return self.left_subtree

    def get_right_child_node(self) -> 'TreeNode':
        return self.right_subtree

    def has_both_children(self) -> bool:
        return self.left_subtree is not None and self.right_subtree is not None

    def is_leaf_node(self) -> bool:
        return self.left_subtree is None and self.right_subtree is None

    def to_string_full_query(self, indentation='', current_node_number=0):
        """
        Represents the tree as a string using some layouting
        :param indentation:
        :param current_node_number:
        :return:
        """
        node_indentation = indentation
        child_indentation = indentation

        if current_node_number == 0:
            child_indentation = '\t'
        elif current_node_number == 1:
            node_indentation += '|-'
            child_indentation += '|\t'
        else:
            node_indentation += '\-'
            child_indentation += '\t'

        if self.is_leaf_node():
            result = self.strategy.to_string(node_indentation)
            # result = node_indentation + "Leaf, class label: " + str(self.classification) + ", [" + str(
            #     self.nb_of_examples_with_label) + "/" + str(self.nb_of_examples_in_this_node) + "]" + '\n'
            return result
        else:
            result = node_indentation + 'INode, query: ' + str(self.query) + '\n'

            if self.get_left_child_node() is not None:
                result = result + self.get_left_child_node().to_string_full_query(child_indentation, 1)
            if self.get_right_child_node() is not None:
                result = result + self.get_right_child_node().to_string_full_query(child_indentation, 2)
            return result

    def to_string_compact(self, indentation='', current_node_number=0):
        """
        Represents the tree as a string using some layouting
        :param indentation:
        :param current_node_number:
        :return:
        """
        node_indentation = indentation
        child_indentation = indentation

        if current_node_number == 0:  # root node
            child_indentation = ''
        elif current_node_number == 1:  # this node is the LEFT child node of its parent
            node_indentation += '+--'
            child_indentation += '|       '
        else:  # this node is the RIGHT child node of its parent
            node_indentation += '+--'
            child_indentation += '        '

        if self.is_leaf_node():
            if current_node_number == 0:
                result = self.strategy.to_string_compact()
            elif current_node_number == 1:
                result = node_indentation + 'yes: ' + self.strategy.to_string_compact()
            else:
                result = node_indentation + 'no: ' + self.strategy.to_string_compact()

            # result = self.strategy.to_string(node_indentation)

            # result = node_indentation + "Leaf, class label: " + str(self.classification) + ", [" + str(
            #     self.nb_of_examples_with_label) + "/" + str(self.nb_of_examples_in_this_node) + "]" + '\n'
            return result
        else:
            if current_node_number == 0:
                if self.query.parent is not None and isinstance(self.query.parent, TILDEQueryHiddenLiteral):
                    result = str(self.query.parent.literal) + '\n'
                else:
                    result = ""

                result = result + str(self.query.get_literal()) + ' ?\n'

            elif current_node_number == 1:
                result = node_indentation + 'yes: ' + str(self.query.get_literal()) + ' ?\n'
            else:
                result = node_indentation + 'no: ' + str(self.query.get_literal()) + ' ?\n'

            # result = node_indentation + 'INode, query: ' + str(self.query) + '\n'

            if self.get_left_child_node() is not None:
                result = result + self.get_left_child_node().to_string_compact(child_indentation, 1)
            if self.get_right_child_node() is not None:
                result = result + self.get_right_child_node().to_string_compact(child_indentation, 2)
            return result

    def __str__(self):
        return self.to_string_compact()

    def get_nb_of_nodes(self) -> int:
        return TreeNode._count_nb_of_nodes(self)

    @staticmethod
    def _count_nb_of_nodes(node:Optional['TreeNode'] = None) -> int:

        if node is None:
            return 0
        else:
            count = 1  # count the node itself
            count += TreeNode._count_nb_of_nodes(node.left_subtree)
            count += TreeNode._count_nb_of_nodes(node.right_subtree)

            return count

    def get_nb_of_inner_nodes(self):
        return TreeNode._count_nb_of_inner_nodes(self)

    @staticmethod
    def _count_nb_of_inner_nodes(node:Optional['TreeNode'] = None) -> int:

        if node.is_leaf_node():
            return 0
        else:
            count = 1
            count += TreeNode._count_nb_of_inner_nodes(node.left_subtree)
            count += TreeNode._count_nb_of_inner_nodes(node.right_subtree)
            return count

    def can_classify(self) -> object:
        if self.strategy is None:
            raise AttributeError('TreeNode has no Strategy')
        else:
            return self.strategy.can_classify()


import json

def round_price(price: float):
    return round(price, 2)

def get_lowest(price_list: list):
    compare_price_list = list()
    for price in price_list:
        if type(price) == float:
            compare_price_list.append(price)
    return min(compare_price_list)

def match_weight(shipping_list: list, weight: float):
    for shipping in shipping_list:
        if shipping.get('weight_range') is not None:
            if shipping['weight_range'][0] <= weight <= shipping['weight_range'][1]:
                return shipping
        elif shipping.get('weight') is not None:
            if shipping['weight'] == weight:
                return shipping
        elif shipping.get('ladder') is not None:
            return shipping

    for shipping in shipping_list:
        if shipping.get('weight') is not None:
            if shipping.get('weight') > weight:
                return shipping
    raise Exception("didn't match weight")

def match_country(data_dict: dict, country_ch: str):
    with open("data/country_data.json", 'r', encoding='utf-8') as data:
        country_data_dict = json.load(data)

    if country_data_dict.get(country_ch) is not None:
        country_en = country_data_dict[country_ch]

        for channel in data_dict:
            if data_dict[channel].get(country_en) is not None:
                return data_dict[channel].get(country_en)
    raise Exception("didn't match country")

def weight_rounding(weight: float, ladder: float):
    if weight < ladder:
        return ladder
    elif weight % ladder == 0:
        return weight
    else:
        return (weight // ladder + 1) * ladder

def calculate(data_dict: dict, input_data: dict):
    try:
        shipping_list = match_country(data_dict, input_data['country'])
        shipping = match_weight(shipping_list, input_data['weight'])
        if shipping.get('shipping_cost') is not None and shipping.get('extra_charge') is not None:
            price = calculate_1(shipping, input_data)
        elif shipping.get('first_weight') is not None and shipping.get('continue') is not None and shipping.get(
                'ladder') is not None and shipping.get('extra_charge') is None:
            price = calculate_2(shipping, input_data)
        elif shipping.get('weight') is not None and shipping.get('shipping_cost') is not None:
            price = calculate_3(shipping)
        elif shipping.get('first_weight') is not None and shipping.get('continue') is not None and shipping.get(
                'ladder') is not None and shipping.get('extra_charge') is not None:
            price = calculate_4(shipping, input_data)
        else:
            raise Exception("this company's country source data is wrong")
        return round_price(price)
    except Exception as ex:
        return ex

# 根据重量的不同，运费加额外费用算法
def calculate_1(shipping: dict, input_data: dict):
    return input_data['weight'] * shipping['shipping_cost'] + shipping['extra_charge']

# 首重加续重算法
def calculate_2(shipping: dict, input_data: dict):
    weight = weight_rounding(input_data['weight'], shipping['ladder'])
    if weight == shipping['ladder']:
        return shipping['first_weight']
    else:
        return shipping['first_weight'] + shipping['continue'] * (weight / shipping['ladder'] - 1)

# 重量对应运费算法
def calculate_3(shipping: dict):
    return shipping['shipping_cost']

# 首重加续重加额外费用算法
def calculate_4(shipping: dict, input_data: dict):
    weight = weight_rounding(input_data['weight'], shipping['ladder'])
    if weight == shipping['ladder']:
        return shipping['first_weight'] + shipping['extra_charge']
    else:
        return shipping['first_weight'] + shipping['continue'] * (weight / shipping['ladder'] - 1) + \
            shipping['extra_charge']


# Line breaker in python: \
class Solution:
    def getFood(self, grid: List[List[str]]) -> int:
        visit = set()
        def bfs(row, col):
            queue = collections.deque()
            queue.append((row, col, 0))#starting point as step 0
            visit.add((row, col))
            while queue:
                r, c, step = queue.popleft()
                if grid[r][c] == '#':
                    return step
                for directions in ((-1, 0), (0, 1), (1, 0), (0, -1)):
                    new_r, new_c = r + directions[0], c + directions[1]
                    if 0 <= new_r < len(grid) and 0 <= new_c < len(grid[0]) and \
                    grid[new_r][new_c] != 'X' and (new_r, new_c) not in visit:
                    # Check if next step is doable. Can enter food or empty
                    # Made a mistake as only enter 'O' in the first place
                        visit.add((new_r, new_c))
                        queue.append((new_r, new_c, step + 1))
            return -1
        for r in range(len(grid)):
            for c in range(len(grid[0])):
                if grid[r][c] == '*':
                    steps = bfs(r, c)
        return steps


import sys

if __name__ == '__main__':
    top_mark = 0
    inp = sys.argv[1]
    with open(inp) as f:
        lines = f.readlines()
    for line in lines:
        try:
            line = line.strip().split()
            if int(line[0]) > top_mark:
                top_mark = int(line[0])
                top_student = line[1:]
        except:
            print('Invalid mark {} encountered. Skipping.'.format(line[0]))
    top_student = " ".join(top_student)
    print('Best student:' + " " + top_student)
    print("Best mark:", top_mark)


import datetime

import db
import sqlalchemy

def assing_presence(con: sqlalchemy.engine.Engine, nick_user:str):
    date = datetime.datetime.now().strftime("%Y-%m-%d")
    sql = "INSERT INTO tb_presence (dtPresence, descNick) VALUES (?,?)"
    con.execute(sql, (date, nick_user))
    return True

def check_assing_presence(con: sqlalchemy.engine.Engine, nick_user:str):
    date = datetime.datetime.now().strftime("%Y-%m-%d")
    sql = f"""SELECT COUNT(*)
              FROM tb_presence
              WHERE dtPresence = '{date}'
              AND descNick = '{nick_user}'"""
    exec = con.execute(sql)
    return exec.fetchone()[0] > 0


'''
Date: 2023-05-26 14:08:13
LastEditors: zhangjian zhangjian@cecinvestment.com
LastEditTime: 2023-11-07 11:25:09
FilePath: /QC-wrist/eval/point_judge.py
Description:

'''

import math
import numpy as np

'''
    上缘是否包含拇指指掌关节
'''
def metacarpophalangeal_joint_is_included(p1):
    if p1[0]==0 and p1[1]==0:
        return 0
    else:
        return 5

'''
    尺桡骨茎突连线中点是否位于图像正中(上下、左右差值<1cm),
    超出时按超出比例减少获得的分数(超出比例最大100%)
'''
def midpoint_of_StyloidProcess_is_center(p1, p2, pixelspacing, size):
    # midpoint: (x, y) = (w, h)
    midpoint = ( (p1[0]+p2[0])/2, (p1[1]+p2[1])/2 )
    # units: cm
    gap0 = abs(size[0] - 2*midpoint[0]) * pixelspacing[0] * 0.1
    gap1 = abs(size[1] - 2*midpoint[1]) * pixelspacing[1] * 0.1

    score = 0
    if gap0 <= 1:
        score += 5
    if 1 < gap0 < 2:
        score += int(4 * (2-gap0)) + 1

    if gap1 <= 1:
        score += 5
    if 1 < gap1 < 2:
        score += int(4 * (2-gap1)) + 1

    return score, round(gap0, 3), round(gap1, 3)

'''
    尺桡骨茎突连线是否与影像纵轴垂直(角度90°±5°以内)
'''
def line_of_StyloidProcess_is_horizontal(p1, p2, size):

    vec = [abs(p1[0] - p2[0]),
           abs(p1[1] - p2[1])]

    if size[0] >= size[1]:
        try:
            angle_yaxis = np.rad2deg(math.atan(vec[0] / vec[1]))
        except:
            angle_yaxis = np.NaN
    else:
        try:
            angle_yaxis = np.rad2deg(math.atan(vec[1] / vec[0]))
        except:
            angle_yaxis = np.NaN

    score = 0
    if not np.isnan(angle_yaxis):
        if int(angle_yaxis) <= 5:
            score = 10
        if 5 < angle_yaxis < 10:
            score = int( 9 * (10-angle_yaxis)/5 ) + 1
        return score, int(angle_yaxis)
    else:
        return 0, 'NaN'

'''
    下缘是否包含尺桡骨3-5cm
'''
def include_radius_ulna(p1, p2, p3, pixelspacing, size):
    # units: cm
    midpoint = ( (p2[0]+p3[0])/2, (p2[1]+p3[1])/2 )

    if size[0] >= size[1]:
        # 判断竖直正方向
        if p1[0] > midpoint[0]: # 尺桡骨从上往下
            distance_from_lowest = midpoint[0] * pixelspacing[0] * 0.1
        else:
            distance_from_lowest = (size[0] - midpoint[0]) * pixelspacing[0] * 0.1
    else:
        # 判断水平正方向
        if p1[1] > midpoint[0]: # 尺桡骨从左往右
            distance_from_lowest = midpoint[1] * pixelspacing[1] * 0.1
        else:
            distance_from_lowest = (size[1] - midpoint[1]) * pixelspacing[1] * 0.1

    score = 0
    if 3 <= distance_from_lowest <= 5:
        score = 5
    if 2 < distance_from_lowest < 3:
        score = int(4 * (distance_from_lowest-2)) + 1
    if 5 < distance_from_lowest < 6:
        score = int(4 * (6-distance_from_lowest)) + 1

    return score, round(distance_from_lowest, 3)

'''
    左右最外侧是否距影像边缘3-5cm
'''
def distance_from_StyloidProcess_to_edge(p1, p2, pixelspacing, size):
    # units: cm

    if size[0] >= size[1]:
        if p1[1] > p2[1]:
            r = p1
            l = p2
        else:
            r = p2
            l = p1

        distance0 = l[1] * pixelspacing[1] * 0.1
        distance1 = (size[1] - r[1]) * pixelspacing[1] * 0.1

        score = 0
        if 3 <= distance0 <= 5:
            score += 3
        if 2 < distance0 < 3:
            score += int(2 * (distance0-2)) + 1
        if 5 < distance0 < 6:
            score += int(2 * (6-distance0)) + 1

        if 3 <= distance1 <= 5:
            score += 3
        if 2 < distance1 < 3:
            score += int(2 * (distance1-2)) + 1
        if 5 < distance1 < 6:
            score += int(2 * (6-distance1)) + 1

    else:
        if p1[1] > p2[1]:
            b = p1
            t = p2
        else:
            b = p2
            t = p1

        distance0 = t[0] * pixelspacing[0] * 0.1
        distance1 = (size[0] - b[0]) * pixelspacing[0] * 0.1

        score = 0
        if 3 <= distance0 <= 5:
            score += 3
        if 2 < distance0 < 3:
            score += int(2 * (distance0-2)) + 1
        if 5 < distance0 < 6:
            score += int(2 * (6-distance0)) + 1

        if 3 <= distance1 <= 5:
            score += 3
        if 2 < distance1 < 3:
            score += int(2 * (distance1-2)) + 1
        if 5 < distance1 < 6:
            score += int(2 * (6-distance1)) + 1

    return score, round(distance0, 3), round(distance1, 3)

'''
    舟骨是否位于图像正中(上下、左右差值<1cm)
'''
def Scaphoid_is_center(p1, pixelspacing, size):
    # units: cm
    gap0 = abs(size[0] - 2*p1[0]) * pixelspacing[0] * 0.1
    gap1 = abs(size[1] - 2*p1[1]) * pixelspacing[1] * 0.1

    score = 0
    if gap0 <= 1:
        score += 6
    if 1 < gap0 < 2:
        score += int(5 * (2-gap0)) + 1

    if gap1 <= 1:
        score += 6
    if 1 < gap1 < 2:
        score += int(5 * (2-gap1)) + 1

    return score, round(gap0, 3), round(gap1, 3)

'''
    腕关节长轴是否与影像纵轴平行(两轴所夹锐角<10°)
    · 如果两条线段之间的夹角在 0 到 5 度之间，可以认为它们非常接近平行。
    · 如果夹角在 5 到 10 度之间，可以认为它们相对平行，但可能有轻微的偏离。
    · 如果夹角在 10 到 15 度之间，可以认为它们大致平行，但具有一定程度的偏离。
    · 如果夹角在 15 到 20 度之间，可以认为它们基本平行，但存在明显的偏离。
'''
def line_of_LongAxis_is_vertical(p1, p2, p3, size):
    # midpoint: (x, y) = (w, h)
    lat_proximal = ( (p2[0]+p3[0])/2, (p2[1]+p3[1])/2 )

    vec = [abs(p1[0] - lat_proximal[0]),
           abs(p1[1] - lat_proximal[1])]

    if size[0] >= size[1]:
        try:
            angle_yaxis = np.rad2deg(math.atan(vec[1] / vec[0]))
        except:
            angle_yaxis = np.NaN
    else:
        try:
            angle_yaxis = np.rad2deg(math.atan(vec[0] / vec[1]))
        except:
            angle_yaxis = np.NaN

    score = 0
    if not np.isnan(angle_yaxis):
        if 0 <= int(angle_yaxis) <= 5:
            score = 12
        if 5 < int(angle_yaxis) <10:
            score = int(11 * (10 - angle_yaxis) / 5) + 1
        return score, int(angle_yaxis)
    else:
        return 0, 'NaN'

'''
    尺桡骨重叠(abandoned)
'''
def radius_and_ulna_overlap(p1, p2, p3, p4):

    # l1 [xa, ya, xb, yb]   l2 [xa, ya, xb, yb]
    # reference: https://blog.csdn.net/weixin_42990464/article/details/120652439
    def Intersect(l1, l2):
        v1 = (l1[0] - l2[0], l1[1] - l2[1])
        v2 = (l1[0] - l2[2], l1[1] - l2[3])
        v0 = (l1[0] - l1[2], l1[1] - l1[3])
        a = v0[0] * v1[1] - v0[1] * v1[0]
        b = v0[0] * v2[1] - v0[1] * v2[0]

        temp = l1
        l1 = l2
        l2 = temp
        v1 = (l1[0] - l2[0], l1[1] - l2[1])
        v2 = (l1[0] - l2[2], l1[1] - l2[3])
        v0 = (l1[0] - l1[2], l1[1] - l1[3])
        c = v0[0] * v1[1] - v0[1] * v1[0]
        d = v0[0] * v2[1] - v0[1] * v2[0]

        if a*b < 0 and c*d < 0:
            return True
        else:
            return False

    l1 = [p1[0], p1[1], p2[0], p2[1]]
    l2 = [p3[0], p3[1], p4[0], p4[1]]

    is_intersecting = Intersect(l1, l2)

    if is_intersecting:
        score = 9
    else:
        score = 0
    return score

'''
    尺桡骨远端重叠
'''
def distal_radius_and_ulna_overlap(p1, p2, p3):

    a=math.sqrt((p2[0]-p3[0])*(p2[0]-p3[0])+(p2[1]-p3[1])*(p2[1] - p3[1]))
    b=math.sqrt((p1[0]-p3[0])*(p1[0]-p3[0])+(p1[1]-p3[1])*(p1[1] - p3[1]))
    c=math.sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1]))
    try:
        angleA=math.degrees(math.acos((a*a-b*b-c*c)/(-2*b*c)))
    except:
        angleA=np.NaN

    score = 0
    if not np.isnan(angleA):
        if angleA <= 45:
            score = 12
        if 45 < angleA < 60:
            score = int(11 * (60-angleA) / 15) + 1
        return score, math.ceil(angleA)
    else:
        return 0, 'NaN'


import numpy
import pygame
import sys
from pygame.locals import *
from abc import ABC

class Simulation(ABC):
    """ Base Simulation Class
    This class is meant to serve as a parent class for you to create your own
    simulations. It handles the main loop for pygame and all its settings so
    that you don't have to copy/paste them all over the place.
    Simply inherit from this class, override the update() function (main game loop),
    and you're good to go.
    Finally, you call it in a main function like so.

    class ExampleSim(Simulation):

        def update():
            # simulation code that will be executed each frame.

    if __name__ == '__main__':
        ExampleSim().run()
    """

    HEIGHT: int = 1000
    WIDTH: int = 1000
    SCREEN_CENTER: tuple[float, float] = (
        HEIGHT / 2,
        WIDTH / 2
    )
    FPS: int = 60

    def __init__(self):
        self.fps_clock = pygame.time.Clock()
        pygame.init()
        self.display = pygame.display.set_mode((self.WIDTH, self.HEIGHT))
        self.set_caption()
        self.surface = pygame.Surface((self.WIDTH, self.HEIGHT))

    def update(self):
        """ Override this function and add your simulation code here.
        """
        pass

    @staticmethod
    def check_exit():
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()

    def get_surface_2d(self) -> numpy.ndarray:
        return pygame.surfarray.array2d(self.surface)

    def run(self):
        while True:
            self.display.blit(self.surface, self.SCREEN_CENTER)
            self.update()
            self.check_exit()
            pygame.display.update()
            self.fps_clock.tick(self.FPS)

    def set_caption(self):
        pygame.display.set_caption(str(self.name()))

    def name(self):
        return str(self.__class__).strip("<>'").split(".")[-1]


from tkinter import *
import collections
import communicationInterface
import widgets

class Terminal():
    # Global variables allow access from anywhere in the program
    # not the best practice, but it made it easier than writing functions with unwieldly parameter lists

    widgets = {}

    labels = []
    num_remember = 100

    # A deque (double-ended queue) allows the program to display
    # the most recent (and most relevant) output from the processor
    # When the size of the deque exceeds num_remember, it deletes the oldest entry
    de = collections.deque([], maxlen=num_remember)

    def __init__(self, tabs, tabIndex):
        self.widgets['Terminal Tab'] = tabs[tabIndex]

        # Enable vertical scroll bar
        self.widgets['Terminal Output Generic Frame'] = Frame(self.widgets['Terminal Tab'])
        self.widgets['Terminal Output Generic Frame'].pack(fill=BOTH, expand=YES)

        self.widgets['Canvas'] = Canvas(self.widgets['Terminal Output Generic Frame'], borderwidth=0, highlightthickness=0)
        self.widgets['Canvas'].pack(side='left', fill='both', expand=True)

        vsb = Scrollbar(self.widgets['Terminal Output Generic Frame'], orient='vertical',
                        command=self.widgets['Canvas'].yview)
        vsb.pack(side='right', fill='y')

        self.widgets['Canvas'].configure(yscrollcommand=vsb.set)

        # Create and display a Terminal Output Frame
        self.widgets['Terminal Output'] = Frame(self.widgets['Canvas'])
        self.widgets['Terminal Output'].pack(fill=BOTH, expand=YES)

        self.widgets['Canvas'].create_window((4, 4), window=self.widgets['Terminal Output'], anchor='nw')
        self.widgets['Terminal Output'].bind('<Configure>', self.onFrameConfigure)

        for i in range(self.num_remember):
            lb = Label(self.widgets['Terminal Output'], width=100, anchor='w')
            self.labels.append(lb)

        # Create and display a Terminal Input Text box
        self.widgets['Terminal Input'] = Text(self.widgets['Terminal Tab'], bg='ghost white',
                                              borderwidth=1, relief=SUNKEN)
        self.widgets['Terminal Input'].pack(fill=BOTH, expand=YES)

        # Bind the <Return> key to the Terminal Input Text box
        # On <Return>, call print_to_terminal()
        self.widgets['Terminal Input'].\
            bind('<Return>', lambda e: communicationInterface.custom_write(self.widgets['Terminal Tab'],
                                                                           self.widgets['Terminal Input'],
                                                                           self.widgets['Terminal Input'].get('1.0', END)))

    def print_to_terminal(self, msg, in_out):
        if msg == None:
            return

        serial_dir = ">> "
        if in_out == 'out':
            serial_dir = "<< "
            serial_dir = serial_dir.encode()

        # msg is a binary string with each line terminated by '\r\n'
        # splitlines() is used to prevent these carriage returns and newlines
        # from appearing in the terminal, by making each line in entry
        # an item in a list; each item in the list is added to the deque, de
        for line in msg.splitlines():
            final_line = serial_dir + line
            self.de.append(final_line)

        # Display each item in de according to its position within de

        for i in range(len(self.de)):
            line = self.de[i]
            widgets.edit_message(self.labels[i], None, -1, line)
            self.labels[i].grid(row=i, column=0)

        self.widgets['Canvas'].yview_moveto(1)

    def onFrameConfigure(self, event):
        self.widgets['Canvas'].configure(scrollregion=self.widgets['Canvas'].bbox('all'))


from __future__ import division

import sys
import os
from select                                     import select
import argparse
import ast
import copy

import fnmatch

import matplotlib
matplotlib.use('agg')
import matplotlib.pyplot                        as plt

import numpy                                    as np
import pandas                                   as pd

from keras.models                               import load_model

from sklearn.model_selection                    import train_test_split
from sklearn.externals                          import joblib

from modules.control                            import config_file_to_dict
from modules.logger                             import logger
from modules.load_model                         import train_model
from modules.data_preparation                   import get_data_dictionary, preprocess, \
                                                       fix_missing_values, get_sub_dictionary
from modules.utils                              import print_dict, split_dictionary, \
                                                       pause_for_input, get_subsample, \
                                                       print_array_in_dictionary_stats, \
                                                       remove_field_name, flatten_dictionary, \
                                                       special_preprocessing, engineer_features, \
                                                       flatten_feature, shape_data
from modules.file_management                    import OutputManager
from modules.evaluation_plots                   import plot_ROCcurve, plot_MVAoutput, \
                                                       plot_cut_efficiencies, plot_all_features, \
                                                       plot_model_loss, plot_autoencoder_output

def main():

    if (sys.version_info < (3, 0)):
        raise OSError('This program needs python3 to work! Currently {} is used.'.format(
            sys.version_info))

    print('run_mode_user: {}'.format(run_mode_user))
    run_params = config_file_to_dict(config_path + 'run_params.conf')
    data_params = config_file_to_dict(config_path + 'data_params.conf')

    data_params = data_params[run_mode_user]
    run_params = run_params[run_mode_user]

    # here is a collection of variables extracted from the config files
    try:
        # ----------- data-parameters --------------
        branches_dic      = data_params['branches']
        evt_id_string     = data_params['evt_id']
        remove_features   = data_params['remove_features']
        print('evt_id_string: {}'.format(evt_id_string))
        # ------------ run-parameters --------------
        do_standard_scale = run_params['do_standard_scale']
        # ------------ model-parametrs -------------
    except KeyError:
        raise KeyError('The variable names in the main either have a typo ' \
                'or do not exist in the config files!')

    try:
        # uncomment the next line if we want to produce the evt-dictionary with the
        # saved pickle files (the event.pkl, etc)
        # raise TypeError('We want to produce the evt_dic again')
        evt_dictionary = get_data_dictionary(inpath)
        print('\n:: Event dictionary loaded from file: {}'.format(inpath))
        # train only on events with no clusters
        indices = np.arange(evt_dictionary['event']['has_no_calo_clusters'].shape[0])[(evt_dictionary['event']['has_no_calo_clusters']==True).ravel()]
        for key in evt_dictionary.keys():
                evt_dictionary[key] = evt_dictionary[key][indices]

        print('::  Saving the id of all events in {}...'.format(model_dir+"all_evts_id.txt"))
        allfile = open(model_dir+"all_evts_id.txt", 'w')
        for item in evt_dictionary['event'][evt_id_string].ravel().tolist():
            allfile.write("%s\n" % item)

    except(OSError, IOError, TypeError, ValueError):
        raise IOError('The event dictionary cannot be loaded from {}!'.format(inpath))

    evt_dictionary = get_sub_dictionary(evt_dictionary, branches_dic)

    if evt_id_string in evt_dictionary['event'].dtype.names:
        print('{} in event category!'.format(evt_id_string))
        print('{}'.format(evt_dictionary['event'].dtype.names))
    else:
        print('{} NOT in event category!'.format(evt_id_string))
        print('{}'.format(evt_dictionary['event'].dtype.names))
    evt_dictionary['event'], evt_id_np = remove_field_name(evt_dictionary['event'], evt_id_string)
    print('\nType evt-id-np: {}'.format(type(evt_id_np)))
    print(evt_id_np)

    if engineer:
        evt_dictionary, list_of_engineered_features = engineer_features(evt_dictionary, replace=False)
    else:
        list_of_engineered_features = []

    # function that extracts the evt-id from each 'event'-array and puts it into a list
    # we do not need the 99 events any more
    not_99_indices = np.arange(evt_dictionary['target'].shape[0])[evt_dictionary['target']!=99]
    for key in evt_dictionary.keys():
        evt_dictionary[key] = evt_dictionary[key][not_99_indices]

    evt_id_list = list(map(int, evt_id_np.ravel().tolist()))
    # remove a feature if it is in the cut_dic and contains no further info
    branches_dic['event'].remove(evt_id_string)
    print(remove_features)
    for key in evt_dictionary.keys():
        if key == 'target':
            continue
        remove_features = list(set(remove_features))
        # have to remove feature from the remove-list that we have engineered!
        remove_features = [x for x in remove_features if x not in list_of_engineered_features]
        for feature_name in remove_features:
            print('key: {}'.format(key))
            evt_dictionary[key] = remove_field_name(evt_dictionary[key], feature_name)[0]
        print('Features left in {}: {}'.format(key, list(evt_dictionary[key].dtype.names)))

    if evt_id_string in evt_dictionary['event'].dtype.names:
        raise KeyError('Attention, the event id key is still in the data! '\
                'By not removing it the machine will treat it as a feature')
    # if plot:
    #     print('\n::  Plotting the features...')
    #     plot_all_features(evt_dictionary, out_path, real_bg=False)

    ######################################################################################
    # STEP 1:
    # ------------------------------- Preprocessing --------------------------------------
    ######################################################################################
    print('\n::  Standarad scaling...')
    # returns a numpy array (due to fit_transform function)
    preprocess(evt_dictionary, model_dir, load_fitted_attributes=True)

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

    print('\n::  Converting the data from numpy record arrays to standard numpy arrays...')
    shape_data(evt_dictionary)

    if flat:
        flatten_feature(evt_dictionary, 'track')
        evt_dictionary['feature_matrix'] = np.c_[evt_dictionary.pop('track'),
                                                 evt_dictionary.pop('event')]

    # if 'NN' in run_mode_user:
    #     flatten_feature(evt_dictionary, 'track')
    #     evt_dictionary['feature_matrix'] = np.c_[evt_dictionary.pop('track'),
    #                                              evt_dictionary.pop('event')]
    print_array_in_dictionary_stats(evt_dictionary, 'Training data info:')
    # Get the best model
    model = load_model(model_path)
    ######################################################################################
    # STEP 3:
    # ----------------------------- Evaluating the model ---------------------------------
    ######################################################################################
    # save the test dictionary for easy testing later on

    print('\nEvaluating the model on the training sample...')
    y_target = evt_dictionary.pop('target')
    y_score = model.predict(evt_dictionary)
    if isinstance(y_score, list):
        # if one or several aux-outputs exist the main output is on the
        # first position in the list
        y_score = y_score[0]

    full_recon = 0
    feed_down = 0
    sig_list = []
    for idx, val in enumerate(y_score):
        if val >= mva_cut:
            # evt_id_list is created in a function that will be created in the near future
            sig_list.append(evt_id_list[idx])
            if y_target[idx] == 1:
                full_recon += 1
            else:
                feed_down += 1

    num_trueSignal, num_trueBackgr = plot_MVAoutput(y_target, y_score,
                                                    model_dir, label='classify')
    if num_trueSignal is not None:
        MVAcut_opt = plot_cut_efficiencies(num_trueSignal, num_trueBackgr, model_dir, 'classify')
        plot_ROCcurve(y_target, y_score, model_dir, label='classify')
    del num_trueSignal, num_trueBackgr

    print('::  Cut quality:')
    print('   Signal events after cut: {}/{}'.format(full_recon, full_recon+feed_down))
    print('   Signal efficiency: {}'.format(full_recon/(full_recon+feed_down)))

    print('::  Saving the predicted signal evts in {}...'.format(model_dir+outfile))
    thefile = open(model_dir+outfile, 'w')
    for item in sig_list:
        thefile.write("%s\n" % item)

if __name__ == "__main__":

    output_path = 'output/'
    data_path   = '../data/'
    config_path = 'config/'
    om = OutputManager(output_path, keep_sessions=20)
    sys.stdout = logger(om.get_session_folder())

    # fix random seed for reproducibility
    # np.random.seed(7)

    user_argv = None

    if(len(sys.argv) > 1):
        user_argv = sys.argv[1:]

    # commend line parser (right now not a own function as only 2 elements are used)
    parser = argparse.ArgumentParser()
    parser.add_argument('-inpath', '-evtdicpath', '-evtdic',
                        help='path to the event dictionary',
                        action='store',
                        dest='inpath',
                        default='output/evt_dic.pkl',
                        type=str)

    parser.add_argument('-run_mode', '-run_setting',
                        help='keyword to identify which run settings to \
			      choose from the config file (default: "run_params")',
                        action='store',
                        dest='run_mode',
                        default='NN',
                        type=str)

    parser.add_argument('-modelpath',
                        help='str: path where the model can be found',
                        action='store',
                        dest='model_path',
                        default=None,
                        type=str)

    parser.add_argument('-mva_cut',
                        help='float: cut value that seperates sig-bg',
                        action='store',
                        dest='mva_cut',
                        default=None,
                        type=float)

    parser.add_argument('-outfile',
                        help='str: filename where the evt-ids will be saved',
                        action='store',
                        dest='outfile',
                        default='signal_evt_ids.txt',
                        type=str)

    parser.add_argument('-flat',
                        help='bool: has only an effect if run_mode NN is used \
                              if used then the rnn structure of the tracks is flattend',
                        action='store_true',
                        dest='flat',
                        default=False)

    parser.add_argument('-engineer',
                        help='bool: if engineer_features function should be called',
                        action='store_true',
                        dest='engineer',
                        default=False)

    command_line_args = parser.parse_args(user_argv)

    run_mode_user = command_line_args.run_mode
    model_path = command_line_args.model_path
    mva_cut = command_line_args.mva_cut
    outfile = command_line_args.outfile
    inpath = command_line_args.inpath
    flat = command_line_args.flat
    engineer = command_line_args.engineer

    if not os.path.isfile(inpath) or not inpath.endswith('.pkl'):
        raise IOError('No valid "inpath" for the event dictionary provided!\nPlease do so via ' \
                'command line argument: -inpath /path/to/evt_dic_folder/evt_dic.pkl')

    if not outfile.endswith('.txt'):
        outfile += '.txt'

    if not model_path.endswith('/') and not model_path.endswith('.hdf5'):
        model_path += '/'

    if model_path.endswith('/'):
        model_path += 'best_model.h5'

    model_dir = os.path.split(model_path)[0]+'/'

    if model_path is None or not os.path.isfile(model_path):
        raise IOError('No valid "model_path" provided!\nPlease do so via ' \
                'command line argument: -modelpath /path/to/modelfolder/model_file.hdf5')

    if not mva_cut or mva_cut < 0. or mva_cut > 1.:
        raise IOError('MVA cut-value has no valid value: {}'.format(mva_cut))

    main()


import numpy as np
import os
import shutil
import tensorflow as tf

class predictService:
    def __init__(self, url, model):
        """
        Create a new predict service.

        Args:
            url: The image URL.
        """
        self.imageURL = url
        self.result = None
        self.models = model

    def predict(self):
        """
        predict.

        Returns:
            The result.
        """
        image = self.preprocessImage()
        predictions = self.models.weightModel.predict(image)
        predicted_class = np.argmax(predictions)
        # print(predicted_class)
        if predicted_class in self.models.labels:
            self.result = self.models.labels[predicted_class]
        else:
            self.result = "Not in desease list!!!"
        return self.result

    def preprocessImage(self):
        cache_subdir = os.path.join(os.getcwd(), "caches/")
        image = tf.keras.preprocessing.image.load_img(tf.keras.utils.get_file(origin=self.imageURL, cache_subdir=cache_subdir), target_size=(200, 200), color_mode = "grayscale")
        image_array = tf.keras.preprocessing.image.img_to_array(image)
        image_array = np.expand_dims(image_array, axis=0)
        image_array = image_array / 255.0
        shutil.rmtree(cache_subdir)
        # print(image_array)
        return image_array


#coding=utf-8
'''
Created on 2016年6月26日

@author: sin
'''
import re,urllib2

url = "http://baozoumanhua.com/"

buf = urllib2.urlopen(url)

urllist = re.findall(r"http://.+",buf.read())

i=0

for u in urllist:
    try:
        if "png" in u:
            new_url = u[:u.find("png")+3]
            print ("crawl image %d:%s"%(i+1,new_url))
            f = open(str(i)+".png",'w')
            data = urllib2.urlopen(new_url)
            f.write(data.read())
            i += 1
    except:
        print ("crawl image failed:%s" %u)


from django.core.management.base import BaseCommand, CommandError
from django.utils import timezone
from users.views import getEndBalanceOfMonth, getNextDelivery, getNextDeliveryAfterTomorrow
from datetime import datetime, timedelta
from users.models import ExtraLess, Vacation, Subscription, UserType, User, Product
import pytz
import http.client
from django.conf import settings

class Command(BaseCommand):
    help = 'Creates daily transacion for all customers'

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def handle(self, *args, **options):
        customers = User.objects.filter(user_type__payment_type='prepaid', user_type__suspend=True)
        for c in customers:
            last_date = timezone.localtime(timezone.now())
            balance = getEndBalanceOfMonth(last_date, c)
            subs = Subscription.objects.filter(user=c)
            vacations = Vacation.objects.filter(user=c)
            extras = ExtraLess.objects.filter(user=c)
            milk = Product.objects.get(id=1)
            next_delivery = getNextDelivery(subs, vacations, extras)
            tomorrow = (last_date + timedelta(days=1)).strftime("%b %d, %Y")
            if next_delivery is not None:
                if tomorrow == next_delivery['date']:
                    price_for_next_delivery = (milk.price + c.user_type.price_variation) * next_delivery['quantity']

                    # check balance for next delivery
                    if balance < price_for_next_delivery:
                        conn = http.client.HTTPSConnection("api.msg91.com")
                        url = "/api/v5/flow?flow_id=" + settings.ENV('MSG91_FLOW_ID') + "&mobile=91" + c.mobile + "&authkey=" + settings.ENV('MSG91_AUTH_KEY')
                        url = url.replace(" ","")
                        conn.request("POST", url)
                        res = conn.getresponse()
                        data = res.read()
                        print(data.decode("utf-8"))
                        continue

                    # check balance for next 2 delivery
                    balance -= price_for_next_delivery
                    next_delivery = getNextDeliveryAfterTomorrow(subs, vacations, extras)
                    price_for_next_delivery = (milk.price + c.user_type.price_variation) * next_delivery['quantity']
                    if balance < price_for_next_delivery:
                        conn = http.client.HTTPSConnection("api.msg91.com")
                        url = "/api/v5/flow?flow_id=" + settings.ENV('MSG91_FLOW_ID') + "&mobile=91" + c.mobile + "&authkey=" + settings.ENV('MSG91_AUTH_KEY')
                        url = url.replace(" ","")
                        conn.request("POST", url)
                        res = conn.getresponse()
                        data = res.read()
                        print(data.decode("utf-8"))


from ipykernel.kernelbase import Kernel
import os
import subprocess

class Flowjupyter(Kernel):
    implementation = 'flowjupyter'
    implementation_version = '0.1'
    language = 'flow command line'
    language_version = '0.1'
    banner = "Flow kernel - flow jupyter! "

    def __init__(self, **kwargs):
        Kernel.__init__(self, **kwargs)
        self.start_flow(**kwargs)

    def start_flow(self, **kwargs):
            cmd = 'flow emulator start'
            print(subprocess.run(["flow", "emulator", "start"], capture_output=True))

    def do_execute(self, code, silent, store_history=True, user_expressions=None,
                   allow_stdin=False):
        if not silent:
            process = subprocess.Popen(code, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            output, error = process.communicate()

            if process.returncode != 0:
                error_message = error.decode()
                self.send_response(self.iopub_socket, 'stream', {'name': 'stderr', 'text': error_message})
                return {'status': 'error', 'execution_count': self.execution_count, 'ename': '', 'evalue': '', 'traceback': []}

            output_message = output.decode()
            self.send_response(self.iopub_socket, 'stream', {'name': 'stdout', 'text': output_message})

        return {'status': 'ok', 'execution_count': self.execution_count}

if __name__ == '__main__':
    from ipykernel.kernelapp import IPKernelApp
    IPKernelApp.launch_instance(kernel_class=Flowjupyter)


# !/usr/bin/env python
# -*- coding: utf-8 -*-

import numpy as np

def PCA(x, n_components=2):
    # 1. 对每个特征（每一行）进行去中心化，即每个数据减去均值
    mean_val = np.mean(x, axis=0)
    mean_x = x - mean_val

    # 2. 求mean_x协方差方阵
    C_x = np.cov(mean_x, rowvar=True)

    # 3. 求C_x特征值和特征向量
    eig_vals, eig_vects = np.linalg.eig(np.mat(C_x))

    # 4. 对特征值从大到小排序
    sorted_idx = np.argsort(-eig_vals)

    # 5. 降维
    topn_index = sorted_idx[:n_components]
    topn_vects = eig_vects[topn_index, :]

    # 6. 投影到低维空间
    pca_x = topn_vects * x
    return pca_x

if __name__ == '__main__':
    x = np.mat([[-1, -1, 0, 2, 0],
                [-2,  0, 0, 1, 1]])
    x_ = PCA(x, n_components=1)
    print(x_)


from yolov4.tf import YOLOv4

yolo = YOLOv4()

yolo.config.parse_names("data/classes.names")
yolo.config.parse_cfg("data/pip-yolov4-vehicle.cfg")

yolo.make_model()
yolo.load_weights("data/yolov4-vehicle_best.weights", weights_type="yolov")
yolo.summary(summary_type="yolov")
yolo.summary()
yolo.model.save("data/vehicle",save_format="tf")


#https://www.coursera.org/learn/python-network-data/lecture/G1up7/worked-example-json-chapter-13
import urllib.request,urllib.parse,urllib.error
import json
data=urllib.request.urlopen(' http://py4e-data.dr-chuck.net/comments_937754.json').read()
info = json.loads(data)
total=0

for tags in info['comments']:
    total=total+tags['count']
print(total)


import threading
import time

def loop():
    ''' 新的线程执行的代码 '''
    now_thread = threading.current_thread()
    print("now loopthread name :{0}".format(now_thread.name))
    n = 0
    while n < 5:
        print(n)
        time.sleep(1)
        n += 1

def use_thead():
    ''' 使用线程来实现'''
    #当前正在执行的线程名称
    now_thread = threading.current_thread()
    print("now thread name :{0}".format(now_thread.name))
    #设置线程
    t = threading.Thread(target=loop,name='loop_thread')
    #启动线程
    t.start()
    #挂起线程
    t.join()

if __name__ == '__main__':
    use_thead()


nums_str = input().split()
n = int(input())

numbers = []
for num_str in nums_str:
    number = int(num_str)
    numbers.append(number)

for i in range(n):
    numbers.remove(min(numbers))
print(numbers)


import os
import sys
import inspect
import imp
import pkgutil
import re

import logging
logger = logging.getLogger("differ.plugins")

class Plugins(object):
  def __init__(self):
    self.plugins = {}
    self.paths = {}

  def get_plugins(self):
    """Retrieve all the available plugins in the plugins directory"""
    dir_path = os.path.dirname(inspect.getfile(inspect.currentframe()))
    for root, dirs, files in os.walk(dir_path):
      for fname in files:
        path = os.path.join(root, fname)
        if fname == "__init__.py":
          continue
        exten = os.path.splitext(fname)[1]
        if exten == ".py":
          module = imp.load_source('plugin', path)
          for item in dir(module):
            obj = getattr(module, item)
            if inspect.isclass(obj):
              self.add(obj())

  def add(self, plugin):
    """Add the plugin to the dictionary of plugins"""
    name = plugin.__class__.__name__
    self.plugins[name] = plugin

  def add_parsers(self, parsers):
    """Update the parser dictionary

    :param parsers: A passed in dictionary of parsers
    :ptype parsers: dict
    """
    self.paths.update(parsers)

  def get(self, name):
    """Retrieve a plugin by its name

    :return: A plugin object or None if not found
    """
    item = self.plugins.get(name)
    if not item:
      print("No such plugin by name {}".format(name))
      return None
    return item

  def strip_hook(self, path, full_path):
    """Hook to strip the path passed in

    This will perform stripping on the file only if the path
    matches any of the plugins and if the plugin has the strip_hook
    functionality.

    :param path: The path to check
    :param full_path: The full path of the file to strip
    """
    for path_regex, plugin in self.paths.items():
      if re.match(path_regex, path):
        # Run the strip_hook if it exists
        if getattr(plugin, "strip_hook"):
          plugin.strip_hook(full_path)

PLUGINS = Plugins()
PLUGINS.get_plugins()

# Define default paths
PLUGINS.add_parsers({
  '.*iptables.*': PLUGINS.get("IptablesStrip"),
})


import re
from collections import defaultdict,Counter
import time
import pickle

no_of_lines = 0
count_words=0
try:
    file = "address"
except FileNotFoundError:
    print('Correct path of file was not provided')
#count_unique_words = Counter()
#count_unigrams = Counter()
#count_bigrams = Counter()

count_unique_words = defaultdict(int) # dicts used for counting
count_unigrams = defaultdict(int)
count_bigrams = defaultdict(int)

string = "" #this is set zero before it becomes <word> after each line is processed
perf_start = time.perf_counter() #time counters
process_start = time.process_time()

with open(file) as f:
    for line in f:
        list_angular = [] #list of words with angular brackets
        no_of_lines+=1
        modified_line = re.sub(r'^\w+',' ',line) # applying regex for each line in text file and retrieving only words == [a-zA-Z]
        modified_line = re.sub(r'[^a-z]', ' ',modified_line, flags=re.IGNORECASE) # taking out any character which is not a ASCII letter
        modified_lower = modified_line.lower() # converting to lower case
        modified_line_lower = modified_lower.split() # tokenizing, this has better performance than --> tokenize = nltk.word_tokenize(modified_line.lower())
        for w in range(len(modified_line_lower)):
            list_angular.append('<'+modified_line_lower[w]+'>')   #placing angular brackets before the beginning and end of each word
        string = ' '.join(list_angular) # making it a string from list of strings
        for w in modified_line_lower:
            count_words+=1            # counting number of words in the corpus
        for w in modified_line_lower:
            count_unique_words[w]+=1  # unique words in corpus
        for w in re.findall(r'(?=([a-z\<\>]{1}))',string):
            count_unigrams[w]+=1 # unigram count of each word
        for w in re.findall(r'(?=([a-z\<\>]{2}))',string):
            count_bigrams[w]+=1   #bigram count of each word

perf_stop = time.perf_counter() # time counter end
process_stop = time.process_time()
total_time = perf_stop - perf_start
total_cpu_time = process_stop - process_start
print('\n\n')
print('start at elapsed time:{:>5.2f}, cpu time:{:>10}'.format(perf_start,process_start))
print('finish reading at elapsed time:{:>10.2f}, cpu time:{:>10}'.format(perf_stop,process_stop))
print('total elapsed time:{:>5.2f}, cpu time:{:>10}'.format(total_time,total_cpu_time))
print('\n\n')

#class Singleton1:
#     _shared_state = {}
#     def __init__(self):
#        self.__dict__ = self._shared_state
#
#class Singleton2(Singleton1):
#    def __init__(self, arg):
#        Singleton1.__init__(self)
#        self.val = arg
#    def __dict__(self):
#        return self.val
class Spell_correction_singleton:
      def __init__(self,count_unique,count_unigram,count_bigram):
          self.a = count_unique
          self.b = count_unigram
          self.c = count_bigram

object_1 = Spell_correction_singleton(count_unique_words,count_unigrams,count_bigrams)
 #object_1 is the only object of singleton class

output = open('pickled_data.dat', 'wb') #pickling the data structures
pickle.dump(object_1, output,-1)
output.close()

print("Number of words: ",count_words)
print("Number of types (distinct words): ",len(count_unique_words))
print('\n')
print('{:<8}'.format("Unigrams"),'{:>8}'.format("Count"))
for (key,value) in sorted(count_unigrams.items()):
    print("{:<8} {:>10}".format(key,value))
print('\n')

print('{:<8}'.format("Bigrams"),'{:>8}'.format("Count"))
for (key,value) in sorted(count_bigrams.items()):
    print("{:<8} {:>10}".format(key,value))
print('\n')

print("10 most frequent words: ")
print('\n')
print('{:<8}'.format("Word"),'{:>8}'.format("Count"))
for (key,value) in (Counter(count_unique_words).most_common(10)):
    print("{:<8} {:>10}".format(key,value))
print('\n')


import os

# Se importa la librería math debido a que la función módulo de Python tiene un comportamiento diferente
# con los números negativos y decimales, la función módulo de la librería math es mejor para este caso.
import math

class Error(Exception):
    pass

class DivisionPorCero(Error):
    pass

def borrar_pantalla():
    if os.name == "posix":
        return os.system ("clear")
    elif os.name == "ce" or os.name == "nt" or os.name == "dos":
        return os.system ("cls")

def detectar_errores(n):
    while True:
        try:
            if n == 1:
                var = input("Introduzca el número: ")
            elif n == 2:
                var = input("Introduzca el número que desea probar como divisor del primero: ")

            var = int(var)

            if n == 2 and var == 0:
                raise DivisionPorCero

        except ValueError:
            try:
                var = float(var)

                if n == 2 and var == 0:
                    raise DivisionPorCero
                else:
                    break
            except ValueError:
                print("Por favor introduzca un número racional.")
            except DivisionPorCero:
                print("El divisor no puede ser el número 0, por favor introduzca otro número.")
        except DivisionPorCero:
            print("El divisor no puede ser el número 0, por favor introduzca otro número.")
        else:
            break

    return var

def modulo(numero, divisor):

    resto = math.fmod(numero, divisor)

    if resto == 0:
        resultado = "El número " + str(divisor) + " es divisor del número " + str(numero)
    else:
        resultado = "El número " + str(divisor) + " no es divisor del número " + str(numero)

    return resultado

def main():
    borrar_pantalla()

    numero = detectar_errores(1)
    divisor = detectar_errores(2)

    print(modulo(numero, divisor))

main()


from __future__ import absolute_import #NEEDS TO STAY AS TOP LEVEL MODULE FOR Py2-3 COMPATIBILITY
import vtk
from vmtk import vtkvmtk
import sys

from vmtk import pypes

class vmtkICPRegistration(pypes.pypeScript):

    def __init__(self):

        pypes.pypeScript.__init__(self)

        self.ReferenceSurface = None
        self.Surface = None
        self.DistanceArrayName = ''
        self.SignedDistanceArrayName = ''
        self.FarThreshold = 0.0
        self.Level = 0.0
        self.MaximumMeanDistance = 1E-2
        self.MaximumNumberOfLandmarks = 1000
        self.MaximumNumberOfIterations = 100
        self.Matrix4x4 = None
        self.MatrixCoefficients = None

        self.FlipNormals = 0

        self.SetScriptName('vmtkicpregistration')
        self.SetScriptDoc('register a surface to a reference surface using the ICP algorithm')
        self.SetInputMembers([
            ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'],
            ['ReferenceSurface','r','vtkPolyData',1,'','the reference surface','vmtksurfacereader'],
            ['DistanceArrayName','distancearray','str',1,'','name of the array where the distance of the input surface to the reference surface has to be stored'],
            ['SignedDistanceArrayName','signeddistancearray','str',1,'','name of the array where the signed distance of the input surface to the reference surface is stored; distance is positive if distance vector and normal to the reference surface have negative dot product, i.e. if the input surface is outer with respect to the reference surface'],
            ['FarThreshold','farthreshold','float',1,'','threshold distance beyond which points are discarded during optimization'],
            ['FlipNormals','flipnormals','bool',1,'','flip normals to the reference surface after computing them'],
            ['MaximumNumberOfLandmarks','landmarks','int',1,'','maximum number of landmarks sampled from the two surfaces for evaluation of the registration metric'],
            ['MaximumNumberOfIterations','iterations','int',1,'','maximum number of iterations for the optimization problems'],
            ['MaximumMeanDistance','maxmeandistance','float',1,'','convergence threshold based on the maximum mean distance between the two surfaces']
            ])
        self.SetOutputMembers([
            ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'],
            ['MatrixCoefficients','omatrixcoefficients','float',16,'','the output transform matrix coefficients'],
            ['Matrix4x4','omatrix4x4','vtkMatrix4x4',1,'','the output transform matrix']
            ])

    def Execute(self):

        if self.Surface == None:
            self.PrintError('Error: No Surface.')

        if self.ReferenceSurface == None:
            self.PrintError('Error: No ReferenceSurface.')

##         if (self.SignedDistanceArrayName != '') & (self.ReferenceSurface.GetPointData().GetNormals() == None):
        if (self.SignedDistanceArrayName != ''):
            normalsFilter = vtk.vtkPolyDataNormals()
            normalsFilter.SetInputData(self.ReferenceSurface)
            normalsFilter.AutoOrientNormalsOn()
            normalsFilter.ConsistencyOn()
            normalsFilter.SplittingOff()
            normalsFilter.SetFlipNormals(self.FlipNormals)
            normalsFilter.Update()
            self.ReferenceSurface.GetPointData().SetNormals(normalsFilter.GetOutput().GetPointData().GetNormals())

        self.PrintLog('Computing ICP transform.')

        icpTransform = vtkvmtk.vtkvmtkIterativeClosestPointTransform()
        icpTransform.SetSource(self.Surface)
        icpTransform.SetTarget(self.ReferenceSurface)
        icpTransform.GetLandmarkTransform().SetModeToRigidBody()
        icpTransform.StartByMatchingCentroidsOn()
        icpTransform.CheckMeanDistanceOn()
        icpTransform.SetMaximumNumberOfLandmarks(self.MaximumNumberOfLandmarks)
        icpTransform.SetMaximumNumberOfIterations(self.MaximumNumberOfIterations)
        icpTransform.SetMaximumMeanDistance(self.MaximumMeanDistance)
        if self.FarThreshold > 0.0:
            icpTransform.UseFarThresholdOn()
            icpTransform.SetFarThreshold(self.FarThreshold)
        else:
            icpTransform.UseFarThresholdOff()

        transformFilter = vtk.vtkTransformPolyDataFilter()
        transformFilter.SetInputData(self.Surface)
        transformFilter.SetTransform(icpTransform)
        transformFilter.Update()

        self.PrintLog('Mean distance: '+str(icpTransform.GetMeanDistance()))

        self.Surface = transformFilter.GetOutput()
        self.Matrix4x4 = icpTransform.GetMatrix()

        matrix = self.Matrix4x4
        self.MatrixCoefficients = [
            matrix.GetElement(0,0), matrix.GetElement(0,1), matrix.GetElement(0,2), matrix.GetElement(0,3),
            matrix.GetElement(1,0), matrix.GetElement(1,1), matrix.GetElement(1,2), matrix.GetElement(1,3),
            matrix.GetElement(2,0), matrix.GetElement(2,1), matrix.GetElement(2,2), matrix.GetElement(2,3),
            matrix.GetElement(3,0), matrix.GetElement(3,1), matrix.GetElement(3,2), matrix.GetElement(3,3)]
        self.PrintLog('Transform matrix:\n  %f %f %f %f\n  %f %f %f %f\n  %f %f %f %f\n  %f %f %f %f' % tuple(self.MatrixCoefficients))

        if (self.DistanceArrayName != '') | (self.SignedDistanceArrayName != ''):
            self.PrintLog('Computing distance.')
            surfaceDistance = vtkvmtk.vtkvmtkSurfaceDistance()
            surfaceDistance.SetInputData(self.Surface)
            surfaceDistance.SetReferenceSurface(self.ReferenceSurface)
            if (self.DistanceArrayName != ''):
                surfaceDistance.SetDistanceArrayName(self.DistanceArrayName)
            if (self.SignedDistanceArrayName != ''):
                surfaceDistance.SetSignedDistanceArrayName(self.SignedDistanceArrayName)
            surfaceDistance.Update()
            self.Surface = surfaceDistance.GetOutput()

if __name__=='__main__':
    main = pypes.pypeMain()
    main.Arguments = sys.argv
    main.Execute()