#Import essential packages
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import random
import numpy as np
import os
import sys

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'

# specify model used by input arguments
unit_name = sys.argv[1]
mode = sys.argv[2]
pred_length = int(sys.argv[3])

if mode == "32":
    rnn_size = 32
elif mode == "64":
    rnn_size = 64
elif mode == "128":
    rnn_size = 128
elif mode == "stack_32":
    rnn_size = 32

# read the data
data_dir = '../data'
mnist = input_data.read_data_sets(data_dir, one_hot=True)

# a function to binarize data
def binarize(data, threshold=0.1):
    data = (threshold < data).astype('float32')

    return data

# binarize the data
X_train_original = binarize(mnist.train.images)
y_train_original = mnist.train.labels

X_vali_original = binarize(mnist.validation.images)
y_vali_original = mnist.validation.labels

X_test_original = binarize(mnist.test.images)
y_test_original = mnist.test.labels

# number of images
num_image_test = 100
# choose a random seed to fix the result
np.random.seed(2018)

# get the random images
inpainting_select_ind = np.random.permutation(X_test_original.shape[0])[:num_image_test]
X_test_original = X_test_original[inpainting_select_ind]
y_test_original = y_test_original[inpainting_select_ind]
# mask the data
ground_truth_images = X_test_original.copy()
ground_truth_labels = y_test_original.copy()
masked_images = X_test_original.copy()
masked_images[:, -300:] = np.nan

# define some hyperparameters
num_images = masked_images.shape[0]
pixel_length = masked_images.shape[1]

n_classes = 2
batch_size = 512
prediction_start = 484
chunk_size = 1
num_chunks = 784
num_sample_image = 10

# define some place holder
x = tf.placeholder("float",[None,num_chunks,chunk_size])
y = tf.placeholder("float",[None,chunk_size])
# define the recurrent neural net in this cell

def recurrent_neural_network(x):
    # get the shape of x
    x_shape = tf.shape(x)[0]
    # define some weights for RNN
    rnn_to_pixel_layer = {'weight':tf.Variable(tf.random_normal([rnn_size,1])),\
                     'bias':tf.Variable(tf.random_normal([1]))}
    # reshape the data
    before = tf.transpose(x,[1,0,2])
    before = tf.reshape(before,[-1,chunk_size])
    before = tf.split(before,num_or_size_splits=num_chunks,axis=0)

    # define RNN cell
    if unit_name == "GRU":
        RNN_cell = tf.nn.rnn_cell.GRUCell(num_units=rnn_size)
    elif unit_name == "LSTM":
        RNN_cell = tf.nn.rnn_cell.LSTMCell(num_units=rnn_size)

    if mode == "stack_32":
        stack_rnn = []
        for i in range(3):
            stack_rnn.append(tf.nn.rnn_cell.GRUCell(num_units=rnn_size))
        RNN_cell = tf.contrib.rnn.MultiRNNCell(stack_rnn, state_is_tuple=True)

    outputs, states = tf.contrib.rnn.static_rnn(RNN_cell,before,dtype=tf.float32)

    # calculate the pixels
    pixels = []
    for this_pixel in range(len(outputs)-1):
        pix = tf.add(tf.matmul(outputs[this_pixel],rnn_to_pixel_layer['weight']),rnn_to_pixel_layer['bias'])
        pixels.append(pix)
    # concat the pixels and output
    final_pixels = tf.concat(pixels,axis=0)
    rnn_output = tf.reshape(final_pixels,[(num_chunks-1) * x_shape,-1])

    return rnn_output

# define the prediction
prediction = recurrent_neural_network(x)
prediction_eval = tf.nn.sigmoid(prediction)
predict_result = tf.round(prediction_eval)
# split for indexing
pixelwise_pred = tf.split(predict_result, num_or_size_splits=pixel_length-1, axis=0)

# allocate an array for reconstruction
random_reconstruction = np.zeros([num_image_test,num_sample_image,784])
image_uncertain_groudtruth = np.zeros([num_image_test,num_sample_image,784])
for this_sample in range(num_sample_image):
    random_reconstruction[:,this_sample,:prediction_start] = ground_truth_images[:,:prediction_start]
    image_uncertain_groudtruth[:,this_sample,:] = ground_truth_images[:]

# a functin to store data needed
def store_data(store_dict):
    if not os.path.exists('../models/'):
        os.mkdir('../models/')
    np.save("../models/inpainting_{}_{}_{}_store_dict.npy".format(unit_name, mode, pred_length), store_dict)
    print("saved to ../models/inpainting_{}_{}_{}_store_dict.npy".format(unit_name, mode, pred_length))

store_dict = {}

inpainting_loss_list = []
ground_truth_loss_list = []

with tf.Session() as sess:
    saver = tf.train.Saver()
    saver.restore(sess, '../models/pixel_{}_{}.checkpoint'.format(unit_name, mode))
    for i in range(pred_length):
        pixel_index = i + prediction_start - 1

        # define a inpainting and grund truth loss list for this prediction
        IP_loss_list = []
        GT_loss_list = []

        # start prediction
        for this_sample in range(num_sample_image):
            #print the process
            current_process = (i*(1/pred_length) + (this_sample+1)*(1/num_sample_image*(1/pred_length)))*100
            print('\rprocessing inpainting {:.2f} % finished'.format(current_process),end="",flush=True)

            # reshape data, get x and y for prediction
            this_input_pixel_x = np.reshape(random_reconstruction[:,this_sample,:],[-1, num_chunks, chunk_size])
            this_input_pixel_y = np.transpose(this_input_pixel_x,[1,0,2])
            this_input_pixel_y = np.reshape(this_input_pixel_y,[-1, chunk_size])
            inpainting_dict = {x:this_input_pixel_x,y:this_input_pixel_y}
            # reshape data, get x and y for ground truth
            this_input_true_x = np.reshape(image_uncertain_groudtruth[:,this_sample,:],[-1, num_chunks, chunk_size])
            this_input_true_y = np.transpose(this_input_true_x,[1,0,2])
            this_input_true_y = np.reshape(this_input_true_y,[-1,chunk_size])
            GT_dict = {x:this_input_true_x,y:this_input_true_y}
            # get the probability of the pixel

            # evaluate for inpainting and ground truth
            inpainting_prob = np.reshape(prediction_eval.eval(inpainting_dict),[num_chunks-1,num_image_test])
            this_inpainting_prob = inpainting_prob[pixel_index,:]
            Ground_truth_prob = np.reshape(prediction_eval.eval(GT_dict),[num_chunks-1,num_image_test])
            GT_pixel_prob = Ground_truth_prob[pixel_index,:]
            pred_GT_pixel_value = pixelwise_pred[pixel_index].eval(GT_dict)
            GT_pixel_value = image_uncertain_groudtruth[:,this_sample,pixel_index]

            # randomly matrix for random sample generation purposes
            random_matrix = np.random.uniform(low=0.0, high=1.0, size=this_inpainting_prob.shape)
            # get sample for this prediction subtract by the random matrix
            this_inpainting_pixel = this_inpainting_prob - random_matrix
            this_inpainting_pixel[this_inpainting_pixel >= 0] = 1.0
            this_inpainting_pixel[this_inpainting_pixel < 0] = 0.0

            random_reconstruction[:,this_sample,pixel_index+1] = this_inpainting_pixel[:]

            #calculate the cross-entropy loss for both inpainting ang ground truth
            inpainting_cross_entropy = -(np.multiply(this_inpainting_pixel, np.log(this_inpainting_prob)) + np.multiply((1 - this_inpainting_pixel), np.log(1 - this_inpainting_prob)))
            IP_loss_list.append(inpainting_cross_entropy)

            ground_truth_cross_entropy = -(np.multiply(GT_pixel_value, np.log(GT_pixel_prob)) + np.multiply((1 - GT_pixel_value), np.log(1 - GT_pixel_prob)))
            GT_loss_list.append(ground_truth_cross_entropy)
        # average the losses
        if i == 0:
            inpainting_loss_list = np.array(IP_loss_list)/pred_length
            ground_truth_loss_list = np.array(GT_loss_list)/pred_length
        else:
            inpainting_loss_list += np.array(IP_loss_list)/pred_length
            ground_truth_loss_list += np.array(GT_loss_list)/pred_length

    # save the loss for future uses
    inpainting_loss_list = np.array(inpainting_loss_list)
    ground_truth_loss_list = np.array(ground_truth_loss_list)
    store_dict["inpainting_loss_list"] = inpainting_loss_list
    store_dict["ground_truth_loss_list"] = ground_truth_loss_list
    store_dict["random_reconstruction"] = random_reconstruction
    store_dict["X_test_original"] = X_test_original
    store_dict["y_test_original"] = y_test_original

    store_data(store_dict)


"""Module containing the MultiSeq class and support functionality.

This class along with yaml extensions implemented in yaml_parse
(!multiseq and !range) allow you to define an experiment once while also
using a range of values for some of the parameters.

The simplest usage would imply defining both the control class (MultiSeq)
and the experiment in the same file like so:

.. code-block:: none

    {
        multiseq: !multiseq: {
            # ...
        },
        train: !obj:pylearn2.train.Train {
            # ...
        }
    }

"""
__authors__ = "Nicu Tofan"
__copyright__ = "Copyright 2015, Universite de Montreal"
__credits__ = ["Nicu Tofan"]
__license__ = "3-clause BSD"
__maintainer__ = "LISA Lab"
__email__ = "pylearn-dev@googlegroups"

import re
import os
from numpy import linspace
from random import randint
from datetime import datetime
from uuid import uuid1

from pylearn2.utils import as_floatX, string_utils
from pylearn2.utils.string_utils import preprocess

# Regular expression used to extract data from !range
RANGE_REGEXP = r'^\$\{([0-9a-zA-Z_]+):([0-9\.]+),([0-9\.]+),([0-9]+)\}$'

class RangeVar(object):
    """
    One range variable.

    Parameters
    ----------

    name : str
        The name as it will be used in the custome environment.
    space : numpy.linspace instance
        The linear space from which we will extract values..
    index : int
        Current index inside space.

    """
    def __init__(self, name, space):
        super(RangeVar, self).__init__()

        self.name = name
        self.space = space
        self.index = -1

    def compute_next_id(self, method):
        """
        Selects the next index based on current value and provided settings.

        If ordered mode is selected the values will be incremented and,
        at the end, will wrap around.MultiSeq

        If random mode is selected a random index is picked up.

        Returns
        -------
        new_idx : int
            Newly assigned index.
        """
        new_idx = self.index
        if method == 'ordered':
            new_idx = new_idx + 1
            if new_idx >= len(self.space):
                new_idx = 0
        elif method == 'random':
            new_idx = randint(0, len(self.space)-1)
        else:
            raise NotImplementedError(method)

        self.index = new_idx
        return new_idx

    def value(self):
        """
        Returns the value based on internal range and index.

        We can't just `float(self.space[self.index])` because it may get
        promoted to float64 and that is only desirable if floatX is float64.

        We can't also just `as_floatX(self.space[self.index])` because there
        are assertions in code that explicitly expect a float and
        as_floatX will create a one dimensional array.

        So, there you go. The solution below appears to work. I'm sure you
        can see why.
        """
        return float(as_floatX(self.space[self.index]))

