#!/usr/bin/env python3

import unittest
import math
import sys
import io

from vectorsnek import *

class TestVectors(unittest.TestCase):
    def test____str__(self):
        v1 = Vector([4,9,1])
        self.assertEqual(str(v1), "(4, 9, 1)")

    def test___repr__(self):
        v1 = Vector([4,9,1])
        # change output buffer
        old_stdout = sys.stdout
        sys.stdout = buffer = io.StringIO()
        print(v1)
        # restore output buffer
        sys.stdout = old_stdout
        # test if output representation worked
        self.assertEqual(buffer.getvalue(), "(4, 9, 1)\n")

    def test_xyzwget(self):
        v1 = Vector([62, 52, 76, 3])
        self.assertEqual(v1.x, v1[0])
        self.assertEqual(v1.y, v1[1])
        self.assertEqual(v1.z, v1[2])
        self.assertEqual(v1.w, v1[3])

    def test_xyzwset(self):
        v1 = Vector([None] * 4)
        v1.x = -20
        v1.y = 19
        v1.z = 180
        v1.w = -9
        self.assertEqual(v1[0], -20)
        self.assertEqual(v1[1], 19)
        self.assertEqual(v1[2], 180)
        self.assertEqual(v1[3], -9)

    def test_zeros(self):
        v1 = Vector.zeros(5)
        self.assertEqual(v1, Vector([0,0,0,0,0]))
        # negative dimension error
        with self.assertRaises(ValueError):
            v2 = Vector.zeros(-2)

    def test_norm(self):
        v1 = Vector([3,-4])
        # 2-norm
        self.assertEqual(v1.norm(2), 5)
        # 1-norm
        self.assertEqual(v1.norm(1), 7)
        # 3-norm
        self.assertAlmostEqual(v1.norm(3), 4.49794144528)
        # inf-norm
        self.assertEqual(v1.norm(math.inf), 4)
        # ValueError test
        with self.assertRaises(ValueError):
            v1.norm(-1)

    def test_magnitude(self):
        v1 = Vector([3,-4])
        self.assertEqual(v1.magnitude(), 5)

    def test_scalar_multiply(self):
        v1 = Vector([2,-3])
        self.assertEqual(v1.scalar_multiply(5), Vector([10, -15]))

    def test_rotated(self):
        v1 = Vector([1,0])
        v2 = v1.rotated(3 * math.pi / 4)
        self.assertAlmostEqual(v2.x, -math.sqrt(2)/2)
        self.assertAlmostEqual(v2.y, math.sqrt(2)/2)
        # ValueError test
        v3 = Vector([0, 2, 3])
        with self.assertRaises(ValueError):
            v4 = v3.rotated(math.pi)

    def test_dot(self):
        v1 = Vector([10, 2, 3])
        v2 = Vector([2, 3, 1])
        self.assertEqual(v1.dot(v2), 29)
        # magnitude-dot product equality
        v3 = Vector([4,-2,5])
        self.assertAlmostEqual(v3.dot(v3), v3.magnitude()**2)
        # ValueError test
        v4 = Vector([5, 1])
        with self.assertRaises(ValueError):
            # non-matching dimensions
            v5 = v4.cross(v3)

    def test_cross(self):
        # computation test
        v1 = Vector([2, -5, 1])
        v2 = Vector([-8, 2, -2])
        self.assertEqual(v1.cross(v2), Vector([8, -4, -36]))
        # ValueError test
        v3 = Vector([6,-2])
        v4 = Vector([0, 1])
        with self.assertRaises(ValueError):
            # non-matching dimensions
            v4 = v2.cross(v3)
        with self.assertRaises(ValueError):
            # wrong dimension for cross product
            v5 = v3.cross(v4)

    def test__add__(self):
        v1 = Vector([-5, 2])
        v2 = Vector([1, -1])
        self.assertEqual(v1 + v2, Vector([-4, 1]))

    def test___sub__(self):
        v1 = Vector([0, 5, 10])
        v2 = Vector([-3, 4, 8])
        self.assertEqual(v1 - v2, Vector([3, 1, 2]))

    def test____mul__(self):
        # scalar multiplication
        v1 = Vector([2, -1])
        s1 = 6
        self.assertEqual(v1 * s1, Vector([12, -6]))
        # dot product
        v2 = Vector([3, 2])
        self.assertAlmostEqual(v1 * v2, 4)

    def test___rmul_(self):
        v1 = Vector([1, -2])
        s1 = 3
        self.assertEqual(s1 * v1, Vector([3, -6]))

    def test___ne__(self):
        v1 = Vector([2, -1])
        v2 = Vector([-2, 1])
        self.assertNotEqual(v1, v2)

    def test___iadd__(self):
        v1 = Vector([1, -6])
        v2 = Vector([-2, 1])
        v1 += v2
        self.assertEqual(v1, Vector([-1, -5]))

    def test___isub__(self):
        v1 = Vector([3, 9])
        v2 = Vector([1, 8])
        v1 -= v2
        self.assertEqual(v1, Vector([2, 1]))

    def test___imul__(self):
        v1 = Vector([1, -6])
        v2 = Vector([-2, 1])
        # dot product
        v1 *= v2
        self.assertAlmostEqual(v1, -8)
        # scalar multiplication
        v2 *= -2
        self.assertEqual(v2, Vector([4, -2]))

    def test___pos__(self):
        v1 = Vector([1,2])
        self.assertEqual(+v1, v1)

    def test___neg__(self):
        v1 = Vector([4,7,1])
        self.assertEqual(-v1, Vector([-4, -7, -1]))

    def test___round__(self):
        v1 = Vector([2.51, -3.2])
        self.assertEqual(round(v1, 0), Vector([3.0, -3.0]))

    def test___floor__(self):
        v1 = Vector([2.51, -3.2])
        self.assertEqual(math.floor(v1), Vector([2.0, -4.0]))

    def test___ceil__(self):
        v1 = Vector([2.51, -3.2])
        self.assertEqual(math.ceil(v1), Vector([3.0, -3.0]))

    def test___trunc__(self):
        v1 = Vector([2.51, -3.2])
        self.assertEqual(math.trunc(v1), Vector([2, -3]))

    def test___len__(self):
        v1 = Vector([1,2,3,4])
        self.assertEqual(len(v1), 4)

    def test___getitem__(self):
        v1 = Vector([5, 6, -7, 3])
        self.assertEqual(v1[2], -7)

    def test___setitem__(self):
        v1 = Vector([5, 6, -7, 3])
        v1[1] = 10
        self.assertEqual(v1, Vector([5, 10, -7, 3]))

    def test___delitem__(self):
        v1 = Vector([5, 6, -7, 3])
        del v1[0]
        self.assertEqual(v1, Vector([6, -7, 3]))

    def test___iter__(self):
        l1 = [5, 6, -7, 3]
        v1 = Vector(l1)
        for a, b in zip(l1, v1):
            self.assertEqual(a, b)

    def test___reversed__(self):
        l1 = [5, 6, -7, 3]
        v1 = Vector([5, 6, -7, 3])
        for a, b in zip(reversed(l1), reversed(v1)):
            self.assertEqual(a, b)

if __name__ == '__main__':
    unittest.main()


# Debug mode를 이용해 상해있는 이 코드를 정상적으로 작동시켜보세요.
# 총 11가지의 강제 error를 만들었습니다.
# 에러를 고치면 에러가 발생한 line 뒤쪽에 주석으로 error의 원인을 적어주세요.
# Debug mode의 call stack, debug console, variable 등의 과정을 충분히 활용해보세요 ^^
# 제출은 고친 파일(error의 원인이 적혀있는)과
# debug mode를 활용해 디버깅하는 과정의 스크린샷을 찍어서 보내주세요!

import torch
import torch.nn as nn
from torch.optim import Adam
from torchvision.datasets import MNIST
from torch.utils.data import DataLoader
from torchvision.transforms import ToTensor

lr = 0.001
image_size = 28
num_classes = 10
batch_size = 100
hidden_size = 500
total_epochs = 3

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')  # cuda & cpu 자리 수정

class MLP(nn.Module):
    def __init__(self, image_size, hidden_size, num_classes) :
        self.image_size = image_size
        super().__init__()
        self.mlp1 = nn.Linear(in_features=image_size*image_size, out_features=hidden_size) # mlp1 모듈을 제대로 불러오지 못함 nn 모듈을 사용하기 위해 super().__init__()으로 모듈을 깨워야함
        self.mlp2 = nn.Linear(in_features=hidden_size, out_features=hidden_size)
        self.mlp3 = nn.Linear(in_features=hidden_size, out_features=hidden_size)
        self.mlp4 = nn.Linear(in_features=hidden_size, out_features=num_classes)

    def forward(self, x) :
        batch_size = x.shape[0]
        x = torch.reshape(x, ( -1, self.image_size * self.image_size))
        x = self.mlp1(x)
        x = self.mlp2(x)
        x = self.mlp3(x)
        x = self.mlp4(x)  # mat1 and mat2 shapes cannot be multiplied (100x10 and 500x10)  // 500이 입력으로 들어오는데 10이 출력으로 받는 모델로 사이즈가 안맞음 // 전 layer의 out_feature 사이즈 수정
        return x

myMLP = MLP(image_size, hidden_size, num_classes)

train_mnist = MNIST(root='../../data/mnist', train=True, transform=ToTensor(), download=True)
test_mnist = MNIST(root='../../data/mnist', train=False, transform=ToTensor(), download=True)

train_loader = DataLoader(dataset=train_mnist, batch_size=batch_size, shuffle=True)   #batch_size should be a positive integer value, but got batch_size=batch_size // batch_size가 integer가 아닌 string으로 되어 있어서 inter 값인 hyperparameter값을 가져오게 수정
test_loader = DataLoader(dataset=test_mnist, batch_size=batch_size, shuffle=True)

loss_fn = nn.CrossEntropyLoss() # 클래스 객체화

optim = Adam(params=myMLP.parameters(), lr=lr) #'<=' not supported between instances of 'float' and 'str' //float 를 지원하지 않기 때문에 lr를 int형으로 변환
                                            # 'method' object is not iterable // params 값을 제대로 불러오지 못함 클래서 형식으로 변경

for epoch in range(total_epochs):
    for idx, (image, label) in enumerate(train_loader) :
        image = image.to(device)  # Torch not compiled with CUDA enabled // cuda 지원을 안하기 때문에 cpu가 진행 되도록 수정
        label = label.to(device)

        output = myMLP(image)

        loss = loss_fn(output, label)  #Boolean value of Tensor with more than one value is ambiguous // nn.crossEntropyLoss 클래스화
                                        #Expected target size [100, 10], got [100] // output 차원이 맞지 않음

        loss.backward()
        optim.step() # 'Tensor' object has no attribute 'step' // step() 사용하기 위해 loss가 아닌 optim에서 불러옴

        optim.zero_grad()

        if idx // 100 == 0 :
            print(loss)


from flask.ext.assets import Bundle, Environment
from .. import app

bundles = {

    'js_all': Bundle(
        'js/lib/jquery-1.11.2.js',
        Bundle(
            'js/app.coffee',
            filters='coffeescript'),
        output='gen/app.js',
        filters='rjsmin'),

    'css_all': Bundle(
        'css/lib/normalize.css',
        Bundle(
            'css/main.scss',
            filters='pyscss'),
        output='gen/min.css',
        filters='cssmin')
}

