#coding:utf-8
from abc import ABCMeta,abstractmethod
from random import randint,uniform,choice
import pickle
import time
#------------------------------------------------------------
#武器类
class Weapon(object):#武器类的属性以         w_开头 我把与武器有关的方法放在了武器类中
    __slots__ = ('w_name','w_aggressive','w_price','w_hp','w_rank','w_armor')
    def __init__(self,name,aggressive,price,hp,rank,armor):
        self.w_name = name
        self.w_aggressive = aggressive
        self.w_price = price
        self.w_hp = hp
        self.w_rank = rank
        self.w_armor = armor

    def __str__(self):
        return '%s\t'%self.w_name+\
      '攻击力:%d\t' %self.w_aggressive+\
        '价格:%d\t' %self.w_price+\
        '适用等级:%d\t' %self.w_rank

#----------------------------------------------------
w1 = Weapon('小刀', 20, 30, 0, 0,5)
w2 = Weapon('木棍', 15, 40, 0, 0,5)
w3 = Weapon('怪兽之刃',15,45,0,0,5)

drop_weapon = [w1,w2,w3]

w3 = Weapon('暴风雪', 100, 150, 200, 5, 50)
w4 = Weapon('冰风', 200, 300, 250, 8, 100)
w5 = Weapon('雷电', 300, 450, 300, 9, 140)
w6 = Weapon('彩虹刀', 800, 2500, 600, 15, 180)
w7 = Weapon('稀有GFX9型光炮', 1500, 1000, 1100, 15, 240)
w8 = Weapon('时空天剑引擎', 1200, 1800, 1500, 15, 250)
w9= Weapon('传奇cpu', 2000, 2800, 1800, 20, 280)
w11 = Weapon('魔杖',2200,100000,2000,15,320)
w10 = Weapon('终结权杖',2500,100000,3000,20,450)#不可以买只能打boss获得,
#---------------------------------------------------------------------------
class hero(object,metaclass= ABCMeta):#英雄基类
    # __slots__  = ('name','hp','money','rank','mp','exp','attack','armor')
    def __init__(self,name,hp,money,rank,exp,mp,armor,attack):
        self.name = name
        self.hp = hp
        self.money = money
        self.mp = mp
        self.armor = armor
        self.attack = attack
        self.exp = exp
        self.rank = rank#八个属性
        self.weapons = []#存放武器对象
        self.wins = {'枉死之身':0,'电气八爪鱼':0,'结合体莫卡伊':0}

   #英雄死亡之后血量为0,退出打怪模式，后回复上次血量,钱减100
    def back_hp(self,hp,mp):
        self.hp = hp
        self.mp = mp
        self.money -= 100
    @property
    def alive(self):
        return  self.hp > 0

    def resume(self):#回复状态
        """
        回复魔法值
        :return: 喝药之后回复的魔法值
        """
        incr_point = self.mp // 4
        self.mp += incr_point
        hp_point =  self.hp // 8
        self.hp += hp_point
        return incr_point,hp_point
    #判断是否升级
    def hero_IsRank(self):
        #200经验值一级
        new_rank= self.exp // 200
        add_rank = new_rank - self.rank#升级的级数
        if add_rank > 0:
            self.rank += add_rank
            self.hp += 150*add_rank
            self.mp += 30*add_rank  #升级加血量和蓝值,攻击和防御属性升级!!!
            self.attack += 100*add_rank
            self.armor += 25*add_rank
            return True#判断是否升级
        else:
            return False

    def hero_add_exp(self,other): #打败其他怪兽获得经验
        self.exp += other.exp
        self.money += other.money
         #返回获得的经验值,然后判断是否升级
    def __str__(self):
        return '~~~%s~~~~\t' % self.name + \
               '生命值: %d\t' % self.hp + \
               '魔法值:%d\t' % self.mp + \
               '当前金币: %d\t' % self.money + \
               '当前等级: %d\t' % self.rank + \
               '当前伤害:%d\t' % self.attack+\
                '当前护甲%d' %self.armor
    def Buy_weapon(self,weapon):#买装备
        if self.money > weapon.w_price:
            self.weapons.append(weapon)#添加自己的武器到背包中
            self.money -= weapon.w_price
            self.attack += weapon.w_aggressive
            self.hp += weapon.w_hp#交易金钱和...
            self.armor += weapon.w_armor
            return True
        else:
            return False

    def Sell_weapon(self,weapon):#卖装备
        self.weapons.remove(weapon)#移除装备获得金钱
        self.money += weapon.w_price
        self.attack -= weapon.w_aggressive
        self.hp -= weapon.w_hp
        self.armor -= weapon.w_armor
    def Get_weapon(self,weapon):
        self.weapons.append(weapon)
        self.attack += weapon.w_aggressive
        self.hp += weapon.w_hp
        self.armor += weapon.w_armor
    def Is_can_Buy(self, w):# 参数是准备要购买的武器
        if self.rank >= w.w_rank and  self.money >= w.w_price:#钱和等级都够了才能购买---
            return True
        else:
            return False

    @abstractmethod#虚方法,让下面的子类进行完善
    def common_Attack(self,other):
        """
        攻击
        :param other: 被攻击对象
        :return:
        """

        pass

#------------------------------------------------------------------------------
class SkySprit(hero):
    """
    天剑通灵
    """
    # __slots__ = ('name', 'hp', 'money', 'rank', 'mp', 'exp', 'attack', 'armor')

    def __init__(self,name='天剑通灵',hp = 1000,money=1000,rank=0,exp=0,mp=500,armor =30,attack=75):
        super().__init__(name,hp,money,rank,exp,mp,armor,attack)
        self.skills = ['不畏刺击', '怒气爆发','冰霜磁场','回复']

    def common_Attack(self,other):
        """
        普通攻击
        :param other: 敌人
        :return: 随机伤害
        """

        damage_Value = self.attack - other.armor
        other.hp -= damage_Value
        return damage_Value

    def small_Attack(self,other): #一技能
        if self.mp > 300:
            self.mp -= 300
            damage_value = randint(1,2)*self.attack +randint(0,250)- other.armor
            other.hp -= damage_value
            return True
        else:
            return False

    def big_Attack(self,other):#二技能
        if self.mp > 400:
            self.mp -= 400
            damage_value = randint(2,3)*self.attack+ randint(0,500) - other.armor
            other.hp -= damage_value
            return True
        else:
            return False
#---------------------------------------------------------------------------------------------------
class RedLotus(hero):
    """
   红莲之忍英雄
    """

    __slots__  = ('name','hp','money','rank','mp','exp','attack','armor')

    def __init__(self,name='红莲之刃',hp = 900,money=1000,rank=0,exp=0,mp=400,armor =30,attack=80):
        super().__init__(name,hp,money,rank,exp,mp,armor,attack)
        self.skills = ['背后利刃', '风火轮', '天莲炫冲','回复']

    def common_Attack(self,other):
        """
        普通攻击
        :param other: 敌人
        :return: 随机伤害
        """
        damage_Value = self.attack - other.armor
        if damage_Value > 0:
            other.hp -= damage_Value
            return damage_Value
        else:
            return 0

    def small_Attack(self,other):
        if self.mp > 200:
            self.mp -= 200
            damage_value = randint(1,2) * self.attack - other.armor
            other.hp -= damage_value
            return True
        else:
            return False

    def big_Attack(self,other):
        if self.mp > 400:
            self.mp -= 400
            damage_value = 3*self.attack + randint(0,500) - other.armor
            other.hp -= damage_value
            return True
        else:
            return False
#-----------------------------------------------------------------------------------------------
class EkGunman(hero):#无影枪炮
    """
    无影枪炮英雄
    """
    __slots__ = ('name', 'hp', 'money', 'rank', 'mp', 'exp', 'attack', 'armor')

    def __init__(self, name='无影枪炮', hp=1200, money=1000, rank=0, exp=0, mp=600, armor=30, attack=70):
        super().__init__(name, hp, money, rank, exp, mp, armor, attack)
        self.skills = ['蜜汁炮弹', '激光炮', '离子机枪','回复']

    def common_Attack(self, other):
        """
        普通攻击
        :param other: 敌人
        :return: 随机伤害
        """
        damage_Value = self.attack - other.armor
        if damage_Value > 0:
            other.hp -= damage_Value
            return damage_Value
        else:
            return 0

    def small_Attack(self, other):
        if self.mp > 200:
            self.mp -= 200
            damage_value = 2 * self.attack - other.armor
            other.hp -= damage_value
            return True
        else:
            return False

    def big_Attack(self, other):
        if self.mp > 400:
            self.mp -= 400
            damage_value = 2.5 * self.attack + randint(0, 500) - other.armor
            other.hp -= damage_value
            return True
        else:
            return False

#-----------------------------------------------------------------------------------------------
class Monster(object):#怪兽基类
    __slots__ = ('name','hp','exp','money','attack','skill','armor')
    def __init__(self,name,hp=300,exp=100,money=120,attack = 100,armor = 0):
        self.name = name
        self.hp = hp
        self.exp = exp
        self.money = money
        self.attack = attack
        self.armor = armor
        self.skill = '打击'
    def m_isAlive(self):#判断怪兽是否活着
        if self.hp > 0:
            return True
        else:
            return False

    def Fir_attack(self, hero):
        # 攻击英雄，对其造成伤害
        damage_Value = randint(1,2)*self.attack - hero.armor
        if damage_Value > 0:
            hero.hp -= damage_Value
            return damage_Value
        else:
            return 0
    def back_hp(self,hp):
        self.hp = hp
    def __str__(self):
        return '名字:%s\t'%self.name+\
            '怪兽血量:%d\t'%self.hp +\
    '怪兽金币:%d\t'%self.money+\
    '怪兽经验:%d'%self.exp
#-----------------------------------------------------------------------------------
class FBoss(Monster):#怪兽BOSS1

    def __init__(self,name='枉死之身',hp=3500,exp=600,money=1000,attack= 300,armor=100):
        super().__init__(name,hp,exp,money,attack,armor)
        self.final_str = return_str('Boss1')
        self.mskills = ['打击','烈火咆哮','烈焰烧身','自杀']
        self.weapons = [w1,w2,w3,w4,w5,w6]
    def Sec_attack(self, hero):
        damage_Value =  self.attack + randint(300,600) - hero.armor
        if damage_Value > 0:
            hero.hp -= damage_Value
            return damage_Value
        else:
            return 0
    def Thr_attack(self,hero):
        damage_value = 3*self.attack +randint(300,1000) - hero.armor
        if damage_value > 0:
            hero.hp -= damage_value
            return damage_value
        else:
            return 0

    def commit_attack(self,hero):
        damage = self.hp // (1.5)
        hero.hp -= damage #Boss自杀，造成巨大伤害
        self.hp = 0
        return damage #伤害

def return_str(filename):
    f = open(filename+ '.txt','r',encoding='utf-8')
    s = f.read()
    f.close()
    return s
class ElectricFish(Monster):
    """
    电气八爪鱼#固定伤害输出
    """

    def __init__(self,name='电气八爪鱼',hp=6000,exp=1200,money=1800,attack=500,armor=180):
        super().__init__(name,hp,exp,money,attack,armor)
        self.mskills = ['压倒','暗之光芒','电闪雷鸣','魔电翻涌']
        self.weapons = [w1,w2,w3,w4,w6,w7]
        self.final_str = return_str('Boss2')
    def Sec_attack(self, hero):
        damage_Value =  randint(2,3)*self.attack + randint(300,1000) - hero.armor
        if damage_Value > 0:
            hero.hp -= damage_Value
            return damage_Value
        else:
            return 0
    def Thr_attack(self,hero):
        damage_value = randint(3,4)*self.attack + randint(400,1400) - hero.armor
        if damage_value > 0:
            hero.hp -= damage_value
            return damage_value
        else:
            return 0

    def commit_attack(self,hero):
        damage = 4000
        hero.hp -= 4000
        return damage
#-----测试字符串
# e1 = electricFish()
# print(e1.final_str)
#-------------------

class Terminator(Monster):
    def __init__(self,name='结合体莫卡伊',hp=15000,exp=2300,money=3000,attack=1250,armor=500):
        super().__init__(name,hp,exp,money,attack,armor)
        self.final_str = return_str('Boss3')
        self.mskills = ['麻痹','无双触手','分身怒吼','六子箴言咒']
        self.weapons = [w3,w4,w5,w6,w7,w8,w9,w10,w11]
    def Sec_attack(self, hero):
        damage_Value =  hero.hp // randint(3,4) - hero.armor
        if damage_Value > 0:
            hero.hp -= damage_Value
            return damage_Value
        else:
            return 0
    def Thr_attack(self,hero):
        damage_value = hero.hp // 3 - hero.armor
        if damage_value > 0:
            hero.hp -= damage_value
            return damage_value
        else:
            return 0

    def commit_attack(self,hero):
        damage_value = 8000
        hero.hp -=  damage_value
        return  damage_value
#--------------------------------------------------------------
#用户类