class MultiSeq(object):
    """
    Implements multiple experiments from a single source using value ranges.

    This is a helper class for yaml_parser module.

    Parameters
    ----------

    multiseq_tag: str
        Unique tag for this run generated using uuid or current time.

    iterations: int
        Number of iterations performed so far.

    dynamic_env: dict of strings
        Variables that are updated at the start of a new iteration

    range_vars: list
        the list of variables with an associated range

    """
    _instance = None
    def __init__(self):

        super(MultiSeq, self).__init__()
        MultiSeq._instance = self

        self.multiseq_tag = None
        self.grouping = 'once'
        self.iterations = 0
        self.dynamic_env = {}
        self.range_vars = {}
        self.__range_regexp__ = re.compile(RANGE_REGEXP)

    @staticmethod
    def get_instance():
        """
        Get existing instance or create a new one.
        """
        if MultiSeq._instance is None:
            MultiSeq()
        return MultiSeq._instance

    @staticmethod
    def get_value(rng_var):
        """
        Get existing instance or create a new one.
        """
        return rng_var.value()

    def reinit(self, grouping, gen_val, gen_tag, max_count, environ=None):
        """
        Prepare to iterate over examples.
        """
        self.iterations = 0
        self.grouping = grouping
        self.gen_tag = gen_tag
        self.gen_val = gen_val
        self.max_count = max_count
        if environ is None:
            self.dynamic_env = {}
        else:
            self.dynamic_env = environ
        self.__order_of_change__ = []
        self.__var_to_change__ = -1

    def unique_tag(self):
        """
        Generate a unique tag for current run.
        """
        if self.gen_tag == 'uuid':
            self.multiseq_tag = str(uuid1())
        else:
            date_tm = datetime.utcnow()
            self.multiseq_tag = '%4d_%02d_%02d_%02d_%02d_%02d_%06d' % \
                                (date_tm.year, date_tm.month, date_tm.day,
                                 date_tm.hour, date_tm.minute, date_tm.second,
                                 date_tm.microsecond)

    def first_iteration(self):
        """
        Prepares the object for first run.
        """
        # prepare the counter
        self.iterations = 0

        # generate a unique tag
        self.unique_tag()

        # update all variables to next value
        for dynk in self.range_vars:
            self.range_vars[dynk].compute_next_id(self.gen_val)

        # we will change variables in this order
        self.__var_to_change__ = -1
        self.__order_of_change__ = self.range_vars.keys()

        # update variables in custom dictionary
        self.set_iter_vars()

    def next_iteration(self):
        """
        Advances to next step.

        Returns False if we're at the end.
        """
        # update the counter
        self.iterations = self.iterations + 1
        if self.iterations >= self.max_count:
            return False

        # generate a unique tag
        self.unique_tag()

        if self.grouping == 'once':
            return False
        elif self.grouping == 'one':
            # select the variable that is going to be changed
            if len(self.__order_of_change__) == 0:
                return False
            self.__var_to_change__ = self.__var_to_change__ + 1
            if self.__var_to_change__ >= len(self.__order_of_change__):
                self.__var_to_change__ = 0

            # only update this variable to next value
            var_name = self.__order_of_change__[self.__var_to_change__]
            self.range_vars[var_name].compute_next_id(self.gen_val)
        else:
            # update all variables to next value
            for dynk in self.range_vars:
                self.range_vars[dynk].compute_next_id(self.gen_val)

        # update variables in custom dictionary
        self.set_iter_vars()

        # continue the iteration
        return True

    def set_iter_vars(self):
        """
        Set the variables that change with each iteration.
        """
        self.dynamic_env['MULTISEQ_ITER'] = str(self.iterations)
        self.dynamic_env['MULTISEQ_TAG'] = self.multiseq_tag

        # add our range variables to custom environment
        for dynk in self.range_vars:
            self.dynamic_env[dynk] = str(self.val_for_name(dynk))

    @staticmethod
    def _to_number(str_to_conv):
        """
        Attempts to convert the value to either an integer or a float.
        """
        try:
            return int(str_to_conv)
        except ValueError:
            return float(str_to_conv)

    def add_range_var(self, var_str):
        """
        Creates or updated a range variable from a string.

        Expected string has the form "${VARNAME:start,stop,num}"
        """
        match = self.__range_regexp__.match(var_str)
        if not match:
            raise ValueError('Value %s is not a valid !range value' % str(var_str))

        start_val = MultiSeq._to_number(match.group(2))
        end_val = MultiSeq._to_number(match.group(3))
        num_val = MultiSeq._to_number(match.group(4))
        lspc = linspace(start=start_val,
                        stop=end_val,
                        num=num_val,
                        endpoint=True)

        # create the variable
        rng_var = RangeVar(name=match.group(1), space=lspc)

        # insert it in our list
        self.range_vars[match.group(1)] = rng_var

        # and return initial value
        return rng_var

    def val_for_name(self, rng_var_name):
        """
        Gets current value of a range variable given range variable's name.
        """
        return self.range_vars[rng_var_name].value()

    def save_params(self):
        """
        Converts the input to a string and dumps it to provided file.

        The file is only generated if local environment contains
        a key called `PARAMETERS_FILE`. Otherwise we assume that the
        user does not want a separate file.

        TODO:generate a runnable yaml file.
        """
        if not self.dynamic_env.has_key('PARAMETERS_FILE'):
            return
        file_path = preprocess(self.dynamic_env['PARAMETERS_FILE'],
                               self.dynamic_env)
        with open(file_path, "w") as f_param:
            for k in self.dynamic_env.keys():
                f_param.write('%s: %s\n' % \
                              (k,
                               preprocess(self.dynamic_env[k],
                                          environ=self.dynamic_env)))
            f_param.write('#----------------------------------------\n')
            for k in os.environ.keys():
                f_param.write('%s: %s\n' % (k, os.environ[k]))


from __future__ import unicode_literals
from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
import unittest
from mousetrap.gui import Pointer
from mousetrap.main import Config

class test_pointer(unittest.TestCase):

    def setUp(self):
        self.pointer = Pointer(Config().load_default())

    def test_get_position(self):
        pointer_x, pointer_y = self.pointer.get_position()
        try:
            pointer_x += 1
            pointer_y += 1
        except TypeError:
            self.assertTrue(False, msg='pointer_x or pointer_y is not a number')

    def test_set_position(self):
        self.pointer.set_position((3, 4))
        pointer_x, pointer_y = self.pointer.get_position()
        self.assertEquals(3, pointer_x)
        self.assertEquals(4, pointer_y)

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


from contextlib import contextmanager
import http.client as http_client
import logging
from datetime import datetime
from time import sleep
import json

import tempfile
import os

from io import BytesIO
from matplotlib import pyplot as plt
from PIL import Image
from h5py import File as H5File
import xarray as xa
import numpy as np
import geopandas as gpd
import contextily as ctx

from satstac import Catalog

import requests
from cachecontrol import CacheController, CacheControlAdapter

def _build_session():
  """Builds a requests session that caches responses where possible, making redirects faster.

  Returns:
      requests.Session -- A shared session to use for the notebook
  """
  result = requests.session()

  # Set up caching.  Particularly obey and cache 307 redirects to avoid duplicate expensive calls when we already
  # have a result
  cache_adapter = CacheControlAdapter()
  cache_adapter.controller = CacheController(cache=cache_adapter.cache, status_codes=(200, 203, 300, 301, 307))

  result.mount('http://', cache_adapter)
  result.mount('https://', cache_adapter)
  return result

# Session accessible by callers
session = _build_session()

def debug_http():
  """Adds debugging output to HTTP requests to show redirects, headers, etc
  """
  http_client.HTTPConnection.debuglevel = 1
  logging.basicConfig()
  logging.getLogger().setLevel(logging.DEBUG)
  requests_log = logging.getLogger("requests.packages.urllib3")
  requests_log.setLevel(logging.DEBUG)
  requests_log.propagate = True

def request(*args, **kwargs):
  """Thin wrapper around requests.Request, logging URL sent and Content-Type received

  See https://requests.readthedocs.io/en/master/api/#requests.Request for args

  Returns:
      requests.Response -- The response to the request
  """
  req = requests.Request(*args, **kwargs)
  prepped = session.prepare_request(req)

  print('%s %s' % (prepped.method, prepped.path_url))
  response = session.send(prepped)
  #print('Received %s' % (response.headers.get('Content-Type', 'unknown content',)))
  return response

def get(*args, **kwargs):
  """Performs a GET request using the request wrapper

  See https://requests.readthedocs.io/en/master/api/#requests.Request for args

  Returns:
      requests.Response -- The response to the request
  """
  return request('GET', *args, **kwargs)

def post(*args, **kwargs):
  """Performs a POST request using the request wrapper

  See https://requests.readthedocs.io/en/master/api/#requests.Request for args

  Returns:
      requests.Response -- The response to the request
  """
  return request('POST', *args, **kwargs)

def show_shape(filename, basemap=True):
  """Plots the shapefile in the given filename with optional basemap (ESRI or GeoJSON)

  Arguments:
      filename {string} -- The filename of the shapefile to display

  Keyword Arguments:
      basemap {bool} -- Whether to display a basemap under the shapefile (default: {True})
  """
  shape = gpd.read_file(filename).to_crs(epsg=3857)
  plot = shape.plot(alpha=0.5, edgecolor='k', figsize=(8, 8))
  if basemap:
    ctx.add_basemap(plot)

def show(response, varList=[], color_index=None, immediate=True, flip=True):
  """Shows a variety of responses possible from Harmony for its example data

  Handles NetCDF files with red_var, green_var, blue_var, and alpha_var bands, compositing output
  into a single colored image, ESRI Shapefiles with basemaps, and any type of image that can be
  read by PIL, including GeoTIFF

  Arguments:
      response {requests.Response} -- The response containing the data to display
      varList {array} -- If set, only plot the variables listed in varList.  Otherwise, plot all.

  Keyword Arguments:
      color_index {number} -- Set for monochromatic images to put the output in a color band (0=red, 1=green, 2=blue) (default: {None})
      immediate {bool} -- True if the data should be shown immediately in the notebook (default: {True})
      flip {bool} -- Whether to flip the numpy arrays for stacked plots

  """

  # show_netcdf (look at dimensions, decide how to display); show_image
  plt.rcParams['figure.figsize'] = [16, 8]
  arrays = []

  check_status(response)
  content_type = response.headers['Content-Type']
  print('Content-type: ', content_type)

  if content_type == 'binary/octet-stream' or content_type == 'application/octet-stream':
    print('WARNING: Let service developer know to set their content_type correctly!')

  if content_type == 'application/x-netcdf' or content_type == 'application/x-netcdf4' or content_type == 'application/netcdf' or content_type == 'binary/octet-stream' or content_type == 'application/octet-stream':
    # Show NetCDF4
    data = H5File(BytesIO(response.content), 'r')

    # If user didn't provide any specific vars to plot check if the nc4 file has rgba vars to plot,
    # otherwise pull all vars into varList
    is_default_rgba = False
    if (len(varList) == 0):
      rgba_var_list = []
      # don't look for an exact match (e.g. == 'red_var')
      # so that we can find subsetted rgba vars as well, which have longer var names
      for rgba_key in ['red', 'green', 'blue', 'alpha']:
        var_iterator = (data_key for data_key in data.keys() if rgba_key in data_key)
        rgba_var_list.append(next(var_iterator, None))
      if None in varList:
        varList = data.keys()
      else:
        is_default_rgba = True
        varList = rgba_var_list

    #Plot the variables requested
    for var in varList:
      if var in data and len(data[var].shape) > 0:
          if (len(data[var].shape) < 3) and not is_default_rgba:
            #Simple plot for 1D or 2D
            plt.plot(data[var])
            plt.show()
          else:
            #Setup for 3D display
            ds = data[var]
            sliced_ds = None
            if len(ds.shape) > 2:
              sliced_ds = ds[0,:]
            else:
              sliced_ds = ds[:,:]
            values = sliced_ds
            if flip:
              values = np.flip(sliced_ds, 0)
            where = (values != ds.attrs.get('_FillValue', None))
            scale = ds.attrs.get('scale_factor', [1])[0]
            offset = ds.attrs.get('add_offset', [0])[0]
            array = np.where(where, values * scale + offset, values)
            arrays.append(array)
      else:
        print('Error: ', var, 'not found in dataset')
    if (len(arrays) != 0):
      #plot the 3D data
      plt.imshow(np.dstack(arrays))
  elif content_type in ['application/zip', 'application/shapefile+zip']:
    # Show ESRI Shapefiles
    tmp = tempfile.NamedTemporaryFile(suffix='.shp.zip', delete=False)
    try:
      tmp.write(response.content)
      show_shape('zip://' + tmp.name, immediate)
    finally:
      os.unlink(tmp.name)
  elif 'application/json' in content_type:
    #Most likely an error
    print(response.json())
    assert(False)
  else:
    # Show Images
    if color_index == None:
      plt.imshow(Image.open(BytesIO(response.content)))
    else:
      gray_image = Image.open(BytesIO(response.content))
      # Move 1-channel green_var TIFF to second channel of RGB
      image = Image.new('RGB', gray_image.size)
      # There's probably a better way to do this with numpy
      if color_index == 0:
        image.putdata([(g, 0, 0) for g in gray_image.getdata()])
      if color_index == 1:
        image.putdata([(0, g, 0) for g in gray_image.getdata()])
      if color_index == 2:
        image.putdata([(0, 0, g) for g in gray_image.getdata()])
      plt.imshow(image)
  if immediate:
    plt.show()

