#Mohamed Kharaev 43121144. Lab Section 13
#othello.py

NONE = 0
WHITE = 1
BLACK = 2

class GameOverError(Exception):
    '''Raised whenever an attempt is made to make a move after the
    game is already over'''
    pass

class InvalidMove(Exception):
    '''Raised whenever an attempt is made to make a move that is not valid'''
    pass

class GameState:
    '''GameState represents an othello game'''
    def __init__(self, rows: int, cols: int, turn: int, mode: str) -> None:
        self.rows = rows
        self.cols = cols
        self.board = _new_game_board(rows, cols)
        self.turn = turn
        self.mode = mode

    def get_rows(self) -> int:
        '''returns the amount of rows in the gameboard'''
        return self.rows

    def get_cols(self) -> int:
        '''returns the amount of cols in the gameboard'''
        return self.cols

    def get_turn(self) -> int:
        '''returns the current turn in the gamestate'''
        return self.turn

    def get_board(self) -> int:
        '''returns the gameboard'''
        return self.board

    def get_scores(self) -> [int, int]:
        '''creates a dictionary containing the amount of black and white pieces on the board. returns the dictionary'''
        scores = {'black': 0, 'white': 0}
        for row in self.board:
            for piece in row:
                if piece == BLACK:
                    scores['black'] += 1
                elif piece == WHITE:
                    scores['white'] += 1
        return scores

    def winner(self) -> int:
        '''Returns the winner of the GameState based on the game mdoe'''
        white_score = self.get_scores()['white']
        black_score = self.get_scores()['black']
        if self.mode == '>':
            if white_score > black_score:
                return WHITE
            elif black_score > white_score:
                return BLACK
            else:
                return NONE
        if self.mode == '<':
            if white_score > black_score:
                return BLACK
            elif black_score > white_score:
                return WHITE
            else:
                return NONE

    def check_move_possible(self, row: int, col: int) -> bool:
        '''checks the game board to see if a move is possible. if one is,
        True is returned. Otherwise the function returns False'''

        try:
            if self.board[row][col] != NONE:
                return False
        except(IndexError):
            return False

        for dir_row in range(-1, 2):
            for dir_col in range(-1, 2):
                try:
                    if (row + dir_row) >= 0 and (col + dir_col) >= 0:
                        if self.board[row + dir_row][col + dir_col] == opposite_turn(self.turn):
                            for i in range(2, max(self.rows, self.cols)):
                                if (row + (dir_row * i)) >= 0 and (col + (dir_col * i)) >= 0:
                                    piece = self.board[row + (dir_row * i)][col + (dir_col * i)]
                                    if piece == NONE:
                                        break
                                    if piece == self.turn:
                                        return True
                except(IndexError):
                    pass
        return False

    def check_any_move_possible(self) -> bool:
        '''Checks if there is any possible move for the current player'''

        for row in range(self.rows):
            for col in range(self.cols):
                if self.check_move_possible(row, col):
                    return True
        return False

    def make_move(self, row: int, col: int) -> [[int]]:
        '''Executes a move'''

        if row not in list(range(self.get_rows())) or col not in list(range(self.get_cols())):
            raise InvalidMove()

        _require_game_not_over(self)

        original_board = copy_game_board(self.board)
        if self.check_move_possible(row, col):
            for dir_row in range(-1, 2):
                for dir_col in range(-1, 2):
                    temp_list = list()
                    try:
                        if (row + dir_row) >= 0 and (col + dir_col) >= 0:
                            if self.board[row + dir_row][col + dir_col] == opposite_turn(self.turn):
                                for i in range(1, max(self.rows, self.cols)):
                                    if (row + (dir_row * i)) >= 0 and (col + (dir_col * i)) >= 0:
                                        piece = self.board[row + (dir_row * i)][col + (dir_col * i)]
                                        if piece == opposite_turn(self.turn):
                                            temp_list.append(piece)
                                        elif piece == self.turn:
                                            temp_list.append(piece)
                                            break
                                        else:
                                            break
                    except(IndexError):
                        pass
                    if len(temp_list) > 0:
                        if temp_list[-1] == self.turn:
                            for i in range(1, len(temp_list)):
                                self.board[row + (dir_row * i)][col + (dir_col * i)] = opposite_turn(temp_list[i - 1])

            self.board[row][col] = self.turn
            self.turn = opposite_turn(self.turn)
            if self.check_any_move_possible():
                pass
            else:
                self.turn = opposite_turn(self.turn)
                if _is_board_full(self.board):
                   pass

def _is_board_full(board: [[int]]) -> bool:
    '''Checks if there are any empty spots on a gameboard (list of list of ints))'''
    for row in range(len(board)):
        for col in range(len(board[0])):
            if board[row][col] == NONE:
                return False
    return True

def _new_game_board(rows: int, cols: int) -> [[int]]:
    '''
    Creates a new game board.  Initially, a game board has the size
    rows x cols and is comprised only of integers with the
    value NONE
    '''
    board = []

    for row in range(rows):
        board.append([])
        for col in range(cols):
            board[-1].append(NONE)

    return board

def copy_game_board(board: [[int]]) -> [[int]]:
    '''Copies the given game board'''
    board_copy = []

    for col in range(len(board)):
        board_copy.append([])
        for row in range(len(board[0])):
            board_copy[-1].append(board[col][row])

    return board_copy

def opposite_turn(turn: int) -> int:
    '''Given the player whose turn it is now, returns the opposite player'''
    if turn == WHITE:
        return BLACK
    else:
        return WHITE

def _require_game_not_over(game: GameState) -> None:
    '''Raises a GameOverError if the game can't have any more moves executed'''
    if not game.check_any_move_possible():
        raise GameOverError()


def caesar_cipher(string, shift_amount):
    return_cipher = ''
    for letter in string:
        # maintain space characters
        if not letter.isalpha():
            return_cipher += letter
        # encrypts uppercase characters without removing case
        elif letter.isupper():
            #convert letter to unicode, subtract base unicode to get place in alpha
            #A=65, A=95 A=30 A=4 A=69
            return_cipher += chr((ord(letter) + shift_amount - 65) % 26 + 65)
        elif letter.islower():
            # same but with lowercase
            return_cipher += chr((ord(letter) + shift_amount - 97) % 26 + 97)
    return(return_cipher)
# caesar_cipher("Boy! What a string!", -5)


from httplib import HTTPConnection, HTTPSConnection, HTTPMessage
from cStringIO import StringIO
from .files import save_cassette, load_cassette
from .cassette import Cassette

class VCRHTTPResponse(object):
    """
    Stub reponse class that gets returned instead of a HTTPResponse
    """
    def __init__(self, recorded_response):
        self.recorded_response = recorded_response
        self.reason = recorded_response['status']['message']
        self.status = recorded_response['status']['code']
        self.version = None
        self._content = StringIO(self.recorded_response['body']['string'])

        self.msg = HTTPMessage(StringIO(''))
        for k, v in self.recorded_response['headers'].iteritems():
            self.msg.addheader(k, v)

        self.length = self.msg.getheader('content-length') or None

    def read(self, *args, **kwargs):
        # Note: I'm pretty much ignoring any chunking stuff because
        # I don't really understand what it is or how it works.
        return self._content.read(*args, **kwargs)

    def close(self):
        return True

    def isclosed(self):
        # Urllib3 seems to call this because it actually uses
        # the weird chunking support in httplib
        return True

    def getheaders(self):
        return self.recorded_response['headers'].iteritems()

class VCRConnectionMixin:
    def _load_old_response(self):
        old_cassette = load_cassette(self._vcr_cassette_path)
        if old_cassette:
            return old_cassette.get_response(self._vcr)

    def request(self, method, url, body=None, headers={}):
        """
        Persist the request metadata in self._vcr
        """
        self._vcr = {
            'method': method,
            'url': url,
            'body': body,
            'headers': headers,
        }
        old_cassette = load_cassette(self._vcr_cassette_path)
        if old_cassette and old_cassette.get_request(self._vcr):
            return
        self._cassette.requests.append(dict(
            method=method,
            url=url,
            body=body,
            headers=headers
        ))
        self._baseclass.request(self, method, url, body=body, headers=headers)

    def getresponse(self, buffering=False):
        old_response = self._load_old_response()
        if not old_response:
            response = HTTPConnection.getresponse(self)
            self._cassette.responses.append({
                'status': {'code': response.status, 'message': response.reason},
                'headers': dict(response.getheaders()),
                'body': {'string': response.read()},
            })
            save_cassette(self._vcr_cassette_path, self._cassette)
        old_response = self._load_old_response()
        return VCRHTTPResponse(old_response)

class VCRHTTPConnection(VCRConnectionMixin, HTTPConnection):

    # Can't use super since this is an old-style class
    _baseclass = HTTPConnection

    def __init__(self, *args, **kwargs):
        self._cassette = Cassette()
        HTTPConnection.__init__(self, *args, **kwargs)

class VCRHTTPSConnection(VCRConnectionMixin, HTTPSConnection):

    _baseclass = HTTPSConnection

    def __init__(self, *args, **kwargs):
        """
        I overrode the init and copied a lot of the code from the parent
        class because HTTPConnection when this happens has been replaced
        by VCRHTTPConnection,  but doing it here lets us use the original
        one.
        """
        HTTPConnection.__init__(self, *args, **kwargs)
        self.key_file = kwargs.pop('key_file', None)
        self.cert_file = kwargs.pop('cert_file', None)
        self._cassette = Cassette()


from django.template.loader import render_to_string
from django.utils.text import slugify
from quantaly.models import User

def create_user(strategy, details, backend, user=None, *args, **kwargs):
    if user:
        return {'is_new': False}

    fields = dict((name, kwargs.get(name, details.get(name)))
                  for name in backend.setting('USER_FIELDS', ['email', 'username']))
    if not fields:
        return

    if fields['email'] is None or fields['email'] == '':
        fields['email'] = kwargs.get('response')['id'] + "@" + backend.name + ".com"

    auth_user = strategy.create_user(**fields)
    auth_user.is_verify = True
    auth_user.save()

    message = render_to_string('quantaly/mail/welcome.html', {
        'user': auth_user,
    })
    auth_user.email_user('Welcome to Quantaly.', message)

    return {
        'is_new': True,
        'user': auth_user
    }


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Because we check for lazy crawlers and we don't want to repeat ourselves,
# have a lazy-crawler check routine based on callbacks so it can do many
# things.

# V a r i a b l e s

# Name we report as
MYNAME = 'lazy-crawlers'

# Clusters and the number of crawlers found in each
CLUSTERS = { 'pr2': 120, 'pr4': 1, 'pr4test': 1 }

# Misc.
QNAME = 'crawl'
NOTFOUND = -1

# F u n c t i o n s

# run: run a lazy-crawler check
# passed: qless connection object, cluster name, lazy callback, MIA callback
# returns: None on success, error message on failure
def run(qless_conn, cluster_name, on_lazy, on_mia):
    global QNAME, NOTFOUND, CLUSTERS, MYNAME

    # Determine how many jobs are running
    njobs = NOTFOUND
    for queue in qless_conn.queues.counts:
        if queue['name'] == QNAME:
            njobs = queue['running']
            break

    # This should not happen...
    if njobs == NOTFOUND:
        return 'No data.'

    # Each crawler must be running at least one third its fair share, else we
    # proclaim it lazy.
    try:
        ncrawlers = CLUSTERS[cluster_name]
    except KeyError:
        return 'Unknown cluster.'
    minjobs = njobs / ncrawlers / 3

    # Determine how many jobs are running on each crawler
    prefix = cluster_name + '-crawler-'
    crawlers = { }
    for node in qless_conn.workers.counts:
        if node['name'].startswith(prefix):
            crawlers[node['name']] = node.get('jobs', 0)

    # Detect any lazy or MIA crawlers.
    for i in range(1, ncrawlers+1):
        key = prefix + '%02d' % i
        if key in crawlers:
            if crawlers[key] < minjobs:
                on_lazy(key)
        else:
            on_mia(key)

    # Return successfully.
    return None