T = SkySprit()
R = RedLotus()
E = EkGunman()
# T.exp = 550
# print(T.hero_IsRank())
# print(T)
class Person():
    __slots__ = ('nickname','name','key_word','bank_money','Heros')

    def __init__(self,nick,name,word,money= 4000,):#参数有初始值就不要传参数
        self.nickname = nick
        self.name = name
        self.key_word = word
        self.bank_money = money#每个人特定银行卡有2000元，与个人账号绑定在一起
        self.Heros = [T,R,E]
    #为英雄充值金币用于购买装备
    def Recharge(self,hero,add_money):
        if self.bank_money > add_money:
            self.bank_money -= add_money
            hero.money += add_money
            return True
        else:
            return False

    def __str__(self):
        return '账号:%s\n' % self.name+\
    '密码%s\n' % self.key_word +\
    '玩家昵称:%s\n'%self.nickname+\
    '银行卡余额:%d\n'%self.bank_money
# p = Person('190832v','小飞','147258')
# for i in p.Heros:
#     print(i)
# person_list = []
# person_list.append(p)

# p1 = Person('1908ab','小康','147852')
# person_list.append(p1)
# for i in person_list:
#     print(i)
#----------------------------------------------------------------------------------
#显示敌人和英雄信息
def display_info(player,enemy):
    print(player)
    print(enemy)

#敌人随机发动技能:
def Enemy_attack(monster,other):
    rand_num = randint(1,100)
    if rand_num >= 90:#发动大招commit_attack
        print('%s对%s使用%s造成了%d点伤害' % (monster.name, other.name,monster.mskills[3],monster.commit_attack(other)))
    elif rand_num >= 80: #Thr_attack
        print('%s对%s使用了%s造成了%d点伤害' % (monster.name, other.name,monster.mskills[2],monster.Thr_attack(other)))
    elif rand_num >= 40:#Sec_attack
        print('%s对%s使用了%s造成了%d点伤害' %(monster.name,other.name,monster.mskills[1],monster.Sec_attack(other)))
    else:
        print('%s对%s使用了%s造成了%d点伤害' % (monster.name, other.name, monster.mskills[0], monster.Fir_attack(other)))
#--------------------------------------------------------------------------------

def fight_Devils(Role,Boss):#与boss对战
    #先记录各自的血量,以便战斗结束后回复血量
    _hp = Role.hp
    _mp = Role.mp
    Hp = Boss.hp
    while True:
        display_info(Role, Boss)
        fight_round = 1#---记录轮数---

        while Role.alive and Boss.m_isAlive():
            print('----第%02d回合--------' % fight_round)
            cho = input('请输入你释放的技能选项(输入其他就逃跑):1.%s\t2.%s\t3.%s\t4.%s' % (Role.skills[0], Role.skills[1], Role.skills[2],Role.skills[3]))
            if cho == '1':
                print('%s对%s使用了%s,造成了%d伤害' % (Role.name, Boss.name, Role.skills[0], Role.common_Attack(Boss)))
            elif cho == '2':
                if Role.small_Attack(Boss):
                    print('%s对%s使用了%s' % (Role.name,Boss.name, Role.skills[1]))
                else:
                    hurt = Role.common_Attack(Boss)
                    print('%s对%s使用了%s,造成了%d伤害' % (Role.name, Boss.name, Role.skills[0], hurt))
            elif cho == '3':
                if Role.big_Attack(Boss):
                    print('%s对%s使用了%s' % (Role.name, Boss.name, Role.skills[2]))
                    re_hp, re_mp = Role.resume()
                    print('%s使用大招后回复了%d点血量,%d点蓝量' % (Role.name,re_hp, re_mp))
                else:
                    print('蓝量不足_释放技能失败')
            elif cho == '4':
                Role.back_hp(_hp,_mp)
                print('你使用了回复满状态了!')
            else:
                print('-----逃跑成功-----')
                break
            Enemy_attack(Boss,Role)
            display_info(Role, Boss)
            fight_round += 1
            time.sleep(2)
        if Role.alive:
            c = input('是否回复血量值:1.Yes 2.NO')
            if c == '1':
                Role.back_hp(_hp, _mp)
            else:
                print('没加血要更加小心战斗哦!!')
            Role.hero_add_exp(Boss)
            Role.wins[Boss.name] = 1#标志获得勋章，打败了这只怪兽
            print('%s成功打败了%s,获得了%d金币,%d经验,获得了%s勋章' % (Role.name, Boss.name, Boss.money, Boss.exp,Boss.name))
            print(Boss.final_str)
            the_weapon = choice(Boss.weapons)
            for i in Role.weapons:
                if i.w_name == the_weapon.w_name:
                    print('怪兽掉落了一件%s,但是很遗憾背包中已经有了' % the_weapon.w_name)
                    break
            else:
                Role.Get_weapon(the_weapon)
                print('你得到了一件%s' % the_weapon.w_name)

            if Role.hero_IsRank():
                print('等级提升')
            else:
                pass

            print(Role)

        else:
            print('你被打死了!')
            print('别灰心，去努刷副本升级得装备和经验吧努力变得更强!加油----')
            print('----正在回复血量和mp中.会消耗一定金币哦，不然你无法站起来和小喵一起战斗了')
            Role.back_hp(_hp, _mp)
            print('回复成功！你又能站起来了!!!')
        Boss.back_hp(Hp) #Boss恢复血量
        num = input('是否继续战斗 1.Yes  2.NO-------')
        if num == '1':
            pass
        else:
            break  # 退出混沌之战，退出战斗

# T1 = SkySprit(hp=10000,money=1000,rank = 100,exp=20000,mp=3000,armor=400,attack = 2000)
#
# boss = Terminator()
# fight_Devils(T1,boss)
#-----------------
class Manger(object):
    def __init__(self,account = '1908328781',code='1472583690adc'):
        self.account = account
        self.code = code
        self.weapon_Shop = []

    def mange_weapon(self,add_weapon):#add_weapon要增加的武器对象
        self.weapon_Shop.append(add_weapon)
    #为商店添加
    def Add_weapons(self,newweapon):
        for i in self.weapon_Shop:
            if i.w_name == newweapon.w_name:#武器名字重复
                return False
        #前面没有找到重复的武器------>添加武器成功
        self.weapon_Shop.append(newweapon)
        return True
    #商店交货
    def del_weapons(self,del_name):#del_name要删除武器的名字
        for i in self.weapon_Shop:
            if i.w_name == del_name:
                self.weapon_Shop.remove(i)#找到了相同的武器名字移除
                return True
        return False


import re
import numpy as np

def find_max(list_of_rect):
    max_x = 0
    max_y = 0

    for rect in list_of_rect:
        x_coord = rect[0] + rect[2]
        y_coord = rect[1] + rect[3]
        if x_coord > max_x:
            max_x = x_coord
        if y_coord > max_y:
            max_y = y_coord

    return max_x, max_y

def calc_overlap(file_name):

    pattern = re.compile(r"#[0-9]* @ ([0-9]*),([0-9]*): ([0-9]*)x([0-9]*)")
    with open(file_name, "r") as f:
        shapes = [tuple(map(lambda x: int(x), pattern.match(line).groups())) for line in f.readlines()]
    # max_x, max_y = find_max(shapes)

    fabric = np.zeros(find_max(shapes))
    for shape in shapes:
        y_start, x_start, y_diff, x_diff = shape
        muster = np.ones((y_diff, x_diff))
        fabric[y_start:y_start+y_diff, x_start:x_start+x_diff] += muster

    overlap_cnt = len(np.where(fabric > 1)[0])

    return overlap_cnt

def calc_overlap_two(file_name, test_string=""):
    file = open(file_name, "r")
    lines = file.readlines()
    file.close()
    pattern = re.compile(r"#[0-9]* @ ([0-9]*),([0-9]*): ([0-9]*)x([0-9]*)")
    shapes = [tuple(map(lambda x: int(x), pattern.match(line).groups())) for line in lines]
    print(shapes)
    overlap = 0
    i = 0

    for shape in shapes:
        dagger_x = shape[0]
        dagger_y = shape[1]
        star_x = dagger_x + shape[2]
        minus_y = dagger_y + shape[3]
        for an_shape in shapes:

            if shape is an_shape[i:]:
                continue

            zero_x = an_shape[0]
            zero_y = an_shape[1]
            one_x = zero_x + an_shape[2]
            two_y = zero_y + an_shape[3]
            if zero_x >= star_x or dagger_x >= one_x or dagger_y >= two_y or zero_y >= minus_y:
                continue

            if zero_x > dagger_x:
                if dagger_y > zero_y:
                    overlap += (star_x - zero_x) * (two_y - dagger_y)
                else:
                    overlap += (star_x - zero_x) * (minus_y - zero_x)
            elif zero_x < dagger_x:
                if dagger_y > zero_y:
                    overlap += (one_x - dagger_x) * (two_y - dagger_y)
                else:
                    overlap += (one_x - dagger_x) * (minus_y - zero_y)
            else:
                overlap += shape[2] * an_shape[3]
        i += 1
    return overlap

file_name = "my_input.txt"

print(calc_overlap(file_name))


import hashlib
import time
import base64
from typing import List, Any
import requests

import json
from os import makedirs
from os.path import exists

INDEX_URL = 'https://spa6.scrape.center/api/movie?limit={limit}&offset={offset}&token={token}'
DETAIL_URL = 'https://spa6.scrape.center/api/movie/{id}?token={token}'
LIMIT = 10
OFFSET = 0
SECRET = 'ef34#teuq0btua#(-57w1q5o5--j@98xygimlyfxs*-!i-0-mb'

def get_token(args: List[Any]):
    '''
    获取接口token
    '''
    # 先将 /api/movie 放到一个列表里面；
    # 列表中加入当前时间戳；
    # 将列表内容用逗号拼接；
    # 将拼接的结果进行 SHA1 编码；
    # 将编码的结果和时间戳再次拼接；
    # 将拼接后的结果进行 Base64 编码。
    timestamp = str(int(time.time()))
    args.append(timestamp)
    sign = hashlib.sha1(','.join(args).encode('utf-8')).hexdigest()
    return base64.b64encode(','.join([sign, timestamp]).encode('utf-8')).decode('utf-8')

RESULTS_DIR = 'case_6/results'
exists(RESULTS_DIR) or makedirs(RESULTS_DIR)
def save_data(data):
    name = data.get('name')
    data_path = f'{RESULTS_DIR}/{name}.json'
    json.dump(data, open(data_path, 'w', encoding='utf-8'), ensure_ascii=False, indent=2)

args = ['/api/movie']
token = get_token(args=args)
index_url = INDEX_URL.format(limit=LIMIT, offset=OFFSET, token=token)
response = requests.get(index_url)
print('response', response.json())

result = response.json()
for item in result['results']:
    id = item['id']
    encrypt_id = base64.b64encode((SECRET + str(id)).encode('utf-8')).decode('utf-8')
    args = [f'/api/movie/{encrypt_id}']
    token = get_token(args=args)
    detail_url = DETAIL_URL.format(id=encrypt_id, token=token)
    response = requests.get(detail_url)
    # print('response', response.json())
    save_data(response.json())


from lxml import html
import requests, time

start_time = time.time()  # 初始时间戳
import jieba

seg_list = jieba.cut("我来到北京清华大学", cut_all=True)
print("Full Mode: " + "/ ".join(seg_list))  # 全模式

seg_list = jieba.cut("我来到北京清华大学", cut_all=False)
print("Default Mode: " + "/ ".join(seg_list))  # 精确模式

seg_list = jieba.cut("他来到了网易杭研大厦")  # 默认是精确模式
print(", ".join(seg_list))

seg_list = jieba.cut_for_search("小明硕士毕业于中国科学院计算所，后在日本京都大学深造")  # 搜索引擎模式
print(", ".join(seg_list))
# ================运行时间计时================
run_time = time.time() - start_time
if run_time < 60:  # 两位小数的秒
    print("耗时:{:.2f}秒".format(run_time))