def get_data_urls(response):
  """Returns the data URLs in an async response

  Arguments:
      response {response.Response} -- The async job response

  Returns:
      string[] -- An array of URLs for data links
  """
  return [link['href'] for link in response.json()['links'] if link.get('rel', 'data') == 'data']

def show_async(response, varList = []):
  """Shows an asynchronous Harmony response.

  Polls the output, displaying it as it changes, displaying any http data
  links in the response as they arrive, and ultimately ending once the request
  is successful or failed

  Arguments:
      response {response.Response} -- the response to display
      varList {array} -- If set, only plot the variables listed in varList.  Otherwise, plot all.

  Returns:
      response.Response -- the response from the final successful or failed poll
  """
  def show_response(response, link_count):
    print('Async response at', datetime.now().strftime("%H:%M:%S"))
    print(json.dumps(response.json(), indent=2))
    links = get_data_urls(response)
    new_links = links[slice(link_count, None)]
    for link in new_links:
      if link.startswith('http'):
        show(get(link), varList)
    return len(links)

  check_status(response)
  displayed_link_count = 0
  body = response.json()
  displayed_link_count = show_response(response, displayed_link_count)
  waiting_message_printed = False
  while body['status'] not in ['successful', 'failed', 'canceled']:
    if not waiting_message_printed:
      print('Waiting for updates...')
      waiting_message_printed = True
    sleep(1)
    progress = body['progress']
    status = body['status']
    response = session.get(response.url)
    body = response.json()
    if progress != body['progress'] or status != body['status']:
      displayed_link_count = show_response(response, displayed_link_count)
      waiting_message_printed = False

  assert(body['status'] not in ['failed'])
  check_stac(response)
  print('Async request is complete')
  return response

def print_async_status(body):
  """Prints the status, progress and any messages for the async job

  Arguments:
      body {json} -- the response body to display

  """
  print('JobID:',body['jobID'],'Status:',body['status'],'(',body['progress'],'%) Messages:', body['message'])

def show_async_condensed(response, varList = [], show_results=True):
  """Shows a condensed version of the asynchronous Harmony response.  Useful for getting status if you don't care about the results.

  Polls the output, displaying status as it changes, and ultimately ending once the request
  is successful or failed

  Arguments:
      response {response.Response} -- the response to display
      varList {array} -- If set, only plot the variables listed in varList.  Otherwise, plot all.
      show_results {bool} -- True will display the results as they arrive.  (default: {True})
  """
  def show_response_condensed(response, varList, link_count):
    links = get_data_urls(response)
    new_links = links[slice(link_count, None)]
    for link in new_links:
      if link.startswith('http'):
        show(get(link), varList)
    return len(links)

  check_status(response)

  displayed_link_count = 0
  body = response.json()
  print ('Getting results for request')
  print_async_status(body)
  if show_results:
    displayed_link_count = show_response_condensed(response, varList, displayed_link_count)
  while body['status'] not in ['successful', 'failed', 'canceled']:
    sleep(0.5)
    progress = body['progress']
    status = body['status']
    response = session.get(response.url)
    body = response.json()
    if progress != body['progress'] or status != body['status']:
      if show_results:
        displayed_link_count = show_response_condensed(response, varList, displayed_link_count)
      print_async_status(body)

  assert(body['status'] not in ['failed'])
  check_stac(response)
  print('Async request is complete')

def check_bbox_subset(response, req_lat_min, req_lat_max, req_lon_min, req_lon_max):
  """Asserts if the spatial extents of the data in the response are within the requested bbox of a spatial subset

  #####  CHECK_BBOX_SUBSET currently is not in use; placeholder for the next round of regression test work

  Arguments:
      response {response.Response} -- the response to display
      req_lat_min -- The minimimum latitude from the request bbox for a spatial subset
      req_lat_max -- The maximum latitude from the request bbox for a spatial subset
      req_lon_min -- The minimimum longitude from the request bbox for a spatial subset
      req_lon_max -- The maximum longitude from the request bbox for a spatial subset
  """

  data = H5File(BytesIO(response.content), 'r')

  attr_data = data['lat'][:]

  print('Orig min and max: ', attr_data.min(), attr_data.max() )
  lat_min = (attr_data.min() + 180) % 360 - 180
  lat_max = (attr_data.max() + 180) % 360 - 180
  print(lat_min)
  print(lat_max)

  assert lat_max <= req_lat_max
  assert lat_min >= req_lat_min

  attr_data = data['lon'][:]
  lon_min = (attr_data.min() + 180) % 360 - 180
  lon_max = (attr_data.max() + 180) % 360 - 180
  print(lon_min)
  print(lon_max)

  assert lon_max <= req_lon_max
  assert lon_min >= req_lon_min

def check_status(response):
  """Asserts if the response is a 200, if not, print out the response code

  Arguments:
      response {response.Response} -- the response to display
  """
  if (response.status_code != 200):
    errStr = 'Request failed with status code ' + str(response.status_code)
    assert False, errStr

def check_stac(response):
  """Asserts if the response contains a valid STAC catalog and prints it out.  More robust assertions could
    be done here in the future to confirm that the STAC metadata is valid per the request parameters

  Arguments:
      response {response.Response} -- the response to display
  """
  for i in range(len(response.json()['links'])):
    if response.json()['links'][i]['title'] == 'STAC catalog':
        stac_url = response.json()['links'][i]['href']

  assert(stac_url)
  cat = Catalog.open(stac_url)

  for i in cat.items():
    assert(i.id)
    assert(i.datetime)
    assert(i.bbox)
    assert(i.assets.keys())
    print('STAC Item')
    print('\t', 'ID:', i.id)
    print('\t', 'Date:', i.datetime)
    print('\t', 'Bounding Box:', i.bbox)
    print('\t', 'File:', list(i.assets.keys()))


import codecs
import locale
import re
import sys
from typing import List, Tuple

BOMS: List[Tuple[bytes, str]] = [
    (codecs.BOM_UTF8, "utf-8"),
    (codecs.BOM_UTF16, "utf-16"),
    (codecs.BOM_UTF16_BE, "utf-16-be"),
    (codecs.BOM_UTF16_LE, "utf-16-le"),
    (codecs.BOM_UTF32, "utf-32"),
    (codecs.BOM_UTF32_BE, "utf-32-be"),
    (codecs.BOM_UTF32_LE, "utf-32-le"),
]

ENCODING_RE = re.compile(rb"coding[:=]\s*([-\w.]+)")

def auto_decode(data: bytes) -> str:
    """Check a bytes string for a BOM to correctly detect the encoding

    Fallback to locale.getpreferredencoding(False) like open() on Python3"""
    for bom, encoding in BOMS:
        if data.startswith(bom):
            return data[len(bom) :].decode(encoding)
    # Lets check the first two lines as in PEP263
    for line in data.split(b"\n")[:2]:
        if line[0:1] == b"#" and ENCODING_RE.search(line):
            result = ENCODING_RE.search(line)
            assert result is not None
            encoding = result.groups()[0].decode("ascii")
            return data.decode(encoding)
    return data.decode(
        locale.getpreferredencoding(False) or sys.getdefaultencoding(),
    )


import numpy as np
import torch

from .source import Source

def adjMatrixHamiltonian(Adj,t,eta):
    shape = eta.shape[-1]
    return torch.matmul(torch.matmul(eta,Adj).reshape(-1,1,shape),eta.reshape(-1,shape,1)).reshape(-1)

class HarmonicChain(Source):
    def __init__(self,n,kappa,K=1.0,name="HarmonicChain"):
        nvars = [2*n]
        super(HarmonicChain,self).__init__(nvars,K,name)
        self.kappa = kappa
        if n >=2:
            adjmeta = torch.diag(torch.tensor([2]*n,dtype=torch.float32))+torch.diag(torch.tensor([-1]*(n-1),dtype=torch.float32),diagonal=1)+torch.diag(torch.tensor([-1]*(n-1),dtype=torch.float32),diagonal=-1)
            adj = torch.cat((torch.cat((self.kappa/2*adjmeta,torch.zeros(n,n)),1),torch.cat((torch.zeros(n,n),0.5*torch.eye(n)),1)),0)
        else:
            adj = torch.tensor([[0.5,0],[0,kappa/2]]).to(torch.float32)
        self.adj=torch.nn.Parameter(adj,requires_grad=False)
    def _energy(self,x):
        return adjMatrixHamiltonian(self.adj,0,x)


import networkx as nx
import os
import time
import seaborn as sns
import matplotlib.pyplot as plt
import random

'''
Script to analyse graphs
'''

def count(graph_dir, plot = False):
    """
    Print stats about a dir of graphs
    :param graph_dir: path containing a list of nx graphs
    :param plot: if True, display the distributions
    """
    number_of_nodes = []
    number_of_cc = []
    number_of_node_per_cc = []
    for pdb in os.listdir(graph_dir):
        path = os.path.join(graph_dir, pdb)
        g = nx.read_gpickle(path)
        number_of_cc += [nx.number_connected_components(g)]
        ccs = []
        for cc in nx.connected_components(g):
            ccs.append(len(cc))
        number_of_node_per_cc += [sum(ccs) / len(ccs)]
        number_of_nodes += [nx.number_of_nodes(g)]
    avg_nn = (sum(number_of_nodes) / len(number_of_nodes))
    print('The average number of nodes is {}'.format(avg_nn))

    avg_cc = (sum(number_of_cc) / len(number_of_cc))
    print('The average number of cc is {}'.format(avg_cc))

    avg_ncc = (sum(number_of_node_per_cc) / len(number_of_node_per_cc))
    print('The average number of node per cc is {}'.format(avg_ncc))

    # Plot it if needed
    if plot:
        sns.distplot(number_of_nodes, kde=False, rug=True)
        plt.show()
        sns.distplot(number_of_cc, kde=False, rug=True)
        plt.show()
        sns.distplot(number_of_node_per_cc, kde=False, rug=True)
        plt.show()

    return number_of_nodes, number_of_cc, number_of_node_per_cc