def search_for_range(array, target):
  f_arr = [-1,-1]
  low, high = 0, len(array)-1
  while low <=high:
    if array[low] == target and f_arr[0] ==-1:
      f_arr[0]=low
    elif f_arr[0]==-1:
      low +=1
    if array[high]== target and f_arr[1] ==-1:
      f_arr[1]=high
    elif f_arr[1]==-1:
      high -=1

    if f_arr[0]!=-1 and f_arr[1]!=-1:
      return f_arr

  return f_arr

print(search_for_range([5,6,6,7,8], 6))


def solution(strs, t):
    n = len(t)
    dp = [0] * (n + 1)
    strs = set(strs)

    for i in range(1, n + 1):
        dp[i] = float('inf')
        for k in range(1, 6):
            if i - k < 0:
                s = 0
            else:
                s = i - k
            if t[s:i] in strs:
                dp[i] = min(dp[i], dp[i - k] + 1)
    if dp[-1] == float('inf'):
        answer = -1
    else:
        answer = dp[-1]

    return answer


#(c) 2016 by Authors
#This file is a part of ABruijn program.
#Released under the BSD license (see LICENSE file)

"""
Runs assemble binary
"""

import subprocess
import logging
import os

from abruijn.utils import which

ASSEMBLE_BIN = "abruijn-assemble"
logger = logging.getLogger()

class AssembleException(Exception):
    pass

def check_binaries():
    if not which(ASSEMBLE_BIN):
        raise AssembleException("Assemble binary was not found. "
                                "Did you run 'make'?")
    try:
        devnull = open(os.devnull, "w")
        subprocess.check_call([ASSEMBLE_BIN, "-h"], stderr=devnull)
    except (subprocess.CalledProcessError, OSError) as e:
        if e.returncode == -9:
            logger.error("Looks like the system ran out of memory")
        raise AssembleException(str(e))

def assemble(args, out_file, log_file):
    logger.info("Assembling reads")
    logger.debug("-----Begin assembly log------")
    cmdline = [ASSEMBLE_BIN, "-k", str(args.kmer_size), "-l", log_file,
               "-t", str(args.threads), "-v", str(args.min_overlap)]
    if args.debug:
        cmdline.append("-d")
    if args.min_kmer_count is not None:
        cmdline.extend(["-m", str(args.min_kmer_count)])
    if args.max_kmer_count is not None:
        cmdline.extend(["-x", str(args.max_kmer_count)])
    cmdline.extend([args.reads, out_file, str(args.coverage)])

    try:
        subprocess.check_call(cmdline)
    except (subprocess.CalledProcessError, OSError) as e:
        if e.returncode == -9:
            logger.error("Looks like the system ran out of memory")
        raise AssembleException(str(e))


import FWCore.ParameterSet.Config as cms

process = cms.Process("EWKTUPLE")

process.load("FWCore.MessageService.MessageLogger_cfi")
process.load("FWCore.MessageService.MessageLogger_cfi")
process.MessageLogger.destinations = ['cout', 'cerr']
process.MessageLogger.cerr.FwkReport.reportEvery = 1000

process.source = cms.Source("PoolSource",
#     fileNames = cms.untracked.vstring('file:RMMEIN.root'),
    fileNames = cms.untracked.vstring(
#        'file:/hadoop/cms/store/user/mwlebour/WJetsToLNu_TuneZ2_7TeV-madgraph-tauola/WW_414_SKIM_V04_ID026_WJetsToLNuMad_Step2/a3ede9ee43e9e4198483e6ce9f0ce8dc/WJetsToLNuMad_16_1_UwO.root'
        '/store/user/mangano/GluGluToHToWWTo2L2Nu_M-160_7TeV-powheg-pythia6/R414_S1_V05_S2_V02_S3_V00_ID101160_ggToH160toWWto2L2Nu_Step2-v2/2ff183dd1f3dc60c128420a6b73e4e4b/ggToH160toWWto2L2Nu_2_1_hFM.root',
        '/store/user/mangano/GluGluToHToWWTo2L2Nu_M-160_7TeV-powheg-pythia6/R414_S1_V05_S2_V02_S3_V00_ID101160_ggToH160toWWto2L2Nu_Step2-v2/2ff183dd1f3dc60c128420a6b73e4e4b/ggToH160toWWto2L2Nu_1_1_Dfc.root',
    ),
)
process.source.inputCommands = cms.untracked.vstring( "keep *", "drop *_conditionsInEdm_*_*",  "drop *_MEtoEDMConverter_*_*")
process.options = cms.untracked.PSet(wantSummary = cms.untracked.bool(True))
process.maxEvents = cms.untracked.PSet( input = cms.untracked.int32(10000) )

Template = cms.EDFilter("ProbeTreeProducer",
    cut = cms.string("leptEtaCut() && ptByPt(0) > 20 && ptByPt(1) > 10"),
    variables = cms.PSet(
        hypo = cms.string("hypo()"),
        mll  = cms.string("mll()"),
        ptll = cms.string("pTll()"),
        pt1  = cms.string("ptByPt(0)"),
        pt2  = cms.string("ptByPt(1)"),
        met  = cms.string("met('PFMET')"),
        mmet = cms.string("met('MINMET')"),
        pmet = cms.string("projMet('PFMET')"),
        pmmet = cms.string("projMet('MINMET')"),
        dphill = cms.string("dPhill()/3.14159"),
        drll   = cms.string("dRll()"),
        dphilmet = cms.string("dPhilMet('PFMET')"),
        mtw1 = cms.string("mTByPt(0,'PFMET')"),
        mtw2 = cms.string("mTByPt(1,'PFMET')"),
        mth  = cms.string("mTHiggs('PFMET')"),
        njet  = cms.string("nJets(30)"),
        cnjet = cms.string("nCentralJets(30,2.5)"),
        bestiso  = cms.string("allIsoByIso(0)/ptByIso(0)"),
        worstiso = cms.string("allIsoByIso(1)/ptByIso(1)"),
        worstJetLepPt = cms.string("max(matchedJetPt(0, 0.5)/pt(0), matchedJetPt(1, 0.5)/pt(1))"),
    ),
    flags = cms.PSet(
        bveto  = cms.string("bTaggedJetsUnder(30,2.1) == 0 && nSoftMu(3) == 0"),
        lveto = cms.string("nExtraLep == 0"),
        zveto = cms.string("abs(mll-91.1876)>15"),
        trigger = cms.string("triggerMatchingCut('MC')"),
    ),
)

process.load("HLTrigger.HLTfilters.triggerResultsFilter_cfi")
process.triggerResultsFilter.triggerConditions = cms.vstring(  )
process.triggerResultsFilter.l1tResults = ''
process.triggerResultsFilter.throw = True
process.triggerResultsFilter.hltResults = cms.InputTag( "TriggerResults", "", "REDIGI311X" )
process.elelTrigger = process.triggerResultsFilter.clone(triggerConditions = [ "HLT_Ele17_SW_TightCaloEleId_Ele8HE_L1R_v*"])
process.elmuTrigger = process.triggerResultsFilter.clone(triggerConditions = [ "HLT_Mu21_v* OR HLT_Mu5_Ele17_v* OR HLT_Mu11_Ele8_v*"])
process.muelTrigger = process.elmuTrigger.clone()
process.mumuTrigger = process.triggerResultsFilter.clone(triggerConditions = [ "HLT_Mu21_v* OR HLT_DoubleMu5_v*"])

for X in "elel", "mumu", "elmu", "muel":
    setattr(process, X+"Tree",     Template.clone(src = cms.InputTag("ww%sIPLHT"   % X)))
    setattr(process, X+"TreeNoPU", Template.clone(src = cms.InputTag("ww%sJetNoPU" % X)))
    setattr(process, X+"Path",     cms.Path(getattr(process,X+"Trigger") + getattr(process,X+"Tree")))# + getattr(process,X+"TreeNoPU")))

# process.TFileService = cms.Service("TFileService",fileName = cms.string("RMMEOUT"))
process.TFileService = cms.Service("TFileService",fileName = cms.string("tree.root"))


import geopandas
from osgeo import gdal, gdal_array
import numpy as np

traceResult={}
polluting= geopandas.read_file('../Data/geoJson/pollution.geojson')

raster="../resultData/computingResult/TN_experience_formula.tif"
srcArray = gdal_array.LoadFile(raster)

srcArray[np.isnan(srcArray)]=-999

n=10
maxten=[]
maxtenposition=[]
for i in range(n):
    bm = np.nanmax(srcArray)
    pos = np.unravel_index(np.argmax(srcArray), srcArray.shape)
    maxten.append(bm)
    maxtenposition.append(pos)
    srcArray[pos[0],pos[1]]=-999

dataset = gdal.Open(raster)

adfGeoTransform = dataset.GetGeoTransform()

nXSize = dataset.RasterXSize #列数
nYSize = dataset.RasterYSize #行数

arrSlope = [] # 用于存储每个像素的（X，Y）坐标

i=0
polluting_list=[]
for i in range(polluting.shape[0]):
    polluting_list.append([])
    polluting_list[-1].append(i+1)
    polluting_list[-1].append(polluting.iat[i,1])
    polluting_list[-1].append(polluting.iat[i,-1].x)
    polluting_list[-1].append(polluting.iat[i,-1].y)

i=0
for i in range(len(maxtenposition)):
    num=maxtenposition[i]
    x=num[0]
    y=num[1]
    px = adfGeoTransform[0] + y * adfGeoTransform[1] + x * adfGeoTransform[2]
    py = adfGeoTransform[3] + y * adfGeoTransform[4] + x * adfGeoTransform[5]

    distance_list=[]
    for m in polluting_list:
        dis=pow((m[2]-px),2)+pow((m[3]-py),2)
        distance_list.append(dis)

    id=distance_list.index(min(distance_list))+1
    traceResult[id]=0

print(traceResult.keys())


import sys

import json
from requests_toolbelt import MultipartEncoder
import requests
import mimetypes

def main(argv=None):
	if argv is None:
		argv = sys.argv
		if len(argv) is 1:
			argv.append(input("Type in URL of the media you are trying to transcribe:\n"))
		elif len(argv) > 2:
			print("Too many arguments!\n")

		media_url = argv[1]
		process_speech_to_text(media_url)

###############
##
###############
def process_speech_to_text(media_url):
	# CREDENTIALS
	with open("credentials.json") as cred_file:
		credentials = json.load(cred_file)

	audio = open(media_url, "rb")
	content_type = mimetypes.guess_type(media_url, strict=True)[0]

	s2t_endpoint = credentials["speech-to-text"]["url"] + "/v1/recognize"
	auth = (credentials["speech-to-text"]["username"], credentials["speech-to-text"]["password"])
	headers = {"Content-Type": content_type}
	params = {"timestamps": "true", "profanity_filter":"false"}

	r = requests.post(s2t_endpoint, data=audio, headers=headers, auth=auth, params=params)

	print(r.json())

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