assets = Environment(app)

assets.register(bundles)


from bs4 import BeautifulSoup
from lxml import etree
import requests

headers = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36'
}

url_main = 'https://minzdrav.gov.ru'
url_standart = 'ministry/61/22/stranitsa-979/stranitsa-983/1-standarty-pervichnoy-mediko-sanitarnoy-pomoschi'

page = requests.get(f'{url_main}/{url_standart}', headers=headers)
soup = BeautifulSoup(page.text, "html.parser")
dom = etree.HTML(str(soup))

xpath_urls = dom.xpath('//*[@id="mz-container"]/div[1]/div/article/div[1]/div/a')

category_pages = []
for url in xpath_urls:
    category_pages.append(
        {
            'name': url.text,
            'url': url.get('href'),
            'order': [],
        }
    )

for page_info in category_pages:
    page = requests.get(f'{url_main}/{page_info["url"]}', headers=headers)
    soup = BeautifulSoup(page.text, "html.parser")
    extra_words = 'prikaz-ministerstva-zdravoohraneniya-rossiyskoy-federatsii'

    url_order = [url.get('href') for url in soup.findAll('a') if extra_words in str(url.get('href'))]

    for url in url_order:
        page_order = requests.get(f'{url}', headers=headers)
        soup_order = BeautifulSoup(page_order.text, "html.parser")
        loader_info = soup_order.find('div', class_='document_title').find('a')

        if loader_info:
            filename = loader_info.get('download')
            load_url = loader_info.get('href')
            filedata = requests.get(f'https:{load_url}', headers=headers)
            with open(f'loaded/{filename}', 'wb') as f:
                f.write(filedata.content)


import configparser
import copy
import errno
import inspect
import json
import os
import shutil
import subprocess
import tempfile

from rally.utils import encodeutils

class RallyCliError(Exception):

    def __init__(self, cmd, code, output):
        self.command = cmd
        self.code = code
        self.output = encodeutils.safe_decode(output)
        self.msg = "Command: %s Code: %d Output: %s\n" % (self.command,
                                                          self.code,
                                                          self.output)

    def __str__(self):
        return self.msg

class JsonTempFile(object):

    def __init__(self, config):
        config_file = tempfile.NamedTemporaryFile(delete=False)
        config_file.write(encodeutils.safe_encode(json.dumps(config)))
        config_file.close()
        self.filename = config_file.name

    def __del__(self):
        os.unlink(self.filename)

class TaskConfig(JsonTempFile):
    pass

class Rally(object):
    """Create and represent separate rally installation.

    Usage:

        rally = Rally()
        rally("deployment", "create", "--name", "Some Deployment Name")
        output = rally("deployment list")

    """
    _DEPLOYMENT_CREATE_ARGS = ""

    def __init__(self, force_new_db=False, plugin_path=None):

        # NOTE(sskripnick): we should change home dir to avoid races
        # and do not touch any user files in ~/.rally
        self.tmp_dir = tempfile.mkdtemp()
        self.env = copy.deepcopy(os.environ)
        self.env["HOME"] = self.tmp_dir
        self.config_filename = None
        self.method_name = None
        self.class_name = None

        caller_frame = inspect.currentframe().f_back
        if caller_frame.f_code.co_name == "__call__":
            caller_frame = caller_frame.f_back

        self.method_name = caller_frame.f_code.co_name
        if self.method_name == "setUp":
            raise Exception("No rally instance should be generated in "
                            "setUp method")

        test_object = caller_frame.f_locals["self"]
        self.class_name = test_object.__class__.__name__

        if force_new_db or ("RCI_KEEP_DB" not in os.environ):
            config_filename = os.path.join(self.tmp_dir, "conf")
            config = configparser.RawConfigParser()
            config.add_section("database")
            config.set("database", "connection",
                       "sqlite:///%s/db" % self.tmp_dir)
            with open(config_filename, "w") as conf:
                config.write(conf)
            self.args = ["rally", "--config-file", config_filename]
            subprocess.call(["rally", "--config-file", config_filename,
                             "db", "recreate"], env=self.env)
            self.config_filename = config_filename
        else:
            self.args = ["rally"]
            subprocess.call(["rally", "db", "recreate"], env=self.env)

        if plugin_path:
            self.args.extend(["--plugin-paths", os.path.abspath(plugin_path)])
        self.reports_root = os.environ.get("REPORTS_ROOT",
                                           "rally-cli-output-files")
        self._created_files = []
        self("deployment create --name MAIN%s" % self._DEPLOYMENT_CREATE_ARGS,
             write_report=False)

    def __del__(self):
        shutil.rmtree(self.tmp_dir)

    def _safe_make_dirs(self, dirs):
        try:
            os.makedirs(dirs)
        except OSError as exc:
            if exc.errno == errno.EEXIST and os.path.isdir(dirs):
                pass
            else:
                raise

    def gen_report_path(self, suffix=None, extension=None, keep_old=False):
        """Report file path/name modifier

        :param suffix: suffix that will be appended to filename.
            It will be appended before extension
        :param extension: file extension.
        :param keep_old: if True, previous reports will not be deleted,
            but rename to 'nameSuffix.old*.extension'

        :return: complete report name to write report
        """

        self._safe_make_dirs("%s/%s" % (self.reports_root, self.class_name))

        suff = suffix or ""
        ext = extension or "txt"
        path = "%s/%s/%s%s.%s" % (self.reports_root, self.class_name,
                                  self.method_name, suff, ext)

        if path not in self._created_files:
            if os.path.exists(path):
                if not keep_old:
                    os.remove(path)
                else:
                    path_list = path.split(".")
                    old_suff = "old"
                    path_list.insert(-1, old_suff)
                    new_path = ".".join(path_list)
                    count = 0
                    while os.path.exists(new_path):
                        count += 1
                        path_list[-2] = "old%d" % count
                        new_path = ".".join(path_list)
                    os.rename(path, new_path)

            self._created_files.append(path)
        return path

    def __call__(self, cmd, getjson=False, report_path=None, raw=False,
                 suffix=None, extension=None, keep_old=False,
                 write_report=True, no_logs=False):
        """Call rally in the shell

        :param cmd: rally command
        :param getjson: in cases, when rally prints JSON, you can catch output
            deserialized
        :param report_path: if present, rally command and its output will be
            written to file with passed file name
        :param raw: don't write command itself to report file. Only output
            will be written
        """

        if not isinstance(cmd, list):
            cmd = cmd.split(" ")
        try:
            if no_logs or getjson:
                cmd = self.args + ["--log-file", "/dev/null"] + cmd
                with open(os.devnull, "w") as DEVNULL:
                    output = encodeutils.safe_decode(subprocess.check_output(
                        cmd, stderr=DEVNULL, env=self.env))
            else:
                cmd = self.args + cmd
                output = encodeutils.safe_decode(subprocess.check_output(
                    cmd, stderr=subprocess.STDOUT, env=self.env))

            if getjson:
                return json.loads(output)

            return output

        except subprocess.CalledProcessError as e:
            output = encodeutils.safe_decode(e.output)
            raise RallyCliError(cmd, e.returncode, output) from None
        finally:
            if write_report:
                if not report_path:
                    report_path = self.gen_report_path(
                        suffix=suffix, extension=extension, keep_old=keep_old)
                with open(report_path, "a") as rep:
                    if not raw:
                        rep.write("\n%s:\n" % " ".join(cmd))
                    rep.write("%s\n" % output)

def get_global(global_key, env):
    home_dir = env.get("HOME")
    with open("%s/.rally/globals" % home_dir) as f:
        for line in f.readlines():
            if line.startswith("%s=" % global_key):
                key, value = line.split("=")
                return value.rstrip()
    return ""


import argparse
import os
import os.path as osp
import shutil
from functools import partial
from glob import glob

import mmcv
import numpy as np
from PIL import Image

full_clsID_to_trID = {
    0: 255,
    1: 0,
    2: 1,
    3: 2,
    4: 3,
    5: 4,
    6: 5,
    7: 6,
    8: 7,
    9: 8,
    10: 9,
    11: 10,
    12: 11,
    13: 12,
    14: 13,
    15: 14,
    16: 15,
    17: 16,
    18: 17,
    19: 18,
    20: 19,
    255: 255,
}

def convert_to_trainID(
    maskpath, out_mask_dir, is_train, clsID_to_trID=full_clsID_to_trID, suffix=""
):
    mask = np.array(Image.open(maskpath))
    mask_copy = np.ones_like(mask, dtype=np.uint8) * 255
    for clsID, trID in clsID_to_trID.items():
        mask_copy[mask == clsID] = trID
    seg_filename = (
        osp.join(out_mask_dir, "train" + suffix, osp.basename(maskpath))
        if is_train
        else osp.join(out_mask_dir, "val" + suffix, osp.basename(maskpath))
    )
    if len(np.unique(mask_copy)) == 1 and np.unique(mask_copy)[0] == 255:
        return
    Image.fromarray(mask_copy).save(seg_filename, "PNG")

def parse_args():
    parser = argparse.ArgumentParser(
        description="Convert VOC2021 annotations to mmsegmentation format"
    )  # noqa
    parser.add_argument("--voc_path", default='datasets/VOCdevkit/VOC2012', help="pas20 path")
    parser.add_argument("--nproc", default=16, type=int, help="number of process")
    args = parser.parse_args()
    return args

def main():
    args = parse_args()
    voc_path = args.voc_path
    nproc = args.nproc
    print(full_clsID_to_trID)
    out_mask_dir = osp.join(voc_path, "annotations_ovs")
    for dir_name in [
        "val",
    ]:
        os.makedirs(osp.join(out_mask_dir, dir_name), exist_ok=True)

    test_list = [
        osp.join(voc_path, "SegmentationClassAug", f + ".png")
        for f in np.loadtxt(osp.join(voc_path, "val.txt"), dtype=np.str).tolist()
    ]

    if args.nproc > 1:
        mmcv.track_parallel_progress(
            partial(convert_to_trainID, out_mask_dir=out_mask_dir, is_train=False),
            test_list,
            nproc=nproc,
        )
    else:
        mmcv.track_progress(
            partial(convert_to_trainID, out_mask_dir=out_mask_dir, is_train=False),
            test_list,
        )
    print("Done!")

if __name__ == "__main__":
    main()


import numpy as np
from scipy.optimize import fsolve
import matplotlib.pyplot as plt

# In[2]:

##bisection method n roots and single roots

#single root
def bisec(g1,g2,tol,f):
    guess_1=g1
    guess_2=g2
    count =1
    while (np.abs(guess_1-guess_2)>=tol):
          x= (guess_1+guess_2)/2.0
          product =f(guess_1)*f(x)
          if product > tol:
             guess_1= x
             count +=1
          else:
               if product < tol:
                 guess_2= x
                 count +=1

    return print("The root is", x, "\n found at",count,"bisections")