def plot_random(graph_dir, number):
    """
    Plot a random subset
    :param graph_dir: path of the dir
    :param number: number of plots needed
    :return:
    """
    files = os.listdir(graph_dir)
    for i in range(number):
        index = random.randrange(0, len(files))
        path = os.path.join(graph_dir, files[index])
        g = nx.read_gpickle(path)
        printer = dict()
        for edge in g.edges.data():
            printer[(edge[0], edge[1])] = edge[2]['interaction']
        print(printer)
        pos = nx.spring_layout(g)
        nx.draw_networkx_edge_labels(g, pos=pos, edge_labels=printer)
        nx.draw_networkx(g, pos=pos)
        plt.show()

if __name__ == "__main__":
    start_time = time.time()

    # count('../data/output_graph/1radius_12minnodes')
    # count('../data/output_graph/3radius_12minnodes')

    # plot_random('../data/output_graph/v5_hbonds',7)
    # wait = input("press enter to continue")
    # plot_random('../data/output_graph/1radius_12minnodes',7)

    # print('no_hbonds')
    # # count('../data/output_graph/test/1a0i_ATP_0.p')
    # print('hbonds')
    plot_random('../data/output_graph/test',5)

    # print('hbond2')
    # count('../data/output_graph/hbond2')
    #
    # print('3radius_12minnodes')
    # count('../data/output_graph/3radius_12minnodes')
    # # print('1radius_12minnodes')
    # # count('../data/output_graph/1radius_12minnodes')
    # print('border')
    # count('../data/output_graph/border')

    # plot_count('../data/output_graph/border')
    # plot_random('../data/output_graph/border', 10)

    print("--- %s seconds ---" % (time.time() - start_time))


from typing import Optional

import numpy as np

# General setting for a scene
class Sett:
	def __init__(self, params):
		self.bg_r = float(params[0])  # background colors (r,g,b)
		self.bg_g = float(params[1])
		self.bg_b = float(params[2])
		self.shadow_rays = int(params[3])  # (N = root number of shadow rays)
		self.rec_max = int(params[4])  # max number of recursions

	@property
	def background_color_3d(self):
		return np.array([self.bg_r, self.bg_g, self.bg_b])

class Camera:
	def __init__(self, params):
		self.pos_x = float(params[0])  # camera position (x,y,z)
		self.pos_y = float(params[1])
		self.pos_z = float(params[2])
		self.look_x = float(params[3])  # look at position (lx,ly,lz)
		self.look_y = float(params[4])
		self.look_z = float(params[5])
		self.up_x = float(params[6])  # up vector (ux,uy,uz)
		self.up_y = float(params[7])
		self.up_z = float(params[8])
		self.sc_dist = float(params[9])
		self.sc_width = float(params[10])
		# use fisheye if true o.w. use pinhole (optional)
		self.fisheye = params[11] == 'true' if len(params) > 11 else False
		self.k_val = float(params[12]) if len(params) > 12 else 0.5  # optional

		self.pos_3d = np.array([self.pos_x, self.pos_y, self.pos_z])
		self.look_at_3d = np.array([self.look_x, self.look_y, self.look_z])
		self.up_3d = np.array([self.up_x, self.up_y, self.up_z])

class Plane:
	@staticmethod
	def create_from_params(params):
		return Plane(float(params[0]), float(params[1]), float(params[2]), float(params[3]), int(params[4]) - 1)

	def __init__(self, nx, ny, nz, offset, mat_ind):
		self.nx = nx  # normal vector (nx,ny,nz)
		self.ny = ny
		self.nz = nz
		self.offset = offset
		self.mat_ind = mat_ind

	def get_material(self, scene):
		return scene.materials[self.mat_ind]

	@property
	def normal_3d(self):
		return np.array([self.nx, self.ny, self.nz])

class Sphere:
	def __init__(self, params):
		self.cx = float(params[0])  # center point (cx,cy,cz)
		self.cy = float(params[1])
		self.cz = float(params[2])
		self.radius = float(params[3])
		self.mat_ind = int(params[4]) - 1

	@property
	def center_3d(self):
		return np.array([self.cx, self.cy, self.cz])

	def get_material(self, scene):
		return scene.materials[self.mat_ind]

class Box:
	def __init__(self, params):
		self.pos_x = float(params[0])  # position of center point (cx,cy,cz)
		self.pos_y = float(params[1])
		self.pos_z = float(params[2])
		self.edge_length = float(params[3])
		self.mat_ind = int(params[4]) - 1
		self.planes = []

		self.min_bound = self.center_3d - (self.edge_length / 2)
		self.max_bound = self.center_3d + (self.edge_length / 2)

		plane_point = self.center_3d + np.array([(self.edge_length / 2), 0, 0])
		plane_normal = np.sign(np.array([plane_point[0], 0, 0]))
		d = np.dot(plane_normal, plane_point)
		self.planes.append(Plane(plane_normal[0], plane_normal[1], plane_normal[2], d, self.mat_ind))

		plane_point = self.center_3d + np.array([0, (self.edge_length / 2), 0])
		plane_normal = np.sign(np.array([0, plane_point[1], 0]))
		d = np.dot(plane_normal, plane_point)
		self.planes.append(Plane(plane_normal[0], plane_normal[1], plane_normal[2], d, self.mat_ind))

		plane_point = self.center_3d + np.array([0, 0, (self.edge_length / 2)])
		plane_normal = np.sign(np.array([0, 0, plane_point[2]]))
		d = np.dot(plane_normal, plane_point)
		self.planes.append(Plane(plane_normal[0], plane_normal[1], plane_normal[2], d, self.mat_ind))

		plane_point = self.center_3d - np.array([(self.edge_length / 2), 0, 0])
		plane_normal = np.sign(np.array([plane_point[0], 0, 0]))
		d = np.dot(plane_normal, plane_point)
		self.planes.append(Plane(plane_normal[0], plane_normal[1], plane_normal[2], d, self.mat_ind))

		plane_point = self.center_3d - np.array([0, (self.edge_length / 2), 0])
		plane_normal = np.sign(np.array([0, plane_point[1], 0]))
		d = np.dot(plane_normal, plane_point)
		self.planes.append(Plane(plane_normal[0], plane_normal[1], plane_normal[2], d, self.mat_ind))

		plane_point = self.center_3d - np.array([0, 0, (self.edge_length / 2)])
		plane_normal = np.sign(np.array([0, 0, plane_point[2]]))
		d = np.dot(plane_normal, plane_point)
		self.planes.append(Plane(plane_normal[0], plane_normal[1], plane_normal[2], d, self.mat_ind))

	@property
	def center_3d(self):
		return np.array([self.pos_x, self.pos_y, self.pos_z])

	def get_material(self, scene):
		return scene.materials[self.mat_ind]

class Light:
	def __init__(self, params):
		self.pos_x = float(params[0])
		self.pos_y = float(params[1])
		self.pos_z = float(params[2])
		self.color_r = float(params[3])
		self.color_g = float(params[4])
		self.color_b = float(params[5])
		self.spec = float(params[6])  # specular intensity
		self.shadow = float(params[7])  # shadow intensity
		self.width = float(params[8])  # light width or radius (used for soft shadow)

	@property
	def pos_3d(self):
		return np.array([self.pos_x, self.pos_y, self.pos_z])

	@property
	def color_3d(self):
		return np.array([self.color_r, self.color_g, self.color_b])

class Material:
	def __init__(self, params):
		self.dr = float(params[0])  # diffuse color (r,g,b)
		self.dg = float(params[1])
		self.db = float(params[2])
		self.sr = float(params[3])  # specular color (r,g,b)
		self.sg = float(params[4])
		self.sb = float(params[5])
		self.rr = float(params[6])  # reflection color (r,g,b)
		self.rg = float(params[7])
		self.rb = float(params[8])
		self.phong = int(params[9])  # phong specularity coefficient (shininess)
		self.trans = float(params[10])  # transparency value between 0 and 1

	@property
	def difuse_color(self):
		return np.array([self.dr, self.dg, self.db])

	@property
	def spec_color(self):
		return np.array([self.sr, self.sg, self.sb])

	@property
	def reflection_color(self):
		return np.array([self.rr, self.rg, self.rb])

class Scene:
	def __init__(self, scene_file):
		self.planes = []
		self.boxes = []
		self.spheres = []
		self.lights = []
		self.materials = []
		self.camera = None  # type: Optional[Camera]
		self.sett = None
		self.parse(scene_file)

	def parse(self, scene_file):
		f = open(scene_file, "r")
		lines = f.readlines()
		for line in lines:
			line = line.strip()
			if len(line) == 0 or line[0] == '#':
				continue
			params = line.split()
			if params[0] == 'cam':
				self.camera = Camera(params[1:])
			elif params[0] == 'set':
				self.sett = Sett(params[1:])
			elif params[0] == 'mtl':
				self.materials.append(Material(params[1:]))
			elif params[0] == 'pln':
				self.planes.append(Plane.create_from_params(params[1:]))
			elif params[0] == 'sph':
				self.spheres.append(Sphere(params[1:]))
			elif params[0] == 'box':
				self.boxes.append(Box(params[1:]))
			elif params[0] == 'lgt':
				self.lights.append(Light(params[1:]))
			else:
				print("Bad param {}".format(params[0]))

if __name__ == "__main__":
	env_path = r"scenes\Pool.txt"
	out_path = r"Pool_test.png"
	scene_object = Scene(env_path)
	print('done')


### 데이터프레임을 사용할 수 있는 라이브러리 불러들이기
import pandas as pd

import json

### 지도 시각화 라이브러리 불러들이기
import folium