from random import Random
class ArrayList:
    """A object that creates and performs functions on a list"""

    def __init__(this, numOfItems):
        this.items = []
        rand = Random()
        for i in range(0, numOfItems):
            this.items.append(rand.randint(0,500))

    def sortList(this):
        items = this.items
        flipped = True

        while(flipped):
            flipped = False
            for i in range(0, len(items)-1):
                for j in range(i + 1, len(items)):
                    if(items[i] > items[j]):
                        temp = items[i]
                        items[i] = items[j]
                        items[j] = temp
                        flipped = True

    def reverseSortList(this):
        items = this.items
        flipped = True

        while(flipped):
            flipped = False
            for i in range(0, len(items)-1):
                for j in range(i + 1, len(items)):
                    if(items[i] < items[j]):
                        temp = items[i]
                        items[i] = items[j]
                        items[j] = temp
                        flipped = True

    def semiSortList(this):
        this.sortList()
        items = this.items
        rand = Random()

        for i in range(0,len(items)):
            swap = rand.randint(1,4)

            if(i+swap > len(items)-1):
                continue

            temp = items[i]
            items[i] = items[i+swap]
            items[i+swap] = temp
            i += rand.randint(0, 4)

            if( i > len(items)-1):
                break


from config import get_config
from Learner import Learner
from PatchLearner import PatchLearner, PatchLearnerMult
import argparse
import torch
from functools import partial
from torch.nn import MSELoss
from Pearson import pearson_corr_loss, ncl_loss

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='for CBIS-DDSM')
    parser.add_argument("-e", "--epochs", help="training epochs", default=20, type=int)
    parser.add_argument('-lr', '--lr', help='learning rate', default=1e-3, type=float)
    parser.add_argument("-b", "--batch_size", help="batch size", default=96, type=int)
    parser.add_argument("-w", "--num_workers", help="number of workers", default=3, type=int)
    parser.add_argument("-d", "--data_mode", help="databases: [crop_data, whole_data]", default='crop_data', type=str)
    parser.add_argument("-s", "--epoch_per_save", help="save_every s epochs", default=1, type=int)
    parser.add_argument("-net", "--net_mode", help="choose net", default='resnet50', type=str)

    parser.add_argument("-n", "--n_models", help="how many duplicate nets to use. 1 leads to basic training, "
                                                 "making -a and -p flags redundant", default=1, type=int)
    parser.add_argument("-patch", "--n_patch", help="how many patches per image", default=2, type=int)
    parser.add_argument("-bkg", "--bkg_prob", help="how many patches per image", default=.5, type=float)
    parser.add_argument("-mul", "--mul", help="use mult mode?", default=0, type=int)
    parser.add_argument("-rank", "--local_rank", help="rank for mul", default=0, type=int)
    parser.add_argument("-pre", "--pre_train", help="use a pretrain net?", default=0, type=int)
    parser.add_argument("-pre_layers", "--pre_layers", help="layer steps to use?", default=[], type=int, nargs='*')
    parser.add_argument("-pre_step", "--pre_steps", help="what steps to use?", default=[3, 10, 37], type=int, nargs='*')
    parser.add_argument("-ngpu", "--ngpu", help="how many gpu's to use?", default=1, type=int)
    parser.add_argument("-half", "--half", help="use half precisions?", default=0, type=int)
    parser.add_argument("-no_bkg", "--no_bkg", help="4 class mode", default=0, type=int)
    parser.add_argument("-cancer", "--cancer_only", help="limit label to benign/malignant", default=0, type=int)
    parser.add_argument("-type", "--type_only", help="limit label to mass/calcification", default=0, type=int)
    parser.add_argument("-single_type", "--single_type", help="limit labels to mass=1 or calcification=2", default=0, type=int)

    # TODO maybe add option to specify a network mix instead of duplicates
    parser.add_argument("-m", "--milestones", help="fractions of where lr will be tuned", default=[], type=int, nargs='*')
    parser.add_argument("-a", "--alpha", help="balancing parameter", default=0, type=float)
    parser.add_argument("-t", "--sig_thresh", help="thresholding of the most correct class", default=0.9, type=float)
    parser.add_argument("-p", "--pearson", help="using pearson loss", default=False, type=bool)
    parser.add_argument("-ncl", "--ncl", help="using Negative Correlation Loss", default=False, type=bool)
    parser.add_argument("-mean", "--joint_mean", help="using mean loss", default=False, type=bool)
    parser.add_argument("-morph_dir", "--morph_dir", help="use a morph directory", default='', type=str)
    parser.add_argument("-morph_a", "--morph_alpha", help="balance parameter", default=10., type=float)

    parser.add_argument("-logdir", "--logdir", help="extend log/saves to a folder for group experiment", default='', type=str)

    parser.add_argument("-c", "--cpu_mode", help="force cpu mode", default=0, type=int)

    args = parser.parse_args()
    conf = get_config(logext=args.logdir)

    # training param
    assert not (args.cancer_only and args.type_only)  # choose at most one
    conf.single_type = args.single_type
    conf.cancer_only = args.cancer_only
    conf.type_only = args.type_only
    conf.no_bkg = args.no_bkg
    conf.half = args.half
    conf.ngpu = args.ngpu
    conf.pre_layers = args.pre_layers
    conf.pre_steps = args.pre_steps
    conf.pre_train = args.pre_train
    conf.local_rank = args.local_rank
    conf.n_patch = args.n_patch
    conf.bkg_prob = args.bkg_prob if not args.no_bkg else 0
    conf.net_mode = args.net_mode
    conf.evaluate_every = 3  # TODO see if relevant
    conf.epoch_per_save = args.epoch_per_save
    conf.data_mode = args.data_mode
    conf.cpu_mode = args.cpu_mode
    conf.device = torch.device("cuda" if (torch.cuda.is_available() and not conf.cpu_mode) else "cpu")
    conf.lr = args.lr
    conf.batch_size = args.batch_size
    conf.num_workers = args.num_workers
    conf.epochs = args.epochs
    conf.milestones = args.milestones

    # pearson param
    conf.alpha = args.alpha
    conf.sig_thresh = args.sig_thresh
    conf.n_models = args.n_models
    conf.pearson = args.pearson
    conf.joint_mean = args.joint_mean
    conf.ncl = args.ncl

    # morph param
    conf.morph_alpha = args.morph_alpha
    conf.morph_dir = args.morph_dir

    # loss funcs
    conf.pearson_loss = partial(pearson_corr_loss, threshold=conf.sig_thresh)
    conf.ncl_loss = partial(ncl_loss)
    conf.morph_loss = MSELoss()

    # create learner and go
    param_desc = '_'.join([
        str(conf.net_mode), 'lr='+str(conf.lr), 'm='+'_'.join([str(m) for m in conf.milestones]),
        ('a='+str(conf.alpha) if conf.n_models>1 else ''),
        str(conf.batch_size), str(conf.n_patch), 'type_only' if conf.type_only else '',
                              'cancer_only' if conf.cancer_only else ''] +
        ([] if not conf.pre_train else
         ['pre', 'pre_layers='+'_'.join([str(m) for m in conf.pre_layers]),
          'pre_steps='+'_'.join([str(m) for m in conf.pre_steps])])
        )
    conf.log_path = str(conf.log_path) + '_' + param_desc
    conf.save_path = str(conf.save_path) + '_' + param_desc

    learner = PatchLearnerMult(conf) if args.mul else PatchLearner(conf)
    # face_learner(conf) if conf.n_models == 1 else face_learner_corr(conf)

    if conf.pre_train:
        learner.pretrain(conf)
    else:
        learner.train(conf, conf.epochs)


# -*- encoding:ascii -*-
from mako import runtime, filters, cache
UNDEFINED = runtime.UNDEFINED
__M_dict_builtin = dict
__M_locals_builtin = locals
_magic_number = 6
_modified_time = 1399385602.205022
_template_filename='templates/webapps/galaxy/dataset/embed.mako'
_template_uri='dataset/embed.mako'
_template_cache=cache.Cache(__name__, _modified_time)
_source_encoding='ascii'
_exports = ['render_item_links', 'render_summary_content']

# SOURCE LINE 2

from galaxy.web.framework.helpers import iff

def _mako_get_namespace(context, name):
    try:
        return context.namespaces[(__name__, name)]
    except KeyError:
        _mako_generate_namespaces(context)
        return context.namespaces[(__name__, name)]
def _mako_generate_namespaces(context):
    pass
def _mako_inherit(template, context):
    _mako_generate_namespaces(context)
    return runtime._inherit_from(context, u'/embed_base.mako', _template_uri)
def render_body(context,**pageargs):
    context.caller_stack._push_frame()
    try:
        __M_locals = __M_dict_builtin(pageargs=pageargs)
        __M_writer = context.writer()
        # SOURCE LINE 1
        __M_writer(u'\n')
        # SOURCE LINE 4
        __M_writer(u'\n\n')
        # SOURCE LINE 12
        __M_writer(u'\n\n')
        # SOURCE LINE 19
        __M_writer(u'\n')
        return ''
    finally:
        context.caller_stack._pop_frame()

def render_render_item_links(context,dataset):
    context.caller_stack._push_frame()
    try:
        h = context.get('h', UNDEFINED)
        trans = context.get('trans', UNDEFINED)
        item = context.get('item', UNDEFINED)
        __M_writer = context.writer()
        # SOURCE LINE 6
        __M_writer(u'\n    \n')
        # SOURCE LINE 9
        __M_writer(u'    \n    \n    \n')
        return ''
    finally:
        context.caller_stack._pop_frame()

def render_render_summary_content(context,dataset,data):
    context.caller_stack._push_frame()
    try:
        __M_writer = context.writer()
        # SOURCE LINE 14
        __M_writer(u'\n')
        return ''
    finally:
        context.caller_stack._pop_frame()


import matplotlib.pyplot as plt
import random

"""
Script for drawing lines demo
"""

# create data
y = []
bins = []

for i in range(500):
    bins.append(i)
    y.append(random.randrange(50))

plt.hist(y, bins)
plt.show()


import numpy as np
import pandas as pd
import copy, os
os.chdir('/Users/eloncha/Documents/GitHub/Elon/python')

### Kmeans
def loadDataSet(fileName):
    dataMat = []
    fr = open(fileName)
    for line in fr.readlines():
        curLine = line.strip().split('\t')
        floatLine = map(float,curLine)
        dataMat.append(list(floatLine))
    return dataMat
def loadDataSetInPandas(fileName, by = '\t', is_header = None):
    dataMat = pd.read_table(fileName, sep = by, header = is_header)
    colNum = dataMat.shape[1]
    newColName = []
    for i in range(0,colNum):
        newColName.append("X{0}".format(str(i+1)))
    dataMat.columns = newColName
    return dataMat
def distMeasure(vecA, vecB, order = 2):
    dist = np.sqrt(np.sum(np.abs(np.power(vecA - vecB, order))))
    return dist #np.linalg.norm(vecA-vecB)
def proximityMatrix(dataMat, order=2):
    n = dataMat.shape[0]
    Mat = np.zeros((n,n))
    for i in range(n):
        for j in range(n):
            Mat[i,j] = distMeasure(dataMat.iloc[i,:], dataMat.iloc[j,:])
    return Mat
def assignCent(dataMat, k):
    n = dataMat.shape[1]
    centroids = np.zeros((k,n))
    for i in range(0,n):
        xMax = np.max(dataMat.iloc[:,i])
        xMin = np.min(dataMat.iloc[:,i])
        xRand = np.random.uniform(xMin, xMax, k)
        for j in range(0,k):
            centroids[j,i] = xRand[j]
    return centroids