# n root
def bisec_n(f,g1,g2,tol):
    guess_1=g1
    guess_2=g2
    count =1
    while (np.abs(guess_1-guess_2)>=tol):
          x= (guess_1+guess_2)/2.0
          product =f(guess_1)*f(x)
          if product > tol:
             guess_1= x
             count +=1
          else:
               if product < tol:
                 guess_2= x
                 count +=1
    x= np.linspace(-20,20,10)
    plt.plot(x,f(x))
    plt.grid()
    plt.show()

    return print("The root are", fsolve(f,[g1,g2]),"\n","found at bisections:", count)

## regula falsi method single root and n roots

#single root
def false_pos(f,i1,i2,tol= 1e-6,max_pos=100):
    x_i= 0
    f_pos= 0
    if f(i1) * f(i2) < 0:
       for f_pos in range(max_pos+1):
            x_i= i2 -(i2-i1) / (f(i2)-f(i1)) * f(i2)
            if abs(f(x_i)) < tol: break
            elif f(i1) * f(x_i) < 0:
                 i2=x_i
            else:
                 i1=x_i
    else:
          print("no roots exist within the interval")

    return print("the root is ",x_i,"\n at epoach:", f_pos)

###place n root for regula falsi

##secant method single and n roots

#single root
def sec_meth (f,g1,g2,tol=1e-6,ep_max=100):
    for i in range(ep_max):
            x_i= g2 -(g2-g1) / (f(g2)-f(g1)) * f(g2)
            if abs(f(x_i)) < tol: break
            elif f(g1) * f(x_i) < 0:
                 g1=g2
                 g2=x_i

    return print("the root is ",x_i,"\n at epoach:", i)

### place secant method for n roots

##Simple Iteration Methodd n roots single roots

#single root

def simp_iter(f,h,epochs = 50):
   #epochs = 50
   x_roots = []
   for epoch in range(epochs):
        x_guess = f(h)
        print(x_guess)
        if x_guess == 0:
            x_roots.append(h)
            break
        else:
              h+=1
   return print(f"The root is: {x_roots}, found at epoch {epoch}")

#n root
def simp_iter_n(f,h,epochs = 10):
  n_roots = 3
  x_roots = []
  end_epoch = 0

  for epoch in range(epochs):
    print(f(h))
    if np.allclose(0,f(h)):
      x_roots.append(h)
      end_epoch = epoch
      if len(x_roots)==n_roots:
        break
    h+=1

  return print(f"The root is: {x_roots}, found at epoch {end_epoch+1}")

##newton rhapson method

#single root
def newt(f,x,x_p,epochs = 100):
    f_prime= x_p
    root = None
    for epoch in range(epochs):
      x_prime = x - (f(x)/f_prime(x))
      if np.allclose(x, x_prime):
        root = x
        break
      x = x_prime
    return print("the root is ",root,"at epoch", epoch)

# n roots
def newt_n(f,range_guess,f_p,epoch=100):
   f_prime= f_p
   x_inits = range_guess
   roots = []
   for x_init in x_inits:
       x = x_init
       for epochs in range(epoch):
           x_prime = x - (f(x)/f_prime(x))
           if np.allclose(x, x_prime):
              roots.append(x)
              break
           x = x_prime
           np_roots = np.round(roots,3)

   return (print("roots are ",np_roots,"found at",epochs))


#!/usr/bin/env python3
# -*- coding: UTF8 -*-

# Author: Guillaume Bouvier -- guillaume.bouvier@pasteur.fr
# https://research.pasteur.fr/en/member/guillaume-bouvier/
# 2017-02-07 10:03:29 (UTC+0100)

import numpy
import scipy.spatial.distance
import scipy.spatial
from subprocess import Popen
from subprocess import PIPE
from tempfile import NamedTemporaryFile
from EMEC import progress_reporting
from EMEC import EMDensity
from EMEC import Graph
from EMEC import em_fit
import scipy.cluster.hierarchy
import operator
import copy

class Alignment(object):
    """
    Alignment object that contain alignment informations
    """
    def __init__(self, alignment, score, n_align, fasta_file=None, npos=None):
        """
        • alignment: Dictionnary of the alignment:
        {resid_input: resid_target, ...}
        • score: score of the alignment
        • n_align: number of residues aligned
        • fasta_file: fasta file with the sequence (optional)
        • npos: The total number of AA (position) in the sequence
        • outfilename: name of the fasta file containing the final alignment
        """
        self.alignment = alignment
        self.score = score
        self.n_align = n_align
        self.npos = npos
        if fasta_file is not None:
            self.sequence = read_sequence(fasta_file)
            self.get_seq()
        else:
            self.sequence = None

    def get_seq(self):
        """
        Get the aligned sequence.
        """
        seq = []  # Sequence aligned
        for i in range(self.npos):  # Iterate over the C alpha position
            if i in self.alignment:
                # The bead is aligned with the contact map
                seq.append(self.sequence[self.alignment[i]])
            else:
                # The bead is not aligned: no sidechain, put a glycine
                seq.append('G')
        self.sequence = seq

class Adjmat(object):
    """
    Class to store the adjacency matrix for peptide object
    """
    def __init__(self):
        self.peptides = {}

    def append(self, peptide):
        """
        Append peptide object to the adjmat
        """
        self.peptides[peptide.key] = peptide

    @property
    def scores(self):
        """
        Get the list of alignment scores for peptides
        """
        return {p.key: p.score for p in self.peptides.values()}

    @property
    def keys(self):
        """
        Return the peptide keys contained in adjmat object
        """
        return self.peptides.keys()

    def get(self, key):
        """
        Return the peptide object contained in adjmat with the corresponding key
        """
        return self.peptides[key]

    def max_score(self, exclusion_set=[]):
        """
        Get the peptide with the maximal alignment score
        • exclusion_set: peptide ids to exclude from the max_score search
        """
        sorted_peptides = sorted(self.scores.items(), key=operator.itemgetter(1), reverse=True)
        keys = [p[0] for p in sorted_peptides\
                    if p[0] not in exclusion_set]
        return self.peptides[keys[0]]

def get_cmap(coords, threshold=8.):
    """
    compute the contact map from the coordinates (coords)
    • coords: numpy array (n*3)
    • threshold: distance threshold to define a contact
    """
    cmap = scipy.spatial.distance.pdist(coords)
    cmap = scipy.spatial.distance.squareform(cmap)
    cmap = numpy.int_(cmap <= threshold)
    return cmap

def write_cmap(cmap, outfilename=None):
    """
    Write contact map to ascci file that complies with map_align cpp binary
    """
    indices = numpy.asarray(numpy.where(numpy.triu(cmap))).T
    n = cmap.shape[0]
    if outfilename is None:
        # Create a temporary file
        outfile = NamedTemporaryFile('w', delete=True)
    else:
        outfile = open(outfilename, 'w')
    outfile.write('LEN %d\n' % n)
    for e in indices:
        outfile.write('CON %d %d 1.0\n' % tuple(e))
    outfile.flush()
    return outfile

def read_gremlin(gremlin_file):
    """
    Read the gremlin formatted output file
    """
    gremlin = numpy.int_(numpy.genfromtxt(gremlin_file, skip_header=1)[:, :2])
    naa = gremlin.max()
    gmap = numpy.zeros((naa, naa))
    for i, j in gremlin:
        gmap[i - 1, j - 1] = 1
        gmap[j - 1, i - 1] = 1
    return gmap

def is_cmap(matrix):
    """
    Check if the given matrix is a contact map
    """
    n, p = matrix.shape
    return numpy.logical_and(n == p, (set(numpy.unique(matrix)) == set([0, 1])))

def map_align(inputdata, cmap_target, fasta_file=None, threshold=8., gap_o=-3., gap_e=0., n_iter=20, outfilename=None):
    """
    Compute the contact map (with the given threshold) from the coordinates
    (inputdata) and align it to the given contact map (cmap_target).
    • inputdata: coordinates or contact map
    • fasta_file: Fasta file containining the sequence
    • gap_o: gap opening penalty
    • gap_e: gap extension penalty
    • n_iter: number of iterations for map_align program
    • outfilename: Name of the output Fasta file name containing the final
                   alignment.
    """
    if is_cmap(inputdata):
        # inputdata is already a contact map
        cmap_input = write_cmap(inputdata)
    else:
        # inputdata are coordinates of CA trace.
        # Compute the corresponding contact map
        cmap_input = write_cmap(get_cmap(inputdata, threshold=threshold))
    cmap_target = write_cmap(cmap_target)
    sbp = Popen([
        'map_align', '-gap_o',
        '%.2f' % gap_o, '-gap_e',
        '%.2f' % gap_e, '-a', cmap_input.name, '-b', cmap_target.name, '-silent', '-iter',
        '%d' % n_iter
    ],
                stdout=PIPE,
                stderr=PIPE)
    stdoutdata, stderrdata = sbp.communicate()
    cmap_input.close()
    cmap_target.close()
    out_splitted = stdoutdata.split()
    if len(out_splitted) > 0:  # the alignment works
        score = float(out_splitted[6])  # alignment score
        n_align = int(out_splitted[7])  # number of residues aligned
        # Correct the alignment score by removing the number of residues not aligned
        score -= inputdata.shape[0] - n_align
        # Dictionnary of the alignment:
        # {resid_input: resid_target, ...}
        alignment = dict([numpy.int_(str(e.decode()).split(':')) for e in out_splitted[8:]])
        return Alignment(alignment, score, n_align, fasta_file=fasta_file, npos=inputdata.shape[0])
    else:
        return None

def read_sequence(fasta_file):
    """
    Read a sequence from a fasta file
    """
    data = numpy.genfromtxt(fasta_file, skip_header=1, dtype=str)
    if numpy.size(data.shape) > 0:  # multiple lines
        seq = ''.join(data)
    else:
        seq = str(data)
    return seq

class Peptide(object):
    """
    Return the CA trace coordinates of the peptide in one direction or the other
    based on the map align score
    """
    def __init__(self, coords, aln, key):
        """
        • coords: coordinates of the peptide
        • aln: alignment object
        • key: identifier for the peptide (i, order), with:
            • i: the index of the peptide
            • order: 1 or -1 for normal or reverse order
        • self.nca: number of ca
        • self.score: score of the given aln
        """
        self.coords = coords
        self.aln = aln
        self.key = key
        self.nca = self.coords.shape[0]
        self.neighbors_r, self.neighbors_l = None, None
        self.components = None

    @property
    def score(self):
        """
        Link to the alignment score
        """
        if self.aln is not None:
            score = self.aln.score
        else:
            score = -numpy.inf
        return score

    @property
    def n_comp(self):
        """
        Return the number of components of the peptide
        """
        if self.components is None:
            return 1
        else:
            return len(self.components)

    @property
    def n_gap(self):
        """
        Number of gap in the alignment
        """
        return (numpy.diff(self.aln.alignment.values()) - 1).sum()

    @property
    def max_gap_size(self):
        """
        Size of the biggest gap
        """
        return (numpy.diff(self.aln.alignment.values()) - 1).max()

    @property
    def gap_penalty(self):
        """
        self.n_gap / self.nca
        """
        return self.n_gap / float(self.nca)