class Employment_map :

    ### 클래스 생성시 아래 함수 모두 실행시키기
    # - 생성자에서 호출
    def __init__(self) :
        self.initDataFrame()
        self.initJson()

    ### 데이터 읽어들이기
    def initDataFrame(self) :
        file_path = "./yeargraphapp/employment/전력량_고용률_마커.csv"
        self.usage_data = pd.read_csv(file_path)
        self.usage_data.drop(columns=['Unnamed: 0'], inplace=True)

    # 특정 년, 월 받아와서 데이터 프레임 만들기
    def setDataFrame(self, year_data, month_data) :
        year = year_data
        if year is "ERROR":
            year = 2021
        year = int(year)
        month = month_data
        if month is "ERROR":
            month = 12
        month = int(month)

        self.df_ver = self.usage_data.query('연도 == @year & 월 == @month')
        self.df_data = self.df_ver[['시도', '고용률', '사용량', '위도', '경도']]
        self.df_data_test = self.df_data.to_dict(orient='records')

    def initJson(self) :
        jsonfile = open('./yeargraphapp/employment/Sido.json','r',encoding='utf8').read()
        self.jsondata = json.loads(jsonfile)
        self.jsondata_loc = {'type': 'FeatureCollection'}
        self.jsondata_pick = []

    def getMap(self) :
        for idx in self.jsondata['features']:
            idx['id'] = idx['properties']['CTP_KOR_NM']
            for i in self.df_data_test:
                if i['시도'] == idx['properties']['CTP_KOR_NM']:
                    idx['properties']['pop'] = i['고용률']
            self.jsondata_pick.append(idx)
        self.jsondata_loc['features'] = self.jsondata_pick

    ### 지도맵 그리기
    def map_base(self) :
        # 지도 생성, location : 시작위치, zoom_start : 시작 시 확대정도
        self.employment_map = folium.Map(location=[36.0068191, 127.6607805],zoom_start=7)
        # 색상단계도 생성, geo_data : 참고할 위치정보 데이터
        cho = folium.Choropleth(geo_data=self.jsondata_loc,
                        # data : geo_data와 비교해 맞출 데이터
                        data=self.df_data,
                        # columns : data에서 사용할 열
                        columns=['시도', '고용률'],
                        fill_color="YlGnBu",                      # fill_color : 색
                        key_on='feature.id',                      # key_on : data와 맞출 geo_data의 데이터
                        legend_name='맵').add_to(self.employment_map)    # legend_name : 범례 제목 입력
        cho.geojson.add_child(                                      # 속성 부여
            folium.features.GeoJsonPopup(['CTP_KOR_NM','pop'],labels=False,style='font-weight : bold')
        )
        for row in self.df_data_test:
            lat = row['위도']
            lon = row['경도']
            folium.CircleMarker(location=[lat, lon],
                                radius=row['사용량'] / 700000, # 전력량 값을 radius로 사용
                                color='red',
                                fill_color='red',
                                fill_opacity=0.3,
                                popup=(row['시도'], row['사용량']),
                                tooltip=row['시도']).add_to(cho)
        return self.employment_map._repr_html_()

    ### 데이터프레임 리턴하기
    def getDataFrame(self) :
        return self.employment_data


import LeducPoker.LeducPokerGame
from LeducPoker.LeducPokerGame import PlayerActions
import numpy as np
from abc import ABC, abstractmethod
from typing import List

class Policy(ABC):
    @abstractmethod
    def action_prob(self, infoset: LeducPoker.LeducPokerGame.LeducInfoset) -> List[float]:
        pass

    def get_action(self, infoset: LeducPoker.LeducPokerGame.LeducInfoset) -> int:
        act_prob = self.action_prob(infoset)
        retval = np.random.choice(
            [PlayerActions.FOLD, PlayerActions.CHECK_CALL, PlayerActions.BET_RAISE], 1, p=act_prob)
        return retval

class AlwaysCheckCall(Policy):
    def action_prob(self, infoset: LeducPoker.LeducPokerGame.LeducInfoset) -> List[float]:
        retval = [0, 0, 0]
        retval[PlayerActions.CHECK_CALL] = 1
        return retval

    def get_action(self, infoset: LeducPoker.LeducPokerGame.LeducInfoset) -> int:
        return PlayerActions.CHECK_CALL

class AlwaysBet(Policy):
    def action_prob(self, infoset: LeducPoker.LeducPokerGame.LeducInfoset) -> List[float]:
        retval = [0, 0, 0]
        if infoset.can_raise:
            retval[PlayerActions.BET_RAISE] = 1
        else:
            retval[PlayerActions.CHECK_CALL] = 1
        return retval

    def get_action(self, infoset: LeducPoker.LeducPokerGame.LeducInfoset) -> int:
        return PlayerActions.BET_RAISE

class NashPolicy(Policy):
    def __init__(self, p0_strat_filename, p1_strat_filename):
        self.player_policies = [
            self.load_policy(p0_strat_filename),
            self.load_policy(p1_strat_filename)
        ]

    def load_policy(self, policy_filename):
        char_to_card = {'J': 0, 'Q': 1, 'K': 2}
        char_to_action = {
            'r': PlayerActions.BET_RAISE,
            'c': PlayerActions.CHECK_CALL
        }

        retval = {}
        with open(policy_filename, "r") as policy_filename:
            for line in policy_filename:
                if line[0] == "#":
                    continue

                cards, actions, probs = line.split(":")

                player_card = char_to_card[cards[0]]
                if len(cards) > 1:
                    board_card = char_to_card[cards[1]]
                else:
                    board_card = None

                round_actions = actions.split("/")[1:]
                round1_actions = tuple(char_to_action[c] for c in round_actions[0])
                if len(round_actions) > 1:
                    round2_actions = tuple(char_to_action[c] for c in round_actions[1])
                else:
                    round2_actions = ()

                infoset_template = (
                    player_card, board_card, round1_actions, round2_actions
                )

                raise_prob, call_prob, fold_prob = list([float(p) for p in probs.strip(" \n").split(" ")])
                infoset_probs = [0, 0, 0]
                infoset_probs[PlayerActions.BET_RAISE] = raise_prob
                infoset_probs[PlayerActions.CHECK_CALL] = call_prob
                infoset_probs[PlayerActions.FOLD] = fold_prob

                assert infoset_template not in retval
                retval[infoset_template] = infoset_probs

        return retval

    def action_prob(self, infoset: LeducPoker.LeducPokerGame.LeducInfoset) -> List[float]:
        assert not infoset.is_terminal

        if infoset.board_card is not None:
            board_card = infoset.board_card % 3
        else:
            board_card = None

        infoset_template = (
            infoset.card % 3, board_card, infoset.bet_sequences[0], infoset.bet_sequences[1]
        )

        return self.player_policies[infoset.player_to_act][infoset_template]


########################################################################################
#                            DSP1 - Programming Assigment
# By:
#   Yoav Ellinson         206036949
#   Chen Yaakov Sror      203531645
########################################################################################

import numpy as np
import matplotlib.pyplot as plt
# from matlabcall_test import dist_image_1, dist_image_2, noised_image, imp_resp_image
# after using the matlab engine we diabled it to save time - all the images are saved as npz files
from utils import *

d_1 = 0.206036949
d_2 = 0.203531645
d = (d_1 + d_2) % 0.5

dist_image_1 = np.load('dist_image_1_yoav.npz')['arr_0']
dist_image_2 = np.load('dist_image_2_yoav.npz')['arr_0']
imp_resp_image =np.load('imp_resp_image_yoav.npz')['arr_0']
noised_image =np.load('noised_image_yoav.npz')['arr_0']

print("If value is True - we will do Decimation in time: ", d % 0.1 < 0.05) # True

########################################################################################
#           Introduction Part - Implementation of FFT and IFFT Algorithm
########################################################################################

def FFT(x, flag = True):
    if flag:
    # Check if the input serie is not a power of 2, and pad it to a power of 2 accordingly
        if not ispowerof2(len(x)):
            zeros_to_pad = getnextpow2(len(x)) - len(x)
            x = np.pad(x, (0, zeros_to_pad), "constant")
            flag = False

    N = len(x)
    if N == 1:
        return x
    else:
        X_even = FFT(x[::2], flag)
        X_odd = FFT(x[1::2], flag)
        factor = np.exp(-2j*np.pi*np.arange(N)/ N)
        X = np.concatenate([X_even+factor[:int(N/2)]*X_odd, X_even+factor[int(N/2):]*X_odd])
        return X

def IFFT(x):
    N = len(x)
    return (1/N)*FFT(x.conj()).conj()

########################################################################################
#           Part 1 - Image proccessing using 2-D DTDT
########################################################################################

def cyclic_convolution(x,h):
    total_length = max(len(x), len(h))
    x = np.pad(x, (0, total_length - len(x)), 'constant')
    h = np.pad(h, (0, total_length - len(h)), 'constant')
    X = FFT(x)
    H = FFT(h)
    Y = IFFT(X * H)
    return Y

def restore_signal(x,h):
    total_length = max(len(x), len(h))
    x = np.pad(x, (0, total_length - len(x)), 'constant')
    h = np.pad(h, (0, total_length - len(h)), 'constant')
    X = FFT(x)
    H = FFT(h)
    result = np.divide(X, H, out=np.zeros_like(X), where=H != 0)
    Y = IFFT(result)
    return Y

def restore_signal_2D(x,h):
    total_length_row = max(x.shape[0], h.shape[0])
    total_length_col = max(x.shape[1], h.shape[1])
    x = np.pad(x, ((0, total_length_row - x.shape[0]), (0, total_length_col - x.shape[1])), "constant")
    h = np.pad(h, ((0, total_length_row - h.shape[0]), (0, total_length_col - h.shape[1])), "constant")
    X = FFT_2D(x)
    H = FFT_2D(h)
    result = np.divide(X, H, out=np.zeros_like(X), where=H != 0)
    Y = IFFT_2D(result)
    return Y

########################################################################################
#           Part 1 - Image analysis and processing using two-dimensional DTFT.
########################################################################################

B1 = 7
B2 = 7
M = 64
N = 32
x = np.zeros((N,M))

for i in range(N):
    for j in range(M):
        if (0 <= i and i < B1) and (0 <= j and j < B2):
            x[i][j] = 1
        else:
            x[i][j] = 0

# Part 1 d:
def FFT_2D(x):
    N, M = x.shape[0], x.shape[1]
    N, M = getnextpow2(N), getnextpow2(M)
    mat = np.zeros((N, M), dtype=np.complex128)
    for i in range(x.shape[1]):
        mat[:, i] = FFT(x[:, i])
    for i in range(x.shape[0]):
        mat[i, :] = FFT(mat[i, :])
    return mat

def IFFT_2D(x):
    N, M = x.shape[0], x.shape[1]
    return ( 1 / (N*M) ) * FFT_2D(x.conj()).conj()

mat_x = FFT_2D(x)
magnitude_spectrum = np.abs(mat_x)
plt.imshow(magnitude_spectrum, cmap='turbo')
plt.colorbar()
plt.title('2D DFT Magnitude Spectrum')
plt.savefig('pictures/q1_D_2d_dft.png')
plt.close()

fig, axs = plt.subplots(2, 2)
plt.subplots_adjust(wspace=0.2, hspace=0.4)
axs[0, 0].imshow(dist_image_1)
axs[0, 0].set_title('Dist imgge 1', verticalalignment='top')
axs[0, 1].imshow(dist_image_2)
axs[0, 1].set_title('Dist imgge 2', verticalalignment='top')
axs[1, 0].imshow(noised_image)
axs[1, 0].set_title('Noised image', verticalalignment='top')
axs[1, 1].imshow(imp_resp_image)
axs[1, 1].set_title('imp resp image', verticalalignment='top')
plt.savefig('pictures/q1_D_all_images.png')
plt.close()

# Part 1 e:
h_0 = imp_resp_image[:, 0]
samples_vector = np.array([0, 2*np.pi/6, 2* 2*np.pi/6, 4 * 2*np.pi/6])
samples_vector_transposed = np.transpose(samples_vector)
calc_ans = FFT(h_0) * samples_vector_transposed
calc_ans_abs = abs(calc_ans)

plt.stem(calc_ans_abs, basefmt=' ', use_line_collection=True)
plt.title(r'${H}_{0}(e^{j\omega})$')
plt.ylabel("Amplitude")
plt.xlabel(r'${\omega}$')
plt.savefig('pictures/q1_E_H_0_fft.png')
plt.close()

# Part 1 f:
w = np.zeros(32)
w[0] = 1
w[29] = 1

conv_ans = cyclic_convolution(h_0, w)

plt.stem(conv_ans, basefmt=' ', use_line_collection=True)
plt.title(r'${h}_{0} \circledast w[n]$')
plt.ylabel("Amplitude")
plt.xlabel(r'${\omega}$')
plt.savefig('pictures/q1_F_wn_conv_h0n.png')
plt.close()