def kMeans(dataMat, k):
    m = dataMat.shape[0]
    p = dataMat.shape[1]
    centroids = assignCent(dataMat, k)
    clusterChanged = True
    iteTime = 0
    print('Random Centroids assigned.')
    print(centroids)
    clusterDoc = copy.copy(dataMat)
    clusterDoc['minIndex'] = -1
    clusterDoc['minDist'] = np.Inf
    while clusterChanged:
        iteTime += 1
        clusterChanged = False
        for i in range(0, m): # loop through each data point to assign it to the nearest centroid
            minDist, minIndex = np.Inf, -1
            distList = np.zeros((1, k))
            for j in range(0, k):
                curDist = distMeasure(centroids[j], dataMat.iloc[i, :], order=2)
                distList[0, j] = curDist
                minIndex = np.argmin(distList)
                minDist = np.min(distList)
            if minDist < clusterDoc.iloc[i, p+1]:
                clusterChanged = True
                clusterDoc.iloc[i, p+1] = minDist
                clusterDoc.iloc[i, p] = minIndex
        for cent in range(0, k): # loop through each clusters to update centroids
            centroids[cent] = np.mean(clusterDoc[clusterDoc['minIndex'] == cent].iloc[:, 0:p], axis=0)
        print('Cluster Assignment Changed.')
        print('Iteration {0}'.format(str(iteTime)))
    return centroids, clusterDoc
dataMat = loadDataSetInPandas('testSet_kmeans.txt')
centroids, cluster = kMeans(dataMat,6)

### Bi-Kmeans
def rankSSE(dataMat1, dataMat2):
    SSE1 = np.sum(dataMat1['minDist'])
    SSE2 = np.sum(dataMat2['minDist'])
    if SSE1 > SSE2:
        print('Cluster 1 has higher SSE')
        return dataMat1, dataMat2
    elif SSE1 <= SSE2:
        print('Cluster 2 has higher SSE')
        return dataMat2, dataMat1
def biKmeans(dataMat, k):
    curK = 0
    m = dataMat.shape[0]
    p = dataMat.shape[1]
    cList = np.zeros((k,p))
    dList = pd.DataFrame(columns = kMeans(dataMat, 2)[1].columns)
    while curK < k:
        centroids, cluster = kMeans(dataMat.iloc[:,0:p], 2)
        dataMat1, dataMat2 = cluster[cluster['minIndex'] == 0], cluster[cluster['minIndex'] == 1]
        deadMat, surviveMat = rankSSE(dataMat1, dataMat2)
        cdf = centroids[surviveMat['minIndex'].values[0]]
        cList[curK] = cdf
        surviveMat.iloc[:,p] = curK
        dList = surviveMat.merge(dList, how = 'outer')
        curK += 1
        dataMat = copy.copy(deadMat)
    return cList, dList
cList, dList = biKmeans(dataMat, 6)

### Kmeans in scikit.learn
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn import datasets

np.random.seed(6)
kmeans = KMeans(n_clusters = 6, init = 'k-means++', n_init = 1).fit(dataMat)
kmeans.cluster_centers_
kmeans.labels_

plt.scatter(kmeans.cluster_centers_[0:6,0], kmeans.cluster_centers_[0:6,1])
plt.show()

### Vector Quantization (LVQ)
import scipy as sp
from sklearn import cluster

from scipy.misc import face
face = face(gray=True)
plt.figure(1, figsize = (3,2.2))
plt.imshow(face, cmap = plt.cm.gray, vmin = 0, vmax = 250)
plt.show()

X = face.reshape((-1,1))
n_clusters = 3
kmeans = KMeans(n_clusters = n_clusters, n_init = 1).fit(X)
values = kmeans.cluster_centers_.squeeze()
labels = kmeans.labels_
face_compressed = np.choose(labels, values)
face_compressed.shape = face.shape

plt.figure(2, figsize = (3,2.2))
plt.imshow(face_compressed, cmap = plt.cm.gray, vmin = 0, vmax = 250)
plt.show()


#!/usr/bin/env python3

import numpy as np
import random
import time
import _matrix

from pytest import approx

class TestMatrix:
    def is_close_to_equal(self, m1, m2, m, n):
        for i in range(m):
            for j in range(n):
                assert m1[i, j] == approx(m2[i, j])
        return True

    def calculation_helper(self, p, q, r, tsize):
        m1 = np.random.rand(p, q)
        m2 = np.random.rand(q, r)
        m3 = np.matmul(m1, m2)

        _m1 = _matrix.Matrix(m1)
        _m2 = _matrix.Matrix(m2)

        tstart = time.clock()
        ret_naive = _matrix.multiply_naive(_m1, _m2)
        tnaive = time.clock() - tstart
        tstart = time.clock()
        ret_tile = _matrix.multiply_tile(_m1, _m2, tsize)
        ttile = time.clock() - tstart
        tstart = time.clock()
        ret_mkl = _matrix.multiply_mkl(_m1, _m2)
        tmkl = time.clock() - tstart

        assert m3.shape[0] == ret_naive.nrow and m3.shape[1] == ret_naive.ncol
        assert m3.shape[0] == ret_tile.nrow and m3.shape[1] == ret_tile.ncol
        assert m3.shape[0] == ret_mkl.nrow and m3.shape[1] == ret_mkl.ncol
        assert(self.is_close_to_equal(m3, ret_naive, p, r))
        assert(self.is_close_to_equal(m3, ret_tile, p, r))
        assert(self.is_close_to_equal(m3, ret_mkl, p, r))

        with open('performance.txt', 'w') as f:
            f.write('multiply_naive: {}\n'.format(tnaive))
            f.write('multiply_tile: {}\n'.format(ttile))
            f.write('multiply_mkl: {}\n'.format(tmkl))
            f.write('tile speed-up over naive: {}\n'.format(tnaive / ttile))
            f.write('MKL speed-up over naive: {}\n'.format(tnaive / tmkl))

    def test_1000(self):
        self.calculation_helper(1000, 1000, 1000, 16)

    def test_random(self):
        p = random.randint(1, 1000)
        q = random.randint(1, 1000)
        r = random.randint(1, 1000)
        tsize = random.randint(1, 1000)
        self.calculation_helper(p, q, r, tsize)


# -*- coding: utf-8 -*-
from itertools import chain

from django.utils.html import conditional_escape
from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe
from django import forms
from django.forms.widgets import CheckboxSelectMultiple, CheckboxInput
from shop.models import OrderExtraInfo

from models import Trailer

class OrderExtraInfoForm(forms.ModelForm):
    class Meta:
        model = OrderExtraInfo
        fields = ('text',)

class CustomCheckboxSelectMultiple(CheckboxSelectMultiple):
    def render(self, name, value, attrs=None, choices=()):
        if value is None: value = []
        has_id = attrs and 'id' in attrs
        final_attrs = self.build_attrs(attrs, name=name)
        output = [u'']
        # Normalize to strings
        str_values = set([force_unicode(v) for v in value])
        for i, (option_value, option_label) in enumerate(
        chain(self.choices, choices)):
            # If an ID attribute was given, add a numeric index as a suffix,
            # so that the checkboxes don't all have the same ID attribute.
            if has_id:
                final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i))
                label_for = u' for="%s"' % final_attrs['id']
            else:
                label_for = ''

            cb = CheckboxInput(final_attrs,
                check_test=lambda value: value in str_values)
            option_value = force_unicode(option_value)
            rendered_cb = cb.render(name, option_value)
            option_label = conditional_escape(force_unicode(option_label))
            output.append(u'<label%s>%s %s</label>' % (
                label_for, rendered_cb, option_label))
        return mark_safe(u'\n'.join(output))

class TrailerSearchForm(forms.Form):
    SHORT = u'1'
    LONG = u'2'
    LENGTH_CHOICES = (
        (SHORT, 'от 1,5 до 3 метров'),
        (LONG, 'от 3 до 6 метров'),
    )

    SMALL = u'1'
    BIG = u'2'
    CAPACITY_CHOICES = (
        (SMALL, 'до 8 тонн'),
        (BIG, 'от 8 тонн'),
    )

    NO_BRAKES = u'0'
    WITH_BRAKES = u'1'
    BRAKES_CHOICES = (
        (NO_BRAKES, 'без тормозов'),
        (WITH_BRAKES, 'с тормозами'),
    )

    number_axis = forms.MultipleChoiceField(Trailer.NUMBER_AXIS_CHOICES, False,
        CustomCheckboxSelectMultiple, 'Количество осей')
    suspension = forms.MultipleChoiceField(Trailer.SUSPENSION_CHOICES, False,
        CustomCheckboxSelectMultiple, 'Подвеска')
    length = forms.MultipleChoiceField(LENGTH_CHOICES, False,
        CustomCheckboxSelectMultiple, 'Длина платформы')
    capacity = forms.MultipleChoiceField(CAPACITY_CHOICES, False,
        CustomCheckboxSelectMultiple, 'Грузоподъемность')
    availability_of_brakes = forms.MultipleChoiceField(BRAKES_CHOICES, False,
        CustomCheckboxSelectMultiple, 'Наличие тормозов')


import numpy as np
import pandas as pd
import numpy_indexed as npi
import joblib
from tqdm import tqdm
import itertools
import copy

NSTEPS = 20       # max episode length in historical data
G_min = -1        # the minimum possible return
nS, nA = 1442, 8

##################
## Preparations ##
##################

def format_data_tensor(df_data, id_col='pt_id'):
    """
    Converts data from a dataframe to a tensor
    - df_data: pd.DataFrame with columns [id_col, Time, State, Action, Reward, NextState]
        - id_col specifies the index column to group episodes
    - data_tensor: integer tensor of shape (N, NSTEPS, 5) with the last last dimension being [t, s, a, r, s']
    """
    data_dict = dict(list(df_data.groupby(id_col)))
    N = len(data_dict)
    data_tensor = np.zeros((N, NSTEPS, 5), dtype=int)
    data_tensor[:, :, 2] = -1 # initialize all actions to -1
    data_tensor[:, :, 1] = -1 # initialize all states to -1
    data_tensor[:, :, 4] = -1 # initialize all next states to -1

    for i, (pt_id, df_values) in tqdm(enumerate(data_dict.items())):
        values = df_values.set_index(id_col).values
        data_tensor[i, :len(values), :] = values
    return data_tensor

def compute_empirical_MDP(df_data, id_col='pt_id'):
    """
    Calculate parameters of the empirical MDP (P, R, isd)
    using Maximum Likelihood Estimation (MLE)
    """
    # Compute empirical MDP from data
    MDP_parameters = joblib.load('../data/MDP_parameters.joblib')
    P_true = MDP_parameters['transition_matrix_absorbing'] # (A, S, S_next)
    R_true = MDP_parameters['reward_matrix_absorbing_SA'] # (S, A)
    isd_true = joblib.load('../data/modified_prior_initial_state_absorbing.joblib')
    isd_true = (isd_true > 0)
    isd_true = isd_true / isd_true.sum()

    # Transition and Reward matrices
    transition_counts = df_data.groupby(['State', 'Action', 'NextState']).count()[['Reward']].rename(columns={'Reward': 'count'}).reset_index()
    P = P_true.copy()                 # retain for absorbing states
    P[:, (isd_true > 0), :] = 0       # estimate values for non-absorbing states
    R = R_true.copy()
    for i, row in transition_counts.iterrows():
        s, a, s_next = row['State'], row['Action'], row['NextState']
        count = row['count']
        if row['Action'] == -1:
            P[:, s, s_next] = count
        else:
            P[a, s, s_next] = count

    # assume unobserved (s,a) leads to death
    unobserved_sa_pairs = (P.sum(axis=-1) == 0)
    P[unobserved_sa_pairs, -2] = 1
    R[unobserved_sa_pairs.T] = -1

    # normalize transition probabilities
    P = P / P.sum(axis=-1, keepdims=True)

    # reset terminal absorbing states
    P[:, -2:, -2:] = P_true[:, -2:, -2:]

    # Initial state distribution
    initial_states = df_data.groupby(id_col)['State'].first()
    initial_states_count = initial_states.value_counts()
    isd = np.zeros_like(isd_true)
    for s in range(nS):
        if s in initial_states_count.index:
            isd[s] = initial_states_count[s]

    isd = isd / isd.sum()

    return P, R, isd