class MapAlign(object):
    """
    Align contact maps based on
    https://github.com/sokrypton/map_align
    """
    def __init__(self,
                 catraces,
                 emd,
                 level,
                 gremlin_file,
                 fasta_file,
                 threshold=8.,
                 neighbor_threshold=11.,
                 n_iter=1.,
                 gap_o=-3.,
                 gap_e=-0.1):
        """
        • catraces: list of coordinates for the C-alpha traces
        list of array of coordinates
        • emd: electron microscopy density file name
        • level: threshold to apply on the electron microscopy density
        • threshold: distance threshold to define a contact
        • gremlin_file: name of the gremlin result file with predicted contacts
          gremlin_file could also be a contact map as a numpy array
        • fasta_file: Fasta file containining the sequence
        • neighbor_threshold: maximal distance to define neighbors of a peptide.
          The neighbors are defined as the peptides whose N-Ter are distant to
          less than neighbor_threshold from the C-Ter of the considered peptide.
        • n_iter: number of iterations for the map_align algorithm
        • gap_o: gap opening penalty for the map_align algorithm
        • gap_e: gap extension penalty for the map_align algorithm
        """
        self.threshold = threshold
        self.neighbor_threshold = neighbor_threshold
        self.n_iter = n_iter
        self.gap_o = gap_o
        self.gap_e = gap_e
        catraces = numpy.asarray(catraces)
        if type(gremlin_file) is numpy.ndarray:
            # gremlin_file is already a contact map
            self.gmap = gremlin_file
        else:
            self.gmap = read_gremlin(gremlin_file)  # gremlin predicted contact map
        self.n_peptide = catraces.shape[0]
        self.peptides = numpy.asarray([Peptide(catrace, None, (i, 1)) for i, catrace in enumerate(catraces)])
        # Compute peptide alignment individually in both order
        self.get_peptide_alignment()
        self.anchors = self.get_anchors()
        self.emd = emd
        self.level = level
        self.coords_best = None  # Coordinates after optimization
        self.aln = None  # Alignment object after optimization
        self.fasta_file = fasta_file
        self.adjmat = Adjmat()  # Adjacency matrix for peptide objects
        # Compute a KDTree on all the coordinates for neighbor search
        pool = self.peptides.values()
        data = numpy.asarray([p.coords[0] for p in pool])
        self.keys = numpy.asarray([p.key for p in pool])
        self.kdtree = scipy.spatial.cKDTree(data)

    def get_anchors(self):
        """
        Define the anchoring peptides as the peptide with the best scores
        The anchors are sorted from the best score to the worst one.
        """
        anchors = []
        for pept_id in range(self.n_peptide):
            pept = []
            for order in [1, -1]:
                pept.append(self.peptides[(pept_id, order)])
            scores = [p.score for p in pept]
            if sum(scores) > 0.:
                anchor = pept[numpy.argmax(scores)]
                anchors.append(anchor)
        # sort anchors:
        scores = [p.score for p in anchors]
        sorter = numpy.argsort(scores)[::-1]
        anchors = numpy.asarray(anchors)[sorter]
        return anchors

    @property
    def anchor_overlaps(self):
        """
        Return the overlap score between the anchors (pairwise matrix).
        The overlap is normalized (1: total overlap, 0: no overlap)
        Two peptides overlap if they aligned in the same region.
        """
        overlap = []
        for i, a1 in enumerate(self.anchors):
            region1 = set(a1.aln.alignment.values())
            for a2 in self.anchors[i + 1:]:
                region2 = set(a2.aln.alignment.values())
                minlen = float(min([len(region1), len(region2)]))
                overlap.append(len(region1 & region2) / minlen)
        return scipy.spatial.distance.squareform(overlap)

    @property
    def coords(self):
        """
        Return the coordinates of all the peptides concatenated
        """
        if self.coords_best is None:  # Before optimization
            return numpy.concatenate([self.peptides[tuple(key)].coords\
                                      for key in self.keys])
        else:
            return self.coords_best

    def get_pdist(self):
        """
        Pairwise distance matrix between peptides.
        The element i, j of this matrix is defined as the minimal distance of
        the pairwise atomic distance between peptide i and j
        """
        pdist = []
        for i in range(self.n_peptide):
            for j in range(i + 1, self.n_peptide):
                pept1, pept2 = self.peptides[(i, 1)], self.peptides[(j, 1)]
                pdist.append(scipy.spatial.distance.cdist(pept1.coords, pept2.coords).min())
        return scipy.spatial.distance.squareform(pdist)

    def get_neighbors(self, peptide):
        """
        Compute the given peptide
        • self.neighbor_threshold: maximal distance to define neighbors of a
          peptide.
          The neighbors are defined as the peptides whose N-Ter are distant to
          less than neighbor_threshold from the C-Ter of the considered peptide.
        """
        if type(peptide.key[0]) is int:
            keys = [
                peptide.key[0],
            ]
        else:
            keys = peptide.key[0]
        # Right neighbors:
        neighbors = self.keys[self.kdtree.query_ball_point(peptide.coords[-1],\
                                                       self.neighbor_threshold)]
        neighbors = [tuple(e) for e in neighbors if e[0] not in keys]
        peptide.neighbors_r = [self.peptides[i] for i in neighbors]
        # Left neighbors:
        neighbors = self.keys[self.kdtree.query_ball_point(peptide.coords[0],\
                                                       self.neighbor_threshold)]
        neighbors = [(k, -o) for (k, o) in neighbors if k not in keys]
        peptide.neighbors_l = [self.peptides[i] for i in neighbors]
        return peptide

    def merge(self, *peptides):
        """
        Merge peptides together and compute the corresponding alignment
        """
        coords = numpy.concatenate([e.coords for e in peptides])
        keys = tuple([e.key[0] for e in peptides])
        keys = tuple(numpy.r_[keys])
        orders = tuple([e.key[1] for e in peptides])
        orders = tuple(numpy.r_[orders])
        concat_key = (keys, orders)
        if concat_key not in self.adjmat.keys:
            aln = map_align(coords, self.gmap, n_iter=1, gap_o=self.gap_o, gap_e=self.gap_e)
            peptide = Peptide(coords, aln, concat_key)
            self._get_components(peptide)
            self._get_coverage(peptide)
            self.adjmat.append(peptide)
            return peptide
        else:
            return self.adjmat.get(concat_key)

    def delete(self, peptide, index):
        """
        Delete the peptide with the given index from the peptide
        """
        if index < 0:
            index = len(peptide.components) + index
        peptides = [p for i, p in enumerate(peptide.components) if i != index]
        return self.merge(*peptides)

    def flip(self, peptide, index):
        """
        Flip the peptide (change the order) with the given index in the peptide
        """
        if index < 0:
            index = len(peptide.components) + index
        keys = [p.key for p in peptide.components]
        peptides = [self.peptides[(k,o)]\
                    if i != index else self.peptides[(k,-o)]\
                    for i, (k,o) in enumerate(keys)]
        return self.merge(*peptides)

    def replace(self, peptide, index, newpeptide):
        """
        Replace the component given by index in the peptide by newpeptide
        """
        if index < 0:
            index = len(peptide.components) + index
        peptides = [p if i != index else newpeptide\
                    for i, p in enumerate(peptide.components)]
        return self.merge(*peptides)

    def swap(self, peptide, index1, index2):
        """
        Swap the components index1 and index2 in peptide
        """
        peptides = [p for p in peptide.components]
        peptides[index1], peptides[index2] = peptides[index2], peptides[index1]
        return self.merge(*peptides)

    def _get_components(self, peptide):
        """
        Split the multi peptide to individual compoenents
        """
        start = 0
        components = []
        if peptide.aln is not None:
            for key in zip(*peptide.key):
                pept_ = copy.deepcopy(self.peptides[key])
                nca = pept_.nca
                alignment = {k - start: v for (k, v) in peptide.aln.alignment.items() if k in range(start, start + nca)}
                pept_.aln = copy.deepcopy(peptide.aln)
                pept_.aln.alignment = alignment
                components.append(copy.deepcopy(pept_))
                start += nca
            peptide.components = components

    def _get_coverage(self, peptide):
        """
        Compute the alignment coverage
        """
        if peptide.aln is not None:
            coverage = peptide.aln.n_align / float(self.gmap.shape[0])
        else:
            coverage = 0
        peptide.coverage = coverage

    def split(self, peptide, threshold=None):
        """
        Split the peptide in multiple peptides at positions where there is a gap
        greater than threshold.
        • If threshold is None, the threshold is set as the length of the
        smallest peptide.
        """
        if threshold is None:
            threshold = min([p.nca for p in self.peptides.values()])
        if peptide.max_gap_size > threshold and peptide.n_comp > 2:
            # Intra peptide gaps
            intragaps = [p.max_gap_size for p in peptide.components]
            limits = numpy.asarray([numpy.asarray(p.aln.alignment.values())[[0,-1]]\
                                    for p in peptide.components])
            intergaps = []
            for i in range(limits.shape[0] - 1):
                intergaps.append(limits[i + 1][0] - limits[i][-1])
            # Assign the maximum of intragaps and intergaps to the components
            mergegaps = numpy.asarray([max(intragaps[i], intergaps[i])\
                                       for i in range(len(intergaps))])
            pointers = numpy.where(mergegaps > threshold)[0]
            pept_split = [[]]
            for i, pept_ in enumerate(peptide.components):
                pept_split[-1].append(self.peptides[pept_.key])
                if i in pointers:
                    pept_split.append([])
            # rebuild the corresponding peptides:
            out_peptides = []
            for pept_ in pept_split:
                out_peptides.append(self.merge(*pept_))
            print("Splitting peptide: %s to %s" % (peptide.key, [p.key for p in out_peptides]))
            return out_peptides
        else:
            return [peptide]

    def get_peptide_alignment(self):
        """
        Get the alignment alignment object for each peptide individually.
        """
        peptides = {}  # Dictionnary containing all peptides in both order
        for i, pept in enumerate(self.peptides):
            # Try the two order for the coordinates
            for order in [1, -1]:
                coords = pept.coords[::order]
                aln = map_align(coords, self.gmap, n_iter=1, gap_o=-1., gap_e=-1)
                peptides[(i, order)] = Peptide(coords, aln, (i, order))
                self._get_coverage(peptides[(i, order)])
        self.peptides = peptides

    def align_fragments(self, max_iter=numpy.inf):
        """
        Compute the best alignment of the fragments to self.gmap
        • max_iter: Maximum number of iterations
        """
        # Compute the alignment scores for pairwise merging
        n_pept = len(self.peptides)
        for i, pept1 in enumerate(self.peptides.values()):
            print("Pairwise merging: %d/%d" % (i + 1, n_pept))
            self.get_neighbors(pept1)
            for pept2 in pept1.neighbors_r:
                self.merge(pept1, pept2)
            for pept2 in pept1.neighbors_l:
                self.merge(pept2, pept1)
        # Subsequent merging operations
        exclusion_set = []
        max_score = -numpy.inf
        #for _ in range(n_iter):
        n_iter = 0
        while len(exclusion_set) < len(self.adjmat.scores):
            pept1 = self.adjmat.max_score(exclusion_set=exclusion_set)
            exclusion_set.append(pept1.key)
            if pept1.score > max_score:
                max_score = pept1.score
            self.get_neighbors(pept1)
            for pept2 in pept1.neighbors_r:
                self.merge(pept1, pept2)
            for pept2 in pept1.neighbors_l:
                self.merge(pept2, pept1)
            print("%d/ %d: %s: score/score_max: %.2f/%.2f coverage: %.2f"\
                      %(len(exclusion_set), len(self.adjmat.scores),
                        str(pept1.key), pept1.score, max_score, pept1.coverage))
            n_iter += 1
            if n_iter >= max_iter:
                print("Maximum number of iterations (%d) reached" % max_iter)
                break
        self.coords_best = self.adjmat.max_score().coords
        self.aln = map_align(self.coords_best, self.gmap, fasta_file=self.fasta_file)

    def optimize_ca(self, outfilename=None):
        """
        Add missing CA on the CA trace after alignment.
        Optimize the position of the CA using the EM density.
        • outfilename: Filename for the output fasta file name containing the
                       alignment.
        """
        i = 0  # pointer for sequence 2
        pos1 = 0
        insertions = []  # list of beads to insert
        deletions = []  # list of beads to remove
        npoints = []  # The number of points to insert each time
        pointer1 = 0  # pointer for seq 1
        pointer2 = 0  # pointer for seq 2
        for pos1 in self.aln.alignment:
            pos2 = self.aln.alignment[pos1]
            while pos1 > pointer1:
                print("Deleting bead %d" % pointer1)
                deletions.append(pointer1)
                pointer1 += 1
            n_ca = 0  # Number of CA to add
            start = pos1 - 1  # where to add ca
            while pos2 > pointer2:
                pointer2 += 1
                n_ca += 1
            end = pos1  # where to add ca
            if n_ca > 0:
                print("Adding %d beads between %d and %d" % (n_ca, start, end))
                if start == -1:
                    # Instead of inserting before the first CA insert between
                    # the first one and the second one
                    start += 1
                    end += 1
                insertions.append(start)
                npoints.append(n_ca)
            pointer1 += 1
            pointer2 += 1
        self.coords_best = self.reshufle(insertions, npoints, deletions)
        # Refine the position of the added CA:
        graph = self.get_topology()
        fit = em_fit.Fit(self.emd,
                         self.level,
                         graph,
                         self.coords_best,
                         20000,
                         alpha_0=.1,
                         alpha_1=0.0,
                         radius_0=1.,
                         radius_1=0.,
                         refine=True)
        fit.learn()
        self.coords_best = fit.coords
        self.aln = map_align(self.coords_best, self.gmap, fasta_file=self.fasta_file, outfilename=outfilename)

    def get_topology(self):
        """
        Build the topology (adjacency matrix) for the current CA trace
        (self.coords)
        Return a graph object
        """
        n_ca = self.coords.shape[0]
        adjmat = numpy.ones((n_ca, n_ca)) * numpy.inf
        for i, j in zip(range(n_ca), range(1, n_ca)):
            adjmat[i, j] = 1.
            adjmat[j, i] = 1.
        graph = Graph.Graph(adjmat)
        graph.minimum_spanning_tree = adjmat
        return graph

    def reshufle(self, insertions, npoints, deletions):
        """
        insert linear interpolated points in self.coords
        • insertions: position of the insertions. The data are inserted before
        the positions given
        • npoints: the number of points to insert each time
        • deletions: list of beads to delete
        """
        offset = 0
        coords = numpy.copy(self.coords)
        total = coords.shape[0]
        i = -1
        seq_coverage_prev = float(total) / len(self.aln.sequence)
        n_beads = total + sum(npoints) - len(deletions)
        seq_coverage = float(n_beads) / len(self.aln.sequence)
        if seq_coverage > 1.:
            # More beads than residues:
            # Remove some beads at the end
            # Number of beads to delete at the end
            n_end_delete = n_beads - len(self.aln.sequence)
            bead_id = total - 1
            for _ in range(n_end_delete):
                while bead_id in deletions:
                    bead_id -= 1
                deletions.append(bead_id)
                print("Deleting ending bead %d (--%d)" % (bead_id, total - 1))
        for pos in range(total):
            if pos in insertions:
                i += 1
                n_ca = npoints[i]
                start = pos
                end = pos + 1
                a = self.coords[start]
                b = self.coords[end]
                data = EMDensity.interpolate(a, b, n_ca + 2)[1:-1]
                coords = numpy.insert(coords, end + offset, data, axis=0)
                offset += n_ca
            if pos in deletions:
                coords = numpy.delete(coords, pos + offset, axis=0)
                offset -= 1
        n_beads = coords.shape[0]
        seq_coverage = float(n_beads) / len(self.aln.sequence)
        print("Sequence coverage: %.2f -> %.2f" % (seq_coverage_prev, seq_coverage))
        return coords