# Part 1 g:
x1_restored = restore_signal_2D(dist_image_1, imp_resp_image)
x1_restored_abs = np.abs(x1_restored)
plt.imshow(x1_restored_abs,cmap='gray')
plt.title(r'${x_1}[n, m] = \frac{y[n, m]}{h[n, m]}$')
plt.ylabel('n')
plt.xlabel('m')
plt.savefig('pictures/q1_G_x1.png')
plt.close()

fig, axs1 = plt.subplots(1, 2)
plt.subplots_adjust(wspace=0.2, hspace=0.4)
x2_restored = restore_signal_2D(dist_image_2, imp_resp_image)
x2_restored_abs = np.real(x2_restored)
x2_resized = np.resize(x2_restored_abs,(70,170))
x2_restored_abs = x2_restored_abs[:70, :170]
axs1[0].imshow(x2_restored_abs, cmap = 'gray')
axs1[0].set_title('Our: ' + r'${x_2}[n, m]$')

x2_restored_fft2 = np.fft.ifft2(np.fft.fft2(dist_image_2) / np.fft.fft2(np.pad(imp_resp_image, ((0,70-3), (0, 170-5)), 'constant')))
x2_restored_fft2_abs = np.abs(x2_restored_fft2)
x2_restored_fft2_abs = x2_restored_fft2_abs[:70, :170]
axs1[1].imshow(x2_restored_fft2_abs, cmap = 'gray')
axs1[1].set_title('np.fft.fft2(): '+ r'${x_2}[n, m]$')

plt.savefig('pictures/q1_G_x2.png')
plt.close()

########################################################################################
#           Part 2 - Speech analysis
########################################################################################
import soundfile as sf

def create_w_linspace(N):
    return np.concatenate((np.linspace(0,2*np.pi,N)[:int(N/2)+1],np.linspace(-2*np.pi,0,N)[int(N/2)+1:]))

def anti_aliasing(x,dec_factor):
    X = FFT(x)
    a_filter = np.ones_like(x)
    w_m = create_w_linspace(len(x))
    a_filter[np.where(abs(w_m)>np.pi/dec_factor)]=0
    x_filtered =IFFT(X*a_filter).real
    return x_filtered

# Part2 a:
wav,sr = sf.read('wavs/out.wav')
N =2**16
x_n = np.array(wav[:N])
Px = (1/N) * np.sum(x_n**2)

# Define z[n]
w1=1.6+0.1*d_1
w2=1.6+0.1*d
w3=3
n = np.arange(N)
z_n = 50*np.sqrt(Px)*(np.cos(w1*n)+np.cos(w2*n)+np.cos(w3*n))

# Part2 a:
# Define y[n] = x[n] + z[n]
y_n = x_n + z_n
sf.write('wavs/x_n.wav',x_n,16000)
sf.write('wavs/y_n.wav',y_n,16000)

# Plotting Y[n]
fig = plt.figure()
fig.suptitle(r'$y[n] = x[n] + z[n]$')
plt.plot(y_n)
plt.ylabel("Amplitude")
plt.xlabel(r'time')
plt.savefig('pictures/q2_y_n.png')
plt.close()

# Part2 d:
# Plotting Y[e^(jw)]
Y_k = FFT(y_n)
w_m = create_w_linspace(128)
fig = plt.figure()
fig.suptitle(r'$Y(e^{j\omega})$ k= [0,128]')
plt.stem(w_m,abs(Y_k)[::512])
plt.ylabel("Amplitude")
plt.xlabel(r'${\omega}$')
plt.savefig('pictures/q2_Y_ejw.png')
plt.close()

# Plotting the noise - extra:
Z_k = FFT(z_n)
w_m = create_w_linspace(len(Z_k))
fig = plt.figure()
fig.suptitle(r'$Z(e^{j\omega}) k=2^{16}$')
plt.stem(w_m,abs(Z_k))
plt.ylabel("Amplitude")
plt.xlabel(r'${\omega}$')
plt.savefig('pictures/q2_Z_ejw.png')
plt.close()

# Part2 e and f:
y_n_2 = anti_aliasing(y_n,dec_factor =2)[::2]
sf.write('wavs/y_2.wav',y_n_2,8000)
z_n_2 = anti_aliasing(z_n,2)[::2]
Y_2_k = FFT(y_n_2)
Z_2_k =FFT(z_n_2)
fig = plt.figure()
fig.suptitle(r'$y_{2}[n]$')
plt.plot(y_n_2)
plt.ylabel("Amplitude")
plt.xlabel(r'time')
plt.savefig('pictures/q2_F_y2.png')
plt.close()

w_m = create_w_linspace(128)
fig = plt.figure()
fig.suptitle(r'$Y_{2}(e^{j\omega})$ k = [0,128]')
plt.stem(w_m,abs(Y_2_k[::256]))
plt.ylabel("Amplitude")
plt.xlabel(r'${\omega}$')
plt.savefig('pictures/q2_F_Y_2_ejw.png')
plt.close()

fig = plt.figure()
fig.suptitle(r'$Z_{2}(e^{j\omega})$ k = [0,128]')
plt.stem(w_m,abs(Z_2_k[::256]))
plt.ylabel("Amplitude")
plt.xlabel(r'${\omega}$')
plt.savefig('pictures/q2_F_Z_2_ejw.png')
plt.close()


import numpy as np
import scipy.constants as SI
from abel import InteractionPoint, Event

class InteractionPointBasic(InteractionPoint):

    # perform a simple interaction (geometric lumosity)
    def interact(self, beam1, beam2):

        # create event
        event = Event(beam1, beam2)

        # geometric factor
        H_D = 1

        # find overlapping area
        sigx = np.sqrt(beam1.beam_size_x()*beam2.beam_size_x())
        sigy = np.sqrt(beam1.beam_size_y()*beam2.beam_size_y())

        # get charge
        N1 = abs(beam1.charge()/SI.e)
        N2 = abs(beam2.charge()/SI.e)

        # calculate the geometric luminosity (per crossing)
        lumi = H_D / (4*np.pi) * N1 * N2 / (sigx * sigy)

        # save to event
        event.luminosity_full = lumi
        event.luminosity_peak = lumi
        event.luminosity_geom = lumi

        return event


import argparse
import collections

import numpy as np

import torch
import torch.optim as optim
from torchvision import transforms

from retinanet import model
from retinanet.dataloader import CocoDataset, CSVDataset, collater, Resizer, AspectRatioBasedSampler, Augmenter, \
    Normalizer
from torch.utils.data import DataLoader

from retinanet import coco_eval
from retinanet import csv_eval

assert torch.__version__.split('.')[0] == '1'

print('CUDA available: {}'.format(torch.cuda.is_available()))

def main(args=None):
    parser = argparse.ArgumentParser(description='Simple training script for training a RetinaNet network.')

    parser.add_argument('--dataset', help='Dataset type, must be one of csv or coco.')
    parser.add_argument('--coco_path', help='Path to COCO directory')
    parser.add_argument('--csv_train', help='Path to file containing training annotations (see readme)')
    parser.add_argument('--csv_classes', help='Path to file containing class list (see readme)')
    parser.add_argument('--csv_val', help='Path to file containing validation annotations (optional, see readme)')

    parser.add_argument('--depth', help='Resnet depth, must be one of 18, 34, 50, 101, 152', type=int, default=50)
    parser.add_argument('--epochs', help='Number of epochs', type=int, default=100)

    parser = parser.parse_args(args)

    # Create the data loaders
    if parser.dataset == 'coco':

        if parser.coco_path is None:
            raise ValueError('Must provide --coco_path when training on COCO,')

        dataset_train = CocoDataset(parser.coco_path, set_name='train2017',
                                    transform=transforms.Compose([Normalizer(), Augmenter(), Resizer()]))
        dataset_val = CocoDataset(parser.coco_path, set_name='val2017',
                                  transform=transforms.Compose([Normalizer(), Resizer()]))

    elif parser.dataset == 'csv':

        if parser.csv_train is None:
            raise ValueError('Must provide --csv_train when training on COCO,')

        if parser.csv_classes is None:
            raise ValueError('Must provide --csv_classes when training on COCO,')

        dataset_train = CSVDataset(train_file=parser.csv_train, class_list=parser.csv_classes,
                                   transform=transforms.Compose([Normalizer(), Augmenter(), Resizer()]))

        if parser.csv_val is None:
            dataset_val = None
            print('No validation annotations provided.')
        else:
            dataset_val = CSVDataset(train_file=parser.csv_val, class_list=parser.csv_classes,
                                     transform=transforms.Compose([Normalizer(), Resizer()]))

    else:
        raise ValueError('Dataset type not understood (must be csv or coco), exiting.')

    sampler = AspectRatioBasedSampler(dataset_train, batch_size=2, drop_last=False)
    dataloader_train = DataLoader(dataset_train, num_workers=3, collate_fn=collater, batch_sampler=sampler)

    if dataset_val is not None:
        sampler_val = AspectRatioBasedSampler(dataset_val, batch_size=1, drop_last=False)
        dataloader_val = DataLoader(dataset_val, num_workers=3, collate_fn=collater, batch_sampler=sampler_val)

    # Create the model
    if parser.depth == 18:
        retinanet = model.resnet18(num_classes=dataset_train.num_classes(), pretrained=True)
    elif parser.depth == 34:
        retinanet = model.resnet34(num_classes=dataset_train.num_classes(), pretrained=True)
    elif parser.depth == 50:
        retinanet = model.resnet50(num_classes=dataset_train.num_classes(), pretrained=True)
    elif parser.depth == 101:
        retinanet = model.resnet101(num_classes=dataset_train.num_classes(), pretrained=True)
    elif parser.depth == 152:
        retinanet = model.resnet152(num_classes=dataset_train.num_classes(), pretrained=True)
    else:
        raise ValueError('Unsupported model depth, must be one of 18, 34, 50, 101, 152')

    use_gpu = True

    if use_gpu:
        if torch.cuda.is_available():
            retinanet = retinanet.cuda()

    if torch.cuda.is_available():
        retinanet = torch.nn.DataParallel(retinanet).cuda()
    else:
        retinanet = torch.nn.DataParallel(retinanet)

    retinanet.training = True

    optimizer = optim.Adam(retinanet.parameters(), lr=1e-5)

    scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, patience=3, verbose=True)

    loss_hist = collections.deque(maxlen=500)

    retinanet.train()
    retinanet.module.freeze_bn()

    print('Num training images: {}'.format(len(dataset_train)))

    for epoch_num in range(parser.epochs):

        retinanet.train()
        retinanet.module.freeze_bn()

        epoch_loss = []

        for iter_num, data in enumerate(dataloader_train):
            try:
                optimizer.zero_grad()

                if torch.cuda.is_available():
                    classification_loss, regression_loss = retinanet([data['img'].cuda().float(), data['annot']])
                else:
                    classification_loss, regression_loss = retinanet([data['img'].float(), data['annot']])

                classification_loss = classification_loss.mean()
                regression_loss = regression_loss.mean()

                loss = classification_loss + regression_loss

                if bool(loss == 0):
                    continue

                loss.backward()

                torch.nn.utils.clip_grad_norm_(retinanet.parameters(), 0.1)

                optimizer.step()

                loss_hist.append(float(loss))

                epoch_loss.append(float(loss))

                print(
                    'Epoch: {} | Iteration: {} | Classification loss: {:1.5f} | Regression loss: {:1.5f} | Running loss: {:1.5f}'.format(
                        epoch_num, iter_num, float(classification_loss), float(regression_loss), np.mean(loss_hist)))

                del classification_loss
                del regression_loss
            except Exception as e:
                print(e)
                continue

        if parser.dataset == 'coco':

            print('Evaluating dataset')

            coco_eval.evaluate_coco(dataset_val, retinanet)

        elif parser.dataset == 'csv' and parser.csv_val is not None:

            print('Evaluating dataset')

            mAP = csv_eval.evaluate(dataset_val, retinanet)

        scheduler.step(np.mean(epoch_loss))

        torch.save(retinanet.module, '{}_retinanet_{}.pt'.format(parser.dataset, epoch_num))

    retinanet.eval()

    torch.save(retinanet, 'model_final.pt')