def compute_behavior_policy(df_data):
    """
    Calculate probabilities of the behavior policy π_b
    using Maximum Likelihood Estimation (MLE)
    """
    # Compute empirical behavior policy from data
    π_b = np.zeros((nS, nA))
    sa_counts = df_data.groupby(['State', 'Action']).count()[['Reward']].rename(columns={'Reward': 'count'}).reset_index()

    for i, row in sa_counts.iterrows():
        s, a = row['State'], row['Action']
        count = row['count']
        if row['Action'] == -1:
            π_b[s, :] = count
        else:
            π_b[s, a] = count

    # assume uniform action probabilities in unobserved states
    unobserved_states = (π_b.sum(axis=-1) == 0)
    π_b[unobserved_states, :] = 1

    # normalize action probabilities
    π_b = π_b / π_b.sum(axis=-1, keepdims=True)

    return π_b

def run_tabular_FQI(df_data, gamma, n_epochs, use_tqdm=False):
    """
    Tabular Fitted-Q Iteration
    """
    S, A, R, S_next = df_data['State'].values, df_data['Action'].values, df_data['Reward'].values, df_data['NextState'].values
    N = len(S)

    Qs = []
    Q = np.zeros((nS, nA))

    # unobserved states lead to minimum reward
    observed_s = set(S) | set(S_next) - {-1}
    unobserved_s = sorted(set(range(nS)) - observed_s)
    Q[unobserved_s, :] = G_min

    # unobserved action in observed states lead to minimum reward
    terminal_action = (A == -1)
    terminal_states = S[terminal_action]
    observed_sa = set(zip(S, A))
    unobserved_sa = np.array(sorted(
        set(itertools.product(observed_s, range(nA)))
        - observed_sa - set(itertools.product(terminal_states, range(nA)))
    ))
    Q[unobserved_sa[:, 0], unobserved_sa[:, 1]] = G_min

    # reset absorbing states
    Q[-2:, :] = 0

    Qs.append(copy.deepcopy(Q))
    for k in tqdm(range(n_epochs), disable=not(use_tqdm)):
        y = R + gamma * Q[S_next, :].max(axis=1)

        # Update value as the sample average
        sa_list, value_list = npi.group_by(np.array([S, A]).T).mean(y)
        Q[sa_list[:, 0], sa_list[:, 1]] = value_list

        # Handle terminal states with action -1, applies to all actions
        terminal_action = (sa_list[:, 1] == -1)
        terminal_states = sa_list[terminal_action, :][:, 0]
        Q[terminal_states, :] = value_list[terminal_action][:,np.newaxis]

        # Save
        Qs.append(copy.deepcopy(Q))

    return Qs

#########################
## Evaluating a policy ##
#########################

def policy_eval_analytic(P, R, π, γ):
    """
    Given the MDP model transition probability P (S,A,S) and reward function R (S,A),
    Compute the value function of a stochastic policy π (S,A) using matrix inversion

        V_π = (I - γ P_π)^-1 R_π
    """
    nS, nA = R.shape
    R_π = np.sum(R * π, axis=1)
    P_π = np.sum(P * np.expand_dims(π, 2), axis=1)
    V_π = np.linalg.inv(np.eye(nS) - γ * P_π) @ R_π
    return V_π

def ground_truth_performance(π, γ):
    """
    Calculate the test-time performance using true MDP parameters
    - π: policy to be evaluated, shape (S,A)
    """
    # Ground truth MDP model
    MDP_parameters = joblib.load('../data/MDP_parameters.joblib')
    P = MDP_parameters['transition_matrix_absorbing'] # (A, S, S_next)
    R = MDP_parameters['reward_matrix_absorbing_SA'] # (S, A)

    # unif rand isd, mixture of diabetic state
    PROB_DIAB = 0.2
    isd = joblib.load('../data/modified_prior_initial_state_absorbing.joblib')
    isd = (isd > 0).astype(float)
    isd[:720] = isd[:720] / isd[:720].sum() * (1-PROB_DIAB)
    isd[720:] = isd[720:] / isd[720:].sum() * (PROB_DIAB)

    V_pi = policy_eval_analytic(P.transpose((1,0,2)), R, π, γ)
    return V_pi @ isd

def OPE_approx_model(π, P_approx, R_approx, isd_approx, γ):
    """
    - π: policy to be evaluated, shape (S,A)
    - P_approx, R_approx, isd_approx: approximate MDP model parameters estimated from data
    """
    V_pi = policy_eval_analytic(P_approx.transpose((1,0,2)), R_approx, π, γ)
    return V_pi @ isd_approx

def OPE_WIS(data, π_b, π_e, γ, epsilon=0.01, bootstrap=None):
    """
    - π_b, π_e: behavior/evaluation policy, shape (S,A)
    """
    # Get a soft version of the evaluation policy for WIS
    π_e_soft = np.copy(π_e).astype(float)
    π_e_soft[π_e_soft == 1] = (1 - epsilon)
    π_e_soft[π_e_soft == 0] = epsilon / (nA - 1)

    # Apply WIS
    return _wis(data, π_b, π_e_soft, γ, bootstrap)

def _wis(data, π_b, π_e, γ, bootstrap):
    """
    Weighted Importance Sampling for Off-Policy Evaluation
        - data: tensor of shape (N, T, 5) with the last last dimension being [t, s, a, r, s']
        - π_b:  behavior policy
        - π_e:  evaluation policy (aka target policy)
        - γ:    discount factor
    """
    t_list = data[..., 0].astype(int)
    s_list = data[..., 1].astype(int)
    a_list = data[..., 2].astype(int)
    r_list = data[..., 3].astype(int)

    # Per-trajectory returns (discounted cumulative rewards)
    G = (r_list * np.power(γ, t_list)).sum(axis=-1)

    # Per-transition importance ratios
    p_b = π_b[s_list, a_list]
    p_e = π_e[s_list, a_list]

    # Deal with variable length sequences by setting ratio to 1
    terminated_idx = (a_list == -1)
    p_b[terminated_idx] = 1
    p_e[terminated_idx] = 1

    if not np.all(p_b > 0):
        import pdb
        pdb.set_trace()
    assert np.all(p_b > 0), "Some actions had zero prob under p_b, WIS fails"

    # Per-trajectory cumulative importance ratios, take the product
    rho = (p_e / p_b).prod(axis=1)

    if bootstrap is None:
        # directly calculate weighted average over trajectories
        wis_value = np.average(G, weights=rho)
        return wis_value, (rho > 0).sum(), rho.sum()
    else:
        # Get indices for bootstrap, because we need to sample from rho and G
        idx = np.random.default_rng(seed=0).choice(np.arange(len(G)), size=(bootstrap, len(G)), replace=True)
        wis_boot = (rho[idx] / rho[idx].mean(axis=1, keepdims=True)) * G[idx]
#         wis_boot = [np.average(G[idx[i]], weights=rho[idx[i]]) for i in range(bootstrap)]

        # Return WIS, one per row
        wis_value = wis_boot.mean(axis=1)
        return wis_value, (rho[idx] > 0).sum(axis=1), rho[idx].sum(axis=1)

def run_tabular_FQE(df_data, π, gamma, n_epochs, use_tqdm=False):
    """
    Tabular Fitted-Q Evaluation
        - π (S,A): policy to be evaluated
    """
    S, A, R, S_next = df_data['State'].values, df_data['Action'].values, df_data['Reward'].values, df_data['NextState'].values
    N = len(S)

    Q = np.zeros((nS, nA))

    # unobserved states lead to minimum reward
    observed_s = set(S) | set(S_next) - {-1}
    unobserved_s = sorted(set(range(nS)) - observed_s)
    Q[unobserved_s, :] = G_min

    # unobserved action in observed states lead to minimum reward
    terminal_action = (A == -1)
    terminal_states = S[terminal_action]
    observed_sa = set(zip(S, A))
    unobserved_sa = np.array(sorted(
        set(itertools.product(observed_s, range(nA)))
        - observed_sa - set(itertools.product(terminal_states, range(nA)))
    ))
    Q[unobserved_sa[:, 0], unobserved_sa[:, 1]] = G_min

    # reset absorbing states
    Q[-2:, :] = 0

    for k in tqdm(range(n_epochs), disable=not(use_tqdm)):
        y = R + gamma * (π[S_next, :] * Q[S_next, :]).sum(axis=1)

        # Update value as the sample average
        sa_list, value_list = npi.group_by(np.array([S, A]).T).mean(y)
        Q[sa_list[:, 0], sa_list[:, 1]] = value_list

        # Handle terminal states with action -1, applies to all actions
        terminal_action = (sa_list[:, 1] == -1)
        terminal_states = sa_list[terminal_action, :][:, 0]
        Q[terminal_states, :] = value_list[terminal_action][:,np.newaxis]

    return Q

def OPE_FQE(df_data, isd, π, n_epochs=50, use_tqdm=False):
    Q = run_tabular_FQE(df_data, π, n_epochs, use_tqdm)
    return isd @ (Q * π).sum(axis=1)

def V2Q(V, P, R, gamma):
    nS, nA = R.shape
    Q = np.zeros((nS, nA))
    for a in range(nA):
        Q[:,a] = sum(P[:,a,s_] * (R[:,a] + gamma * V[s_]) for s_ in range(nS))
    return Q

def OPE_WDR(data, V, Q, π_b, π_e, γ, epsilon=0.01):
    # Get a soft version of the evaluation policy for WIS
    π_e_soft = np.copy(π_e).astype(float)
    π_e_soft[π_e_soft == 1] = (1 - epsilon)
    π_e_soft[π_e_soft == 0] = epsilon / (nA - 1)

    # Apply WDR
    return _wdr(data, V, Q, π_b, π_e_soft, γ)

def _wdr(data, V, Q, π_b, π_e, γ):
    """
    Weighted Doubly Robust for Off Policy Evaluation
    * Reference: http://proceedings.mlr.press/v48/thomasa16.html
        - data: tensor of shape (N, T, 5) with the last last dimension being [t, s, a, r, s']
        - V, Q: estimated value functions
        - π_b:  behavior policy
        - π_e:  evaluation policy (aka target policy)
        - γ:    discount factor
    """
    t_list = data[..., 0].astype(int)
    s_list = data[..., 1].astype(int)
    a_list = data[..., 2].astype(int)
    r_list = data[..., 3].astype(int)

    # Per-transition importance ratios
    p_b = π_b[s_list, a_list]
    p_e = π_e[s_list, a_list]

    # Deal with variable length sequences by setting ratio to 1
    terminated_idx = (a_list == -1)
    p_b[terminated_idx] = 1
    p_e[terminated_idx] = 1

    if not np.all(p_b > 0):
        import pdb
        pdb.set_trace()
    assert np.all(p_b > 0), "Some actions had zero prob under p_b, WIS fails"

    # Per-trajectory cumulative importance ratios rho_{1:t} at each timestep
    rho_cum = (p_e / p_b).cumprod(axis=1)

    # Average cumulative importance ratio at every horizon t
    weights = rho_cum.mean(axis=0)

    # Weighted importance sampling ratios at each timestep
    w = rho_cum / weights
    w_1 = np.hstack([np.ones((w.shape[0],1)), w[..., :-1]]) # offset one timestep

    # Apply WDR estimator
    wdr_terms = np.power(γ, t_list) * (w_1 * V[s_list] + w * r_list - w * Q[s_list, a_list])
    wdr_list = wdr_terms.sum(axis=1)
    wdr_value = wdr_list.mean()

    return wdr_value