from keras import backend as K
from keras import activations, initializations, regularizers
from keras.engine import InputSpec
from keras.layers import Recurrent, Convolution2D, MaxPooling2D
from keras.layers.core import Masking

from keras.layers.convolutional import conv_output_length
import numpy as np
from theano import tensor as T

class RecurrentConv2D(Masking):
    '''Abstract base class for recurrent layers.
    Do not use in a model -- it's not a functional layer!
    All recurrent layers (GRU, LSTM, SimpleRNN) also
    follow the specifications of this class and accept
    the keyword arguments listed below.
    # Input shape
        5D tensor with shape `(nb_samples, timesteps, channels,rows,cols)`.
    # Output shape
        - if `return_sequences`: 5D tensor with shape
            `(nb_samples, timesteps, channels,rows,cols)`.
        - else, 2D tensor with shape `(nb_samples, channels,rows,cols)`.
    # Arguments
        weights: list of numpy arrays to set as initial weights.
            The list should have 3 elements, of shapes:
            `[(input_dim, nb_filter), (nb_filter, nb_filter), (nb_filter,)]`.
        return_sequences: Boolean. Whether to return the last output
            in the output sequence, or the full sequence.
        go_backwards: Boolean (default False).
            If True, rocess the input sequence backwards.
        stateful: Boolean (default False). If True, the last state
            for each sample at index i in a batch will be used as initial
            state for the sample of index i in the following batch.
        nb_filter: Number of convolution filters to use.
        nb_row: Number of rows in the convolution kernel.
        nb_col: Number of columns in the convolution kernel.
            is required when using this layer as the first layer in a model.
        input_shape: input_shape
    # Masking
        This layer supports masking for input data with a variable number
        of timesteps. To introduce masks to your data,
        use an [Embedding](embeddings.md) layer with the `mask_zero` parameter
        set to `True`.
        **Note:** for the time being, masking is only supported with Theano.
    # TensorFlow warning
        For the time being, when using the TensorFlow backend,
        the number of timesteps used must be specified in your model.
        Make sure to pass an `input_length` int argument to your
        recurrent layer (if it comes first in your model),
        or to pass a complete `input_shape` argument to the first layer
        in your model otherwise.
    # Note on using statefulness in RNNs
        You can set RNN layers to be 'stateful', which means that the states
        computed for the samples in one batch will be reused as initial states
        for the samples in the next batch.
        This assumes a one-to-one mapping between
        samples in different successive batches.
        To enable statefulness:
            - specify `stateful=True` in the layer constructor.
            - specify a fixed batch size for your model, by passing
                a `batch_input_size=(...)` to the first layer in your model.
                This is the expected shape of your inputs *including the batch
                size*.
                It should be a tuple of integers, e.g. `(32, 10, 100)`.
        To reset the states of your model, call `.reset_states()` on either
        a specific layer, or on your entire model.
    '''
    input_ndim = 5

    def __init__(self, weights=None,
                 return_sequences=False, go_backwards=False, stateful=False,
                 nb_row=None, nb_col=None, nb_filter=None,
                 dim_ordering=None,
                 input_dim=None, input_length=None, input_shape=None, **kwargs):
        self.return_sequences = return_sequences
        self.initial_weights = weights
        self.go_backwards = go_backwards
        self.stateful = stateful

        self.nb_row = nb_row
        self.nb_col = nb_col
        self.nb_filter = nb_filter
        self.dim_ordering = dim_ordering

        self.input_dim = input_dim
        self.input_length = input_length
        if self.input_dim:
            kwargs['input_shape'] = (self.input_length, self.input_dim)

        super(RecurrentConv2D, self).__init__(**kwargs)

    def get_output_mask(self, train=False):
        if self.return_sequences:
            return super(RecurrentConv2D, self).get_output_mask(train)
        else:
            return None

    @property
    def output_shape(self):

        input_shape = self.input_shape
        if self.dim_ordering == 'th':
            rows = input_shape[2+1]
            cols = input_shape[3+1]
        elif self.dim_ordering == 'tf':
            rows = input_shape[1+1]
            cols = input_shape[2+1]
        else:
            raise Exception('Invalid dim_ordering: ' + self.dim_ordering)

        rows = conv_output_length(rows, self.nb_row,
                                  self.border_mode, self.subsample[0])
        cols = conv_output_length(cols, self.nb_col,
                                  self.border_mode, self.subsample[1])

        if self.return_sequences:
            if self.dim_ordering == 'th':
                return (input_shape[0], input_shape[1],
                        self.nb_filter, rows, cols)
            elif self.dim_ordering == 'tf':
                return (input_shape[0], input_shape[1],
                        rows, cols, self.nb_filter)
            else:
                raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
        else:
            if self.dim_ordering == 'th':
                return (input_shape[0], self.nb_filter, rows, cols)
            elif self.dim_ordering == 'tf':
                return (input_shape[0], rows, cols, self.nb_filter)
            else:
                raise Exception('Invalid dim_ordering: ' + self.dim_ordering)

    def step(self, x, states):
        raise NotImplementedError

    def get_constants(self, X, train=False):
        return None

    def get_initial_states(self, X):
        # (samples, timesteps, row, col, filter)
        initial_state = K.zeros_like(X)
        # (samples,row, col, filter)
        initial_state = K.sum(initial_state, axis=1)
        # initial_state = initial_state[::,]
        initial_state = self.conv_step(initial_state, K.zeros(self.W_shape),
                                       border_mode=self.border_mode)

        initial_states = [initial_state for _ in range(2)]
        return initial_states

    def get_output(self, train=False):

        X = self.get_input(train)
        mask = self.get_input_mask(train)
        constants = self.get_constants(X, train)

        assert K.ndim(X) == 5
        if K._BACKEND == 'tensorflow':
            if not self.input_shape[1]:
                raise Exception('When using TensorFlow, you should define ' +
                                'explicitely the number of timesteps of ' +
                                'your sequences. Make sure the first layer ' +
                                'has a "batch_input_shape" argument ' +
                                'including the samples axis.')

        if self.stateful:
            initial_states = self.states
        else:
            initial_states = self.get_initial_states(X)

        last_output, outputs, states = K.rnn(self.step, X,
                                             initial_states,
                                             go_backwards=self.go_backwards,
                                             mask=mask,
                                             constants=constants)
        if self.stateful:
            self.updates = []
            for i in range(len(states)):
                self.updates.append((self.states[i], states[i]))

        if self.return_sequences:
            return outputs
        else:
            return last_output

    def get_config(self):
        config = {"name": self.__class__.__name__,
                  "return_sequences": self.return_sequences,
                  "go_backwards": self.go_backwards,
                  "stateful": self.stateful}
        if self.stateful:
            config['batch_input_shape'] = self.input_shape
        else:
            config['input_dim'] = self.input_dim
            config['input_length'] = self.input_length

        base_config = super(RecurrentConv2D, self).get_config()
        return dict(list(base_config.items()) + list(config.items()))