if __name__ == '__main__':
    main()


import cv2
import numpy as np
img = cv2.imread("D://python//opencv2//cat.jpg")
cv2.imshow('picture',img)
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
matSrc = np.float32([[0,0],[0,height-1],[width-1,0]])
matDst = np.float32([[50,50],[300,height-200],[width-300,100]])
matAffine = cv2.getAffineTransform(matSrc,matDst)
dst = cv2.warpAffine(img,matAffine,(width,height))
cv2.imshow('Affine',dst)
cv2.imwrite("D://python//opencv2//Affine.jpg",dst)
cv2.waitKey(0)


''' This TwitterBot AustinPeayGradBot was created by Ryan Honea.

It utilizes the Twitter API to update students with a graduation
countdown based on the current date and dates in the
Graduation_Days.txt file

Credit to the creator of the tweepy package for making this process
incredibly simple. '''

import tweepy
import time
from datetime import datetime
from credentials import *
from random import randint
from sys import exit

# These keys come from credentials
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
api = tweepy.API(auth)

DAY_OF_YEAR = datetime.now().timetuple().tm_yday
CURRENT_YEAR = int(datetime.now().year)

SEASON_DICT = {"spring" : 1, "summer" : 2, "winter" : 3}

# This function deletes a graduation on the day it occurs
def deleteRecentGraduation():
	lines = open("Graduation_Days.txt", 'r').readlines()
	file = open("Graduation_Days.txt", 'w')
	for i in range(1,len(lines)):
		file.write(lines[i])
	file.close()

# This returns at most 1000 tweets that contain @APGradCountDown
def pullLast24Hours():
	query = screen_name
	max_tweets = 1000
	tweets = [tweet for tweet in
				tweepy.Cursor(api.search, q=query).items(max_tweets)
				if (datetime.utcnow() - tweet.created_at).days < 1
					and (datetime.utcnow() - tweet.created_at).seconds < 3600]
	return tweets

# This opens the file with the graduation dates and returns them
def getGraduationDates():
	with open("Graduation_Days.txt") as f:
		content = f.readlines()

	graduations = [x.strip().split(',') for x in content]
	return graduations

# This just calculates the days until the selected graduation. Attempt at DRY
def days_until(current_day, CURRENT_YEAR, grad_day, grad_year):
	return str((grad_year - CURRENT_YEAR)*365 + (grad_day-current_day))

# This creates the daily tweet noting days until closest and random graduation
def createDailyTweet(graduations):
	tweet_lines = []

	days_until_closest = days_until(
						DAY_OF_YEAR, CURRENT_YEAR,
						int(graduations[0][0]),
						int(graduations[0][1]))

	if (days_until_closest == '0'):
		tweet_lines.append("Congratulations to the " + graduations[0][2]
							+ " class of " + graduations[0][1] + "!")
		deleteRecentGraduation()
	else:
		# Creates part of tweet for closest graduation
		tweet_lines.append(days_until_closest + " days until the "
							+ graduations[0][1] + " "
							+ graduations[0][2] + "!")

		# Creates part of tweet for random future graduation
		rand = randint(1,len(graduations)-1)
		days_until_rand = days_until(
						DAY_OF_YEAR, CURRENT_YEAR,
						int(graduations[rand][0]),
						int(graduations[rand][1]))

		tweet_lines.append(days_until_rand + " days until the "
							+ graduations[rand][1] + " "
							+ graduations[rand][2] + "!")

	tweet_lines.append('#AustinPeay #CollegeGraduation')

	status = '\n'.join(tweet_lines)
	post_tweet(status)

# This first collects 1000 tweets from the last 24 hours and checks to see if
# any match the criterion for a response. If they tweet with the following
# format: [@APGradCountDown season yyyy] then a response will be made with
# how many days they have until they graduate.
def respond(graduations):
	latest_tweets = pullLast24Hours()
	min_year = graduations[0][1]
	max_year = graduations[-1][1]
	min_season = SEASON_DICT[graduations[0][2].split()[0].lower()]
	max_season = SEASON_DICT[graduations[-1][2].split()[0].lower()]
	for tweet in latest_tweets:
		days_until_grad = ''
		status = tweet.text.split()
		response = '@' + str(tweet.user.screen_name) + ' '
		tweetId = tweet.id
		if len(status) != 3: break
		season = status[1].lower()
		season_key = SEASON_DICT[season]
		status_year = status[2] # in case punctuation is added after year
		if season == 'spring' or season == 'winter' or season == 'summer':
			if (status_year > max_year or
					(status_year == max_year and season_key > max_season)):
				response = response + 'You\'ve got a long way to go!'
			elif (status_year < min_year or
					(status_year == min_year and season_key < min_season)):
				response = response + 'You already graduated!'
			else:
				for graduation in graduations:
					if (graduation[1] == status_year
							and graduation[2].split()[0].lower() == season):
						days_until_grad = days_until(
										DAY_OF_YEAR, CURRENT_YEAR,
										int(graduation[0]),int(graduation[1]))
				if days_until_grad == '':
					response += 'Your graduation is not on record. Sorry!'
				else:
					response += "You graduate in " + days_until_grad + " days!"
			reply(response, tweetId)

# This uses the API to post the tweet
def post_tweet(status):
	# print(status)
	api.update_status(status)

# This happens when a reply is made so it lists as a reply
def reply(status, tweetId):
	# print(status)
	api.update_status(status, tweetId)


"""imie = input("Jak masz na imie")
imie = imie.strip( )
dlugosc = len(imie)
ostatni_litera_imienia = imie[dlugosc-1]
print("Cześć")
print(imie.upper())
print(imie[-1:])
print("Twoje imie ma: " + str(dlugosc) + " liter")
print("Twoja ostatnia litera imienia to : " + ostatni_litera_imienia
      """

"""imie = input("Jak masz na imie")
imie = imie.strip( )
dlugosc = len(imie)
ostatni_litera_imienia = imie[dlugosc-1]
print("Cześć")
print(imie.upper())
ostatnia_litera = imie[-1:]
if(ostatnia_litera == 'a'):
    print("Witam Panią")
else:
    print("Witam Pana")"""

wyraz = 'encyklopedia'

print(wyraz[2:8],
      wyraz[8:],
      wyraz[1:7:2],
      )

lista1 = [1, 2, 3]
lista2 = ["kwiatek", "doniczka", "ziemia", "woda"]
lista3 = []
lista4 = [1, "dwa", 3, 4]
lista5 = list("dwa piętnaście")
lista6 = list(1)
lista7 = list(range(0,20,3))

print(lista1)
print(lista2)
print(lista3)
print(lista4)
print(lista5)
print(lista7)
# print(lista1)
# print(lista1)

lista = [ [1,2,3],[4,5,6],[7,8,9] ]
# lista = [
#
# [1,2,3],
# [4,5,6],
# [7,8,9]
#
# ]

print(lista[1][2])

lista = [
    [1,2,3],
    [4,5,6,"napis"],
    [7,8,9]
]
print(lista[1][3][1])

lista.append(['lalala'])

print(lista)
lista[1][3] = lista[1][2]*5

print(lista)
lista[3].extend('tak')
print(lista)

lista[1][2] = 'zwariuje'
print(lista)

krotka1 = (1, 2, 3)
krotka2 = ("kwiatek", "doniczka", "ziemia", "woda")
krotka3 = ()
krotka4 = (1, "dwa", 3, 4)
krotka5 = tuple("dwa")
# krotka6 = tuple(1)
krotka7 = list(range(2,5))

print(krotka1, krotka2,krotka3,krotka4,krotka5,krotka7)

wyrazy = ("raz", "dwa", "trzy")
a, b, c = wyrazy

print(a)

ieie = 'Jola'
def zmien_imie():
    ieie = 'Teresa'

print(ieie)

zmien_imie()
print(ieie)

osoby = {"studenci": ["Ala", "Jan", "Ania"], "wykladowcy": ["doktor", "profesor"]}
print(osoby["studenci"][1])

osoby["wykladowcy"].append("magister")
print(osoby)
osoby["administracja"] = ["pani Basia z dziekanatu"]
print(osoby)

osoby.update({"ochrona":"Impel"})
print(osoby)

print(osoby.keys)
print(osoby.values)

for key, item in osoby.items():
    print(key, item)


# from math import ceil, sqrt
import math
import yaml
import os
import threading
from typing import Union
import rospy
import tf
import numpy as np
import time
from flatland_msgs.srv import MoveModel, MoveModelRequest, SpawnModelRequest, SpawnModel
from flatland_msgs.srv import StepWorld
from geometry_msgs.msg import Pose2D, PoseWithCovarianceStamped, PoseStamped
from pedsim_srvs.srv import SpawnObstacle, SpawnObstacleRequest
from pedsim_msgs.msg import LineObstacle
from pedsim_msgs.msg import LineObstacles

from nav_msgs.msg import OccupancyGrid, Path

from .utils import generate_freespace_indices, get_random_pos_on_map, get_robot_goal_on_map