import unittest
from tbmetapoppy import *
import os
import ConfigParser as cp

class TBModelTestCase(unittest.TestCase):
    def setUp(self):
        self.boundary = [(10.0,5.0), (10.0,0.0), (0.0,0.0), (0.0,10.0), (10.0,10.0)]
        self.apex = 10
        self.base = 0
        self.length_divisor = 2.0
        self.minimum_space = 2.0
        self.ventilation_skew = 2
        self.perfusion_skew = 3
        self.drainage_skew = 1
        self.output_filename_network = 'test_network.ini'
        self.output_filename_attributes = 'test_attribute.ini'
        create_space_filling_tree_topology(self.boundary, self.minimum_space, self.length_divisor,
                                           self.ventilation_skew, self.perfusion_skew, self.drainage_skew,
                                           self.output_filename_network, self.output_filename_attributes)

        self.output_filename_events = 'test_events.ini'
        create_event_config(self.output_filename_events)

        self.mr_kill_bac = 0.001
        self.ma_kill_bac = 0.002
        self.ber_rep_rate = 0.003
        self.bed_rep_rate = 0.004
        self.bim_rep_rp = 0.005
        self.mac_cap = 20
        self.bim_rep_sig = 2
        self.bed_to_ber_rp = 0.006
        self.bed_to_ber_sig = 1
        self.bed_to_ber_hs = 98
        self.ber_to_bed_rp = 0.007
        self.ber_to_bed_sig = -1
        self.ber_to_bed_hs = 99
        self.bac_trans_rp = 0.008

        self.dci_death_rp = 0.009
        self.dcm_death_rp = 0.010
        self.dc_mat_rp = 0.011
        self.dc_mat_hs = 100
        self.dc_rec_st = 0.012
        self.dc_rec_enh_rp = 0.013
        self.dc_rec_enh_hs = 101
        self.dc_trans_rp = 0.014

        self.mac_act_rp = 0.015
        self.mac_act_hs = 102
        self.mr_death_rp = 0.016
        self.ma_death_rp = 0.017
        self.mi_death_rp = 0.018
        self.mac_burst_rp = 0.019
        self.mac_death_tc_rp = 0.020
        self.mac_death_tc_hs = 103
        self.mac_inf_rp = 0.021
        self.mac_inf_hs = 104
        self.mac_rec_lung_st = 0.022
        self.mac_rec_lym_st = 0.023
        self.mac_rec_lung_enh_mi = 0.024
        self.mac_rec_lung_enh_ma = 0.025
        self.mac_rec_lym_enh_mi = 0.026
        self.mac_rec_lym_enh_ma = 0.027
        self.mac_transl = 0.028

        self.tc_act_dcm = 0.029
        self.tc_act_mi = 0.030
        self.tcn_death = 0.031
        self.tca_death = 0.031
        self.tc_rec_st = 0.032
        self.tc_rec_enh_dcm = 0.033
        self.tc_rec_enh_mi = 0.034
        self.tc_transl = 0.035

        event_config = ConfigParser.ConfigParser()
        event_config.read(self.output_filename_events)

        event_config.set(ExtracellularBacterialReplication.__name__, BACTERIUM_EXTRACELLULAR_REPLICATING, self.ber_rep_rate)
        event_config.set(ExtracellularBacterialReplication.__name__, BACTERIUM_EXTRACELLULAR_DORMANT, self.bed_rep_rate)
        event_config.set(IntracellularBacterialReplication.__name__, REACTION_PARAMETER, self.bim_rep_rp)
        event_config.set(IntracellularBacterialReplication.__name__, CAPACITY, self.mac_cap)
        event_config.set(IntracellularBacterialReplication.__name__, SIGMOID, self.bim_rep_sig)
        event_config.set(BacterialDestruction.__name__, MACROPHAGE_RESTING, self.mr_kill_bac)
        event_config.set(BacterialDestruction.__name__, MACROPHAGE_ACTIVATED, self.ma_kill_bac)
        event_config.set(BacteriumChangeToReplicating.__name__, REACTION_PARAMETER, self.bed_to_ber_rp)
        event_config.set(BacteriumChangeToReplicating.__name__, SIGMOID, self.bed_to_ber_sig)
        event_config.set(BacteriumChangeToReplicating.__name__, HALF_SAT, self.bed_to_ber_hs)
        event_config.set(BacteriumChangeToDormant.__name__, REACTION_PARAMETER, self.ber_to_bed_rp)
        event_config.set(BacteriumChangeToDormant.__name__, SIGMOID, self.ber_to_bed_sig)
        event_config.set(BacteriumChangeToDormant.__name__, HALF_SAT, self.ber_to_bed_hs)
        event_config.set(BacterialTranslocationBlood.__name__, REACTION_PARAMETER, self.bac_trans_rp)

        event_config.set(DendriticCellDeath.__name__, DENDRITIC_CELL_IMMATURE, self.dci_death_rp)
        event_config.set(DendriticCellDeath.__name__, DENDRITIC_CELL_MATURE, self.dcm_death_rp)
        event_config.set(DendriticCellMaturation.__name__, REACTION_PARAMETER, self.dc_mat_rp)
        event_config.set(DendriticCellMaturation.__name__, HALF_SAT, self.dc_mat_hs)
        event_config.set(DendriticCellRecruitmentStandard.__name__, REACTION_PARAMETER, self.dc_rec_st)
        event_config.set(DendriticCellRecruitmentEnhanced.__name__, REACTION_PARAMETER, self.dc_rec_enh_rp)
        event_config.set(DendriticCellRecruitmentEnhanced.__name__, HALF_SAT, self.dc_rec_enh_hs)
        event_config.set(DendriticCellTranslocation.__name__, REACTION_PARAMETER, self.dc_trans_rp)

        event_config.set(MacrophageActivation.__name__, REACTION_PARAMETER, self.mac_act_rp)
        event_config.set(MacrophageActivation.__name__, HALF_SAT, self.mac_act_hs)
        event_config.set(MacrophageDeathStandard.__name__, MACROPHAGE_RESTING, self.mr_death_rp)
        event_config.set(MacrophageDeathStandard.__name__, MACROPHAGE_ACTIVATED, self.ma_death_rp)
        event_config.set(MacrophageDeathStandard.__name__, MACROPHAGE_INFECTED, self.mi_death_rp)
        event_config.set(MacrophageBurst.__name__, REACTION_PARAMETER, self.mac_burst_rp)
        event_config.set(MacrophageDestructionByTCell.__name__, REACTION_PARAMETER, self.mac_death_tc_rp)
        event_config.set(MacrophageDestructionByTCell.__name__, HALF_SAT, self.mac_death_tc_hs)
        event_config.set(MacrophageBecomesInfected.__name__, REACTION_PARAMETER, self.mac_inf_rp)
        event_config.set(MacrophageBecomesInfected.__name__, HALF_SAT, self.mac_inf_hs)
        event_config.set(MacrophageRecruitmentLungStandard.__name__, REACTION_PARAMETER, self.mac_rec_lung_st)
        event_config.set(MacrophageRecruitmentLymphStandard.__name__, REACTION_PARAMETER, self.mac_rec_lym_st)
        event_config.set(MacrophageRecruitmentLungEnhanced.__name__, MACROPHAGE_INFECTED, self.mac_rec_lung_enh_mi)
        event_config.set(MacrophageRecruitmentLungEnhanced.__name__, MACROPHAGE_ACTIVATED, self.mac_rec_lung_enh_ma)
        event_config.set(MacrophageRecruitmentLymphEnhanced.__name__, MACROPHAGE_INFECTED, self.mac_rec_lym_enh_mi)
        event_config.set(MacrophageRecruitmentLymphEnhanced.__name__, MACROPHAGE_ACTIVATED, self.mac_rec_lym_enh_ma)
        event_config.set(MacrophageTranslocation.__name__, REACTION_PARAMETER, self.mac_transl)

        event_config.set(TCellActivation.__name__, DENDRITIC_CELL_MATURE, self.tc_act_dcm)
        event_config.set(TCellActivation.__name__, MACROPHAGE_INFECTED, self.tc_act_mi)
        event_config.set(TCellDeath.__name__, T_CELL_NAIVE, self.tcn_death)
        event_config.set(TCellDeath.__name__, T_CELL_ACTIVATED, self.tca_death)
        event_config.set(TCellRecruitmentStandard.__name__, REACTION_PARAMETER, self.tc_rec_st)
        event_config.set(TCellRecruitmentEnhanced.__name__, DENDRITIC_CELL_MATURE, self.tc_rec_enh_dcm)
        event_config.set(TCellRecruitmentEnhanced.__name__, MACROPHAGE_INFECTED, self.tc_rec_enh_mi)
        event_config.set(TCellTranslocation.__name__, REACTION_PARAMETER, self.tc_transl)

        event_file = open(self.output_filename_events, 'w')
        event_config.write(event_file)
        event_file.close()

        self.model = TBModel(self.output_filename_network, self.output_filename_events)

    def tearDown(self):
        if os.path.exists(self.output_filename_network):
            os.remove(self.output_filename_network)
        if os.path.exists(self.output_filename_attributes):
            os.remove(self.output_filename_attributes)
        if os.path.exists(self.output_filename_events):
            os.remove(self.output_filename_events)

    def test_initialise(self):
        lymph_patches = [n for n in self.model.patches if isinstance(n, LymphPatch)]
        self.assertEqual(len(lymph_patches), 1)
        lymph_patch = lymph_patches[0]
        self.assertItemsEqual(lymph_patch.edges.keys(), [BloodEdge.__name__])
        self.assertEqual(len(lymph_patch.edges[BloodEdge.__name__]), len(self.model.patches)-1)

        for p in [n for n in self.model.patches if isinstance(n, AlveolarPatch)]:
            self.assertItemsEqual(p.edges.keys(), [LymphaticDrainageEdge.__name__])
            self.assertEqual(len(p.edges[LymphaticDrainageEdge.__name__]), 1)
            edge = next(e for e in p.edges[LymphaticDrainageEdge.__name__])
            self.assertEqual(edge.get_neighbour(p), lymph_patch)

        # Events - lung
        for p in [n for n in self.model.patches if isinstance(n, AlveolarPatch)]:
            bac_deaths = [e for e in p.events if isinstance(e, BacterialDestruction)]
            self.assertEqual(len(bac_deaths), 4)
            ber_mr = [e for e in bac_deaths if
                      e._bacterium == BACTERIUM_EXTRACELLULAR_REPLICATING and e._macrophage == MACROPHAGE_RESTING]
            self.assertEqual(len(ber_mr), 1)
            self.assertEqual(ber_mr[0].reaction_parameter, self.mr_kill_bac)
            bed_mr = [e for e in bac_deaths if
                      e._bacterium == BACTERIUM_EXTRACELLULAR_DORMANT and e._macrophage == MACROPHAGE_RESTING]
            self.assertEqual(len(bed_mr), 1)
            self.assertEqual(bed_mr[0].reaction_parameter, self.mr_kill_bac)
            ber_ma = [e for e in bac_deaths if
                      e._bacterium == BACTERIUM_EXTRACELLULAR_REPLICATING and e._macrophage == MACROPHAGE_ACTIVATED]
            self.assertEqual(len(ber_ma), 1)
            self.assertEqual(ber_ma[0].reaction_parameter, self.ma_kill_bac)
            bed_ma = [e for e in bac_deaths if
                      e._bacterium == BACTERIUM_EXTRACELLULAR_DORMANT and e._macrophage == MACROPHAGE_ACTIVATED]
            self.assertEqual(len(bed_ma), 1)
            self.assertEqual(bed_ma[0].reaction_parameter, self.ma_kill_bac)

            ex_bac_reps = [e for e in p.events if isinstance(e, ExtracellularBacterialReplication)]
            self.assertEqual(len(ex_bac_reps), 2)
            ber_rep = [e for e in ex_bac_reps if e._bacterium == BACTERIUM_EXTRACELLULAR_REPLICATING]
            self.assertEqual(len(ber_rep), 1)
            self.assertEqual(self.ber_rep_rate, ber_rep[0].reaction_parameter)
            bed_rep = [e for e in ex_bac_reps if e._bacterium == BACTERIUM_EXTRACELLULAR_DORMANT]
            self.assertEqual(len(bed_rep), 1)
            self.assertEqual(self.bed_rep_rate, bed_rep[0].reaction_parameter)

            bim_rep = [e for e in p.events if isinstance(e, IntracellularBacterialReplication)]
            self.assertEqual(len(bim_rep), 1)
            self.assertEqual(bim_rep[0].reaction_parameter, self.bim_rep_rp)
            self.assertEqual(bim_rep[0]._carrying_capacity, self.mac_cap)
            self.assertEqual(bim_rep[0]._sigmoid, self.bim_rep_sig)

            ber_to_bed = [e for e in p.events if isinstance(e, BacteriumChangeToDormant)]
            self.assertEqual(len(ber_to_bed), 1)
            self.assertEqual(ber_to_bed[0].reaction_parameter, self.ber_to_bed_rp)
            self.assertEqual(ber_to_bed[0]._sigmoid, self.ber_to_bed_sig)
            self.assertEqual(ber_to_bed[0]._half_sat, self.ber_to_bed_hs)
            bed_to_ber = [e for e in p.events if isinstance(e, BacteriumChangeToReplicating)]
            self.assertEqual(len(bed_to_ber), 1)
            self.assertEqual(bed_to_ber[0].reaction_parameter, self.bed_to_ber_rp)
            self.assertEqual(bed_to_ber[0]._sigmoid, self.bed_to_ber_sig)
            self.assertEqual(bed_to_ber[0]._half_sat, self.bed_to_ber_hs)

            dc_deaths = [e for e in p.events if isinstance(e, DendriticCellDeath)]
            self.assertEqual(len(dc_deaths), 2)
            dci_death = [e for e in dc_deaths if e._compartment == DENDRITIC_CELL_IMMATURE]
            self.assertEqual(len(dci_death), 1)
            self.assertEqual(dci_death[0].reaction_parameter, self.dci_death_rp)
            dcm_death = [e for e in dc_deaths if e._compartment == DENDRITIC_CELL_MATURE]
            self.assertEqual(len(dcm_death), 1)
            self.assertEqual(dcm_death[0].reaction_parameter, self.dcm_death_rp)

            dc_mat = [e for e in p.events if isinstance(e, DendriticCellMaturation)]
            self.assertEqual(len(dc_mat), 2)
            self.assertEqual(dc_mat[0].reaction_parameter, self.dc_mat_rp)
            self.assertEqual(dc_mat[1].reaction_parameter, self.dc_mat_rp)

            dc_rec = [e for e in p.events if isinstance(e, DendriticCellRecruitmentStandard)]
            self.assertEqual(len(dc_rec), 1)
            self.assertEqual(dc_rec[0].reaction_parameter, self.dc_rec_st)

            dc_rec_enh = [e for e in p.events if isinstance(e, DendriticCellRecruitmentEnhanced)]
            self.assertEqual(len(dc_rec_enh), 1)
            self.assertEqual(dc_rec_enh[0].reaction_parameter, self.dc_rec_enh_rp)

            dc_transl = [e for e in p.events if isinstance(e, DendriticCellTranslocation)]
            self.assertEqual(len(dc_transl), 1)
            self.assertEqual(dc_transl[0].reaction_parameter, self.dc_trans_rp)

            mac_act = [e for e in p.events if isinstance(e, MacrophageActivation)]
            self.assertEqual(len(mac_act), 1)
            self.assertEqual(mac_act[0].reaction_parameter, self.mac_act_rp)

            mac_death = [e for e in p.events if isinstance(e, MacrophageDeathStandard)]
            self.assertEqual(len(mac_death), 3)
            mr_death = [e for e in mac_death if e._macrophage == MACROPHAGE_RESTING]
            self.assertEqual(len(mr_death), 1)
            self.assertEqual(mr_death[0].reaction_parameter, self.mr_death_rp)
            ma_death = [e for e in mac_death if e._macrophage == MACROPHAGE_ACTIVATED]
            self.assertEqual(len(ma_death), 1)
            self.assertEqual(ma_death[0].reaction_parameter, self.ma_death_rp)
            mi_death = [e for e in mac_death if e._macrophage == MACROPHAGE_INFECTED]
            self.assertEqual(len(mi_death), 1)
            self.assertEqual(mi_death[0].reaction_parameter, self.mi_death_rp)

            mac_burst = [e for e in p.events if isinstance(e, MacrophageBurst)]
            self.assertEqual(len(mac_burst), 1)
            self.assertEqual(mac_burst[0].reaction_parameter, self.mac_burst_rp)
            self.assertEqual(mac_burst[0]._capacity, self.mac_cap)
            self.assertEqual(mac_burst[0]._sigmoid, self.bim_rep_sig)

            mac_death_t_cell = [e for e in p.events if isinstance(e, MacrophageDestructionByTCell)]
            self.assertEqual(len(mac_death_t_cell), 1)
            self.assertEqual(mac_death_t_cell[0].reaction_parameter, self.mac_death_tc_rp)

            mac_inf = [e for e in p.events if isinstance(e, MacrophageBecomesInfected)]
            self.assertEqual(len(mac_inf), 2)
            self.assertEqual(mac_inf[0].reaction_parameter, self.mac_inf_rp)
            self.assertEqual(mac_inf[1].reaction_parameter, self.mac_inf_rp)

            mac_rec_st = [e for e in p.events if isinstance(e, MacrophageRecruitmentLungStandard)]
            self.assertEqual(len(mac_rec_st), 1)
            self.assertEqual(mac_rec_st[0].reaction_parameter, self.mac_rec_lung_st)

            mac_rec_enh = [e for e in p.events if isinstance(e, MacrophageRecruitmentLungEnhanced)]
            self.assertEqual(len(mac_rec_enh), 2)
            mr_rec_mi = [e for e in mac_rec_enh if e._enhancer == MACROPHAGE_INFECTED]
            self.assertEqual(len(mr_rec_mi), 1)
            self.assertEqual(mr_rec_mi[0].reaction_parameter, self.mac_rec_lung_enh_mi)
            mr_rec_ma = [e for e in mac_rec_enh if e._enhancer == MACROPHAGE_ACTIVATED]
            self.assertEqual(len(mr_rec_ma), 1)
            self.assertEqual(mr_rec_ma[0].reaction_parameter, self.mac_rec_lung_enh_ma)

            mac_transl = [e for e in p.events if isinstance(e, MacrophageTranslocation)]
            self.assertEqual(len(mac_transl), 1)
            self.assertEqual(mac_transl[0].reaction_parameter, self.mac_transl)

            tc_death = [e for e in p.events if isinstance(e, TCellDeath)]
            self.assertEqual(len(tc_death), 1)
            self.assertEqual(tc_death[0]._t_cell, T_CELL_ACTIVATED)
            self.assertEqual(tc_death[0].reaction_parameter, self.tca_death)

        # Events - lymph
        bac_deaths = [e for e in lymph_patch.events if isinstance(e, BacterialDestruction)]
        self.assertEqual(len(bac_deaths), 4)
        ber_mr = [e for e in bac_deaths if
                      e._bacterium == BACTERIUM_EXTRACELLULAR_REPLICATING and e._macrophage == MACROPHAGE_RESTING]
        self.assertEqual(len(ber_mr), 1)
        bed_mr = [e for e in bac_deaths if
                      e._bacterium == BACTERIUM_EXTRACELLULAR_DORMANT and e._macrophage == MACROPHAGE_RESTING]
        self.assertEqual(len(bed_mr), 1)
        ber_ma = [e for e in bac_deaths if
                      e._bacterium == BACTERIUM_EXTRACELLULAR_REPLICATING and e._macrophage == MACROPHAGE_ACTIVATED]
        self.assertEqual(len(ber_ma), 1)
        bed_ma = [e for e in bac_deaths if
                      e._bacterium == BACTERIUM_EXTRACELLULAR_DORMANT and e._macrophage == MACROPHAGE_ACTIVATED]
        self.assertEqual(len(bed_ma), 1)

        ex_bac_reps = [e for e in lymph_patch.events if isinstance(e, ExtracellularBacterialReplication)]
        self.assertEqual(len(ex_bac_reps), 2)
        ber_rep = [e for e in ex_bac_reps if e._bacterium == BACTERIUM_EXTRACELLULAR_REPLICATING]
        self.assertEqual(len(ber_rep), 1)
        self.assertEqual(self.ber_rep_rate, ber_rep[0].reaction_parameter)
        bed_rep = [e for e in ex_bac_reps if e._bacterium == BACTERIUM_EXTRACELLULAR_DORMANT]
        self.assertEqual(len(bed_rep), 1)
        self.assertEqual(self.bed_rep_rate, bed_rep[0].reaction_parameter)

        bim_rep = [e for e in lymph_patch.events if isinstance(e, IntracellularBacterialReplication)]
        self.assertEqual(len(bim_rep), 1)
        self.assertEqual(bim_rep[0].reaction_parameter, self.bim_rep_rp)
        self.assertEqual(bim_rep[0]._carrying_capacity, self.mac_cap)
        self.assertEqual(bim_rep[0]._sigmoid, self.bim_rep_sig)

        bac_transl = [e for e in lymph_patch.events if isinstance(e, BacterialTranslocationBlood)]
        self.assertEqual(len(bac_transl), 2)
        self.assertEqual(bac_transl[0].reaction_parameter, self.bac_trans_rp)
        self.assertEqual(bac_transl[1].reaction_parameter, self.bac_trans_rp)

        dc_deaths = [e for e in lymph_patch.events if isinstance(e, DendriticCellDeath)]
        self.assertEqual(len(dc_deaths), 1)
        self.assertEqual(dc_deaths[0].reaction_parameter, self.dcm_death_rp)

        mac_act = [e for e in lymph_patch.events if isinstance(e, MacrophageActivation)]
        self.assertEqual(len(mac_act), 1)
        self.assertEqual(mac_act[0].reaction_parameter, self.mac_act_rp)

        mac_death = [e for e in lymph_patch.events if isinstance(e, MacrophageDeathStandard)]
        self.assertEqual(len(mac_death), 3)
        mr_death = [e for e in mac_death if e._macrophage == MACROPHAGE_RESTING]
        self.assertEqual(len(mr_death), 1)
        self.assertEqual(mr_death[0].reaction_parameter, self.mr_death_rp)
        ma_death = [e for e in mac_death if e._macrophage == MACROPHAGE_ACTIVATED]
        self.assertEqual(len(ma_death), 1)
        self.assertEqual(ma_death[0].reaction_parameter, self.ma_death_rp)
        mi_death = [e for e in mac_death if e._macrophage == MACROPHAGE_INFECTED]
        self.assertEqual(len(mi_death), 1)
        self.assertEqual(mi_death[0].reaction_parameter, self.mi_death_rp)

        mac_burst = [e for e in lymph_patch.events if isinstance(e, MacrophageBurst)]
        self.assertEqual(len(mac_burst), 1)
        self.assertEqual(mac_burst[0].reaction_parameter, self.mac_burst_rp)
        self.assertEqual(mac_burst[0]._capacity, self.mac_cap)
        self.assertEqual(mac_burst[0]._sigmoid, self.bim_rep_sig)

        mac_death_t_cell = [e for e in lymph_patch.events if isinstance(e, MacrophageDestructionByTCell)]
        self.assertEqual(len(mac_death_t_cell), 1)
        self.assertEqual(mac_death_t_cell[0].reaction_parameter, self.mac_death_tc_rp)

        mac_inf = [e for e in lymph_patch.events if isinstance(e, MacrophageBecomesInfected)]
        self.assertEqual(len(mac_inf), 2)
        self.assertEqual(mac_inf[0].reaction_parameter, self.mac_inf_rp)
        self.assertEqual(mac_inf[1].reaction_parameter, self.mac_inf_rp)

        mac_rec_st = [e for e in lymph_patch.events if isinstance(e, MacrophageRecruitmentLymphStandard)]
        self.assertEqual(len(mac_rec_st), 1)
        self.assertEqual(mac_rec_st[0].reaction_parameter, self.mac_rec_lym_st)

        mac_rec_enh = [e for e in lymph_patch.events if isinstance(e, MacrophageRecruitmentLymphEnhanced)]
        self.assertEqual(len(mac_rec_enh), 2)
        mr_rec_mi = [e for e in mac_rec_enh if e._enhancer == MACROPHAGE_INFECTED]
        self.assertEqual(len(mr_rec_mi), 1)
        self.assertEqual(mr_rec_mi[0].reaction_parameter, self.mac_rec_lym_enh_mi)
        mr_rec_ma = [e for e in mac_rec_enh if e._enhancer == MACROPHAGE_ACTIVATED]
        self.assertEqual(len(mr_rec_ma), 1)
        self.assertEqual(mr_rec_ma[0].reaction_parameter, self.mac_rec_lym_enh_ma)

        tc_act = [e for e in lymph_patch.events if isinstance(e, TCellActivation)]
        self.assertEqual(len(tc_act), 2)
        tc_act_mi = [e for e in tc_act if e._apc == MACROPHAGE_INFECTED]
        self.assertEqual(len(tc_act_mi), 1)
        tc_act_dcm = [e for e in tc_act if e._apc == DENDRITIC_CELL_MATURE]
        self.assertEqual(len(tc_act_dcm), 1)

        tc_death = [e for e in lymph_patch.events if isinstance(e, TCellDeath)]
        self.assertEqual(len(tc_death), 2)
        tcn_death = [e for e in tc_death if e._t_cell == T_CELL_NAIVE]
        self.assertEqual(len(tcn_death), 1)
        self.assertEqual(tcn_death[0].reaction_parameter, self.tcn_death)
        tca_death = [e for e in tc_death if e._t_cell == T_CELL_ACTIVATED]
        self.assertEqual(len(tca_death), 1)
        self.assertEqual(tca_death[0].reaction_parameter, self.tca_death)

        tc_rec_st = [e for e in lymph_patch.events if isinstance(e, TCellRecruitmentStandard)]
        self.assertEqual(len(tc_rec_st), 1)
        self.assertEqual(tc_rec_st[0].reaction_parameter, self.tc_rec_st)

        tc_rec_enh = [e for e in lymph_patch.events if isinstance(e, TCellRecruitmentEnhanced)]
        self.assertEqual(len(tc_rec_enh), 2)
        tc_rec_enh_mi = [e for e in tc_rec_enh if e._enhancer == MACROPHAGE_INFECTED]
        self.assertEqual(len(tc_rec_enh_mi), 1)
        self.assertEqual(tc_rec_enh_mi[0].reaction_parameter, self.tc_rec_enh_mi)
        tc_rec_enh_dcm = [e for e in tc_rec_enh if e._enhancer == DENDRITIC_CELL_MATURE]
        self.assertEqual(len(tc_rec_enh_dcm), 1)
        self.assertEqual(tc_rec_enh_dcm[0].reaction_parameter, self.tc_rec_enh_dcm)

        tc_transl = [e for e in lymph_patch.events if isinstance(e, TCellTranslocation)]
        self.assertEqual(len(tc_transl), 1)
        self.assertEqual(tc_transl[0].reaction_parameter, self.tc_transl)

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