elif run_time < 3600:  # 分秒取整
    print("耗时:{:.0f}分{:.0f}秒".format(run_time // 60, run_time % 60))
else:  # 时分秒取整
    print("耗时:{:.0f}时{:.0f}分{:.0f}秒".format(run_time // 3600, run_time % 3600 // 60, run_time % 60))


# -*- coding: utf-8 -*-
import re
import os
import scrapy
from ScrapyImage.items import ScrapyimageItem

class ScrapyimgSpider(scrapy.Spider):
    name = 'scrapyImg'
    allowed_domains = []
    start_urls = []
    with open('src_rtys6.csv', 'r') as f:
        while True:
            link = f.readline()
            if not link:
                break
            link = link.strip()
            if not re.match(r'http.*\.jpg', link):
                continue
            save_path = link.replace('http://', '').replace('https://', '')
            if os.path.isfile(save_path):
                continue
            start_urls.append(link)
    with open('src_rentiyishu.csv', 'r') as f:
        while True:
            link = f.readline()
            if not link:
                break
            link = link.strip()
            if not re.match(r'http.*\.jpg', link):
                continue
            save_path = link.replace('http://', '').replace('https://', '')
            if os.path.isfile(save_path):
                continue
            start_urls.append(link)

    def parse(self, response):
        item = ScrapyimageItem()
        item['name'] = response.url.replace('http://', '').replace('https://', '')
        item['data'] = response.body
        # print(item['name'])
        yield item


def isanagram( word1:str  , word2 :str)->bool:
     word1=word1.split()
     word2=word2.split()
     if(len(word1)!=len(word2)):
         return False
     else:
         if(word1.sort()==word2.sort()):
             return True
         else:
             return False
print(isanagram("note","tone"))


from abc import ABC, abstractmethod
from collections import namedtuple

import numpy as np
import torch

from cellbgnet.simulation import psf_kernel as psf_kernel

class Background(ABC):
    """
    Abstract background class. All childs must implement a sample method.
    """

    _forward_modes = ('like', 'cum', 'tuple')
    _bg_return = namedtuple('bg_return', ['xbg', 'bg'])  # return arguments, x plus bg and bg term alone

    def __init__(self, forward_return: str = None):
        """
        Args:
            forward_return: determines the return of the forward function. 'like' returns a sample of the same size
                as the input, 'cum' adds the sample to the input and 'tuple' returns both the sum and the bg component
                alone.
        """
        super().__init__()

        self.forward_return = forward_return if forward_return is not None else 'tuple'

        self.sanity_check()

    def sanity_check(self):
        """
        Tests the sanity of the instance.
        """

        if self.forward_return not in self._forward_modes:
            raise ValueError(f"Forward return mode {self.forward_return} unsupported. "
                             f"Available modes are: {self._forward_modes}")

    @abstractmethod
    def sample(self, size: torch.Size, device=torch.device('cpu')) -> torch.Tensor:
        """
        Samples from background implementation in the specified size.
        Args:
            size: size of the sample
            device: where to put the data
        Returns:
            background sample
        """
        raise NotImplementedError

    def sample_like(self, x: torch.Tensor) -> torch.Tensor:
        """
        Samples background in the shape and on the device as the the input.
        Args:
            x: input
        Returns:
            background sample
        """
        return self.sample(size=x.size(), device=x.device)

    def forward(self, x: torch.Tensor):
        """
        Samples background in the same shape and on the same device as the input x.
        Depending on the 'forward_return' attribute the bg is
            - returned alone ('like')
            - added to the input ('cum')
            - is added and returned as tuple ('tuple')
        Args:
            x: input frames. Dimension :math:`(N,C,H,W)`
        Returns:
            (see above description)
        """

        bg = self.sample_like(x)

        if self.forward_return == 'like':
            return bg

        elif self.forward_return == 'cum':
            return bg + x

        elif self.forward_return == 'tuple':
            return self._bg_return(xbg=x + bg, bg=bg)

        else:
            raise ValueError

class UniformBackground(Background):
    """
    Spatially constant background (i.e. a constant offset).
    """

    def __init__(self, bg_uniform: (float, tuple) = None, bg_sampler=None, forward_return=None):
        """
        Adds spatially constant background.
        Args:
            bg_uniform (float or tuple of floats): background value or background range. If tuple (bg range) the value
                will be sampled from a random uniform.
            bg_sampler (function): a custom bg sampler function that can take a sample_shape argument
        """
        super().__init__(forward_return=forward_return)

        if (bg_uniform is not None) and (bg_sampler is not None):
            raise ValueError("You must either specify bg_uniform XOR a bg_distribution")

        if bg_sampler is None:
            if isinstance(bg_uniform, (list, tuple)):
                self._bg_distribution = torch.distributions.uniform.Uniform(*bg_uniform).sample
            else:
                self._bg_distribution = _get_delta_sampler(bg_uniform)

        else:
            self._bg_distribution = bg_sampler

    @staticmethod
    def parse(param):
        return UniformBackground(param.Simulation.bg_uniform)

    def sample(self, size, device=torch.device('cpu')):

        assert len(size) in (2, 3, 4), "Not implemented size spec."

        # create as many sample as there are batch-dims
        bg = self._bg_distribution(sample_shape=[size[0]] if len(size) >= 3 else torch.Size([]))

        # unsqueeze until we have enough dimensions
        if len(size) >= 3:
            bg = bg.view(-1, *((1,) * (len(size) - 1)))

        return bg.to(device) * torch.ones(size, device=device)

def _get_delta_sampler(val: float):
    def delta_sampler(sample_shape) -> float:
        return val * torch.ones(sample_shape)

    return delta_sampler


# 给你两个非空的链表，表示两个非负的整数。它们每位数字都是按照逆序的方式存储的，并且每个节点只能存储一位数字
# 请你将两个数字相加，并以相同形式返回一个表示和的链表
# 你可以假设除了数字0之外，这两个数都不会以0开头

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

class Solution(object):
    def addTwoNumbers(self, l1, l2):
        carry = 0
        # dummy head
        head = curr = ListNode(0)
        while l1 or l2:
            val = carry
            if l1:
                val += l1.val
                l1 = l1.next
            if l2:
                val += l2.val
                l2 = l2.next
            curr.next = ListNode(val % 10)
            curr = curr.next
            carry = val / 10
        if carry > 0:
            curr.next = ListNode(carry)
        return head.next

if __name__ == '__main__':
    # begin
    # list_node1 = ListNode()
    # list_node2 = ListNode()
    s = Solution()
    print (s.addTwoNumbers([2,4,3], [5,6,4]))


import sqlite3
import sys
import time
import traceback

from google.cloud import translate

class GCTranslate():

    ddl = """
        CREATE TABLE IF NOT EXISTS gc_translate_cache (
            input TEXT NOT NULL,
            tgt TEXT NOT NULL,
            output TEXT NOT NULL,
            src TEXT NOT NULL,
            model TEXT NOT NULL,
            created_at REAL NOT NULL,
            PRIMARY KEY(input, tgt)
        )
    """

    def __init__(self, cache_path=None, local=False):
        if not cache_path and local:
            raise ValueError('local mode is enabled without cache_path')
        self.client = translate.Client()
        self.cache_path = cache_path
        self.local = local
        if cache_path:
            self.conn = sqlite3.connect(cache_path)
            self.conn.cursor().execute(self.ddl)
        else:
            self.conn = None
        self.n_requests = 0
        self.cache_hits = 0
        self.n_gct_requests = 0

    def __del__(self):
        if self.n_requests:
            print('Cache hit ratio: {:.4f}'.format(
                self.cache_hits/self.n_requests), file=sys.stdout)
        if self.conn:
            self.conn.close()

    def translate(self, inp, tgt, src=None, model='nmt'):
        self.n_requests += 1
        if self.conn:
            cursor = self.conn.cursor()
            translatedText = self.lookup_cache(cursor, inp, tgt)
            if translatedText:
                return translatedText

            if self.local:
                return None

            translatedText = self.google_cloud_translate(inp, tgt, src, model)

            try:
                if src is None:
                    src = ''
                if model is None:
                    model = 'nmt'
                cursor.execute("""
                    REPLACE INTO gc_translate_cache
                        (input, tgt, output, src, model, created_at)
                    VALUES
                        (?, ?, ?, ?, ?, ?)
                """, (inp, tgt, translatedText, src, model, time.time()))
                self.conn.commit()
            except Exception:
                traceback.print_exc()

            return translatedText
        else:
            return self.google_cloud_translate(inp, tgt, src, model)

    def google_cloud_translate(self, inp, tgt, src, model):
        self.n_gct_requests += 1
        translation = self.client.translate(
            inp, target_language=tgt, source_language=src, model=model)
        return translation['translatedText']

    def lookup_cache(self, cursor, inp, tgt):
        cursor.execute(
            'SELECT output FROM gc_translate_cache WHERE input = ? and tgt = ?', (inp, tgt))
        data = cursor.fetchone()
        if data:
            self.cache_hits += 1
            return data[0]
        else:
            return None

    def print_stats(self):
        print('requests: {:d} google requests {:d} cache hits: {:.3f}'.format(
            self.n_requests, self.n_gct_requests, self.cache_hits/self.n_requests if self.n_requests else 0))


"""Declare all global constants."""

COMMANDS = {
    "start": "Check whether I am alive",
    "forward": "Settings for Bot",
    "remove": "Update the bot",
    "help": "Contact Owner",
}

REGISTER_COMMANDS = True

KEEP_LAST_MANY = 10000

CONFIG_FILE_NAME = "tgcf.config.yml"
CONFIG_ENV_VAR_NAME = "TGCF_CONFIG"

class BotMessages:
    """Messages given by the bot to users."""

    # pylint: disable=too-few-public-methods
    start = "Hi! I am alive"
    bot_help = "Buy Your Own Bot @Gamer_4560"


from fastapi.encoders import jsonable_encoder

from app import settings
from app.repository import get_db_client
from app.schemas.model import ModelCreateSchema, ModelSchema

class ModelCollectionRepository:

    @staticmethod
    def insert(model: ModelCreateSchema):
        with get_db_client() as db_client:
            db_client = db_client[settings.DB_NAME]
            models_collection = db_client['models']
            if not models_collection.find_one({"code": model.code}):
                models_collection.insert_one(jsonable_encoder(model))

    @staticmethod
    def find_one(model: ModelCreateSchema):
        with get_db_client() as db_client:
            db_client = db_client["fipe_db"]
            models_collection = db_client['brands']
            brand = models_collection.find_one({"code": model.code})
        return brand

    @staticmethod
    def find(model: ModelCreateSchema):
        with get_db_client() as db_client:
            db_client = db_client["fipe_db"]
            models_collection = db_client['brands']
            brands = [ModelSchema(model) for model in models_collection.find({"code": model.code})]
        return brands


# 3개의 주사위를 던져서 상금을 받는다
# 1. 같은 눈이 3개 나오면 10000+(같은눈)*1000
# 2. 같은 눈이 2개만 나오면 1000+(같은눈)*100
# 3. 모두 다른 눈이 나오면 (가장 큰 눈)*100
# n명이 주사위 게임해서 가장 많은 상금을 받은 사람의 상금 출력
n = int(input())
dices = []
result = []
for _ in range(n):
    dices.append(list(map(int, input().split())))
for dice in dices:
    dice.sort()
    cnt = 0
    for i in range(2):
        if dice[i] == dice[i+1]:
            cnt += 1
    if cnt == 2:
        result.append(10000 + dice[1] * 1000)
    elif cnt == 1:
        result.append(1000 + dice[1] * 100)
    else:
        result.append(max(dice)*100)
print(max(result))


import torchvision

from torchvision import datasets, transforms

if __name__ == "__main__":
    mnist_dataset = torchvision.datasets.MNIST(root='./data',
                               train=True,
                               transform=None,
                               target_transform=None,
                               download=True)

    print(len(mnist_dataset.train_data))
    print(mnist_dataset[0])

    print("**transform operation**")
    my_transform = transforms.Compose([transforms.ToTensor(),
                                      transforms.Normalize((0.5), (0.5))
                                      ])
    # Read MNIST dataset and perform data transformation at the same time
    mnist_dataset = datasets.MNIST(root='./data',
                                   train=False,
                                   transform=my_transform,
                                   target_transform=None,
                                   download=True)
    item = mnist_dataset.__getitem__(0)
    print(type(item[0]))


import logging
from typing import Callable

import watchdog.events  # type: ignore

CallbackFn = Callable[[], None]
CreatedCallbackFn = Callable[[str], None]

logger = logging.getLogger(__name__)

class SCBWatcher(watchdog.events.PatternMatchingEventHandler):
    """Monitors a directory for changes to CTS Startlist files"""

    def __init__(self, callback: CallbackFn):
        super().__init__(patterns=["*.scb"], ignore_directories=True)
        self._callback = callback

    def on_any_event(self, event: watchdog.events.FileSystemEvent):
        # Limit triggering to only events that modify the contents to avoid
        # creating a loop
        if event.event_type in [
            watchdog.events.EVENT_TYPE_CREATED,
            watchdog.events.EVENT_TYPE_DELETED,
            watchdog.events.EVENT_TYPE_MODIFIED,
            watchdog.events.EVENT_TYPE_MOVED,
        ]:
            logger.debug(
                "SCBWatcher: operation=%s, path=%s", event.event_type, event.src_path
            )
            self._callback()

class DO4Watcher(watchdog.events.PatternMatchingEventHandler):
    """Monitors a directory for new .do4 race result files"""

    def __init__(self, callback: CreatedCallbackFn):
        super().__init__(patterns=["*.do4"], ignore_directories=True)
        self._callback = callback

    def on_created(self, event: watchdog.events.FileCreatedEvent):
        logger.debug(
            "DO4Watcher: operation=%s, path=%s", event.event_type, event.src_path
        )
        self._callback(event.src_path)


import streamlit as st
import pickle

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from ast import literal_eval
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import warnings
warnings.filterwarnings('ignore')

movie_df = pd.read_csv("movies.csv")
movie_keywords = pd.read_csv("keywords.csv")
movie_credits = pd.read_csv("credits.csv")

movie_df = movie_df[['id','original_title','overview','genres']]

movie_df["title"] = movie_df["original_title"].copy()
movie_df.reset_index(inplace=True, drop=True)

movie_df["id"] = movie_df["id"].astype(int)
df = pd.merge(movie_df, movie_keywords, on="id")

df = pd.merge(df, movie_credits, on="id")

df["overview"] = df["overview"].fillna("[]")

df["genres"] = df["genres"].apply(lambda x: [i["name"] for i in eval(x)])
df["genres"] = df["genres"].apply(lambda x: ' '.join([i.replace(" ","") for i in x]))

df["keywords"] = df["keywords"].apply(lambda x: [i["name"] for i in eval(x)])
df["keywords"] = df["keywords"].apply(lambda x: ' '.join([i.replace(" ","") for i in x]))

df["director"] = df["crew"].apply(literal_eval).apply(lambda x: [i["name"] for i in x if i["job"]=="Director"])
df["director"] = df["director"].apply(lambda x: ' '.join([i.replace(" ","") for i in x]))

df.drop("crew", axis=1, inplace=True)

df["cast"] = df["cast"].apply(lambda x: [i["name"][:5] for i in eval(x)])
df["cast"] = df["cast"].apply(lambda x: ' '.join([i.replace(" ","") for i in x]))

df["tags"] = df["overview"] + " " + df["genres"] + " " + df["original_title"] + " " + df["keywords"] + " " + df["cast"] + " " + df["director"] + " " +  df["director"] + " " + df["director"]

df.drop(columns=["overview", "original_title", "keywords", "cast"], axis=1, inplace=True)

df.drop_duplicates(inplace=True)

tfidf = TfidfVectorizer(analyzer='word',ngram_range=(1, 2),min_df=0, stop_words='english')
vectorized_df = tfidf.fit_transform(df["tags"])

cosine_sim = cosine_similarity(vectorized_df)

def recommendation_title(title):
    id_recom = df[df["title"]==title].index[0]
    distances = cosine_sim[id_recom]
    top_list = sorted(list(enumerate(distances)), reverse=True, key=lambda x:x[1])[1:10]
    movie_list = []
    ids = []
    for i in top_list:
        movie_list.append(df.iloc[i[0]].title)
        ids.append(df.iloc[i[0]].id)
    return movie_list

def recommendation_genre(genre):
    id_recom = df[df["genres"]==genre].index[0]
    distances = cosine_sim[id_recom]
    top_list = sorted(list(enumerate(distances)), reverse=True, key=lambda x:x[1])[1:10]
    movie_list = []
    ids = []
    for i in top_list:
        movie_list.append(df.iloc[i[0]].title)
        ids.append(df.iloc[i[0]].id)
    return movie_list

def recommendation_director(director):
    id_recom = df[df["director"]==director].index[0]
    distances = cosine_sim[id_recom]
    top_list = sorted(list(enumerate(distances)), reverse=True, key=lambda x:x[1])[1:10]
    movie_list = []
    ids = []
    for i in top_list:
        movie_list.append(df.iloc[i[0]].title)
        ids.append(df.iloc[i[0]].id)
    return movie_list

pickle.dump(df.to_dict(),open('movies.pkl','wb'))

pickle.dump(cosine_sim,open('similarity.pkl','wb'))

st.title('Movies Recommendation System')
movies=pickle.load(open('./movies.pkl','rb'))
movies=pd.DataFrame(movies)
similarity=pickle.load(open('./similarity.pkl','rb'))

criteria = st.selectbox('Select Criteria for Recommendation', options= ['Title','Genre','Director'],index=0)

if criteria == "Title":
    selected = st.selectbox('Select',df['title'].values)
    if st.button('Recommend'):
        names = recommendation_title(selected)
        st.write(''' ## Top Five Recommended Movies: ''')
        st.text(names[0])
        st.text(names[1])
        st.text(names[2])
        st.text(names[3])
        st.text(names[4])

elif criteria == "Genre":
     selected = st.selectbox('Select',df['genres'].unique())
     if st.button('Recommend'):
        names = recommendation_genre(selected)
        st.write(''' ## Top Five Recommended Movies: ''')
        st.text(names[0])
        st.text(names[1])
        st.text(names[2])
        st.text(names[3])
        st.text(names[4])

else:
     selected = st.selectbox('Select',df['director'].unique())
     if st.button('Recommend'):
        names = recommendation_director(selected)
        st.write(''' ## Top Five Recommended Movies: ''')
        st.text(names[0])
        st.text(names[1])
        st.text(names[2])
        st.text(names[3])
        st.text(names[4])


from oci.object_storage import ObjectStorageClient
from ScoutSuite.providers.oci.authentication_strategy import OracleCredentials
from oci.pagination import list_call_get_all_results

from ScoutSuite.providers.utils import run_concurrently

class ObjectStorageFacade:
    def __init__(self, credentials: OracleCredentials):
        self._credentials = credentials
        self._client = ObjectStorageClient(self._credentials.config)

    async def get_namespace(self):
        response = await run_concurrently(
            lambda: list_call_get_all_results(self._client.get_namespace))
        # for some reason it returns a list of chars instead of a string
        return ''.join(response.data)

    async def get_bucket_details(self, namespace, bucket_name):
        response = await run_concurrently(
            lambda: self._client.get_bucket(namespace, bucket_name))
        return response.data

    async def get_buckets(self, namespace):
        response = await run_concurrently(
            lambda: list_call_get_all_results(self._client.list_buckets, namespace, self._credentials.compartment_id))
        return response.data

    async def get_bucket_objects(self, namespace, bucket_name):
        response = await run_concurrently(
            lambda: list_call_get_all_results(self._client.list_objects, namespace, bucket_name))
        return response.data


# Откройте сайт https://parsinger.ru/infiniti_scroll_1/ с помощью Selenium;
# На сайте есть список из 100 элементов, которые генерируются при скроллинге;
# В списке есть интерактивные элементы, по которым можно осуществить скроллинг вниз;
# Цель: получить все значение в элементах, сложить их;
# Получившийся результат вставить в поле ответа.

# Подсказка:
# Элементы могут грузится медленнее чем работает ваш код, установите задержки.
# Подумайте над условием прерывания цикла, последний элемент в списке имеет class="last-of-list"

import time
from selenium.webdriver import Keys
from selenium import webdriver
from selenium.webdriver.common.by import By

with webdriver.Chrome() as browser:
    browser.get('https://parsinger.ru/infiniti_scroll_1/')
    total = 0
    time.sleep(1)
    unique_tags = []
    scroll = False

    while not scroll:
        buttons = browser.find_element(By.ID, 'scroll-container').find_elements(By.TAG_NAME, 'span')
        for btn in buttons:
            tag_id = btn.get_attribute('id')
            if tag_id not in unique_tags:
                btn.find_element(By.TAG_NAME, 'input').send_keys(Keys.DOWN)
                total += int(btn.text)
                unique_tags.append(tag_id)
                time.sleep(0.5)
                try:
                    scroll = btn.get_attribute('class') == 'last-of-list'
                except:
                    continue
    print(total)

# 86049950


import sys
import os
import signal
import trace
import atexit
from xicam.core.args import parse_args
import ctypes

if os.name == 'nt':
    # https://stackoverflow.com/questions/67599432/setting-the-same-icon-as-application-icon-in-task-bar-for-pyqt5-application
    myappid = 'camera.xicam'  # arbitrary string
    ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)  # Allows taskbar icon to be shown on windows

print("args:", sys.argv)
print("path:", sys.path)

if sys.argv[0].endswith("Xi-cam"):
    root = os.path.dirname(sys.argv[0])
    sys.path = [path for path in sys.path if os.path.abspath(root) in os.path.abspath(path)]

# Quickly extract zip file to make imports easier
if ".zip/" in os.__file__:
    import zipfile

    zip_ref = zipfile.ZipFile(os.path.dirname(os.__file__), "r")
    zip_ref.extractall(os.path.dirname(os.path.dirname(os.__file__)))
    zip_ref.close()

os.environ["QT_API"] = "pyqt5"
import qtpy
from qtpy.QtWidgets import QApplication, QErrorMessage
from qtpy.QtCore import QCoreApplication, QProcess, QTimer

if qtpy.API_NAME == "PyQt5" and "PySide" in sys.modules:
    del sys.modules["PySide"]
elif qtpy.API_NAME == "PySide2" and "PyQt5" in sys.modules:
    del sys.modules["PyQt5"]

QCoreApplication.setOrganizationName("Camera")
QCoreApplication.setApplicationName("Xi-cam")

mainwindow = None
splash_proc = None
show_check_timer = None

def check_show_mainwindow():
    if splash_proc and splash_proc.state() == QProcess.NotRunning and mainwindow:
        # splash_proc.waitForFinished()
        mainwindow.show()
        mainwindow.activateWindow()
        show_check_timer.stop()

def _main(args, exec=True):
    global mainwindow, splash_proc, show_check_timer
    # import pydm
    # app = QApplication([])
    # app = pydm.PyDMApplication()
    app = QApplication.instance() or QApplication([])
    signal.signal(signal.SIGINT, signal.SIG_DFL)

    from xicam.gui.windows import splash
    from xicam.core import msg

    if getattr(args, 'verbose', False):
        QErrorMessage.qtHandler()

    # start splash in subprocess
    splash_proc = QProcess()
    # splash_proc.started.connect(lambda: print('started splash'))
    # splash_proc.finished.connect(lambda: print('finished splashing'))
    log_file = msg.file_handler.baseFilename
    initial_length = os.path.getsize(log_file)
    splash_proc.start(sys.executable, [splash.__file__, log_file, str(initial_length)])

    show_check_timer = QTimer()
    show_check_timer.timeout.connect(check_show_mainwindow)
    show_check_timer.start(100)

    from xicam.gui.windows.mainwindow import XicamMainWindow

    mainwindow = XicamMainWindow()

    if exec:
        return app.exec_()
    else:
        return mainwindow

def main():
    args = parse_args(exit_on_fail=True)
    if args.verbose > 1:
        tracer = trace.Trace(count=False, trace=True)
        tracer.run(f"_main(None)")  # TODO: map args into main
    else:
        return _main(args)

def exit_checks():
    from xicam.core import msg
    import threading
    msg.logMessage('Background threads:', threading.active_count()-1)
    # msg.logMessage('Active background threads:', len([thread for thread in threading.enumerate() if not isinstance(thread, threading._DummyThread)])-1)
    msg.logMessage('Active background threads:',
                   len(list(filter(lambda thread: not isinstance(thread, threading._DummyThread) and not thread.daemon,
                                   threading.enumerate())))-1)

    for thread in threading.enumerate():
        if thread is threading.current_thread() or isinstance(thread, threading._DummyThread) or thread.daemon:
            continue
        msg.logMessage('Waiting for thread:', thread.name)

        thread.join(timeout=3)
        msg.logError(TimeoutError(f'Thread named "{thread.name}" took too long to exit as Xi-CAM was closing. '
                                       # 'Please report this.')
        ))

atexit.register(exit_checks)

if __name__ == "__main__":
    return_code = main()
    sys.exit(return_code)


import imagehash
import os
from PIL import Image
import pickle

##Turn that for filename in dir do function into function that accepts function and params as param
PHASH_LOCATION = 'vynil_id/data/phashs.dat'
DISCOGS_IMAGE_DIRECTORY = 'raw_data/discogs_images'

def phash_collection(directory=False, candidates=False, **kwargs):

    if directory:
        phash_directory(directory)
    elif candidates:
        phash(candidates)
    pass

def read_phash(location):
    pass

def phash_directory(directory):
    hashs = {}
    for filename in os.listdir(directory):
        f = os.path.join(directory, filename)
        # checking if it is a file
        if os.path.isfile(f):
            image = Image.open(f)
            discogs_id = filename[:filename.index(".")]
            hash = phash(image)
            hashs[discogs_id] = hash
    with open(PHASH_LOCATION, 'wb') as f:
        pickle.dump(hashs, f)

def load_phash(directory):
    with open(directory, 'rb') as filename:
        hashs = pickle.load(filename)
    return hashs

def phash_candidates(candidates):
    hashs = []
    for candidate in candidates:
        hash = phash(candidate)
        hashs.append(hash)
    return hashs

def phash(image):
    hash = imagehash.average_hash(image)
    return(hash)

if __name__ == '__main__':
    phash_collection(directory=DISCOGS_IMAGE_DIRECTORY)
    hashs = load_phash(PHASH_LOCATION)
    print(hashs)


from motor.motor_asyncio import AsyncIOMotorDatabase
from typing import List
from database.scheme import SchemeConfig

async def find_employee(db: AsyncIOMotorDatabase,
                        names: List[str] = None, jobs: List[str] = None, companies: List[str] = None):
    employee = db[SchemeConfig.collection_employee]
    query = {}
    if names:
        query[SchemeConfig.employee_name] = {"$in": names}
    if jobs:
        query[SchemeConfig.employee_job_title] = {"$in": jobs}
    if companies:
        query[SchemeConfig.employee_company] = {"$in": companies}
    cursor = employee.find(query)
    return await cursor.to_list(None)


from __future__ import annotations

from typing import TYPE_CHECKING, Collection

import numpy as np
import pytest
from numpy.typing import NDArray
from stable_baselines3.common.env_checker import check_env

import qgym.spaces
from qgym.custom_types import Gate
from qgym.envs import Scheduling
from qgym.envs.scheduling import SchedulingState

if TYPE_CHECKING:
    MP_DICT = dict[
        str, int | dict[str, int] | dict[str, Collection[str] | dict[str, list[str]]]
    ]

@pytest.fixture
def diamond_mp_dict() -> MP_DICT:
    return {
        "n_qubits": 10,
        "gates": {
            "prep": 1,
            "x": 2,
            "y": 2,
            "z": 2,
            "h": 2,
            "cnot": 4,
            "swap": 3,
            "measure": 10,
        },
        "machine_restrictions": {
            "same_start": {"measure"},
            "not_in_same_cycle": {"x": ["y", "z"], "y": ["x", "z"], "z": ["x", "y"]},
        },
    }

@pytest.fixture
def diamond_env(diamond_mp_dict: MP_DICT) -> Scheduling:
    return Scheduling(diamond_mp_dict)

def naive_schedule_algorithm(
    scheduling_env: Scheduling, circuit: list[Gate] | None = None
) -> NDArray[np.int_]:
    obs, _ = scheduling_env.reset(options={"circuit": circuit})
    action = np.array([0, 0])
    done = False

    while not done:
        while obs["legal_actions"].any():
            action[0] = obs["legal_actions"].argmax()
            obs, _, done, _, _ = scheduling_env.step(action)

        action[1] = 1
        obs, _, done, _, _ = scheduling_env.step(action)
        action[1] = 0

    if not isinstance(scheduling_env._state, SchedulingState):
        raise TypeError("The state of the scheduling env is not correct.")
    return scheduling_env._state.circuit_info.schedule

def test_state(diamond_env: Scheduling) -> None:
    assert isinstance(diamond_env, Scheduling)
    assert isinstance(diamond_env._state, SchedulingState)

def test_observation_space(diamond_env: Scheduling) -> None:
    assert isinstance(diamond_env.observation_space, qgym.spaces.Dict)

    observation_space = [
        ("legal_actions", qgym.spaces.MultiBinary),
        ("gate_names", qgym.spaces.MultiDiscrete),
        ("acts_on", qgym.spaces.MultiDiscrete),
        ("dependencies", qgym.spaces.MultiDiscrete),
    ]

    for name, space_type in observation_space:
        space = diamond_env.observation_space[name]
        assert isinstance(space, space_type)

def test_action_space(diamond_mp_dict: MP_DICT) -> None:
    env = Scheduling(diamond_mp_dict, max_gates=100)

    assert isinstance(env.action_space, qgym.spaces.MultiDiscrete)

    assert [0, False] in env.action_space
    assert [0, 0] in env.action_space
    assert [0, 1] in env.action_space
    assert [0, True] in env.action_space
    assert [99, 0] in env.action_space
    assert [99, 1] in env.action_space

    assert [-1, 0] not in env.action_space
    assert [0, -1] not in env.action_space

    assert [100, 0] not in env.action_space
    assert [0, 2] not in env.action_space

    for _ in range(100):
        sample = env.action_space.sample()
        assert sample[0] in range(100)
        assert sample[1] in range(2)

def test_scheduled_after(diamond_mp_dict: MP_DICT) -> None:
    env = Scheduling(diamond_mp_dict, dependency_depth=2)
    circuit = [Gate("cnot", 1, 2), Gate("x", 2, 2), Gate("cnot", 1, 3)]
    obs, _ = env.reset(options={"circuit": circuit})

    expected_scheduled_after = np.zeros(400, dtype=int)
    expected_scheduled_after[0] = 1
    expected_scheduled_after[200] = 2

    assert (obs["dependencies"] == expected_scheduled_after).all()

def test_same_gates_commute(diamond_env: Scheduling) -> None:
    circuit = [Gate("cnot", 1, 2), Gate("cnot", 1, 2)]
    obs, _ = diamond_env.reset(options={"circuit": circuit})

    expected_scheduled_after = np.zeros(200, dtype=int)

    assert (obs["dependencies"] == expected_scheduled_after).all()

def test_legal_actions(diamond_env: Scheduling) -> None:
    circuit = [Gate("cnot", 1, 2), Gate("x", 2, 2), Gate("cnot", 1, 3)]
    obs, _ = diamond_env.reset(options={"circuit": circuit})

    expected_legal_actions = np.zeros(200, dtype=bool)
    expected_legal_actions[1] = True
    expected_legal_actions[2] = True

    assert (obs["legal_actions"] == expected_legal_actions).all()

def test_validity(diamond_env: Scheduling) -> None:
    check_env(diamond_env, warn=True)  # todo: maybe switch this to the gym env checker
    assert True

def test_full_cnot_circuit(diamond_env: Scheduling) -> None:
    circuit = [
        Gate("cnot", 0, 1),
        Gate("cnot", 2, 3),
        Gate("cnot", 4, 5),
        Gate("cnot", 6, 7),
        Gate("cnot", 8, 9),
    ]
    schedule = naive_schedule_algorithm(diamond_env, circuit=circuit)
    assert (schedule == np.zeros(5)).all()

def test_same_start_machine_restriction(diamond_env: Scheduling) -> None:
    circuit = [Gate("measure", 1, 1), Gate("y", 1, 1), Gate("measure", 0, 0)]
    schedule = naive_schedule_algorithm(diamond_env, circuit=circuit)
    assert (schedule == np.array([10, 0, 0])).all()

def test_not_in_same_cycle_machine_restriction(diamond_env: Scheduling) -> None:
    circuit = [Gate("x", 0, 0), Gate("y", 1, 1), Gate("y", 3, 3), Gate("z", 2, 2)]
    schedule = naive_schedule_algorithm(diamond_env, circuit=circuit)
    assert (schedule == np.array([0, 2, 2, 4])).all()

def test_parse_machine_properties() -> None:
    with pytest.raises(
        TypeError,
        match="<class 'int'> is not a supported type for 'machine_properties'",
    ):
        Scheduling._parse_machine_properties(1)  # type: ignore[arg-type]

def test_parse_random_circuit_mode() -> None:
    with pytest.raises(
        ValueError, match="'test' is not a supported random circuit mode"
    ):
        Scheduling._parse_random_circuit_mode("test")


import unittest
import json
import os
import numpy as np

from demask.utils import entropies, load_dataset, read_fasta, read_matrix, seq_matrix
from demask.matrix import get_subs_matrix, prepare_matrix
from demask.homologs import process_query, find_homologs
from demask.profiles import get_aligned_profile, get_weights
from demask.predict import compute_scores, read_coefficients

class TestMatrix(unittest.TestCase):
    def setUp(self):
        if os.path.exists("test/tmp.txt"):
            os.remove("test/tmp.txt")

    def test_load_dataset_col_order(self):
        # Ensure data cols can be in any order.
        d1 = load_dataset("test/data.txt")
        d2 = load_dataset("test/data_order.txt")
        self.assertEqual(d1, d2)

    def test_load_dataset_col_names(self):
        # Ensure custom column names can be specified.
        d1 = load_dataset("test/data.txt")
        d2 = load_dataset(
            "test/data_colnames.txt", cols=["Position", "wt", "Mutant", "fitness"]
        )
        self.assertEqual(d1, d2)

    def test_load_dataset_filtering(self):
        # Ensure synonymous variants and those with non-canonical WT
        # or variant AAs are ignored.
        d = load_dataset("test/data.txt")
        self.assertEqual(len(d), 380)

    def test_get_subs_matrix(self):
        d = load_dataset("test/data.txt")
        mat = get_subs_matrix(d)
        self.assertEqual(len(mat), 400)

    def test_get_subs_matrix_incomplete(self):
        # Ensure understandable exception is raised when a WT/var
        # combo is absent from the data.
        d = load_dataset("test/data_incomplete.txt")
        self.assertRaises(AssertionError, get_subs_matrix, d)

    def test_prepare_matrix_file(self):
        # Ensure matrix file is produced from a single data file.
        prepare_matrix("test/data.txt", "test/tmp.txt")
        self.assertTrue(os.path.isfile("test/tmp.txt"))

    def test_prepare_matrix_dir(self):
        # Ensure matrix file is produced from a directory of data.
        prepare_matrix("test/data", "test/tmp.txt")
        self.assertTrue(os.path.isfile("test/tmp.txt"))

    def tearDown(self):
        if os.path.exists("test/tmp.txt"):
            os.remove("test/tmp.txt")

class TestHomologs(unittest.TestCase):
    def test_process_query(self):
        with open("test/P46937.blast.json", "r") as f:
            query = json.load(f)["BlastOutput2"][0]
        hits = process_query(query)
        self.assertTrue(len(hits) == 50)

    def test_no_blast_hits(self):
        ## Uncomment this to actually run blastp:
        # find_homologs(
        #     "test/random.fa",
        #     blastp="/usr/local/ncbi/blast/bin/blastp",
        #     db="/Volumes/storage/db/uniref90.fasta",
        #     threads=2,
        #     outfile="test/random.a2m",
        # )
        seqs = read_fasta("test/random.a2m")
        self.assertEqual(len(seqs), 1)

class TestProfiles(unittest.TestCase):
    def test_get_weights(self):
        seqs = read_fasta("test/P46937.a2m", as_dict=False)
        aln = seq_matrix(seqs)[:, 1:]
        wts = get_weights(aln)
        self.assertTrue(np.all(wts > 0) and np.all(wts < 1))

    def test_get_aligned_profile(self):
        # Ensure sum of each row of output array is > 0 and <= 1.
        seqs = read_fasta("test/P46937.a2m", as_dict=False)
        aln = seq_matrix(seqs)[:, 1:]
        wts = get_weights(aln)
        profile = get_aligned_profile(aln, wts)
        sums = np.sum(profile, axis=1)
        self.assertTrue(np.all(sums > 0) and np.all(sums <= 1.01))

    def test_gaps_in_query(self):
        # demask should accept gaps in query, e.g. for true MSA input.
        seqs1 = read_fasta("test/test_aln_ungapped.a2m", as_dict=False)
        aln1 = seq_matrix(seqs1)
        seqs2 = read_fasta("test/test_aln_gapped.a2m", as_dict=False)
        aln2 = seq_matrix(seqs2)
        self.assertTrue(aln1.shape == aln2.shape and np.all(aln1 == aln2))

    def test_no_homologs(self):
        seqs = read_fasta("test/random.a2m", as_dict=False)
        aln = seq_matrix(seqs)[:, 1:]
        wts = get_weights(aln)
        profile = get_aligned_profile(aln, wts)
        self.assertTrue(np.all(profile == 1/20))

class TestPredict(unittest.TestCase):
    def setUp(self):
        self.seqs = read_fasta("test/P46937.a2m", as_dict=False)
        aln = seq_matrix(self.seqs)[:, 1:]
        profile = get_aligned_profile(aln)
        self.entropies = entropies(profile)
        self.log_profile = np.log2(profile + 1 / profile.shape[1])
        self.matrix = read_matrix("data/matrix.txt")
        self.coefs = read_coefficients("data/coefficients.txt")

    def test_compute_scores_string(self):
        # Ensure output file is written given WT sequence as a string.
        wt = self.seqs[0]
        predictions = compute_scores(wt, self.entropies, self.log_profile, self.matrix, self.coefs)
        self.assertEqual(len(predictions), len(self.seqs[0]) * 19)

    def test_compute_scores_list(self):
        # Ensure output file is written given WT sequence as a list.
        wt = list(self.seqs[0])
        predictions = compute_scores(wt, self.entropies, self.log_profile, self.matrix, self.coefs)
        self.assertEqual(len(predictions), len(self.seqs[0]) * 19)

    def test_compute_scores_array(self):
        # Ensure output file is written given WT sequence as an array.
        wt = np.array(list(self.seqs[0]))
        predictions = compute_scores(wt, self.entropies, self.log_profile, self.matrix, self.coefs)
        self.assertEqual(len(predictions), len(self.seqs[0]) * 19)

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


from __future__ import print_function, division

import numpy as np
import matplotlib.pyplot as plt

from skimage.io import imread
from skimage import data_dir
from skimage.transform import radon, rescale
import math
from numba import jit
import timeit
from scipy import sparse
import seaborn as sns
from sklearn.linear_model import Lasso

# image = imread(data_dir + "/phantom.png", as_grey=True)
# image = imread("bubbles.png", as_grey=True)  # 20180810
# image = imread("L.png", as_grey=True)  # 20180920
image = imread("dot3.png", as_grey=True)  # 20181109
# image = rescale(image, scale=0.4, mode='reflect')
image = rescale(image, scale=0.5, mode='reflect')

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 4.5))

ax1.set_title("Original")
ax1.imshow(image, cmap=plt.cm.Greys_r)

theta = np.linspace(0., 180., max(image.shape), endpoint=False)
# theta = np.linspace(0., 360., max(image.shape), endpoint=False)
sinogram = radon(image, theta=theta, circle=True)
ax2.set_title("Radon transform\n(Sinogram)")
ax2.set_xlabel("Projection angle (deg)")
ax2.set_ylabel("Projection position (pixels)")
ax2.imshow(sinogram, cmap=plt.cm.Greys_r,
           extent=(0, 180, 0, sinogram.shape[0]), aspect='auto')

fig.tight_layout()
plt.show()

# --Calc reconstruction
# -Parameters
# radian
theta_rad = theta * ( np.pi / 180.0 )

# Pixel pitch of original image (dx, dy)
dx = 1.0
dy = 1.0

# Pixel pitch of detector (du)
du = 1.0

# x-,y-plane Numbers of original image (Nx, Ny)
# Nx、Nyはそれぞれx面、y面の数なので、画素数+1となることに注意。
Nx = image.shape[0] + 1
Ny = image.shape[1] + 1

# Pixel Number of Detector (Nk)
Nk = max(image.shape)

# Data points of theta (Nc)
Nc = theta.shape[0]

# Origin of original image (bx, by)
# "//"は切り捨て除算
# 20180902 - begin # 原点も0.5だけずらす必要あり
bx = -(Nx-1) // 2 + 0.5
by = -(Ny-1) // 2 + 0.5
# bx = -(Nx-1) // 2
# by = -(Ny-1) // 2
# 20180902 - end

# Number of cross points for each line (Nv[k][theta]) - reshape after
Nv = np.empty

# System matrix (L) - reshape after
# 20180708 - begin
# 「画素数」は(Nx-1)*(Ny-1)
sL = np.zeros( (Nx-1) + (Ny-1) )
L = np.zeros( (Nk * Nc, (Nx-1) * (Ny-1) ) )
Lsp = sparse.lil_matrix( (Nk * Nc, (Nx-1) * (Ny-1) ) )
# 20180708 - end

# Reconstructed image (P[Nv*theta.shape[0]]) - reshape after
# 20180708 - begin
# 「画素数」は(Nx-1)*(Ny-1)
rho = np.zeros( (Nk, (Nx-1) * (Ny-1) ) )
rho_sp = np.zeros( (Nk,  (Nx-1) * (Ny-1) ) )
reconIm = np.zeros( ( (Nx-1), (Ny-1) ) )
reconIm_SIRT = np.zeros( ( (Nx-1), (Ny-1) ) )   # 20180917
reconIm_part = np.zeros( ( (Nx-1), (Ny-1) ) )
# 20180708 - end

# 呼び出されたインデックスの回数を保存
counterMap = np.zeros( (Nx, Ny) )

# Crosspoint specify array of x,y (alpha_x[k][theta][Nx], alpha_y[k][theta][Ny])
alpha_x = np.zeros(Nx)
alpha_y = np.zeros(Ny)
# 20180728 - begin
alpha_align_x = np.empty
alpha_align_y = np.empty
# 20180728 - end

# Crosspoint specify array (alpha_xy[k][theta][Nv]) - reshape after
alpha_xy = np.empty

# index
i_min = np.empty
i_max = np.empty
j_min = np.empty
j_max = np.empty

# index of reconstructed image data
# 20180708 - begin
i_m = np.zeros(Nx-1 + Ny-1)
j_m = np.zeros(Nx-1 + Ny-1)
# 20180708 - end

# Length btw. p1 and p2
d_conv = np.empty

# 光線・検出器の位置ベクトル確認用
chk1x = np.zeros((Nk, Nc))
chk1y = np.zeros((Nk, Nc))
chk2x = np.zeros((Nk, Nc))
chk2y = np.zeros((Nk, Nc))

# 光線とボクセルの交点を可視化する
crosspointsX = np.zeros( (Nk * Nc, Nx + Ny) )
crosspointsY = np.zeros( (Nk * Nc, Nx + Ny) )

# 20180707 - begin
print("sinogram.shape", sinogram.shape)
# 20180707 - end

# 関数定義
def pPos(alpha, p1, p2):
    return p1 + alpha * ( p2 - p1 )

def phi(alpha, p1, p2, b, d):
    return ( pPos(alpha, p1, p2) - b) / d

@jit
def calc_system_matrix(theta_rad, dx, dy, du, Nx, Ny, Nk, Nc, bx, by, Nv, sL, \
                       alpha_x, alpha_y, alpha_xy, i_min, i_max, j_min, j_max, i_m, j_m, \
                       d_conv, chk1x, chk1y, chk2x, chk2y, \
                       crosspointsX, crosspointsY):
    L = np.zeros( (Nk * Nc, (Nx-1) * (Ny-1) ) )  # 20180708
    #     L = np.zeros( (Nk * Nc, Nx * Ny) )
    for k in range(Nk):
        for t in range(Nc):
            # 回転行列
            U = np.matrix([[np.cos(theta_rad[t]), -np.sin(theta_rad[t])], [np.sin(theta_rad[t]), np.cos(theta_rad[t])]])
#             U = np.matrix([[np.cos(-theta_rad[t]), -np.sin(-theta_rad[t])], [np.sin(-theta_rad[t]), np.cos(-theta_rad[t])]])   # 20180920
# 20180902 - begin
#             p1x = float(np.dot(U, np.matrix( [[ (k-Nk/2.0)*du + du/2.0 ], [ -(Ny-1)*dy + dy/2.0 ]] ))[0])
#             p1y = float(np.dot(U, np.matrix( [[ (k-Nk/2.0)*du + du/2.0 ], [ -(Ny-1)*dy + dy/2.0 ]] ))[1])
# 20180902 - end
# 20180920 - begin  # p1とp2の位置関係が逆になっていたので修正。サイノグラムとシステム行列の検出器のインデックスの方向が逆だったので修正。
#             p1x = float(np.dot(U, np.matrix( [[ (Nk/2.0 - (k+1) )*du + du/2.0 ], [ -(Ny-1)*dy + dy/2.0 ]] ))[0])
#             p1y = float(np.dot(U, np.matrix( [[ (Nk/2.0 - (k+1) )*du + du/2.0 ], [ -(Ny-1)*dy + dy/2.0 ]] ))[1])
# 20180920 - end
# 20181109 - begin  # p1とp2の位置関係が逆になっていたので修正。
            p1x = float(np.dot(U, np.matrix( [[ (k-Nk/2.0)*du + du/2.0 ], [ (Ny-1)*dy + dy/2.0 ]] ))[0])
            p1y = float(np.dot(U, np.matrix( [[ (k-Nk/2.0)*du + du/2.0 ], [ (Ny-1)*dy + dy/2.0 ]] ))[1])
# 20181109 - end
            chk1x[k][t] = p1x
            chk1y[k][t] = p1y
# 20180902 - begin # y方向にも0.5だけずらさなければならないのでは?
            p2x = float(np.dot(U, np.matrix([[(k-Nk/2.0)*du + du/2.0 ], [ (Ny-1)*dy + dy/2.0 ]]))[0])
            p2y = float(np.dot(U, np.matrix([[(k-Nk/2.0)*du + du/2.0 ], [ (Ny-1)*dy + dy/2.0 ]]))[1])
# 20180902 - end
# 20180920 - begin
#             p2x = float(np.dot(U, np.matrix([[(Nk/2.0 - (k+1) )*du + du/2.0 ], [ (Ny-1)*dy + dy/2.0 ]]))[0])
#             p2y = float(np.dot(U, np.matrix([[(Nk/2.0 - (k+1) )*du + du/2.0 ], [ (Ny-1)*dy + dy/2.0 ]]))[1])
# 20180920 - end
# 20181109 - begin  # p1とp2の位置関係が逆になっていたので修正。
            p2x = float(np.dot(U, np.matrix([[(k-Nk/2.0)*du + du/2.0 ], [ -(Ny-1)*dy + dy/2.0 ]]))[0])
            p2y = float(np.dot(U, np.matrix([[(k-Nk/2.0)*du + du/2.0 ], [ -(Ny-1)*dy + dy/2.0 ]]))[1])
# 20181109 - end
            chk2x[k][t] = p2x
            chk2y[k][t] = p2y

            # p1x==p2x,p1y==p2yの場合はαの分母が0になってしまうので処理を分ける。
            if p1x != p2x and p1y != p2y:
                alpha_x = ( bx + np.array(np.arange(Nx)) * dx - p1x ) / ( p2x - p1x )
                alpha_y = ( by + np.array(np.arange(Ny)) * dy - p1y ) / ( p2y - p1y )
                alpha_xmin = np.min((alpha_x[0], alpha_x[Nx-1]))
                alpha_xmax = np.max((alpha_x[0], alpha_x[Nx-1]))
                alpha_ymin = np.min((alpha_y[0], alpha_y[Ny-1]))
                alpha_ymax = np.max((alpha_y[0], alpha_y[Ny-1]))
                alpha_min = np.max((alpha_xmin, alpha_ymin))
                alpha_max = np.min((alpha_xmax, alpha_ymax))
                if p1x < p2x:
                    if alpha_min == alpha_xmin:
                        i_min = 1
                    else:
                        i_min = math.ceil( phi(alpha_min, p1x, p2x, bx, dx) )  # 20180723
                    if alpha_max == alpha_xmax:
                        i_max = Nx - 1
                    else:
                        i_max = math.floor( phi(alpha_max, p1x, p2x, bx, dx) )
                    alpha_align_x = alpha_x[ i_min : i_max+1 ]  # 20180728

                else: # p1x > p2x
                    if alpha_min == alpha_xmin:
                        i_max = Nx - 2
                    else:
                        i_max = math.floor( phi( alpha_min, p1x, p2x, bx, dx) )
                    if alpha_max == alpha_xmax:
                        i_min = 0
                    else:
                        i_min = math.ceil( phi( alpha_max, p1x, p2x, bx, dx) )
                    # 20180728 - begin
                    temp_alpha_x = alpha_x[ i_min : i_max+1 ]
                    alpha_align_x = temp_alpha_x[::-1]
                    # 20180728 - end

                if p1y < p2y:
                    if alpha_min == alpha_ymin:
                        j_min = 1
                    else:
                        j_min = math.ceil( phi(alpha_min, p1y, p2y, by, dy) )  # 20180723
                    if alpha_max == alpha_ymax:
                        j_max = Ny - 1
                    else:
                        j_max = math.floor( phi(alpha_max, p1y, p2y, by, dy) )
                    alpha_align_y = alpha_y[ j_min : j_max+1 ] # 20180728

                else: # p1y > p2y
                    if alpha_min == alpha_ymin:
                        j_max = Ny - 2
                    else:
                        j_max = math.floor( phi( alpha_min, p1y, p2y, by, dy) )
                    if alpha_max == alpha_ymax:
                        j_min = 0
                    else:
                        j_min = math.ceil( phi( alpha_max, p1y, p2y, by, dy) )
                    # 20180728 - begin
                    temp_alpha_y = alpha_y[ j_min : j_max+1 ]
                    alpha_align_y = temp_alpha_y[::-1]
                    # 20180728 - end

                # αx、αyのi_min～i_max、j_min～j_maxのみ切り出したものを結合し、昇順にソート(sort)する。
                # 20180728 - begin
                alpha_xy = np.sort( np.unique( np.append( np.concatenate( (alpha_align_x, alpha_align_y), axis=0 ), alpha_min ) ) ) # 20180811
                # 20180728 - end
                Nv = len(alpha_xy)
                # 20180805 - begin
                alpha_ave  = ( alpha_xy[1 : Nv] + alpha_xy[0 : Nv - 1] ) / 2.0
                alpha_diff = ( alpha_xy[1 : Nv] - alpha_xy[0 : Nv - 1] )
                # 【メモ】i_min,i_maxを使っていない。i_m[0] = i_min, i_m[Nv-1] = i_maxか？
                #【メモ】αxyを作成するときにsortにかけているので、αx、αyをp1、p2の大小で並び順を直した意味がないのでは？
                i_m = np.floor( phi(alpha_ave, p1x, p2x, bx, dx) )
                j_m = np.floor( phi(alpha_ave, p1y, p2y, by, dy) )
                i_m = i_m.astype( np.int64 )
                j_m = j_m.astype( np.int64 )
                d_conv = np.sqrt( (p2x - p1x)**2 + (p2y - p1y)**2 )
                sL = alpha_diff * d_conv
                # 20180805 - end

            elif p1x == p2x:
                alpha_y = ( by + np.array(np.arange(Ny)) * dy - p1y ) / ( p2y - p1y )
                # 20180723 - begin
                alpha_ymin = np.min( (alpha_y[0], alpha_y[Ny-1]) )
                alpha_ymax = np.max( (alpha_y[0], alpha_y[Ny-1]) )
                # 20180723 - end
                alpha_min = alpha_ymin
                alpha_max = alpha_ymax
                # 20180726 - begin
                if p1y < p2y:
                    j_min = 1
                    j_max = Ny - 1
                    alpha_align_y = alpha_y[ j_min : j_max+1 ]  # 20180728
                else:
                    j_min = 0
                    j_max = Ny - 2
                    # 20180728 - begin
                    temp_alpha_y = alpha_y[ j_min : j_max+1 ]
                    alpha_align_y = temp_alpha_y[::-1]
                    # 20180728 - end
                # 20180726 - end
                # 20180728 - begin
                alpha_xy = np.sort( np.append( alpha_align_y, alpha_min ) )
                # 20180728 - end
                Nv = len(alpha_xy)
                # 20180805 - begin
                alpha_ave  = ( alpha_xy[1 : Nv] + alpha_xy[0 : Nv - 1] ) / 2.0
                alpha_diff = ( alpha_xy[1 : Nv] - alpha_xy[0 : Nv - 1] )
                # 【メモ】i_min,i_maxを使っていない。i_m[0] = i_min, i_m[Nv-1] = i_maxか？
                #【メモ】αxyを作成するときにsortにかけているので、αx、αyをp1、p2の大小で並び順を直した意味がないのでは？
                i_m = np.floor( ( p1x * np.ones( len(alpha_ave) ) - bx ) / dx )
                j_m = np.floor( phi(alpha_ave, p1y, p2y, by, dy) )
                i_m = i_m.astype( np.int64 )
                j_m = j_m.astype( np.int64 )
                d_conv = np.sqrt( (p2x - p1x)**2 + (p2y - p1y)**2 )
                sL = alpha_diff * d_conv
                # 20180805 - end

            elif p1y == p2y:
                alpha_x = ( bx + np.array(np.arange(Nx)) * dx - p1x) / ( p2x - p1x )
                # 20180723 - begin
                alpha_xmin = np.min( (alpha_x[0], alpha_x[Nx-1]) )
                alpha_xmax = np.max( (alpha_x[0], alpha_x[Nx-1]) )
                # 20180723 - end
                alpha_min = alpha_xmin
                alpha_max = alpha_xmax
                # 20180726 - begin
                if p1x < p2x:
                    i_min = 1
                    i_max = Nx - 1
                    alpha_align_x = alpha_x[ i_min : i_max+1 ]  # 20180728
                else:
                    i_min = 0
                    i_max = Nx - 2
                    # 20180728 - begin
                    temp_alpha_x = alpha_x[ i_min : i_max+1 ]
                    alpha_align_x = temp_alpha_x[::-1]
                    # 20180728 - end
                # 20180726 - end
                # 20180728 - begin
                alpha_xy = np.sort( np.append( alpha_align_x, alpha_min ) )
                # 20180728 - end
                Nv = len(alpha_xy)
                # 20180805 - begin
                alpha_ave  = ( alpha_xy[1 : Nv] + alpha_xy[0 : Nv - 1] ) / 2.0
                alpha_diff = ( alpha_xy[1 : Nv] - alpha_xy[0 : Nv - 1] )
                # 【メモ】i_min,i_maxを使っていない。i_m[0] = i_min, i_m[Nv-1] = i_maxか？
                #【メモ】αxyを作成するときにsortにかけているので、αx、αyをp1、p2の大小で並び順を直した意味がないのでは？
                i_m = np.floor( phi(alpha_ave, p1x, p2x, bx, dx) )
                j_m = np.floor( ( p1y * np.ones( len(alpha_ave) ) - by ) / dy )
                i_m = i_m.astype( np.int64 )
                j_m = j_m.astype( np.int64 )
                d_conv = np.sqrt( (p2x - p1x)**2 + (p2y - p1y)**2 )
                sL = alpha_diff * d_conv
                # 20180805 - end

            # 光線とボクセルの交点を可視化するために交点座標を保存 - [0]
            # 要素数160以下のalpha_xyを要素数161*161のcrosspointsX/Yに代入するためにパディング
            crosspointsX_ = p1x + alpha_xy * ( p2x - p1x )
            crosspointsY_ = p1y + alpha_xy * ( p2y - p1y )
            crosspointsX[ Nc * k + t ][:] = np.pad( crosspointsX_, (0, Nx + Ny - len(crosspointsX_)), 'constant', constant_values=0 )
            crosspointsY[ Nc * k + t ][:] = np.pad( crosspointsY_, (0, Nx + Ny - len(crosspointsY_)), 'constant', constant_values=0 )
            # - [0]
            ssL = np.zeros( (Nx-1) * (Ny-1) )  # 20180708
            for m in range( len(sL) ):
                ssL[ (Nx-1) * i_m[m] + j_m[m] ] = sL[m]  # 20180708
            L[ Nc * k + t ][:] = ssL

    return L

# システム行列の計算
print( calc_system_matrix(theta_rad, dx, dy, du, Nx, Ny, Nk, Nc, bx, by, Nv, sL, \
                       alpha_x, alpha_y, alpha_xy, i_min, i_max, j_min, j_max, i_m, j_m, \
                       d_conv, chk1x, chk1y, chk2x, chk2y, \
                       crosspointsX, crosspointsY).shape )
L = calc_system_matrix(theta_rad, dx, dy, du, Nx, Ny, Nk, Nc, bx, by, Nv, sL, \
                       alpha_x, alpha_y, alpha_xy, i_min, i_max, j_min, j_max, i_m, j_m, \
                       d_conv, chk1x, chk1y, chk2x, chk2y, \
                       crosspointsX, crosspointsY)

timecheck = timeit.timeit( "calc_system_matrix(theta_rad, dx, dy, du, Nx, Ny, Nk, Nc, bx, by, Nv, sL, \
                      alpha_x, alpha_y, alpha_xy, i_min, i_max, j_min, j_max, i_m, j_m, \
                      d_conv, chk1x, chk1y, chk2x, chk2y, \
                      crosspointsX, crosspointsY)", globals=globals(), number=1 )
print( "time of calc_system_matrix",  timecheck )

# 疎行列に変換
Lsp = sparse.lil_matrix(L)
Lsp = Lsp.tocsc()
LspT = Lsp.T.tocsr()

# system行列を可視化してみる
x = np.arange(Nx * Ny)
y = np.arange(Nc)
X, Y = np.meshgrid(x, y)
plt.figure(figsize=(10,10))
sns.heatmap(Lsp.toarray()[Nc * 80 : Nc * 81, :(Nx*Ny)])

# 光線とボクセルの交点を可視化 - start
fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(1,1,1)
for t in range(Nc):
    ax.scatter(crosspointsX[ Nc * 80 + t ][:], crosspointsY[ Nc * 80 + t ][:], marker=".")
ax.scatter(chk1x[80][:], chk1y[80][:], marker=".")
ax.scatter(chk2x[80][:], chk2y[80][:], c='orange', marker=".")
ax.set_xlabel('x')
ax.set_ylabel('y')
# 光線とボクセルの交点を可視化 - end

# 表示して確認 - start
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.scatter(chk1x[0][:], chk1y[0][:], marker=".")
ax.scatter(chk2x[0][:], chk2y[0][:], c='orange', marker=".")
ax.set_title('k=0 scatter plot')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_aspect('1.0')
# 表示して確認 - end

# 光源と検出器の位置がずれていないか確認 - start
fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(1,1,1)
ax.scatter(crosspointsX[Nc * 60 + 0][:], crosspointsY[ Nc * 60 + 0 ][:], marker=".")
ax.scatter(chk1x[80][:], chk1y[80][:], marker=".")
ax.scatter(chk2x[80][:], chk2y[80][:], c='orange', marker=".")
ax.set_xlabel('x')
ax.set_ylabel('y')
# 光線とボクセルの交点を可視化 - end

# ----

#20180917 - SIRTの実装
def SIRT(W, p, Nm, Nn, Ni):
    # Ni : Number of iteration
    R = sparse.lil_matrix((Nm, Nm))
    C = sparse.lil_matrix((Nn, Nn))

    W_rowsum = W.sum(axis=0)
    W_colsum = W.sum(axis=1)
    R_temp =  np.ravel( 1 / W_colsum )
    C_temp =  np.ravel( 1 / W_rowsum )
    R = sparse.diags(R_temp, 0).tocsr()
    C = sparse.diags(C_temp, 0).tocsr()

    v = np.zeros(Nn)
    v = sparse.lil_matrix(v).tocsr()
    for i  in range(Ni-1):
        WPD = R.dot( p.T - W.dot(v.T) ).tocsr()  # Weighted Projection Difference
        WBP = C.dot( W.T.dot(WPD) ).tocsr()  # Weighted BackProjection
        v.T = v.T + WBP

    return v.T

Ni = 100

y = sparse.lil_matrix( sinogram.flatten() ).tocsc()
x = sparse.lil_matrix( np.zeros( Lsp.shape[1] ) ).tocsr()
x = SIRT(Lsp, y, Lsp.shape[0], Lsp.shape[1], Ni)

reconIm_SIRT = np.reshape(x.todense(), (Nx-1, Ny-1))

# 回転角方向に間引く(LASSOとの比較のため) - begin
Nstep_c_SIRT = 10
abstL_SIRT = Lsp[:Nc][:]
partL_c_SIRT = abstL_SIRT[::Nstep_c_SIRT][:]
part_y_c_SIRT = sparse.lil_matrix( np.ravel( sinogram[0][::Nstep_c_SIRT]) ).tocsc()

for k in range( 1, Nk ):
    # 一旦、Nc行分だけ抜き出す
    abstL_SIRT = Lsp[ Nc * k : Nc * ( k + 1 ) ][:]
    # 間引く
    tempL_c_SIRT = abstL_SIRT[::Nstep_c_SIRT][:]
    partL_c_SIRT = sparse.vstack( ( partL_c_SIRT, tempL_c_SIRT ) )

    abst_y_SIRT = sparse.lil_matrix( sinogram[k][::Nstep_c_SIRT] ).tocsc()
    part_y_c_SIRT = sparse.hstack( ( part_y_c_SIRT, abst_y_SIRT ) )

x0_c_SIRT = partL_c_SIRT.T.dot(part_y_c_SIRT.T).tocsc()
x_c_SIRT = x0_c_SIRT
x_part_c_SIRT = SIRT(partL_c_SIRT, part_y_c_SIRT, partL_c_SIRT.shape[0], partL_c_SIRT.shape[1], Ni)
reconIm_part_c_SIRT = np.reshape( x_part_c_SIRT.todense(), (Nx-1, Ny-1) )
# 回転角方向に間引く(LASSOとの比較のため) - end

# ２次元に戻す
plt.figure( figsize=(8, 8) )
plt.pcolor(np.array(reconIm_SIRT.T))

plt.figure( figsize=(8, 8) )
plt.pcolor(np.array(reconIm_part_c_SIRT.T))

# ---

# 最小二乗法のiteration回数の指定  # 20180717
Ni = 1000

# 検出器のラベルごとに分解して線型方程式の解を求める
for k in range(Nk):
    partL = Lsp[ Nc * k : Nc * k + Nc ][:]   #csc
    d = sinogram[k][:].flatten()

    # 20180717 - begin
    X = sparse.linalg.lsmr(partL, d, damp=0.0, atol=0.0, btol=0.0, conlim=100000000.0, maxiter=None, show=False, x0=None)
    # 20180718 - end

    rho[k][:] = X[0]

    # 2次元に戻す
    reconIm = reconIm + np.reshape( rho[k][:], (Ny-1, Nx-1) )  # 20180709

# 結果を表示
plt.figure( figsize=(8, 8) )
plt.pcolor(reconIm.T)

# ---

# 軟判定しきい値関数
def SoftThr(x,lam):
    z = np.zeros(x.shape).astype(np.float32)
    mask = x > lam
    z = z + (x - lam) * mask
    mask = x < -lam
    z = z + (x + lam) * mask
    return z

# LASSOの誤差関数
def loss_LASSO(A, x, y, lam):
    v = y.T - A.dot(x).tocsr() # CSR
    cost = sparse.linalg.norm(v, ord='fro')**2 # Frobenius norm (Same as ord=2 in numpy.linalg.norm)
    cost = 0.5 * cost + lam * sparse.linalg.norm(x, ord=1)
    return cost

def ISTA(A, x, y, lam, L0):  # Assume A,y,x are CSC
    kx = x  # CSC
    v = y.T - A.dot(x).tocsr()  # CSR
    ktemp = 0.5 * sparse.linalg.norm(v, ord='fro')**2
    L = L0

    grad_x = -A.T.dot(v).tocsc() / lam  # CSC
    MMx = x - grad_x / L # CSC
    MMv = y.T - A.dot(MMx).tocsr() # CSR
    temp = 0.5 * sparse.linalg.norm(MMv, ord='fro')**2
    Diffx = MMx - kx # CSC

    MMtemp = ktemp + grad_x.T.dot(Diffx.tocsr()).todense() + 0.5 * L * sparse.linalg.norm(Diffx, ord='fro')**2
    # ラインサーチ法を入れるとMMx=xとなるまでMMxを更新してしまう。
#     while MMtemp < temp:
#         L = L * 1.1
#         MMx = x - grad_x / L  # CSC
#         print("<1.1> x, MMx", x[0][0], MMx[0][0])
#         temp = 0.5 * sparse.linalg.norm(y.T - A.dot(MMx), ord='fro')**2
#         Diffx2 = MMx - kx  # CSC
#         MMtemp = ktemp + grad_x.T.dot(Diffx2.tocsr()).todense() + 0.5 * L * sparse.linalg.norm(Diffx2, ord='fro')**2

    # SoftThrの計算が間違っていそう
    # Matrix型の変数を与えているので、ndarrayで計算できていたアルゴリズムが正しく動いていない？
    # -> 正解。SoftThrに与える時にxをtodense()でmatrix型として与えてしまっていた。toarray()で与えることでndarray型で渡すことができる。
    # 20181123 - begin
    x_out = SoftThr(MMx.toarray(), 1 / L)
    x_out = sparse.lil_matrix(x_out).tocsc()
#     x = SoftThr(MMx.toarray(), 1 / L)
#     x = sparse.lil_matrix(x).tocsc()
    # 20181123 - end

    return x_out

# ISTAで値を更新してLASSOの誤差関数で評価。ある程度まで誤差が小さくなったら、解が得られたものとする。
EPSILON = 10**(-5)
y = sparse.lil_matrix( sinogram.flatten() )
y = y.tocsc()  # CSC

err = 1.0
# Initial condition
x0 = LspT.dot(y.T).tocsc() # LspT:CSR, y.T:CSR, x:CSC
x = x0
lam = 0.1  # lambda
P0 = 10**6  # Lipschitz定数の初期値

# ISTAを繰り返す回数を指定
Nt = 5000

# 結果とコストを格納する配列
cost = np.zeros(Nt)

# 20180930 temporarily comment out
for t in range(Nt):
    out = ISTA(Lsp, x, y, lam, P0)
    x = out.tocsr()
    cost[t] = 0.5 * sparse.linalg.norm(y.T - Lsp.dot(x).tocsr() , ord='fro')**2

reconIm = np.reshape(x.todense(), (Nx-1, Ny-1))   # 20180723
# 20180930 temporarily comment out

# 一部の検出器のデータのみで再構成
# 20181120 temporarily comment out
# kの値を間引く
Nstep_k = 2
partL = Lsp[ : Nc ][:]
part_y = sparse.lil_matrix( np.ravel( sinogram[0][:] ) ).tocsc()

for k in range( 1, Nk // Nstep_k ):
    tempL = Lsp[ Nc * ( Nstep_k * k ) : Nc * ( Nstep_k * k + 1 ) ][:]
    partL = sparse.vstack( ( partL, tempL ) )
    temp_y = sparse.lil_matrix( np.ravel( sinogram[ Nstep_k * k ][:] ) ).tocsc()
    part_y = sparse.hstack( (part_y, temp_y) )
x0 = partL.T.dot(part_y.T).tocsc() # LspT:CSR, y.T:CSR, x:CSC
x = x0
# # 20181020 - begin
for t in range(Nt):
    out = ISTA(partL, x, part_y, lam, P0)
    out = out.tocsr()
    x = out
# 20181020 - end
reconIm_part = np.reshape( out.todense(), (Nx-1, Ny-1) )
# 20181120 temporarily comment out

# 20181123 temporarily comment out
# 20181114 - begin
# 回転角方向を間引く
print("Calc Angular Decimation")

Nstep_c = 10
cost_c = np.zeros(Nt)

abstL = Lsp[:Nc][:]
partL_c = abstL[::Nstep_c][:]
part_y_c = sparse.lil_matrix( np.ravel( sinogram[0][::Nstep_c]) ).tocsc()

for k in range( 1, Nk ):
    # 一旦、Nc行分だけ抜き出す
    abstL = Lsp[ Nc * k : Nc * ( k + 1 ) ][:]
    # 間引く
    tempL_c = abstL[::Nstep_c][:]
    partL_c = sparse.vstack( ( partL_c, tempL_c ) )

    abst_y = sparse.lil_matrix( np.ravel( sinogram[k][::Nstep_c] ) ).tocsc()
    part_y_c = sparse.hstack( ( part_y_c, abst_y ) )

x0_c = partL_c.T.dot(part_y_c.T).tocsc()
x_c = x0_c
for t in range(Nt):
    out_c = ISTA(partL_c, x_c, part_y_c, lam, P0)
    out_c = out_c.tocsr()
    x_c = out_c
    cost_c[t] = 0.5 * sparse.linalg.norm(part_y_c.T - partL_c.dot(x_c).tocsr() , ord='fro')**2

reconIm_part_c = np.reshape( out_c.todense(), (Nx-1, Ny-1) )
# 20181123 temporarily comment out

# for k in range(81):
#     partL = Lsp[ Nc * k : Nc * k + Nc ][:]   #csc
#     d = sparse.lil_matrix( sinogram[k][:].flatten() )
#     d = d.tocsc()
#     for t in range(Nt):
#         x = ISTA(partL, x, d, lam, P0)
#         x = x.tocsr()
#     rho_sp[k][:] = x.toarray().flatten()

# reconIm_part = reconIm_part + np.reshape( rho_sp[80][:], (Ny-1, Nx-1) )

# 結果を表示
# コスト関数の変化を描画
plt.figure()
plt.plot(np.arange(Nt), cost, marker="o")

# ２次元に戻す
plt.figure( figsize=(8, 8) )
plt.pcolor(np.array(reconIm.T))

# 検出器を間引き
plt.figure( figsize=(8, 8) )
plt.pcolor(np.array(reconIm_part.T))
# plt.pcolor(np.array(np.reshape( rho_sp[80][:], (Ny-1, Nx-1) ).T))  # 20180723

# コスト関数の変化を描画
plt.figure()
plt.plot(np.arange(Nt), cost_c, marker="o")

# 回転角を間引き
plt.figure( figsize=(8, 8) )
plt.pcolor(np.array(reconIm_part_c.T))

# ---

# 20181222 - ISTA from Qiita
def solve_lasso(A, y, alpha, maxiter=100, tol=1.0e-4):
    """ Solve lasso problem """
    x0 = np.zeros(A.shape[1])
    rho = supermum_eigen(A.T @ A)
    x = []
    for it in range(maxiter):
        x_new = update(x0, A, y, alpha, rho)
#         if (np.abs(x0 - x_new) < tol).all():
#             return x_new
        x0 = x_new
#     raise ValueError('Not converged.')
    return x_new   # 一定回数計算したら結果を返すように変更。

def update(x0, A, y, alpha, rho):
    """ Make an iteration with given initial guess x0 """
    res = y - A @ x0
    return soft_threashold(x0 + (A.T @ res) / rho, alpha / rho)

def soft_threashold(y, alpha):
    return np.sign(y) * np.maximum(np.abs(y) - alpha, 0.0)

def supermum_eigen(A):
    return np.max(np.sum(np.abs(A), axis=0))

# full data
y = sinogram.flatten()

alpha = 0.1
out = solve_lasso(L, y, alpha, tol=1e-5, maxiter=1000000)
reconIm = np.reshape(out, (Nx-1, Ny-1))

# Angular sparse
Nstep_c = 10

abstL = L[:Nc][:]
partL_c = abstL[::Nstep_c][:]
part_y_c = np.ravel( sinogram[0][::Nstep_c])

for k in range( 1, Nk ):
    # 一旦、Nc行分だけ抜き出す
    abstL = L[ Nc * k : Nc * ( k + 1 ) ][:]
    # 間引く
    tempL_c = abstL[::Nstep_c][:]
    partL_c = np.vstack( ( partL_c, tempL_c ) )

    abst_y = np.ravel( sinogram[k][::Nstep_c] )
    part_y_c = np.hstack( (part_y_c, abst_y) )

out_c = solve_lasso(partL_c, part_y_c, alpha, tol=1e-5, maxiter=1000)
reconIm_c = np.reshape(out_c, (Nx-1, Ny-1))

# ２次元に戻す
plt.figure( figsize=(8, 8) )
plt.pcolor(np.array(reconIm.T))

plt.figure( figsize=(8, 8) )
plt.pcolor(np.array(reconIm_c.T))

# ---

# scikit-learnによるLassoを利用
y = sinogram.flatten()

rgr_lasso = Lasso(alpha=0.001)
rgr_lasso.fit(L, y)
rec_l1 = rgr_lasso.coef_.reshape(Nx-1, Ny-1)

# 20181219 - begin
# 回転角方向を間引く
Nstep_c = 10

abstL = L[:Nc][:]
partL_c = abstL[::Nstep_c][:]
part_y_c = np.ravel( sinogram[0][::Nstep_c])

for k in range( 1, Nk ):
    # 一旦、Nc行分だけ抜き出す
    abstL = L[ Nc * k : Nc * ( k + 1 ) ][:]
    # 間引く
    tempL_c = abstL[::Nstep_c][:]
    partL_c = np.vstack( ( partL_c, tempL_c ) )

    abst_y = np.ravel( sinogram[k][::Nstep_c] )
    part_y_c = np.hstack( (part_y_c, abst_y) )

rgr_lasso_c = Lasso(alpha=0.001)
print(partL_c.shape, part_y_c.shape)
rgr_lasso_c.fit(partL_c, part_y_c)
rec_l1_c = rgr_lasso_c.coef_.reshape(Nx-1, Ny-1)
# 20181219 - end

# ２次元に戻す
plt.figure( figsize=(8, 8) )
plt.pcolor(np.array(rec_l1.T))

plt.figure( figsize=(8, 8) )
plt.pcolor(np.array(rec_l1_c.T))

# ---

# 軟判定しきい値関数
def SoftThr(x,lam):
    z = np.zeros(x.shape).astype(np.float32)
    mask = x > lam
    z = z + (x - lam) * mask
    mask = x < -lam
    z = z + (x + lam) * mask
    return z

# ADMM
# Initial condition
y = sparse.lil_matrix( sinogram.flatten() ).tocsc()
x = LspT.dot(y.T).tocsc()
z = x
u = sparse.lil_matrix( np.zeros( x.shape[0] ) ).T.tocsc()
lam = 0.1  # lambda
# 罰金項の係数の設定
mu = 1.0
# 予め固定値を計算
## C = sparse.linalg.inv( mu * sparse.identity( Lsp.shape[1] ) + 1/lam * Lsp.T.dot(Lsp) )
C = sparse.lil_matrix( np.linalg.inv( mu * np.identity( Lsp.shape[1] ) + 1/lam * LspT.dot(Lsp) ) )

# 繰り返し回数
Ni = 5

#ADMM更新式
for i in range(Ni):
    x = sparse.lil_matrix( C.dot( 1/lam * LspT.dot(y.T) + mu * (z - u) ) ).tocsc()
    z = SoftThr( x.toarray() + u.toarray(), 1/mu )
    z = sparse.lil_matrix(z).tocsc()
    u = u + x - z

reconIm = np.reshape( x.todense(), (Nx-1, Ny-1) )

# ２次元に戻す
plt.figure( figsize=(8, 8) )
plt.pcolor(np.array(reconIm.T))

# ---

#---疎行列を使わないバージョン---
'''
# LASSOの誤差関数
def loss_LASSO(A, x, y, lam):
    v = y - np.dot(A, x)
    cost = np.linalg.norm(v, ord=2)**2
    cost = 0.5 * cost + lam * np.linalg.norm(x, ord=1)
    return cost

# 軟判定しきい値関数
def SoftThr(x,lam):
    z = np.zeros(x.shape).astype(np.float32)
    mask = x > lam
    z = z + (x - lam) * mask
    mask = x < -lam
    z = z + (x + lam) * mask
    return z

def ISTA(A, x, y, lam, L0):
    kx = x
    print("y, A, x", y.shape, A.shape, x.shape)
    v = y - np.dot(A, x)
    ktemp = 0.5 * np.linalg.norm(v, ord=2)**2
    L = L0

    # 勾配計算
    grad_x = -np.dot(A.T, v) / lam
    # 更新候補点へ移動
    MMx = x - grad_x / L
    MMv = y - np.dot(A, MMx)
    # コスト関数の一部を計算
    temp = 0.5 * np.linalg.norm(MMv, ord=2)**2
    # 現在点と更新候補点との差分を計算
    Diffx = MMx - kx

    # メジャライザーを計算
    MMtemp = ktemp + np.dot(grad_x, Diffx) + 0.5 * L * np.linalg.norm(Diffx, ord=2)**2
    print("temp", temp)
    print("ktemp", ktemp)
    print("grad_x * Diffx=", np.dot(grad_x, Diffx))
    print("0.5 * L * || Diffx ||**2", 0.5 * L * np.linalg.norm(Diffx, ord=2)**2)

    while MMtemp < temp:
        print("MMtemp, temp", MMtemp, temp)
        # リプシッツ定数を大きくする
        L = L * 1.1
        # 更新候補位置再計算
        MMx = x - grad_x / L
        # コスト関数の一部を再計算
        temp = 0.5 * np.linalg.norm(y - np.dot(A, MMx), ord=2)**2
        # 現在点と再計算した更新候補位置の差分を計算
        Diffx2 = MMx - kx
        # メジャライザーを再計算
        MMtemp = ktemp + np.dot(grad_x, Diffx2) + 0.5 * L * np.linalg.norm(Diffx2, ord=2)**2

    x = SoftThr(MMx, 1/L)
    return x

# ISTAで値を更新してLASSOの誤差関数で評価。ある程度まで誤差が小さくなったら、解が得られたものとする。
EPSILON = 10**(-5)
y = sinogram.flatten()

err = 1.0
print("err=", err)
# Initial condition
x = np.dot(L.T, y)
print("x.shape", x.shape)
lam = 0.1  # lambda
# P0 = np.linalg.norm(np.dot(L.T, L), ord=2) / lam  # Lipschitz定数の初期値
P0 = 10**6
print("P0", P0)
print("y, A, x", y.shape, L.shape, x.shape)
print("A*x", np.dot(L, x).shape)
print("y-A*x", y - np.dot(L, x))

# ISTAを繰り返す回数を指定
Nt = 100

# 結果とコストを格納する配列
cost = np.zeros(Nt)

for t in range(Nt):
    x = ISTA(L, x, y, lam, P0)
    cost[t] = 0.5 * np.linalg.norm(y - np.dot(L, x), ord=2)**2

reconIm = np.reshape(x, (Nx, Ny))

# 結果を表示
# コスト関数の変化を描画
plt.figure()
plt.plot(np.arange(Nt), cost, marker="o")

# ２次元に戻す
plt.figure( figsize=(8, 8) )
plt.pcolor(reconIm.T)
'''
#---疎行列を使わないバージョン--- end