class RobotManager:
    """
    A manager class using flatland provided services to spawn, move and delete Robot. Currently only one robot
    is managed
    """

    def __init__(self, ns: str, map_: OccupancyGrid, robot_yaml_path: str, timeout=20):
        """[summary]

        Args:
            ns(namespace): if ns == '', we will use global namespace
            map_ (OccupancyGrid): the map info
            robot_yaml_path (str): the file name of the robot yaml file.

        """
        self.ns = ns
        self.ns_prefix = "/" if ns == "" else "/"+ns+"/"

        self.safe_dist_adult=1.0
        self.safe_dist_child=1.2
        self.safe_dist_elder=1.5

        self.is_training_mode = rospy.get_param("/train_mode")
        self.step_size = rospy.get_param("step_size")
        self._get_robot_configration(robot_yaml_path)
        # setup proxy to handle  services provided by flatland
        rospy.wait_for_service(f'{self.ns_prefix}move_model', timeout=timeout)
        rospy.wait_for_service(f'{self.ns_prefix}spawn_model', timeout=timeout)
        rospy.wait_for_service(f'{self.ns_prefix}pedsim_simulator/add_obstacle', timeout=timeout)
        #rospy.wait_for_service('step_world', timeout=20)
        self._srv_move_model = rospy.ServiceProxy(
            f'{self.ns_prefix}move_model', MoveModel)
        self._srv_spawn_model = rospy.ServiceProxy(
            f'{self.ns_prefix}spawn_model', SpawnModel)
        # it's only needed in training mode to send the clock signal.
        self._step_world = rospy.ServiceProxy(
            f'{self.ns_prefix}step_world', StepWorld)
        self.__add_obstacle_srv = rospy.ServiceProxy(
            f'{self.ns_prefix}pedsim_simulator/add_obstacle' ,SpawnObstacle, persistent=True)

        # publisher
        # publish the start position of the robot
        # self._initialpose_pub = rospy.Publisher(
        #     'initialpose', PoseWithCovarianceStamped, queue_size=1)
        self._goal_pub = rospy.Publisher(
            f'{self.ns_prefix}goal', PoseStamped, queue_size=1, latch=True)

        self.update_map(map_)
        self._spawn_robot(robot_yaml_path)

        # path generated by the  global planner
        self._global_path = Path()
        # the timestamp will be used for checking whether the global planner can find a valid path
        # between new start position and new goal
        self._old_global_path_timestamp = None
        self._new_global_path_generated = False
        # a condition variable used for
        self._global_path_con = threading.Condition()

    def _spawn_robot(self, robot_yaml_path: str):
        request = SpawnModelRequest()
        request.yaml_path = robot_yaml_path
        request.name = "myrobot"
        request.ns = self.ns
        self._srv_spawn_model(request)

    def _get_robot_configration(self, robot_yaml_path):
        """get robot info e.g robot name, radius, Laser related infomation

        Args:
            robot_yaml_path ([type]): [description]
        """
        self.ROBOT_NAME = os.path.basename(robot_yaml_path).split('.')[0]
        with open(robot_yaml_path, 'r') as f:
            robot_data = yaml.safe_load(f)
            # get robot radius
            for body in robot_data['bodies']:
                if body['name'] == "base_footprint":
                    for footprint in body['footprints']:
                        if footprint['type'] == 'circle':
                            self.ROBOT_RADIUS = footprint.setdefault(
                                'radius', 0.2)
            # get laser_update_rate
            for plugin in robot_data['plugins']:
                if plugin['type'] == 'Laser':
                    self.LASER_UPDATE_RATE = plugin.setdefault(
                        'update_rate', 1)

    def update_map(self, new_map: OccupancyGrid):
        self.map = new_map
        # a tuple stores the indices of the non-occupied spaces. format ((y,....),(x,...)
        self._free_space_indices = generate_freespace_indices(self.map)

    def move_robot(self, pose: Pose2D):
        """move the robot to a given position

        Args:
            pose (Pose2D): target postion
        """
        # call service move_model

        srv_request = MoveModelRequest()
        srv_request.name = self.ROBOT_NAME
        srv_request.pose = pose

        # call service
        self._srv_move_model(srv_request)
        if self.is_training_mode:
            # a necessaray procedure to let the flatland publish the
            # laser,odom's Transformation, which are needed for creating
            # global path
            # assert self.step_size * \
            #     self.LASER_UPDATE_RATE == 1, f"TO run the traning successfully, make sure the laser_update_rate*step_size == 1 \
            #     \n\tcurrent step_size:\t {self.step_size}\n\tcurrent laser's update rate:\t {self.LASER_UPDATE_RATE} "
            for _ in range(math.ceil(1/(self.step_size*self.LASER_UPDATE_RATE))):
                self._step_world()

    def set_start_pos_random(self):
        start_pos = Pose2D()
        start_pos.x, start_pos, start_pos.theta = get_random_pos_on_map(
            self._free_space_indices, self.map, self.ROBOT_RADIUS)
        self.move_robot(start_pos)

    def set_start_pos_goal_pos(self, isCirclePattern:bool, start_pos: Union[Pose2D, None]= None,
                                                                goal_pos: Union[Pose2D, None] = None, min_dist=7,
                                                                obs_dict=None, forbiddenPoints=None):
        """set up start position and the goal postion. Path validation checking will be conducted. If it failed, an
        exception will be raised.

        Args:
            start_pos (Union[Pose2D,None], optional): start position. if None, it will be set randomly. Defaults to None.
            goal_pos (Union[Pose2D,None], optional): [description]. if None, it will be set randomly .Defaults to None.
            isCirclePattern:bool.  if true, start_pos and goal_pos will be spawned around the circle, otherwise will be set randomly.
            min_dist (float): minimum distance between start_pos and goal_pos
            obs_dict: observations from the last time step
        Exception:
            Exception("can not generate a path with the given start position and the goal position of the robot")
        """

        def dist(x1, y1, x2, y2):
            return math.sqrt((x1 - x2)**2 + (y1 - y2)**2)

        forbiddenZones=[]
        if obs_dict is not None:
            # print("calculate the forbidden zones")
            coordinates=obs_dict['human_coordinates_in_robot_frame'].T
            tys=obs_dict['human_type']
            for i, coordinate in enumerate(coordinates):
                if tys[i]==0: #adult
                    forbiddenZones.append((coordinate[0],coordinate[1],self.safe_dist_adult*1.05))
                elif tys[i]==1: #child
                    forbiddenZones.append((coordinate[0],coordinate[1],self.safe_dist_child*1.05))
                elif tys[i]==3: #elder
                    forbiddenZones.append((coordinate[0],coordinate[1],self.safe_dist_elder*1.05))

        if forbiddenPoints is not None:
            for coordinate in forbiddenPoints: # use the safe_dist of elder becuase it is the largest among all types of humans
                forbiddenZones.append((coordinate[0],coordinate[1],self.safe_dist_elder*1.05))

        if start_pos is None or goal_pos is None:
            # if any of them need to be random generated, we set a higher threshold,otherwise only try once
            max_try_times = 100
        else:
            max_try_times = 1

        i_try = 0
        start_pos_ = None
        goal_pos_ = None
        while i_try < max_try_times:
            if isCirclePattern:
                if start_pos is None:
                    start_pos_ = Pose2D()
                    goal_pos_ = Pose2D()
                    start_pose, end_pose = get_robot_goal_on_map(
                        self._free_space_indices, self.map, 10 ,self.ROBOT_RADIUS ,forbiddenZones)
                    start_pos_.x, start_pos_.y, start_pos_.theta= start_pose[0], start_pose[1], start_pose[2]
                    goal_pos_.x, goal_pos_.y, goal_pos_.theta= end_pose[0] , end_pose[1] , end_pose[2]
                    goal_pos_.x, goal_pos_.y, goal_pos_.theta= 20 , 8 , 0
                    start_pos_.x, start_pos_.y, start_pos_.theta= -2, 8, 0
                    # print('g', goal_pos_.x)
                else:
                    start_pos_ = start_pos
                    goal_pos_ = goal_pos
            else:
                if start_pos is None:
                    start_pos_ = Pose2D()
                    start_pos_.x, start_pos_.y, start_pos_.theta = get_random_pos_on_map(
                        self._free_space_indices, self.map, self.ROBOT_RADIUS, forbidden_zones=forbiddenZones)
                    start_pos_.x, start_pos_.y, start_pos_.theta= -3.5, -3, 0
                else:
                    start_pos_ = start_pos
                if goal_pos is None:
                    goal_pos_ = Pose2D()
                    goal_pos_.x, goal_pos_.y, goal_pos_.theta = get_random_pos_on_map(
                        self._free_space_indices, self.map, self.ROBOT_RADIUS, forbidden_zones=forbiddenZones)
                    goal_pos_.x, goal_pos_.y, goal_pos_.theta= 23.5 , 16 , 0
                else:
                    goal_pos_ = goal_pos
            if dist(start_pos_.x, start_pos_.y, goal_pos_.x, goal_pos_.y) < min_dist:
                i_try += 1
                continue
            # move the robot to the start pos
            self.move_robot(start_pos_)
            try:
                # publish the goal, if the gobal plath planner can't generate a path, a, exception will be raised.
                self.publish_goal(goal_pos_.x, goal_pos_.y, goal_pos_.theta)
                self.setGoalInfoToPedsim(goal_pos_)
                # print("publish goal")
                break
            except rospy.ServiceException:
                i_try += 1
        if i_try == max_try_times:
            # TODO Define specific type of Exception
            raise rospy.ServiceException(
                "can not generate a path with the given start position and the goal position of the robot")
        else:
            return start_pos_, goal_pos_

    def _validate_path(self):
        """ after publish the goal, the global planner should publish path. If it's not published within 0.1s, an exception will
        be raised.

        Raises:
            Exception: [description]
        """

        with self._global_path_con:
            self._global_path_con.wait_for(
                predicate=self._new_global_path_generated, timeout=0.1)
            if not self._new_global_path_generated:
                raise rospy.ServiceException(
                    "can not generate a path with the given start position and the goal position of the robot")
            else:
                self._new_global_path_generated = False  # reset it

    def publish_goal(self, x, y, theta):
        """
        Publishing goal (x, y, theta)
        :param x x-position of the goal
        :param y y-position of the goal
        :param theta theta-position of the goal
        """
        self._old_global_path_timestamp = self._global_path.header.stamp
        goal = PoseStamped()
        goal.header.stamp = rospy.get_rostime()
        goal.header.frame_id = "map"
        goal.pose.position.x = x
        goal.pose.position.y = y
        quaternion = tf.transformations.quaternion_from_euler(0, 0, 0)
        goal.pose.orientation.w = quaternion[0]
        goal.pose.orientation.x = quaternion[1]
        goal.pose.orientation.y = quaternion[2]
        goal.pose.orientation.z = quaternion[3]
        self._goal_pub.publish(goal)
        # self._validate_path()

    def _global_path_callback(self, global_path: Path):
        with self._global_path_con:
            self._global_path = global_path
            if self._old_global_path_timestamp is None or global_path.header.stamp > self._old_global_path_timestamp:
                self._new_global_path_generated = True
            self._global_path_con.notify()

    def setGoalRadius(self, goal_radius):
        self.goalRadius=goal_radius

    def setGoalInfoToPedsim(self, goal_pos):
        #partition of the goal area as a polygon
        vertices=np.array([[goal_pos.x, goal_pos.y+1.1*self.goalRadius],
                                                [goal_pos.x, goal_pos.y-1.1*self.goalRadius],
                                                [goal_pos.x+1.1*self.goalRadius, goal_pos.y],
                                                [goal_pos.x-1.1*self.goalRadius, goal_pos.y]])
        add_pedsim_srv=SpawnObstacleRequest()
        size=vertices.shape[0]
        for i in range(size):
            lineObstacle=LineObstacle()
            lineObstacle.start.x,lineObstacle.start.y=vertices[i,0], vertices[i,1]
            lineObstacle.end.x,lineObstacle.end.y=vertices[(i+1)%size,0], vertices[(i+1)%size,1]
            add_pedsim_srv.staticObstacles.obstacles.append(lineObstacle)
        # tell the pedsim the position of goal
        self.__add_obstacle_srv.call(add_pedsim_srv)


def rec(arr, i, subset: list, subsets):
    if i == len(arr):
        subsets.append(subset.copy())
    else:
        rec(arr, i + 1, subset + [arr[i]], subsets)
        rec(arr, i + 1, subset, subsets)

def gen(arr):
    subsets = []
    rec(arr, 0, [], subsets)

    print(subsets)

gen([1, 2, 3])


import random

def createRange(values):
    tot = sum([x[1] for x in values])
    probs = [(x[0],x[1]/tot) for x in values]
    rangeArray = []
    prev = 0
    for p in probs:
        nextVal = prev + p[1]
        slot = (prev, nextVal)
        prev = nextVal
        rangeArray.append((p[0],slot))
    return rangeArray

def chooseFromRanges(ranges):
    r = random.random()
    choice = [x[0] for x in ranges if x[1][0] <= r and x[1][1] > r]
    return choice[0]

def inverseSequence(sequence):
    seq_max = max(sequence)
    seq_inverse = [(x,seq_max-x+1) for x in sequence]
    return seq_inverse