import setuptools
import scyjava_config
from os import path

here = path.abspath(path.dirname(__file__))

with open(path.join(here, 'README.md')) as f:
    scyjava_long_description = f.read()

setuptools.setup(
    name='scyjava',
    python_requires='>=3',
    packages=['scyjava', 'scyjava.convert'],
    py_modules=['scyjava_config'],
    version=scyjava_config.version,
    author='Philipp Hanslovsky, Curtis Rueden',
    author_email='hanslovskyp@janelia.hhmi.org',
    description='scyjava',
    long_description=scyjava_long_description,
    long_description_content_type='text/markdown',
    license='Public domain',
    url='https://github.com/scijava/scyjava',
    install_requires=['pyjnius', 'jgo'],
)


import unittest
from collections import namedtuple

from p1844 import class_solution

class MyTestCase(unittest.TestCase):
    def setUp(self) -> None:
        self.solution = class_solution.Solution()
        self.Case = namedtuple('Case', 's expect')
        # example cases
        self.cases_example = [
            self.Case(s="a1c1e1", expect="abcdef"),
            self.Case(s="a1b2c3d4e", expect="abbdcfdhe"),
        ]

    # replaceDigits1
    def test_examples1(self):
        for i, Case in enumerate(self.cases_example):
            with self.subTest(f'replaceDigits1: case: {i}'):
                act = self.solution.replaceDigits1(Case.s)
                self.assertEqual(act, Case.expect)

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