class LSTMConv2D(RecurrentConv2D):
    '''
    # Input shape
            5D tensor with shape:
            `(samples,time, channels, rows, cols)` if dim_ordering='th'
            or 5D tensor with shape:
            `(samples,time, rows, cols, channels)` if dim_ordering='tf'.
     # Output shape
        if return_sequences=False
            4D tensor with shape:
            `(samples, nb_filter, o_row, o_col)` if dim_ordering='th'
            or 4D tensor with shape:
            `(samples, o_row, o_col, nb_filter)` if dim_ordering='tf'.
        if return_sequences=True
            5D tensor with shape:
            `(samples, time,nb_filter, o_row, o_col)` if dim_ordering='th'
            or 5D tensor with shape:
            `(samples, time, o_row, o_col, nb_filter)` if dim_ordering='tf'.
        where o_row and o_col depend on the shape of the filter and
        the border_mode
        # Arguments
            nb_filter: Number of convolution filters to use.
            nb_row: Number of rows in the convolution kernel.
            nb_col: Number of columns in the convolution kernel.
            border_mode: 'valid' or 'same'.
            sub_sample: tuple of length 2. Factor by which to subsample output.
            Also called strides elsewhere.
            dim_ordering: "tf" if the feature are at the last dimension or "th"
            stateful : has not been checked yet.
            init: weight initialization function.
                Can be the name of an existing function (str),
                or a Theano function
                (see: [initializations](../initializations.md)).
            inner_init: initialization function of the inner cells.
            forget_bias_init: initialization function for the bias of the
            forget gate.
                [Jozefowicz et al.]
                (http://www.jmlr.org/proceedings/papers/v37/jozefowicz15.pdf)
                recommend initializing with ones.
            activation: activation function.
                Can be the name of an existing function (str),
                or a Theano function (see: [activations](../activations.md)).
            inner_activation: activation function for the inner cells.
    # References
        - [Convolutional LSTM Network: A Machine Learning Approach for
        Precipitation Nowcasting](http://arxiv.org/pdf/1506.04214v1.pdf)
        The current implementation does not include the feedback loop on the
        cells output
    '''
    def __init__(self, nb_filter, nb_row, nb_col,
                 init='glorot_uniform', inner_init='orthogonal',
                 forget_bias_init='one', activation='tanh',
                 inner_activation='hard_sigmoid', dim_ordering="tf",
                 border_mode="valid", sub_sample=(1, 1),
                 W_regularizer=None, U_regularizer=None, input_shape=None, b_regularizer=None,
                 dropout_W=0., dropout_U=0., **kwargs):

        self.nb_filter = nb_filter
        self.nb_row = nb_row
        self.nb_col = nb_col
        self.init = initializations.get(init)
        self.inner_init = initializations.get(inner_init)
        self.forget_bias_init = initializations.get(forget_bias_init)
        self.activation = activations.get(activation)
        self.inner_activation = activations.get(inner_activation)
        self.border_mode = border_mode
        self.subsample = sub_sample

        assert dim_ordering in {'tf', "th"}, 'dim_ordering must be in {tf,"th}'
        self.dim_ordering = dim_ordering

        kwargs["nb_filter"] = nb_filter
        kwargs["nb_row"] = nb_row
        kwargs["nb_col"] = nb_col
        kwargs["dim_ordering"] = dim_ordering

        self.W_regularizer = W_regularizer
        self.U_regularizer = U_regularizer
        self.b_regularizer = b_regularizer
        self.dropout_W, self.dropout_U = dropout_W, dropout_U

        super(LSTMConv2D, self).__init__(**kwargs)

    def build(self, in_shape):
        input_shape = in_shape
        # input_shape = self.input_shape
        # self.input = K.placeholder(input_shape)

        if self.dim_ordering == 'th':
            # stack_size = self.input_shape[1+1]
            stack_size = in_shape[1+1]
            self.W_shape = (self.nb_filter, stack_size,
                            self.nb_row, self.nb_col)
        elif self.dim_ordering == 'tf':
            # stack_size = self.input_shape[3+1]
            stack_size = in_shape[3+1]
            self.W_shape = (self.nb_row, self.nb_col,
                            stack_size, self.nb_filter)
        else:
            raise Exception('Invalid dim_ordering: ' + self.dim_ordering)

        if self.dim_ordering == 'th':
            self.W_shape1 = (self.nb_filter, self.nb_filter,
                             self.nb_row, self.nb_col)
        elif self.dim_ordering == 'tf':
            self.W_shape1 = (self.nb_row, self.nb_col,
                             self.nb_filter, self.nb_filter)
        else:
            raise Exception('Invalid dim_ordering: ' + self.dim_ordering)

        if self.stateful:
            self.reset_states()
        else:
            # initial states: 2 all-zero tensor of shape (nb_filter)
            self.states = [None, None, None, None]

        self.W_i = self.init(self.W_shape)
        self.U_i = self.inner_init(self.W_shape1)
        self.b_i = K.zeros((self.nb_filter,))

        self.W_f = self.init(self.W_shape)
        self.U_f = self.inner_init(self.W_shape1)
        self.b_f = self.forget_bias_init((self.nb_filter,))

        self.W_c = self.init(self.W_shape)
        self.U_c = self.inner_init(self.W_shape1)
        self.b_c = K.zeros((self.nb_filter))

        self.W_o = self.init(self.W_shape)
        self.U_o = self.inner_init(self.W_shape1)
        self.b_o = K.zeros((self.nb_filter,))

        def append_regulariser(input_regulariser, param, regularizers_list):
            regulariser = regularizers.get(input_regulariser)
            if regulariser:
                regulariser.set_param(param)
                regularizers_list.append(regulariser)

        self.regularizers = []
        for W in [self.W_i, self.W_f, self.W_i, self.W_o]:
            append_regulariser(self.W_regularizer, W, self.regularizers)
        for U in [self.U_i, self.U_f, self.U_i, self.U_o]:
            append_regulariser(self.U_regularizer, U, self.regularizers)
        for b in [self.b_i, self.b_f, self.b_i, self.b_o]:
            append_regulariser(self.b_regularizer, b, self.regularizers)

        self.trainable_weights = [self.W_i, self.U_i, self.b_i,
                                  self.W_c, self.U_c, self.b_c,
                                  self.W_f, self.U_f, self.b_f,
                                  self.W_o, self.U_o, self.b_o]

        if self.initial_weights is not None:
            self.set_weights(self.initial_weights)
            del self.initial_weights

    def reset_states(self):
        assert self.stateful, 'Layer must be stateful.'
        input_shape = self.input_shape
        if not input_shape[0]:
            raise Exception('If a RNN is stateful, a complete ' +
                            'input_shape must be provided ' +
                            '(including batch size).')

        if self.return_sequences:
            out_row, out_col, out_filter = self.output_shape[2:]
        else:
            out_row, out_col, out_filter = self.output_shape[1:]

        if hasattr(self, 'states'):
            K.set_value(self.states[0],
                        np.zeros((input_shape[0],
                                  out_row, out_col, out_filter)))
            K.set_value(self.states[1],
                        np.zeros((input_shape[0],
                                  out_row, out_col, out_filter)))
        else:
            self.states = [K.zeros((input_shape[0],
                                    out_row, out_col, out_filter)),
                           K.zeros((input_shape[0],
                                    out_row, out_col, out_filter))]

    def conv_step(self, x, W, b=None, border_mode="valid"):

        conv_out = K.conv2d(x, W, strides=self.subsample,
                            border_mode=border_mode,
                            dim_ordering=self.dim_ordering,
                            image_shape=(self.input_shape[0],
                                         self.input_shape[2],
                                         self.input_shape[3],
                                         self.input_shape[4]),
                            filter_shape=self.W_shape)
        if b:
            if self.dim_ordering == 'th':
                conv_out = conv_out + K.reshape(b, (1, self.nb_filter, 1, 1))
            elif self.dim_ordering == 'tf':
                conv_out = conv_out + K.reshape(b, (1, 1, 1, self.nb_filter))
            else:
                raise Exception('Invalid dim_ordering: ' + self.dim_ordering)

        return conv_out

    def conv_step_hidden(self, x, W, border_mode="valid"):
        # This new function was defined because the
        # image shape must be hardcoded

        if self.return_sequences:
            out_row, out_col, out_filter = self.output_shape[2:]
        else:
            out_row, out_col, out_filter = self.output_shape[1:]

        conv_out = K.conv2d(x, W, strides=(1, 1),
                            border_mode=border_mode,
                            dim_ordering=self.dim_ordering,
                            image_shape=(self.input_shape[0],
                                         out_row, out_col,
                                         out_filter),
                            filter_shape=self.W_shape1)

        return conv_out

    def step(self, x, states):
        assert len(states) == 4
        h_tm1 = states[0]
        c_tm1 = states[1]
        B_W = states[2]
        B_U = states[3]

        x_i = self.conv_step(x * B_W[0], self.W_i, self.b_i,
                             border_mode=self.border_mode)
        x_f = self.conv_step(x * B_W[1], self.W_f, self.b_f,
                             border_mode=self.border_mode)
        x_c = self.conv_step(x * B_W[2], self.W_c, self.b_c,
                             border_mode=self.border_mode)
        x_o = self.conv_step(x * B_W[3], self.W_o, self.b_o,
                             border_mode=self.border_mode)

        # U : from nb_filter to nb_filter
        # Same because must be stable in the ouptut space
        h_i = self.conv_step_hidden(h_tm1, self.U_i * B_U[0],
                                    border_mode="same")
        h_f = self.conv_step_hidden(h_tm1, self.U_f * B_U[1],
                                    border_mode="same")
        h_c = self.conv_step_hidden(h_tm1, self.U_c * B_U[2],
                                    border_mode="same")
        h_o = self.conv_step_hidden(h_tm1, self.U_o * B_U[3],
                                    border_mode="same")

        i = self.inner_activation(x_i + h_i)
        f = self.inner_activation(x_f + h_f)
        c = f * c_tm1 + i * self.activation(x_c + h_c)
        o = self.inner_activation(x_o + h_o)
        h = o * self.activation(c)

        return h, [h, c]

    def get_constants(self, X, train=False):
        retain_p_W = 1. - self.dropout_W
        retain_p_U = 1. - self.dropout_U
        if train and (self.dropout_W > 0 or self.dropout_U > 0):
            nb_samples = K.shape(X)[0]
            if K._BACKEND == 'tensorflow':
                if not self.input_shape[0]:
                    raise Exception('For RNN dropout in tensorflow, ' +
                                    'a complete input_shape must be ' +
                                    'provided (including batch size).')
                nb_samples = self.input_shape[0]
            B_W = [K.random_binomial((nb_samples, self.input_dim),
                                     p=retain_p_W) for _ in range(4)]
            B_U = [K.random_binomial((nb_samples, self.output_dim),
                                     p=retain_p_U) for _ in range(4)]
        else:
            B_W = np.ones(4, dtype=K.floatx()) * retain_p_W
            B_U = np.ones(4, dtype=K.floatx()) * retain_p_U
        return [B_W, B_U]

    def get_config(self):
        config = {"name": self.__class__.__name__,
                  "nb_filter": self.nb_filter,
                  'nb_row': self.nb_row,
                  'nb_col': self.nb_col,
                  "init": self.init.__name__,
                  "inner_init": self.inner_init.__name__,
                  "forget_bias_init": self.forget_bias_init.__name__,
                  "activation": self.activation.__name__,
                  'dim_ordering': self.dim_ordering,
                  'border_mode': self.border_mode,
                  "inner_activation": self.inner_activation.__name__}
        base_config = super(LSTMConv2D, self).get_config()
        return dict(list(base_config.items()) + list(config.items()))