from PIL import Image
import matplotlib.pylab as plt
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Flatten, Dense
from keras import backend as K
from keras.callbacks import ModelCheckpoint
import keras

def image_size(img_path):

    """

    :param img_path: Path of one image to determine the height and the width
    :return: height and width of the image
    """
    img_width, img_height = img_path.size
    return img_width, img_height

def model_build(img_width, img_height, num_classes):

    """

    :param img_width: Width of the images
    :param img_height: Height of the image
    :param num_classes: Number of classes. In this case 10
    :return: Custom built CNN model
    """

    if K.image_data_format() == 'channels_first':
        input_shape = (1, img_width, img_height)
    else:
        input_shape = (img_width, img_height, 1)

    model = Sequential()
    model.add(Conv2D(16, kernel_size=(5, 5), strides=(1, 1), padding = 'same',
                     activation='relu',
                     input_shape=input_shape))
    model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
    model.add(Conv2D(32, (5, 5), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Flatten())
    model.add(Dense(128, activation='relu'))
    model.add(Dense(num_classes, activation='softmax'))

    model.compile(loss=keras.losses.categorical_crossentropy,
                  optimizer=keras.optimizers.Adam(),
                  metrics=['accuracy'])

    checkpointer = ModelCheckpoint(filepath='./mnist_weights.hdf5',
                                   verbose=1, save_best_only=True)

    return model, checkpointer

def datagenerator():

    """
    :return: datagen required for data augmentation to prevent overfitting
    """

    # this is the augmentation configuration we will use for training
    train_datagen = ImageDataGenerator(
        rescale=1. / 255,
        shear_range=0.2,
        zoom_range=0.2,
        horizontal_flip=True)

    # this is the augmentation configuration we will use for testing:
    # only rescaling
    test_datagen = ImageDataGenerator(rescale=1. / 255)

    return train_datagen, test_datagen

def train_validation_split(train_datagen, test_datagen, img_height, img_width, batch_size):

    """

    :param train_datagen: training data generator
    :param test_datagen: testing data generator
    :param img_height: height of the image
    :param img_width: width of the image
    :param batch_size: batch size depending on the number of samples
    :return: training data and the testing data
    """

    train_generator = train_datagen.flow_from_directory(
        train_data_dir,
        target_size=(img_width, img_height),
        color_mode="grayscale",
        batch_size=batch_size,
        class_mode='categorical')

    validation_generator = test_datagen.flow_from_directory(
        validation_data_dir,
        target_size=(img_width, img_height),
        color_mode="grayscale",
        batch_size=batch_size,
        class_mode='categorical')

    return train_generator, validation_generator

def fit(train_generator, validation_generator, checkpointer, model, epochs,
        n_train_samples, n_test_samples):

    """

    :param train_generator: training data
    :param validation_generator: testing data
    :param checkpointer: checkpoint to save the weights of the best model
    :param model: custom built CNN model
    :param epochs: number of epochs
    :param n_train_samples: number of train samples in the dataset
    :param n_test_samples: number of test samples in the dataset
    :return:
    """

    history = model.fit_generator(
        train_generator,
        steps_per_epoch=n_train_samples // batch_size,
        epochs=epochs,
        validation_data=validation_generator,
        validation_steps=n_test_samples // batch_size,
        callbacks=[checkpointer])

    model.save_weights('mnist_model.h5')

    score = model.evaluate_generator(validation_generator, verbose=0, callbacks=[history])

    return history, score

def run(img_path, batch_size, num_classes, epochs, n_train_samples, n_test_samples):

    """

    :param img_path: Path of the image to determine the height and the width
    :param batch_size: batch size depending on the number of samples
    :param num_classes: number of classes in this case 10
    :param epochs: number of epochs
    :param n_train_samples: number of training samples
    :param n_test_samples: number of testing samples
    :return:
    """

    img_width, img_height = image_size(img_path)

    train_datagen, test_datagen = datagenerator()

    train_generator, validation_generator = train_validation_split(train_datagen,
                                                             test_datagen,
                                                             img_height,
                                                             img_width,
                                                             batch_size)

    model, checkpointer = model_build(img_width, img_height, num_classes)

    history, score = fit(train_generator,
                         validation_generator,
                         checkpointer,
                         model,
                         epochs,
                         n_train_samples,
                         n_test_samples)

    return history, score

def plots(History):

    """

    :param History: Metrics of the model.
    :return: Accuracy and loss plots
    """

    plt.plot(History.history['loss'])
    plt.plot(History.history['val_loss'])
    plt.title('Model Loss')
    plt.ylabel('Loss')
    plt.xlabel('Epochs')
    plt.legend(['train', 'test'])
    plt.show()

    plt.plot(History.history['accuracy'])
    plt.plot(History.history['val_accuracy'])
    plt.title('Model Accuracy')
    plt.ylabel('Accuracy')
    plt.xlabel('Epochs')
    plt.legend(['train', 'test'])
    plt.show()

if __name__ == '__main__':

    train_data_dir = '../../data/raw/data/mnist/training'
    validation_data_dir = '../../data/raw/data/mnist/testing'

    n_train_samples = 60000
    n_test_samples = 10000

    batch_size = 512
    num_classes = 10
    epochs = 50

    img_path = Image.open('../../data/raw/data/mnist/training/0/1.png')

    history, score = run(img_path, batch_size, num_classes, epochs, n_train_samples, n_test_samples)

    plots(history)

    print("Training Accuracy: {}".format(history.history['accuracy']))
    print("Testing Accuracy: {}".format(history.history['val_accuracy']))

    """
    The validation accuracy was 98.81% at the 23rd Epoch.
    loss: 0.0479 - accuracy: 0.9847 - val_loss: 0.0229 - val_accuracy: 0.9881

    """