class ConvRNN(Recurrent):
    """RNN with all connections being convolutions:
    H_t = activation(conv(H_tm1, W_hh) + conv(X_t, W_ih) + b)
    with H_t and X_t being images and W being filters.

    We use Keras' RNN API, thus input and outputs should be 3-way tensors.
    Assuming that your input video have frames of size
    [nb_channels, nb_rows, nb_cols], the input of this layer should be reshaped
    to [batch_size, time_length, nb_channels*nb_rows*nb_cols]. Thus, you have to
    pass the original images shape to the ConvRNN layer.

    Parameters:
    -----------
    filter_dim: list [nb_filters, nb_row, nb_col] convolutional filter
        dimensions
    reshape_dim: list [nb_channels, nb_row, nb_col] original dimensions of a
        frame.
    batch_size: int, batch_size is useful for TensorFlow backend.
    time_length: int, optional for Theano, mandatory for TensorFlow
    subsample: (int, int), just keras.layers.Convolutional2D.subsample

    """
    def __init__(self, filter_dim, reshape_dim,
                 batch_size=None, subsample=(1, 1),
                 init='glorot_uniform', inner_init='glorot_uniform',
                 activation='tanh', inner_activation='hard_sigmoid',
                 weights=None, **kwargs):
        self.batch_size = batch_size
        self.border_mode = 'same'
        self.filter_dim = filter_dim
        self.reshape_dim = reshape_dim
        self.init = initializations.get(init)
        self.inner_init = initializations.get(inner_init)
        self.activation = activations.get(activation)
        self.inner_activation = activations.get(inner_activation)
        self.initial_weights = weights

        self.subsample = tuple(subsample)
        self.output_dim = (filter_dim[0], reshape_dim[1]//self.subsample[0],
                           reshape_dim[2]//self.subsample[1])

        super(ConvRNN, self).__init__(**kwargs)

    def _get_batch_size(self, X):
        if K._BACKEND == 'theano':
            batch_size = X.shape[0]
        else:
            batch_size = self.batch_size
        return batch_size

    def build(self, input_shapes):
        if K._BACKEND == 'theano':
            batch_size = None
        else:
            batch_size = None  # self.batch_size
        input_dim = self.input_shape
        bm = self.border_mode
        reshape_dim = self.reshape_dim
        hidden_dim = self.output_dim

        nb_filter, nb_rows, nb_cols = self.filter_dim
        self.input = K.placeholder(shape=(batch_size, input_dim[1], input_dim[2]))

        # self.b_h = K.zeros((nb_filter,))
        self.conv_h = Convolution2D(nb_filter, nb_rows, nb_cols, border_mode=bm, input_shape=hidden_dim)
        self.conv_x = Convolution2D(nb_filter, nb_rows, nb_cols, border_mode=bm, input_shape=reshape_dim)

        # hidden to hidden connections
        self.conv_h.build()
        # input to hidden connections
        self.conv_x.build()

        self.max_pool = MaxPooling2D(pool_size=self.subsample, input_shape=hidden_dim)
        self.max_pool.build()

        self.trainable_weights = self.conv_h.trainable_weights + self.conv_x.trainable_weights

        if self.initial_weights is not None:
            self.set_weights(self.initial_weights)
            del self.initial_weights

    def get_initial_states(self, X):
        batch_size = self._get_batch_size(X)
        hidden_dim = np.prod(self.output_dim)
        if K._BACKEND == 'theano':
            h = T.zeros((batch_size, hidden_dim))
        else:
            h = K.zeros((batch_size, hidden_dim))
        return [h, ]

    def step(self, x, states):
        batch_size = self._get_batch_size(x)
        input_shape = (batch_size, ) + self.reshape_dim
        hidden_dim = (batch_size, ) + self.output_dim
        nb_filter, nb_rows, nb_cols = self.output_dim
        h_tm1 = K.reshape(states[0], hidden_dim)

        x_t = K.reshape(x, input_shape)
        Wx_t = self.conv_x(x_t, train=True)
        h_t = self.activation(Wx_t + self.conv_h(h_tm1, train=True))
        h_t = K.batch_flatten(h_t)
        return h_t, [h_t, ]

    @property
    def output_shape(self):
        input_shape = self.input_shape
        if self.return_sequences:
            return (input_shape[0], input_shape[1], np.prod(self.output_dim))
        else:
            return (input_shape[0], np.prod(self.output_dim))

    def get_config(self):
        config = {"name": self.__class__.__name__,
                  "filter_dim": self.filter_dim,
                  "output_dim": self.output_dim,
                  "init": self.init.__name__,
                  "inner_init": self.inner_init.__name__,
                  "activation": self.activation.__name__,
                  "inner_activation": self.inner_activation.__name__,
                  "return_sequences": self.return_sequences,
                  "reshape_dim": self.reshape_dim,
                  "go_backwards": self.go_backwards}
        base_config = super(ConvRNN, self).get_config()
        return dict(list(base_config.items()) + list(config.items()))

class ConvGRU(ConvRNN):
    """ConvGRU is similar to ConvRNN, but with a GRU like state transition
    For documentation and details check seya.layers.conv_rnn.ConvRNN and
    keras.layers.recurrent.GRU

    """
    def __init__(self, filter_dim, reshape_dim, batch_size=None,
                 subsample=(1, 1),
                 init='glorot_uniform', inner_init='glorot_uniform',
                 activation='tanh', inner_activation='hard_sigmoid',
                 weights=None, **kwargs):
        super(ConvGRU, self).__init__(
            filter_dim=filter_dim, reshape_dim=reshape_dim,
            batch_size=batch_size, subsample=subsample,
            init=init, inner_init=inner_init, activation=activation,
            inner_activation=inner_activation, weights=weights, **kwargs)

    def build(self, input_shapes):
        batch_size = None
        input_dim = input_shapes
        bm = self.border_mode
        reshape_dim = tuple(self.reshape_dim)
        hidden_dim = tuple(self.output_dim)

        self.input_spec = [InputSpec(shape=input_shapes)]
        self.input_dim = input_shapes[2]

        nb_filter, nb_rows, nb_cols = self.filter_dim
        #self.input = K.placeholder(shape=(batch_size, input_dim[1], input_dim[2]))

        self.b_h = K.zeros((nb_filter,))
        self.b_r = K.zeros((nb_filter,))
        self.b_z = K.zeros((nb_filter,))

        self.conv_h = Convolution2D(nb_filter, nb_rows, nb_cols, border_mode=bm, input_shape=hidden_dim)
        self.conv_z = Convolution2D(nb_filter, nb_rows, nb_cols, border_mode=bm, input_shape=hidden_dim)
        self.conv_r = Convolution2D(nb_filter, nb_rows, nb_cols, border_mode=bm, input_shape=hidden_dim)

        self.conv_x_h = Convolution2D(nb_filter, nb_rows, nb_cols, border_mode=bm, input_shape=reshape_dim)
        self.conv_x_z = Convolution2D(nb_filter, nb_rows, nb_cols, border_mode=bm, input_shape=reshape_dim)
        self.conv_x_r = Convolution2D(nb_filter, nb_rows, nb_cols, border_mode=bm, input_shape=reshape_dim)

        # hidden to hidden connections
        self.conv_h.build((nb_filter, hidden_dim[0], nb_rows, nb_cols))
        self.conv_z.build((nb_filter, hidden_dim[0], nb_rows, nb_cols))
        self.conv_r.build((nb_filter, hidden_dim[0], nb_rows, nb_cols))
        # input to hidden connections
        self.conv_x_h.build((nb_filter, reshape_dim[0], nb_rows, nb_cols))
        self.conv_x_z.build((nb_filter, reshape_dim[0], nb_rows, nb_cols))
        self.conv_x_r.build((nb_filter, reshape_dim[0], nb_rows, nb_cols))

        self.max_pool = MaxPooling2D(pool_size=self.subsample, input_shape=reshape_dim)

        self.trainable_weights = self.conv_h.trainable_weights + self.conv_z.trainable_weights + self.conv_r.trainable_weights + \
            self.conv_x_h.trainable_weights + self.conv_x_z.trainable_weights + self.conv_x_r.trainable_weights

        if self.initial_weights is not None:
            self.set_weights(self.initial_weights)
            del self.initial_weights

    def step(self, x, states):
        batch_size = self._get_batch_size(x)
        input_shape = (batch_size, ) + tuple(self.reshape_dim)
        hidden_dim = (batch_size, ) + tuple(self.output_dim)
        nb_filter, nb_rows, nb_cols = self.output_dim
        h_tm1 = K.reshape(states[0], hidden_dim)

        x_t = K.reshape(x, input_shape)
        xz_t = self.conv_x_z(x_t)
        xr_t = self.conv_x_r(x_t)
        xh_t = self.conv_x_h(x_t)

        # xz_t = apply_layer(self.max_pool, xz_t)
        # xr_t = apply_layer(self.max_pool, xr_t)
        # xh_t = apply_layer(self.max_pool, xh_t)

        #xz_t = self.max_pool(xz_t)
        #xr_t = self.max_pool(xr_t)
        #xh_t = self.max_pool(xh_t)

        z = self.inner_activation(xz_t + self.conv_z(h_tm1))
        r = self.inner_activation(xr_t + self.conv_r(h_tm1))
        hh_t = self.activation(xh_t + self.conv_h(r * h_tm1))
        h_t = z * h_tm1 + (1 - z) * hh_t
        h_t = K.batch_flatten(h_t)
        return h_t, [h_t, ]

    def get_output_shape_for(self, input_shape):
        if self.return_sequences:
            return (input_shape[0], input_shape[1], np.prod(self.output_dim))
        else:
            return (input_shape[0], np.prod(self.output_dim))

    @property
    def output_shape(self):
        input_shape = self.input_shape
        if self.return_sequences:
            return (input_shape[0], input_shape[1], np.prod(self.output_dim))
        else:
            return (input_shape[0], np.prod(self.output_dim))

    def get_config(self):
        config = {"name": self.__class__.__name__,
                  "filter_dim": self.filter_dim,
                  "output_dim": self.output_dim,
                  "init": self.init.__name__,
                  "inner_init": self.inner_init.__name__,
                  "activation": self.activation.__name__,
                  "inner_activation": self.inner_activation.__name__,
                  "return_sequences": self.return_sequences,
                  "reshape_dim": self.reshape_dim,
                  "go_backwards": self.go_backwards}
        base_config = super(ConvGRU, self).get_config()
        return dict(list(base_config.items()) + list(config.items()))


from django.shortcuts import render, redirect
from .models import *
from .forms import WidgetForm

# Create your views here.
def home(request):
    widgets_list = Widget.objects.all()
    widget_form = WidgetForm()
    return render(request, 'main.html', {
		'widget_list': widgets_list,
		'widget_form': widget_form
		})

def add_widget(request):
    form = WidgetForm(request.POST)
    if form.is_valid():
        new_widget = form.save(commit=False)
        new_widget.save()
    return redirect('home')

def delete_widget(request, widget_id):
    Widget.objects.filter(id=widget_id).delete()
    return redirect('home')


import logging
import os
import time

from minio_utils import backup_log_file

class LogHandler(logging.handlers.TimedRotatingFileHandler):
    """This is a subclass of python TimedRotatingFileHandler, but eventually backs up the logs on minio
    before older logs are deleted
    """

    def doRollover(self):
        """
        do a rollover; in this case, a date/time stamp is appended to the filename
        when the rollover happens.  However, you want the file to be named for the
        start of the interval, not the current time.  If there is a backup count,
        then we have to get a list of matching filenames, sort them and remove
        the one with the oldest suffix.
        """
        if self.stream:
            self.stream.close()
            self.stream = None
        # get the time that this sequence started at and make it a TimeTuple
        currentTime = int(time.time())
        dstNow = time.localtime(currentTime)[-1]
        t = self.rolloverAt - self.interval
        if self.utc:
            timeTuple = time.gmtime(t)
        else:
            timeTuple = time.localtime(t)
            dstThen = timeTuple[-1]
            if dstNow != dstThen:
                if dstNow:
                    addend = 3600
                else:
                    addend = -3600
                timeTuple = time.localtime(t + addend)
        dfn = self.rotation_filename(self.baseFilename + "." +
                                     time.strftime(self.suffix, timeTuple))
        if os.path.exists(dfn):
            os.remove(dfn)
        self.rotate(self.baseFilename, dfn)
        if self.backupCount > 0:
            for s in self.getFilesToDelete():
                backup_log_file(s)
                os.remove(s)
        if not self.delay:
            self.stream = self._open()
        newRolloverAt = self.computeRollover(currentTime)
        while newRolloverAt <= currentTime:
            newRolloverAt = newRolloverAt + self.interval
        #If DST changes and midnight or weekly rollover, adjust for this.
        if (self.when == 'MIDNIGHT' or self.when.startswith('W')) and not self.utc:
            dstAtRollover = time.localtime(newRolloverAt)[-1]
            if dstNow != dstAtRollover:
                if not dstNow:  # DST kicks in before next rollover, so we need to deduct an hour
                    addend = -3600
                else:           # DST bows out before next rollover, so we need to add an hour
                    addend = 3600
                newRolloverAt += addend
        self.rolloverAt = newRolloverAt


#Import Json
import json

#Import requests
import requests

#Input artist name and song title
artist_name = input("Enter the artist name: ")
song_title = input("Enter the song title: ")

#Define function to search for lyrics
def search_lyrics(artist_name, song_title):
    #Search for lyrics
    url = "https://api.lyrics.ovh/v1/" + artist_name + "/" + song_title
    response = requests.get(url)
    #If no lyrics found, print error message
    if response.status_code != 200:
        print("No lyrics found for " + song_title + " by " + artist_name)
    #If lyrics found, print lyrics
    else:
        print(response.json()["lyrics"])

#Call search_lyrics function
search_lyrics(artist_name, song_title)

#Would like to add functions to write to a file...soon

#End Program
print("Lyrics Found!")


from Cryptodome.Util.number import getPrime, inverse, GCD, getRandomRange
from decimal import Decimal, localcontext
import os
from Cryptodome.Random.random import randint
from argparser import parser
from generatedRsaParams import p, q
from generateRsaParams import generate_e_d_P1, getPrimePair, generators
import millerrabin

def get_f_s_from_N (N):

    f = 0
    copyN = N
    while (N % 2 == 0):
        f = f + 1
        N = N // 2

    s = N

    #print("N = (2^f)*s")
    #print(copyN," = (2^",f,") * ",s,"\n")
    return f, s

def find_l (b, n):
    l = 0
    pow_b = pow(2, l)
    kv_pow = pow(b,pow_b)
    while (pow(b,pow_b,n)!=1):
        print("b^2^",l," = ",pow(b,pow_b,n))
        l = l+1
        pow_b = pow(2, l)
    return l

def _common_module_attack(n, e_b, d_b, e_a):

    N = (e_b * d_b) - 1             # 1) N <- (e_b*d_b)-1
    f, s = get_f_s_from_N(N)        #    N = (2^f)*s

    a = randint(1, n-1)             # 2) a <- rand (Z/nZ)
    b = pow(int(a), int(s), int(n))                #    b <- a^s (mod n)
    print ("b = ", b)
    l_and_t_found = False
    print("start finding l")
    l = find_l(b, int(n))

    while (not l_and_t_found):      # 3) b^(2^l) = 1 (mod n)
                                    #    if (b^(2^(l-1)) = -1 (mod n))
        pow_b = pow(2, l-1)         #       new rand a, go to 2)
        if (pow(b,pow_b,n)==-1):    #    else
            a = randint(1, n-1)     #       t <- b^(2^(l-1)) (mod n)
            b = pow(a, s, n)
            l = find_l(b)
        else:
            t = pow(b,pow_b,n)
            l_and_t_found = True

    p = GCD(t+1, n)                 # 4) p <- gcd(t+1,n)
    q = GCD(t-1, n)                 #    q <- gcd(t-1,n)

    f_n_2 = (p-1)*(q-1)
    d_a = inverse(e_a, f_n_2)
    while (d_a == d_b):
        d_a = inverse(e_b, f_n_2)
    if d_b != d_a:
        print("Attack for common module: Success")
    else:
        print("Attack for common module: Failed")

if __name__ == "__main__":
    p, q = getPrimePair()
    print("p = ",p)
    print("q = ",q)
    print("LENS = ", len(generators(q)))

    #n, e_a, d_a = generate_e_d_P1(p, q)
    #n, e_b, d_b = generate_e_d_P1(p, q)
    #_common_module_attack(int(n),int(e_b),int(d_b), int(e_a))


# SCRAPE mars

import time
from bs4 import BeautifulSoup as bs
import requests
from splinter import Browser
from selenium import webdriver
import pandas as pd
import time

# Replacing the path with machine's actual path to the chromedriver

def init_browser():

    executable_path = {"executable_path": "/usr/local/bin/chromedriver"}
    return Browser("chrome", **executable_path, headless=False)

def scrape():
    browser = init_browser()

# Creating dictionary for scraped data

    mars_data = {}

# Accessing Nasa news on mars

    url = "https://mars.nasa.gov/news/"
    browser.visit(url)
    new_html = browser.html

# Scraping the page into soup

    bsoup = bs(new_html, 'html.parser')

# Find the latest Mars news.

    article = bsoup.find("div", class_="list_text")
    news_p = bsoup.find('div', class_='rollover_description_inner').text
    news_title = bsoup.find("div", class_="content_title").text
    news_date = article.find("div", class_="list_date").text

# Accessing JPL's Featured Space Image page

    url2 = "https://www.jpl.nasa.gov/spaceimages/?search=&category=Mars"
    browser.visit(url2)

# Scraping the browser into soup and use soup to find the full resolution image of mars
# Saving image url to a variable `featured_image_url`

    new_html = browser.html
    bsoup = bs(new_html, 'html.parser')
    image = bsoup.find('img', class_="thumb")["src"]
    img_url = "https://jpl.nasa.gov"+image
    featured_image_url = img_url

# - From the [Mars Weather twitter](https://twitter.com/marswxreport?lang=en) account scrape the latest Mars weather tweet from the page.
# - Save the tweet text for the weather report.

    twt_url = 'https://twitter.com/marswxreport?lang=en'

    browser.visit(twt_url)
    new_html = browser.html
    bsoup = bs(new_html, 'html.parser')
    twt_rslt = bsoup.find_all('p', class_="TweetTextSize TweetTextSize--normal js-tweet-text tweet-text")

# Acessing next tweet from the twitter url

    twt_weather = twt_rslt[1].text
    twt_weather_twt = twt_weather.replace('pic.twitter.com/WlR4gr8gpC','')

# Adding the weather data

    mars_weather = twt_weather_twt

# mars facts

    url3 = "https://space-facts.com/mars/"
    browser.visit(url3)

# Creating data frame

    grab = pd.read_html(url3)
    fact_df = pd.DataFrame(grab[0])
    fact_df = fact_df.rename(columns={0:'Description',1: 'Values'})
    fact_df = fact_df.set_index('Description')
    df_to_html = fact_df.to_html(classes='mars_scrape_info')
    df_to_html = df_to_html.replace("\n"," ")

# Visit the USGS Astogeology site and scrape pictures of the hemispheres
    url4 = "https://astrogeology.usgs.gov/search/results?q=hemisphere+enhanced&k1 =target&v1=Mars"
    browser.visit(url4)

    new_html = browser.html
    bsoup = bs(new_html, 'html.parser')

    image_mars = []

    for item in range(4):
        time.sleep(1)
        images = browser.find_by_tag('h3')
        images[item].click()
        new_html = browser.html
        bsoup = bs(new_html, 'html.parser')
        newContent = bsoup.find("img", class_="wide-image")["src"]
        img_title = bsoup.find("h2", class_="title").text
        img_url = 'https://astrogeology.usgs.gov'+ newContent
        img_dict = {"title":img_title,"img_url":img_url}
        image_mars.append(img_dict)
        browser.back()

# Adding to dictionary

    mars_data = {
        'News_Title': news_title,
        'News_Heading': news_p,
        'Feature_Image': featured_image_url,
        'Weather': mars_weather,
        'Facts': df_to_html,
        'Hemisphere': image_mars
    }

    browser.quit()

    return mars_data


from keras.callbacks import BaseLogger
import matplotlib.pyplot as plt
import numpy as np
import json
import os
from .utils import Utils

class TrainingMonitor(BaseLogger):
    def __init__(self, figPath, jsonPath=None, startAt=0):
        super(TrainingMonitor, self).__init__()
        self.figPath = figPath
        self.jsonPath = jsonPath
        self.startAt = startAt

    def on_train_begin(self, logs={}):
        self.history = {}

        if self.jsonPath is not None:
            if os.path.exists(self.jsonPath):
                self.history = json.loads(open(self.jsonPath).read())

                if self.startAt > 0:
                    for key in self.history.keys():
                        self.history[key] = self.history[key][:self.startAt]

    def on_epoch_end(self, epoch, logs={}):
        for (key, value) in logs.items():
            logs = self.history.get(key, [])
            logs.append(value)
            self.history[key] = logs
        if self.jsonPath is not None:
            file = open(self.jsonPath, "w")
            file.write(json.dumps(self.history))
            file.close()
        if len(self.history["loss"]) > 1:
            plt.style.use("ggplot")
            plt.figure()
            plt.plot(Utils.smooth_curve(self.history['loss']), label="train_loss")
            plt.plot(Utils.smooth_curve(self.history['val_loss']), label="val_loss")
            plt.plot(Utils.smooth_curve(self.history['acc']), label="train_acc")
            plt.plot(Utils.smooth_curve(self.history['val_acc']), label="val_acc")
            plt.title("Training Loss and Accuracy [Epoch {}]".format(len(self.history["loss"])))
            plt.legend()

            plt.savefig(self.figPath)
            plt.close()