├── README.md ├── docs ├── cs5073_large_project_proposal_draft.pdf └── cs5073_large_project_proposal_final.pdf ├── waveform.py ├── Pipfile ├── read_files.py ├── target.py ├── radar.py ├── .gitignore ├── interference.py ├── radar_env.py ├── DQNRadar.py ├── MDPRadar.py ├── MDPRadar.ipynb └── Pipfile.lock /README.md: -------------------------------------------------------------------------------- 1 | # RadarRL 2 | Reinforcement Learning for Cognitive Radar (CS5073 Final Project) 3 | -------------------------------------------------------------------------------- /docs/cs5073_large_project_proposal_draft.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShaneFlandermeyer/RadarRL/HEAD/docs/cs5073_large_project_proposal_draft.pdf -------------------------------------------------------------------------------- /docs/cs5073_large_project_proposal_final.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShaneFlandermeyer/RadarRL/HEAD/docs/cs5073_large_project_proposal_final.pdf -------------------------------------------------------------------------------- /waveform.py: -------------------------------------------------------------------------------- 1 | class LinearFMWaveform: 2 | """Linear FM Waveform object""" 3 | 4 | def __init__(self, bandwidth, pulsewidth): 5 | self.bandwidth = bandwidth 6 | self.pulsewidth = pulsewidth 7 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | numpy = "*" 8 | scipy = "*" 9 | ipykernel = "*" 10 | autopep8 = "*" 11 | sklearn = "*" 12 | matplotlib = "*" 13 | pymdptoolbox = "*" 14 | pettingzoo = {extras = ["classic"], version = "*"} 15 | 16 | [dev-packages] 17 | ipykernel = "*" 18 | 19 | [requires] 20 | python_version = "3" 21 | 22 | [pipenv] 23 | allow_prereleases = true 24 | -------------------------------------------------------------------------------- /read_files.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mon May 2 21:16:41 2022 4 | 5 | @author: Geoffrey Dolinger 6 | """ 7 | import pickle 8 | import fnmatch 9 | import os 10 | import numpy as np 11 | 12 | def read_all_rotations(dirname,filebase): 13 | '''Read results from dirname from files matching filebase''' 14 | 15 | # The set of files in the directory 16 | files = fnmatch.filter(os.listdir(dirname),filebase) 17 | files.sort() 18 | results = [] 19 | 20 | # Loop over matching files 21 | for f in files: 22 | fp = open("%s/%s"%(dirname,f), "rb") 23 | r = pickle.load(fp) 24 | fp.close() 25 | results.append(r) 26 | return results 27 | 28 | dirname = "final_runs" 29 | filebase = 'sweep_10_*_results.pkl' 30 | results = read_all_rotations(dirname,filebase) 31 | 32 | mean_testing_total = [] 33 | std_testing_total = [] 34 | mean_opt_total = [] 35 | std_opt_total = [] 36 | 37 | for r in results: 38 | rewards = r['reward_totals'] 39 | mean_testing = np.mean(rewards[-500:]) 40 | std_testing = np.std(rewards[-500:]) 41 | mean_testing_total = np.append(mean_testing_total,mean_testing) 42 | std_testing_total = np.append(std_testing_total,std_testing) 43 | 44 | optimal = r['optimal_rewards'] 45 | mean_opt = np.mean(optimal[-500:]) 46 | std_opt = np.std(optimal[-500:]) 47 | mean_opt_total = np.append(mean_opt_total,mean_opt) 48 | std_opt_total = np.append(std_opt_total,std_opt) 49 | 50 | final_mean = np.mean(mean_testing_total) 51 | final_std = np.sqrt(np.mean(std_testing_total**2)) 52 | final_opt_mean= np.mean(mean_opt_total) 53 | final_opt_std= np.sqrt(np.mean(std_opt_total**2)) -------------------------------------------------------------------------------- /target.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | class Target: 5 | """Point target object""" 6 | 7 | def __init__(self, position, velocity, rcs, P=np.array([]), V=np.array([])): 8 | """Instantiate a target object 9 | 10 | Args: 11 | position (ndarray): A vector of the XYZ position of the target in an 12 | arbitrary coordinate system 13 | velocity (ndarray): A vector of the XYZ velocity of the target in an 14 | arbitrary coordinate system 15 | rcs (float): The radar cross section of the target (m^2) 16 | """ 17 | self.position = np.array(position) 18 | self.velocity = np.array(velocity) 19 | self.rcs = rcs 20 | self.P = P 21 | self.V = V 22 | self.pos_state_ind = -1 23 | self.vel_state_ind = -1 24 | if P.size > 0 and self.position.size > 0: 25 | self.pos_state_ind = np.linalg.norm( 26 | self.position - P, keepdims=True, axis=1).argmin() 27 | if V.size > 0 and self.velocity.size > 0: 28 | self.vel_state_ind = np.linalg.norm( 29 | self.velocity - V, keepdims=True, axis=1).argmin() 30 | 31 | def step(self, dt): 32 | """Update the target motion profile 33 | 34 | Args: 35 | dt (float): Time change since last step 36 | """ 37 | self.position += self.velocity*dt 38 | if self.P.size > 0: 39 | self.pos_state_ind = np.linalg.norm( 40 | self.position - self.P, keepdims=True, axis=1).argmin() 41 | if self.V.size > 0: 42 | self.vel_state_ind = np.linalg.norm( 43 | self.velocity - self.V, keepdims=True, axis=1).argmin() 44 | -------------------------------------------------------------------------------- /radar.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.constants as sc 3 | 4 | 5 | class Radar: 6 | """Monostatic radar object""" 7 | 8 | def __init__(self, position=np.zeros((3,)), prf=1e3, center_freq=10e9, 9 | tx_gain=100, tx_power=100, samp_rate=1e6, num_pulse_cpi=128, noise_fig=5, T0=270): 10 | self.position = np.array(position) 11 | self.prf = prf 12 | self.center_freq = center_freq 13 | self.tx_gain = tx_gain 14 | self.noise_fig = noise_fig 15 | self.T0 = T0 16 | # Assume monostatic 17 | self.rx_gain = tx_gain 18 | self.tx_power = tx_power 19 | self.samp_rate = samp_rate 20 | self.num_pulse_cpi = num_pulse_cpi 21 | # Derived parameters 22 | self.lambda0 = sc.c / center_freq 23 | self.max_range = sc.c/(2*prf) 24 | self.max_doppler = prf/2 25 | 26 | self.action = np.array([]) 27 | 28 | def rx_power(self, target): 29 | R = np.linalg.norm(target.position - self.position) 30 | Pr = self.tx_power*self.tx_gain*self.rx_gain*self.lambda0**2 * \ 31 | target.rcs/((4*sc.pi)**3*R**4) 32 | return Pr 33 | 34 | def SINR(self, target, interference, wave): 35 | noise_power = sc.k*self.T0*self.samp_rate*self.noise_fig 36 | # Interference power only contributes to SINR if it is in the same 37 | # frequency band 38 | if sum(self.action*interference.current_state) > 0: 39 | interference_power = interference.tx_power 40 | else: 41 | interference_power = 0 42 | sinr = self.rx_power(target) / (noise_power + interference_power) 43 | # SINR after pulse compression and coherent integration 44 | sinr *= self.num_pulse_cpi * (wave.pulsewidth*wave.bandwidth) 45 | sinr = 10*np.log10(sinr) 46 | 47 | return sinr -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Figures 129 | *.png 130 | *.mp4 131 | *.gif 132 | 133 | # Pyre type checker 134 | .pyre/ 135 | -------------------------------------------------------------------------------- /interference.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from abc import ABC, abstractmethod 3 | 4 | 5 | class Interference(ABC): 6 | """Interference object base class""" 7 | 8 | def __init__(self, tx_power, states, state_ind): 9 | """Instantiate a new interference object 10 | 11 | Args: 12 | tx_power (float): Transmit power of the interference AT THE RADAR RECEIVER. 13 | Therefore, this is a very small value. 14 | TODO: Make this the actual transmitted power, then use scenario 15 | geometry to compute the power at the radar receiver. 16 | 17 | states (_type_, optional): A matrix of all possible transmission 18 | frequencies in a discretized spectrum, where each row is a possible 19 | state. 20 | Defaults to np.array([]). 21 | 22 | state_ind (int, optional): The row index of the current state in the 23 | states matrix. 24 | Defaults to 0. 25 | """ 26 | self.tx_power = tx_power 27 | self.states = states 28 | self.state_ind = state_ind 29 | self.current_state = states[state_ind] 30 | 31 | @abstractmethod 32 | def step(self): 33 | """ 34 | Define the frequency hopping behavior of the interference at each time step 35 | """ 36 | pass 37 | 38 | 39 | class ConstantInterference(Interference): 40 | """Constant interference object. 41 | 42 | This interferer transmits at a single frequency pattern for the entire simulation 43 | 44 | """ 45 | 46 | def __init__(self, tx_power=0, states=np.array([]), state_ind=0): 47 | super(ConstantInterference, self).__init__(tx_power, states, state_ind) 48 | 49 | def step(self): 50 | """ 51 | Continue transmitting at the same frequency 52 | """ 53 | pass 54 | 55 | 56 | class IntermittentInterference(Interference): 57 | """Time-intermittent interference object. 58 | 59 | This interference transmits in a single pre-defined frequency band, but 60 | toggles on and off with a user-defined probability at every time step. 61 | """ 62 | 63 | def __init__(self, tx_power=0, states=np.array([]), state_ind=0, transition_prob=0.1): 64 | super(IntermittentInterference, self).__init__( 65 | tx_power, states, state_ind) 66 | self.transition_prob = transition_prob 67 | self.original_state_ind = state_ind 68 | self.on = 1 69 | 70 | def step(self): 71 | """ 72 | Transition on/off with a constant probability 73 | """ 74 | if np.random.rand() < self.transition_prob: 75 | self.on = int(not self.on) 76 | # Determine the state based on the transition probability 77 | # If the interference is on, the state is the original state. Otherwise, 78 | # it is zero 79 | self.state_ind = self.original_state_ind * self.on 80 | self.current_state = self.states[self.state_ind] 81 | 82 | 83 | class HoppingInterference(): 84 | """Frequency-hopping interference object. 85 | 86 | Repeatedly hops frequency bins in a pre-defined pattern 87 | """ 88 | 89 | def __init__(self, pattern, tx_power, states): 90 | """Create a HoppingInterference object 91 | 92 | Args: 93 | pattern: Numpy array of state indices defining the hopping pattern 94 | of the emitter 95 | tx_power: Transmit power (W) 96 | states: Numpy array of all possible interference states 97 | """ 98 | self.pattern = pattern 99 | self.tx_power = tx_power 100 | self.states = states 101 | self.pattern_ind = 0 102 | self.state_ind = pattern[0] 103 | self.current_state = self.states[self.state_ind] 104 | 105 | def step(self): 106 | """Step to the next frequency in the sequence, restarting if the end is reached""" 107 | self.pattern_ind = (self.pattern_ind + 1) % len(self.pattern) 108 | self.state_ind = self.pattern[self.pattern_ind] 109 | self.current_state = self.states[self.state_ind] 110 | -------------------------------------------------------------------------------- /radar_env.py: -------------------------------------------------------------------------------- 1 | from gym.spaces import Discrete 2 | import numpy as np 3 | import functools 4 | import itertools 5 | from pettingzoo import AECEnv 6 | from pettingzoo.utils import agent_selector 7 | from pettingzoo.utils import wrappers 8 | from pettingzoo.test import api_test 9 | import matplotlib.pyplot as plt 10 | 11 | 12 | 13 | N = 5 14 | MOVES = np.array(list(itertools.product([0, 1], repeat=N))) 15 | NUM_ITERS = 2500 16 | 17 | 18 | def RadarEnvironment(): 19 | ''' 20 | The env function often wraps the environment in wrappers by default. 21 | You can find full documentation for these methods 22 | elsewhere in the developer documentation. 23 | ''' 24 | env = raw_RadarEnvironment() 25 | # This wrapper is only for environments which print results to the terminal 26 | env = wrappers.CaptureStdoutWrapper(env) 27 | # this wrapper helps error handling for discrete action spaces 28 | env = wrappers.AssertOutOfBoundsWrapper(env) 29 | # Provides a wide vareity of helpful user errors 30 | # Strongly recommended 31 | env = wrappers.OrderEnforcingWrapper(env) 32 | return env 33 | 34 | 35 | class raw_RadarEnvironment(AECEnv): 36 | ''' 37 | The metadata holds environment constants. From gym, we inherit the "render_modes", 38 | metadata which specifies which modes can be put into the render() method. 39 | At least human mode should be supported. 40 | The "name" metadata allows the environment to be pretty printed. 41 | ''' 42 | metadata = {'render_modes': ['human'], "name": "rps_v2"} 43 | 44 | def __init__(self): 45 | ''' 46 | The init method takes in environment arguments and 47 | should define the following attributes: 48 | - possible_agents 49 | - action_spaces 50 | - observation_spaces 51 | 52 | These attributes should not be changed after initialization. 53 | ''' 54 | # self.possible_agents = ["player_" + str(r) for r in range(2)] 55 | self.possible_agents = ["Radar_0", "Comms_0"] 56 | self.agent_name_mapping = dict( 57 | zip(self.possible_agents, list(range(len(self.possible_agents))))) 58 | 59 | # Gym spaces are defined and documented here: https://gym.openai.com/docs/#spaces 60 | self._action_spaces = {agent: Discrete( 61 | 2**N) for agent in self.possible_agents} 62 | self._observation_spaces = {agent: Discrete( 63 | 2**N) for agent in self.possible_agents} 64 | 65 | 66 | # this cache ensures that same space object is returned for the same agent 67 | # allows action space seeding to work as expected 68 | @functools.lru_cache(maxsize=None) 69 | def observation_space(self, agent): 70 | # Gym spaces are defined and documented here: https://gym.openai.com/docs/#spaces 71 | return Discrete(2**N) 72 | 73 | @functools.lru_cache(maxsize=None) 74 | def action_space(self, agent): 75 | return Discrete(2**N) 76 | 77 | def render(self, mode="human"): 78 | ''' 79 | Renders the environment. In human mode, it can print to terminal, open 80 | up a graphical window, or open up some other display that a human can see and understand. 81 | ''' 82 | if len(self.agents) == 2: 83 | string = ("Current state: Radar: {} , Comms: {}".format( 84 | MOVES[self.state[self.agents[0]]], MOVES[self.state[self.agents[1]]])) 85 | else: 86 | string = "Game over" 87 | print(string) 88 | 89 | def observe(self, agent): 90 | ''' 91 | Observe should return the observation of the specified agent. This function 92 | should return a sane observation (though not necessarily the most up to date possible) 93 | at any time after reset() is called. 94 | ''' 95 | # observation of one agent is the previous state of the other 96 | return np.array(self.observations[agent]) 97 | 98 | def close(self): 99 | ''' 100 | Close should release any graphical displays, subprocesses, network connections 101 | or any other environment data which should not be kept around after the 102 | user is no longer using the environment. 103 | ''' 104 | pass 105 | 106 | def reset(self): 107 | ''' 108 | Reset needs to initialize the following attributes 109 | - agents 110 | - rewards 111 | - _cumulative_rewards 112 | - dones 113 | - infos 114 | - agent_selection 115 | And must set up the environment so that render(), step(), and observe() 116 | can be called without issues. 117 | 118 | Here it sets up the state dictionary which is used by step() and the observations dictionary which is used by step() and observe() 119 | ''' 120 | self.agents = self.possible_agents[:] 121 | self.rewards = {agent: 0 for agent in self.agents} 122 | self._cumulative_rewards = {agent: 0 for agent in self.agents} 123 | self.dones = {agent: False for agent in self.agents} 124 | self.infos = {agent: {} for agent in self.agents} 125 | self.state = {agent: 0 for agent in self.agents} 126 | self.observations = {agent: 1 for agent in self.agents} 127 | self.num_moves = 0 128 | ''' 129 | Our agent_selector utility allows easy cyclic stepping through the agents list. 130 | ''' 131 | self._agent_selector = agent_selector(self.agents) 132 | self.agent_selection = self._agent_selector.next() 133 | 134 | def step(self, action): 135 | ''' 136 | step(action) takes in an action for the current agent (specified by 137 | agent_selection) and needs to update 138 | - rewards 139 | - _cumulative_rewards (accumulating the rewards) 140 | - dones 141 | - infos 142 | - agent_selection (to the next agent) 143 | And any internal state used by observe() or render() 144 | ''' 145 | if self.dones[self.agent_selection]: 146 | # handles stepping an agent which is already done 147 | # accepts a None action for the one agent, and moves the agent_selection to 148 | # the next done agent, or if there are no more done agents, to the next live agent 149 | return self._was_done_step(action) 150 | 151 | agent = self.agent_selection 152 | 153 | # the agent which stepped last had its _cumulative_rewards accounted for 154 | # (because it was returned by last()), so the _cumulative_rewards for this 155 | # agent should start again at 0 156 | self._cumulative_rewards[agent] = 0 157 | 158 | # stores action of current agent 159 | self.state[self.agent_selection] = action 160 | 161 | # collect reward if it is the last agent to act 162 | if self._agent_selector.is_last(): 163 | # rewards for all agents are placed in the .rewards dictionary 164 | self.reward() 165 | # self.rewards[self.agents[0]], self.rewards[self.agents[1]] = REWARD_MAP[( 166 | # self.state[self.agents[0]], self.state[self.agents[1]])] 167 | 168 | self.num_moves += 1 169 | # The dones dictionary must be updated for all players. 170 | self.dones = {agent: self.num_moves >= 171 | NUM_ITERS for agent in self.agents} 172 | 173 | # observe the current state 174 | for i in self.agents: 175 | self.observations[i] = self.state[self.agents[1 - 176 | self.agent_name_mapping[i]]] 177 | else: 178 | # necessary so that observe() returns a reasonable observation at all times. 179 | self.state[self.agents[1 - self.agent_name_mapping[agent]]] = 0 180 | # no rewards are allocated until both players give an action 181 | self._clear_rewards() 182 | 183 | # selects the next agent. 184 | self.agent_selection = self._agent_selector.next() 185 | # Adds .rewards to ._cumulative_rewards 186 | self._accumulate_rewards() 187 | 188 | def reward(self): 189 | # TODO: Generalize this so that each agent can have a unique reward 190 | # TODO: Generalize this to more than one agent 191 | radar_state = MOVES[self.state[self.agents[0]]] 192 | comms_state = MOVES[self.state[self.agents[1]]] 193 | 194 | r = 0 195 | # Number of collisions with the interference 196 | num_collision = np.sum(np.equal(radar_state, 1) & 197 | np.equal(comms_state,1)) 198 | # Number of sub-bands utilized by the radar 199 | num_subband = np.sum(radar_state) 200 | # Number of missed opportunities for radar transmission, where no 201 | # interference exists but the radar did not transmit there 202 | num_missed_opportunity = np.sum( 203 | (radar_state == 0) & (comms_state == 0)) 204 | 205 | r += -45*num_collision 206 | r += 10*(num_subband-1) 207 | self.rewards[self.agents[0]] = r 208 | 209 | 210 | # RadarEnvironment = RadarEnvironment() 211 | 212 | # pattern = [1,2] 213 | # ind = 0 214 | # def policy(observation, agent): 215 | # global ind 216 | # if agent == "Radar_0": 217 | # action = np.random.randint(0,2**N) 218 | # elif agent == "Comms_0": 219 | # action = pattern[ind % len(pattern)] 220 | # ind += 1 221 | # return action 222 | 223 | # # Run a basic simulation 224 | # RadarEnvironment.reset() 225 | # for agent in RadarEnvironment.agent_iter(): 226 | # observation, reward, done, info = RadarEnvironment.last() 227 | # print('agent:%s'%(agent)) 228 | # print('obs:%s'%(observation)) 229 | # action = policy(observation, agent) if not done else None 230 | # RadarEnvironment.step(action) 231 | # if agent == 'Comms_0': 232 | # RadarEnvironment.render() 233 | # print(RadarEnvironment._cumulative_rewards) 234 | 235 | 236 | 237 | -------------------------------------------------------------------------------- /DQNRadar.py: -------------------------------------------------------------------------------- 1 | import mdptoolbox 2 | import mdptoolbox.example 3 | import numpy as np 4 | import scipy.constants as sc 5 | import itertools 6 | from sklearn.preprocessing import normalize 7 | import matplotlib.pyplot as plt 8 | from matplotlib import animation 9 | 10 | import random 11 | import numpy as np 12 | import pickle 13 | import tensorflow as tf 14 | from tensorflow.keras import layers 15 | from keras.layers import Dense, LeakyReLU, Input 16 | from tensorflow.keras.models import Model 17 | from radar_env import * 18 | 19 | iterations=2500 20 | def policy(observation, agent): 21 | ''' 22 | Test function for environment testing. DQN does not use this function 23 | ''' 24 | global ind 25 | if agent == "Radar_0": 26 | action = observation+1 27 | elif agent == "Comms_0": 28 | action = interference(observation, pattern, std=None, experiment='A') 29 | return action 30 | 31 | #Function for translating int to a binary list of size N. 32 | def int_to_binlist(int_num, bin_size): 33 | binary = '{0:0%sb}'%(bin_size) 34 | return [int(i) for i in list(binary.format(int_num))] 35 | 36 | #Function to translate a binary list to its integer equivalent 37 | def binlist_to_int(bin_list): 38 | return int("".join(str(x) for x in bin_list), 2) 39 | 40 | def interference(prev_state, pattern, std=None, experiment='sweep'): 41 | ''' 42 | Function to generate the interference pattern for 2 experiments. 43 | Inputs: 44 | prev_state = previous state from environment(must be in pattern) 45 | pattern = the states that the interferece will occupy 46 | std = for normal dist experiemnt this represents the standard deviation 47 | of normal dist for that pattern. 48 | experiemnts = label for the experiements 49 | sweep = sweep single interference states 50 | normal_dist = the new interfernce position is based on a normal 51 | curve centered at the previous state. 52 | Output: The next pattern. 53 | ''' 54 | if experiment == 'sweep': 55 | #determine index of last pattern 56 | current_ind=pattern.index(prev_state) 57 | # if at the end of pattern loop to the front 58 | if current_ind == len(pattern)-1: 59 | return pattern[0] 60 | #sweep pattern 61 | else: 62 | return pattern[current_ind+1] 63 | if experiment == 'normal_dist': 64 | #determine index of last pattern 65 | current_ind=pattern.index(prev_state) 66 | #normal dist to find new state index 67 | new_ind = round(np.random.normal(current_ind,std[current_ind])) 68 | # if dist is out of range then change to limit 69 | new_ind = 0 if new_ind < 0 else N-1 if new_ind > N-1 else new_ind 70 | return pattern[new_ind] 71 | 72 | def max_reward(state, N): 73 | interf_ind = np.argmax(state) 74 | span = max(interf_ind,N-interf_ind-1) 75 | return (span-1)*10 76 | 77 | def build_model(input_size,output_size,dense_layers, activation='elu', lrate=0.001): 78 | ''' 79 | This function builds a single dense ANN to act as the DQN. 80 | Inputs: 81 | input_size = size of input expectation 82 | output_size = size of expected output 83 | dense_layer = list of neuron in each layer. 84 | activation = activation function for dense layers 85 | lrate = learning rate 86 | Output: model 87 | ''' 88 | input_tensor = Input(shape =input_size,name = "input") 89 | tensor=input_tensor 90 | for i, dense in enumerate(dense_layers): 91 | #Add Dense layers based on input parameters for each layer 92 | tensor=Dense(dense, use_bias=True, name="FC%02d"%(i), 93 | activation=activation)(tensor) 94 | 95 | output_tensor = Dense(output_size, use_bias=True, name="Output", activation="linear")(tensor) 96 | 97 | opt = tf.keras.optimizers.RMSprop(lr=0.00025, rho=0.95, epsilon=0.01) 98 | model=Model(inputs=input_tensor, outputs=output_tensor) 99 | model.compile(loss='mse', optimizer=opt,metrics=["accuracy"]) 100 | 101 | return model 102 | 103 | def build_agent_pair(input_size, output_size, position_layers, 104 | span_layers, activation='elu', lrate=0.001): 105 | ''' 106 | This function builds the specific architecture for position and span. 107 | Inputs: 108 | input_size = size of input expectation 109 | output_size = size of expected output 110 | position_layer = list of neuron in each layer in position model. 111 | span_layer = list of neuron in each layer in span model. 112 | activation = activation function for dense layers 113 | lrate = learning rate 114 | Output: position model, span model 115 | ''' 116 | position_model = build_model(input_size,output_size,position_layers, activation=activation, lrate=lrate) 117 | print(position_model.summary()) 118 | span_model = build_model(input_size+output_size,output_size, span_layers, activation=activation, lrate=lrate) 119 | print(span_model.summary()) 120 | 121 | return position_model,span_model 122 | 123 | RadarEnvironment = RadarEnvironment() 124 | runs = 10 125 | final_pattern_reward=[] 126 | for r in range(runs): 127 | # experiment set-up and operation for DQN 128 | 129 | RadarEnvironment.reset() 130 | 131 | experiment = 'normal_dist' 132 | pattern = [1,2,4,8,16] #interference pattern 133 | # pattern = [1,2,4,8,16,32,64,128,256,512] #interference pattern 134 | std = [.5,.3,.2,.3,.5] #standard deviation for experiment normal_dist 135 | # std = [.5,.3,.2,.3,.5,.5,.3,.2,.3,.5] 136 | gamma = .9 #discount factor for DQN learning 137 | eps = 1 #starting epsilon for greedy epsilon selection 138 | eps_decay = 0.998 #decay factor for epsilon 139 | eps_min = .001 #minimum epsilon 140 | N= 5 # number of sub-bands 141 | lrate = 0.05 142 | #build the position/span DQN 143 | position_model,span_model = build_agent_pair(input_size =N, output_size=N, position_layers=[128,64], 144 | span_layers=[128,64], activation='elu', lrate=lrate) 145 | reward_totals =[] #empty lists for appending 146 | reward_cumulative =[] 147 | state_totals = [] 148 | action_totals = [] 149 | optimal_reward_totals =[] 150 | 151 | #experiment iteration 152 | for i,agent in enumerate(RadarEnvironment.agent_iter()): 153 | #pull previous state 154 | observation, reward, done, info = RadarEnvironment.last() 155 | #each iterations radar agent update 156 | if agent == "Radar_0": 157 | #previous state 158 | sys_obs = observation 159 | #state converted to binary list for DQN forward pass 160 | obs_list = int_to_binlist(observation, N) 161 | # position forward pass Q value list 162 | Q_pos = position_model.predict(np.reshape(obs_list,(1,N))).tolist()[0] 163 | #Input for span network as position output and state 164 | in_span = [*obs_list, *Q_pos] 165 | # span forward pass Q value list 166 | Q_span = span_model.predict(np.reshape(in_span,(1,2*N))).tolist()[0] 167 | #epsilon greeding selection 168 | if random.random()<=eps and i<2*iterations-1001: #select random action state 169 | Ap = random.randrange(1,N) 170 | As = random.randrange(1,N) 171 | else: #select maximum Q value option. 172 | Ap = np.argmax(position_model.predict(np.reshape(obs_list,(1,N))))+1 173 | As = np.argmax(span_model.predict(np.reshape(in_span,(1,2*N))))+1 174 | action_lst = [0]*N #empty final action list 175 | for j in range(N): #loop positions 176 | if j>Ap-2 and j 0: 323 | current_reward[itime, itest] = current_reward[itime - 324 | 1, itest] + reward(radar.action, comms.current_state) 325 | cumulative_reward[itest] += reward(radar.action, comms.current_state) 326 | next_state = (current_state[1], compute_state()) 327 | 328 | # Variables for plotting 329 | interference_history = np.append(interference_history, np.reshape( 330 | Theta[comms.state_ind], (1, N)), axis=0) 331 | tx_history = np.append(tx_history, np.reshape( 332 | radar.action, (1, N)), axis=0) 333 | sinr = radar.SINR(target, comms, wave) 334 | current_sinr[itime, itest] = sinr 335 | 336 | # Print RL statistics for report 337 | mean_reward = np.mean(cumulative_reward) 338 | mean_bw /= (time.shape[0]*num_test) 339 | reward_std_dev = np.sqrt(np.var(cumulative_reward)) 340 | print("Mean reward: " + str(mean_reward)) 341 | print("Reward std. dev: " + str(reward_std_dev)) 342 | print("Mean bandwidth: " + str(mean_bw/1e6)) 343 | current_sinr = np.mean(current_sinr, axis=1) 344 | 345 | 346 | # %% [markdown] 347 | # ## Visualizations 348 | 349 | # %% 350 | plt.figure() 351 | plt.plot(time, current_reward, '.-') 352 | plt.xlabel('Time (s)') 353 | plt.ylabel('Average Cumulative Reward') 354 | plt.savefig('reward') 355 | 356 | plt.figure() 357 | plt.plot(time, current_sinr, '.-') 358 | plt.xlabel('Time (s)') 359 | plt.ylabel('Average SINR (dB)') 360 | plt.savefig('SINR') 361 | animate_spectrum(tx_history, interference_history) 362 | -------------------------------------------------------------------------------- /MDPRadar.ipynb: -------------------------------------------------------------------------------- 1 | {"cells":[{"cell_type":"markdown","metadata":{},"source":[" # Final Project\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["import mdptoolbox\n","import mdptoolbox.example\n","import numpy as np\n","import scipy.constants as sc\n","import itertools\n","from sklearn.preprocessing import normalize\n","import matplotlib.pyplot as plt\n","from matplotlib import animation\n","from radar import *\n","from interference import *\n","from target import *\n","from waveform import *\n","\n"]},{"cell_type":"markdown","metadata":{},"source":[" ### Radar Environment\n"]},{"cell_type":"markdown","metadata":{},"source":[" The radar environment is defined by a set of possible postion states\n","\n"," $\\mathcal{P}$ and a set of velocity states $\\mathcal{V}$.\n","\n","\n"," $\\mathcal{P} = \\{\\mathbf{r_1}, \\mathbf{r_2}, \\dots, \\mathbf{r_\\rho}\\}$\n","\n","\n"," $\\mathcal{V} = \\{\\mathbf{v_1}, \\mathbf{v_2}, \\dots, \\mathbf{v_\\nu}\\}$\n","\n","\n"," where $\\rho$ is the number of possible position states and $\\nu$ is the number\n","\n"," of possible velocities.\n","\n","\n"," Each $\\mathbf{r_i}, \\mathbf{v_i}$ are 3-dimensional row vectors\n","\n","\n"," $\\mathbf{r_i} = \\left[r_x, r_y, r_z \\right]$\n","\n","\n"," $\\mathbf{v_i} = \\left[v_x, v_y, v_z \\right]$\n","\n"," **NOTE:** The current iteration of the simulation only considers the frequency\n"," environment for the MDP. By not including the target position and velocity, we\n"," **significantly** reduce training time and the sample support needed for a good\n"," estimate. The downside to this is that we cannot use the target position in the\n"," reward function (e.g., through SINR), but initial experimentation suggests that\n"," this is a suboptimal reward function anyways."]},{"cell_type":"markdown","metadata":{},"source":[" ### Interference Environment\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["use_memory = True\n","N = 5\n","channel_bw = 200e6\n","subband_bw = channel_bw / N\n","channel = np.zeros((N,))\n","# Matrix of all unique interference states, where each row is a unique state and\n","# each column is a frequency bin\n","Theta = np.array(list(itertools.product([0, 1], repeat=N)))\n","\n","# Interfering system\n","# comms = HoppingInterference(pattern=np.array(\n","# [1]),\n","# tx_power=4.6e-13, states=Theta)\n","# comms = HoppingInterference(pattern=np.array(\n","# [2**n for n in itertools.chain(range(N), range(N-2, 0, -1))]),\n","# tx_power=4.6e-13, states=Theta)\n","seq_length = 100\n","comms = HoppingInterference(pattern=2**(np.random.randint(\n"," 0, N, seq_length)), tx_power=4.6e-13, states=Theta)\n","comms.pattern[comms.pattern == 2**N] -= 1\n"]},{"cell_type":"markdown","metadata":{},"source":[" ## Simulation Environment"]},{"cell_type":"markdown","metadata":{},"source":[" ### Radar and Target Parameters"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# Radar system\n","radar = Radar(position=np.zeros((3,)), prf=2000,\n"," center_freq=10e9, tx_gain=100, tx_power=1e3, num_pulse_cpi=20)\n","# Transmitted waveform (linear FM)\n","wave = LinearFMWaveform(bandwidth=20e6, pulsewidth=10e-6)\n","# Possible actions (assume transmission over contiguous sub-bands)\n","actions = np.zeros((1, N))\n","for i in range(N):\n"," state = np.zeros((N,))\n"," state[:i+1] = 1\n"," actions = np.append(actions, np.array([np.roll(state, j) for j in\n"," range(N-i)]), axis=0)\n","# Number of position states in each dimension\n","rho_x = 2\n","rho_y = 2\n","rho_z = 1\n","rho = rho_x*rho_y*rho_z\n","rx = np.linspace(-5e3, 5e3, rho_x)\n","ry = np.linspace(1e3, 5e3, rho_y)\n","rz = np.linspace(0, 0, rho_z)\n","P = np.vstack(np.meshgrid(rx, ry, rz)).reshape(3, -1).T\n","# Number of velocity states\n","nu_x = 2\n","nu_y = 2\n","nu_z = 1\n","nu = nu_x*nu_y*nu_z\n","# NOTE: The min/max velocity I have set in each dimension is completely arbitrary\n","vx = np.linspace(-5, 5, nu_x)\n","vy = np.linspace(-5, 5, nu_y)\n","vz = np.linspace(0, 0, nu_z)\n","V = np.vstack(np.meshgrid(vx, vy, vz)).reshape(3, -1).T\n","target = Target(position=[], velocity=[], rcs=0.1, P=P, V=V)\n","\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["plt.plot(P[:, 0], P[:, 1], 'ro', label='Position States')\n","plt.plot(radar.position[0], radar.position[1], 'b.', label='Radar Position')\n","plt.xlabel('x (m)')\n","plt.ylabel('y (m)')\n","plt.rc('font', size=14) # controls default text sizes\n","plt.rc('font', weight='bold') # controls boldness\n","plt.legend(loc='upper right')\n","# plt.show()\n"]},{"cell_type":"markdown","metadata":{},"source":[" ### Reward structure\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["\n","\n","def reward(radar_state, interference_state):\n"," r = 0\n"," # Number of collisions with the interference\n"," num_collision = np.sum(np.equal(radar_state, 1) &\n"," (radar_state == interference_state))\n"," # Number of sub-bands utilized by the radar\n"," num_subband = np.sum(radar_state)\n"," # Number of missed opportunities for radar transmission, where no\n"," # interference exists but the radar did not transmit there\n"," num_missed_opportunity = np.sum(\n"," (radar_state == 0) & (interference_state == 0))\n"," r += -45*num_collision\n"," r += 10*(num_subband-1)\n"," return r\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["\n","\n","def animate_spectrum(tx_history, interference_history):\n"," # tx: array of radar transmission actions, where each row is the spectrum\n"," # state for a test run\n"," # int: Array of interference states with the same shape as for the transmission\n","\n"," def animate(i):\n"," radar_action = tx_history[i, :]\n"," interference_state = interference_history[i, :]\n"," for ibin in range(len(radar_spectrum.patches)):\n"," # Get the histogram bin object\n"," bin = radar_spectrum.patches[ibin]\n"," int_bin = interference.patches[ibin]\n"," # Set the height of each bin\n"," bin.set_height(radar_action[ibin])\n"," int_bin.set_height(interference_state[ibin])\n"," # Set the color of each bin based on whether or not a collision exists\n"," if radar_action[ibin] == interference_state[ibin]:\n"," bin.set_color('r')\n"," int_bin.set_color('r')\n"," else:\n"," bin.set_color('b')\n"," int_bin.set_color('g')\n","\n"," return radar_spectrum.patches\n","\n"," fig, ax = plt.subplots()\n"," plt.xlabel('Frequency (MHz)')\n"," plt.ylabel('State')\n"," plt.rc('font', size=14) # controls default text sizes\n"," plt.rc('font', weight='bold') # controls boldness\n"," subband_bw_mhz = subband_bw / 1e6\n"," interference = plt.bar(np.arange(N)*subband_bw_mhz, np.ones(\n"," (N,)), width=subband_bw_mhz, edgecolor='k', color='g', align='edge')\n"," radar_spectrum = plt.bar(\n"," np.arange(N)*subband_bw_mhz, np.ones((N,)), width=subband_bw_mhz,\n"," edgecolor='k', color='b', align='edge')\n"," anim = animation.FuncAnimation(\n"," fig, animate, tx_history.shape[0], repeat=False, blit=True)\n"," anim.save('./test.gif', fps=1)\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["\n","\n","def compute_state():\n"," state_ind = comms.state_ind*rho*nu + \\\n"," target.vel_state_ind*rho + target.pos_state_ind\n"," return state_ind\n"]},{"cell_type":"markdown","metadata":{},"source":[" ## Train the MDP"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# Number of possible states (here, equal to the number of interference states)\n","# use_memory = False\n","S = (2**N)*rho*nu\n","if use_memory:\n"," S *= 2**N\n","# Number of possible actions\n","A = actions.shape[0]\n","# Initialize the transition and reward matrices\n","T = np.zeros((A, S, S))\n","R = np.zeros((A, S, S))\n","\n","num_train = int(1e3)\n","num_test = int(1e2)\n","time = np.linspace(0, 1500, 20)\n","# Time step for the simulation\n","dt = time[1] - time[0]\n","for itrain in range(num_train):\n"," # Randomly select a starting position and target velocity\n"," target.position = P[np.random.choice(P.shape[0]), :]\n"," target.velocity = V[np.random.choice(V.shape[0]), :]\n"," # Add a gaussian perturbance to the position and velocity\n"," target.position[:-1] += np.random.randn(2)\n"," target.velocity += np.random.randn()\n"," target.pos_state_ind = np.linalg.norm(\n"," target.position - P, keepdims=True, axis=1).argmin()\n"," target.vel_state_ind = np.linalg.norm(\n"," target.velocity - V, keepdims=True, axis=1).argmin()\n"," # Start at a random place in the pattern\n"," comms.pattern_ind = np.random.randint(0, comms.pattern.shape[0])\n"," comms.state_ind = comms.pattern[comms.pattern_ind]\n"," comms.current_state = comms.states[comms.state_ind]\n"," prev_comms_state = 0\n"," next_state = (0, compute_state())\n"," for t in time:\n"," # Initial environment state\n"," current_state = next_state\n"," # Randomly select a valid action\n"," action_index = np.random.randint(0, A)\n"," radar.action = actions[action_index, :]\n"," # Determine the bandwidth used, then update the interference, position, range, and SINR\n"," wave.bandwidth = subband_bw*np.sum(radar.action)\n"," current_comms_state = comms.state_ind\n"," comms.step()\n"," target.step(dt)\n"," next_state = (current_state[1], compute_state())\n"," current_state_ind = current_state[1]\n"," next_state_ind = next_state[1]\n"," # If memory is used, need to index into a biggger array\n"," if use_memory:\n"," current_state_ind += prev_comms_state*(2**N)*rho*nu\n"," next_state_ind += current_comms_state*(2**N)*rho*nu\n"," prev_comms_state = current_comms_state\n"," # Update transition and reward estimate\n"," T[action_index, current_state_ind, next_state_ind] += 1\n"," R[action_index, current_state_ind,\n"," next_state_ind] += reward(radar.action, comms.current_state)\n","\n","# Normalize the transition probability matrix to make it stochastic\n","T = np.array([normalize(T[a], axis=1, norm='l1') for a in range(A)])\n","# Also need to add a 1 to the diagonals of the matrices where the probability is zero\n","for a in range(A):\n"," ind = np.where(T[a].sum(axis=1) == 0)[0]\n"," for i in ind:\n"," T[a, i, i] = 1\n"," R[a, i, i] = 0\n","\n","# Use policy iteration to determine the optimal policy\n","pi = mdptoolbox.mdp.PolicyIteration(T, R, 0.9)\n","pi.run()\n","\n"]},{"cell_type":"markdown","metadata":{},"source":[" ## Test the MDP"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["current_reward = np.zeros((time.shape[0], num_test))\n","current_sinr = np.zeros((time.shape[0], num_test))\n","cumulative_reward = np.zeros((num_test,))\n","mean_bw = 0\n","for itest in range(num_test):\n"," # Select a NEW trajectory that was not used for training\n"," # Randomly select a starting position and target velocity\n"," target.position = np.random.rand(3)*(np.max(P)-np.min(P)) + np.min(P)\n"," target.velocity = np.random.rand()*(np.max(V)-np.min(V)) + np.min(V)\n"," target.pos_state_ind = np.linalg.norm(\n"," target.position - P, keepdims=True, axis=1).argmin()\n"," target.vel_state_ind = np.linalg.norm(\n"," target.velocity - V, keepdims=True, axis=1).argmin()\n"," tx_history = np.empty((0, N))\n"," interference_history = np.empty((0, N))\n"," # Randomly select a starting frequency for the interferer\n"," comms.pattern_ind = np.random.randint(0, comms.pattern.shape[0])\n"," comms.state_ind = comms.pattern[comms.pattern_ind]\n"," comms.current_state = comms.states[comms.state_ind]\n"," next_state = (0, compute_state())\n"," prev_comms_state = 0\n"," for itime in range(time.shape[0]):\n"," # Initial environment state\n"," current_state = next_state\n"," current_state_ind = current_state[1]\n"," if use_memory:\n"," current_state_ind += prev_comms_state*(2**N)*rho*nu\n"," # Select an action from the policy\n"," radar.action = actions[pi.policy[current_state_ind], :]\n","\n"," # Determine the bandwidth used, then update the interference, position, range, and SINR\n"," wave.bandwidth = subband_bw*np.sum(radar.action)\n"," mean_bw += wave.bandwidth\n"," prev_comms_state = comms.state_ind\n"," comms.step()\n"," target.step(dt)\n"," if itime > 0:\n"," current_reward[itime, itest] = current_reward[itime -\n"," 1, itest] + reward(radar.action, comms.current_state)\n"," cumulative_reward[itest] += reward(radar.action, comms.current_state)\n"," next_state = (current_state[1], compute_state())\n","\n"," # Variables for plotting\n"," interference_history = np.append(interference_history, np.reshape(\n"," Theta[comms.state_ind], (1, N)), axis=0)\n"," tx_history = np.append(tx_history, np.reshape(\n"," radar.action, (1, N)), axis=0)\n"," sinr = radar.SINR(target, comms, wave)\n"," current_sinr[itime, itest] = sinr\n","\n","# Print RL statistics for report\n","mean_reward = np.mean(cumulative_reward)\n","mean_bw /= (time.shape[0]*num_test)\n","reward_std_dev = np.sqrt(np.var(cumulative_reward))\n","print(\"Mean reward: \" + str(mean_reward))\n","print(\"Reward std. dev: \" + str(reward_std_dev))\n","print(\"Mean bandwidth: \" + str(mean_bw/1e6))\n","current_sinr = np.mean(current_sinr, axis=1)\n","\n"]},{"cell_type":"markdown","metadata":{},"source":[" ## Visualizations"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["plt.figure()\n","plt.plot(time, current_reward, '.-')\n","plt.xlabel('Time (s)')\n","plt.ylabel('Average Cumulative Reward')\n","plt.savefig('reward')\n","\n","plt.figure()\n","plt.plot(time, current_sinr, '.-')\n","plt.xlabel('Time (s)')\n","plt.ylabel('Average SINR (dB)')\n","plt.savefig('SINR')\n","animate_spectrum(tx_history, interference_history)\n"]}],"metadata":{"interpreter":{"hash":"36bfa51ffa2f802e2f9ed636c27afdebfc31442618a5ac81c3811ab9156cf8d0"},"kernelspec":{"display_name":"Python 3.8.10 ('RadarRL-hbTOQ7ye')","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.8.10"},"orig_nbformat":4},"nbformat":4,"nbformat_minor":2} 2 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "10c2ddea900ca22bcdb0c2e2f6d685bd901304c470868e62d7f5dfded983fb27" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "asttokens": { 20 | "hashes": [ 21 | "sha256:0844691e88552595a6f4a4281a9f7f79b8dd45ca4ccea82e5e05b4bbdb76705c", 22 | "sha256:9a54c114f02c7a9480d56550932546a3f1fe71d8a02f1bc7ccd0ee3ee35cf4d5" 23 | ], 24 | "version": "==2.0.5" 25 | }, 26 | "autopep8": { 27 | "hashes": [ 28 | "sha256:44f0932855039d2c15c4510d6df665e4730f2b8582704fa48f9c55bd3e17d979", 29 | "sha256:ed77137193bbac52d029a52c59bec1b0629b5a186c495f1eb21b126ac466083f" 30 | ], 31 | "index": "pypi", 32 | "version": "==1.6.0" 33 | }, 34 | "backcall": { 35 | "hashes": [ 36 | "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e", 37 | "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255" 38 | ], 39 | "version": "==0.2.0" 40 | }, 41 | "cycler": { 42 | "hashes": [ 43 | "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3", 44 | "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f" 45 | ], 46 | "markers": "python_version >= '3.6'", 47 | "version": "==0.11.0" 48 | }, 49 | "debugpy": { 50 | "hashes": [ 51 | "sha256:01e98c594b3e66d529e40edf314f849cd1a21f7a013298df58cd8e263bf8e184", 52 | "sha256:16db27b4b91991442f91d73604d32080b30de655aca9ba821b1972ea8171021b", 53 | "sha256:17a25ce9d7714f92fc97ef00cc06269d7c2b163094990ada30156ed31d9a5030", 54 | "sha256:194f95dd3e84568b5489aab5689a3a2c044e8fdc06f1890b8b4f70b6b89f2778", 55 | "sha256:1ec3a086e14bba6c472632025b8fe5bdfbaef2afa1ebd5c6615ce6ed8d89bc67", 56 | "sha256:23df67fc56d59e386c342428a7953c2c06cc226d8525b11319153e96afb65b0c", 57 | "sha256:26fbe53cca45a608679094791ce587b6e2798acd1d4777a8b303b07622e85182", 58 | "sha256:2b073ad5e8d8c488fbb6a116986858bab0c9c4558f28deb8832c7a5a27405bd6", 59 | "sha256:318f81f37341e4e054b4267d39896b73cddb3612ca13b39d7eea45af65165e1d", 60 | "sha256:3a457ad9c0059a21a6c7d563c1f18e924f5cf90278c722bd50ede6f56b77c7fe", 61 | "sha256:4404a62fb5332ea5c8c9132290eef50b3a0ba38cecacad5529e969a783bcbdd7", 62 | "sha256:5d76a4fd028d8009c3faf1185b4b78ceb2273dd2499447664b03939e0368bb90", 63 | "sha256:70b422c63a833630c33e3f9cdbd9b6971f8c5afd452697e464339a21bbe862ba", 64 | "sha256:82f5f9ce93af6861a0713f804e62ab390bb12a17f113153e47fea8bbb1dfbe36", 65 | "sha256:a2aa64f6d2ca7ded8a7e8a4e7cae3bc71866b09876b7b05cecad231779cb9156", 66 | "sha256:b2df2c373e85871086bd55271c929670cd4e1dba63e94a08d442db830646203b", 67 | "sha256:b5b3157372e0e0a1297a8b6b5280bcf1d35a40f436c7973771c972726d1e32d5", 68 | "sha256:d2b09e91fbd1efa4f4fda121d49af89501beda50c18ed7499712c71a4bf3452e", 69 | "sha256:d876db8c312eeb02d85611e0f696abe66a2c1515e6405943609e725d5ff36f2a", 70 | "sha256:f3a3dca9104aa14fd4210edcce6d9ce2b65bd9618c0b222135a40b9d6e2a9eeb", 71 | "sha256:f73988422b17f071ad3c4383551ace1ba5ed810cbab5f9c362783d22d40a08dc" 72 | ], 73 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 74 | "version": "==1.5.1" 75 | }, 76 | "decorator": { 77 | "hashes": [ 78 | "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330", 79 | "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186" 80 | ], 81 | "markers": "python_version >= '3.5'", 82 | "version": "==5.1.1" 83 | }, 84 | "entrypoints": { 85 | "hashes": [ 86 | "sha256:b706eddaa9218a19ebcd67b56818f05bb27589b1ca9e8d797b74affad4ccacd4", 87 | "sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f" 88 | ], 89 | "markers": "python_version >= '3.6'", 90 | "version": "==0.4" 91 | }, 92 | "executing": { 93 | "hashes": [ 94 | "sha256:c6554e21c6b060590a6d3be4b82fb78f8f0194d809de5ea7df1c093763311501", 95 | "sha256:d1eef132db1b83649a3905ca6dd8897f71ac6f8cac79a7e58a1a09cf137546c9" 96 | ], 97 | "version": "==0.8.3" 98 | }, 99 | "fonttools": { 100 | "hashes": [ 101 | "sha256:2b288eae806800668cb5cdf52a37b5ac701c5adda2dd5c88b685581ce3385285", 102 | "sha256:f8b35ed9ba189710994cec2c86b8eb5f0c49336698575e439a0d5671d3ca1ace" 103 | ], 104 | "markers": "python_version >= '3.7'", 105 | "version": "==4.31.1" 106 | }, 107 | "ipykernel": { 108 | "hashes": [ 109 | "sha256:4c3cc8cb359f2ead70c30f5504971c0d285e2c1c699d2ce9af0216fe9c9fb17c", 110 | "sha256:c977cff576b8425a68d3a6916510903833f0f25ed8d5c282a0c51c35de27bd47" 111 | ], 112 | "index": "pypi", 113 | "version": "==6.9.2" 114 | }, 115 | "ipython": { 116 | "hashes": [ 117 | "sha256:6f56bfaeaa3247aa3b9cd3b8cbab3a9c0abf7428392f97b21902d12b2f42a381", 118 | "sha256:8138762243c9b3a3ffcf70b37151a2a35c23d3a29f9743878c33624f4207be3d" 119 | ], 120 | "markers": "python_version >= '3.8'", 121 | "version": "==8.1.1" 122 | }, 123 | "jedi": { 124 | "hashes": [ 125 | "sha256:637c9635fcf47945ceb91cd7f320234a7be540ded6f3e99a50cb6febdfd1ba8d", 126 | "sha256:74137626a64a99c8eb6ae5832d99b3bdd7d29a3850fe2aa80a4126b2a7d949ab" 127 | ], 128 | "markers": "python_version >= '3.6'", 129 | "version": "==0.18.1" 130 | }, 131 | "joblib": { 132 | "hashes": [ 133 | "sha256:4158fcecd13733f8be669be0683b96ebdbbd38d23559f54dca7205aea1bf1e35", 134 | "sha256:f21f109b3c7ff9d95f8387f752d0d9c34a02aa2f7060c2135f465da0e5160ff6" 135 | ], 136 | "markers": "python_version >= '3.6'", 137 | "version": "==1.1.0" 138 | }, 139 | "jupyter-client": { 140 | "hashes": [ 141 | "sha256:4ea61033726c8e579edb55626d8ee2e6bf0a83158ddf3751b8dd46b2c5cd1e96", 142 | "sha256:d56f1c57bef42ff31e61b1185d3348a5b2bcde7c9a05523ae4dbe5ee0871797c" 143 | ], 144 | "markers": "python_full_version >= '3.6.1'", 145 | "version": "==7.1.2" 146 | }, 147 | "jupyter-core": { 148 | "hashes": [ 149 | "sha256:d69baeb9ffb128b8cd2657fcf2703f89c769d1673c851812119e3a2a0e93ad9a", 150 | "sha256:f875e4d27e202590311d468fa55f90c575f201490bd0c18acabe4e318db4a46d" 151 | ], 152 | "markers": "python_version >= '3.6'", 153 | "version": "==4.9.2" 154 | }, 155 | "kiwisolver": { 156 | "hashes": [ 157 | "sha256:139c75216e5875ee5f8f4f7adcc3cd339f46f0d66bda2e10d8d21386d635476f", 158 | "sha256:14f43edc25daa0646d4b4e86c2ebdd32d785ab73a65a570130a3d234a4554b07", 159 | "sha256:17ec8bd4e162fd0a8723467395c5bb16fd665a528b78e9339886c82965ed8efb", 160 | "sha256:199f32bf6f3d3e2246024326497513c5c49c62aecee86f0ac019f5991978d505", 161 | "sha256:1cf8c81e8a5fb4f5dcbd473fdb619b895313d29b7c60e4545827dcc6efbd8efc", 162 | "sha256:2467fe5fff6ed2a728e10dca9b1f37e9b911ca5b228a7d8990c8e3abf80c1724", 163 | "sha256:313724e85fd14d581a939fa02424f4dc772fd914bc04499a8a6377d47313b966", 164 | "sha256:334a7e3d498a0a791245f0964c746d0414e9b13aef73237f0d798a2101fdbae9", 165 | "sha256:34e2e39a219b203fa3a82af5b9f8d386a8718677de7a9b82a9634e292a8f4e0a", 166 | "sha256:384b5076b2c0172003abca9ba8b8c5efcaaffd31616f3f5e0a09dcc34772d012", 167 | "sha256:3891527ec51b0365bb50de9bf826ce3d5b1adc276685b2779889762437bbd359", 168 | "sha256:38ebc0cb30ed2f59bd15e23591a53698005123e90e880f1af4600fcdbe4912e1", 169 | "sha256:4471a48f53d20d49f263ca888aab77b754525ef35e6767657e1a44a724a8b0af", 170 | "sha256:4b70f0729947d6327cd659e1b3477ced44a317a4ba441238b2a3642990f0ebd7", 171 | "sha256:576ba51b9f4e4d0d583c1cd257f53397bdc5e66a5e49fe68712f658426115777", 172 | "sha256:5ca92de8e48678a2cbbd90adb10773e3553bb9fd1c090bf0dfe5fc3337a181ea", 173 | "sha256:5ecf82bb25cec7df4bfcf37afe49f6f6202b4fa4029be7cb0848ed319c72d356", 174 | "sha256:65cbdbe14dc5988e362eb15e02dd24c6724238cb235132f812f1e3a29a61a3de", 175 | "sha256:676f9fac93f97f529dc80b5d6731099fad337549408e8bdd929343b7cb679797", 176 | "sha256:6bf0080449d6ea39b817d85abd2c20d2d42fd9b1587544d64371d28d93c379cf", 177 | "sha256:6c19457f58941da61681efaabd5b1c37893108a2f922b9b19538f6921911186d", 178 | "sha256:70e7b7a4ebeddef423115ea31857732fc04e0f38dd1e6385e1af05b6164a3d0f", 179 | "sha256:71d44a6a59ea53d41e5950a42ec496fa821bd86f292fb3e10aa1b3932ecfc65e", 180 | "sha256:734e943ae519cdb8534d9053f478417c525ec921c06896ec7119e65d9ea4a687", 181 | "sha256:7508b01e211178a85d21f1f87029846b77b2404a4c68cbd14748d4d4142fa3b8", 182 | "sha256:87367ba1ad3819f7189fe8faff5f75a7603f526576033e7b86e10b598f8790b2", 183 | "sha256:895b2df026006ff7434b03ca495983d0d26da96f6d58414c77d616747ee77e34", 184 | "sha256:8cd1f81bc35ec24cb82a7d0b805521e3d71b25b8a493d5810d18dc29644c6ef8", 185 | "sha256:8f63b981678ca894bb665bcd5043bde2c9ba600e69df730c1ceeadd73ddbcb8c", 186 | "sha256:925a32900fc16430ba0dec2c0fca2e776eaf2fdc0930d5552be0a59e23304001", 187 | "sha256:97372c837add54e3e64a811464b14bb01428c4e9256072b6296f04157ea23246", 188 | "sha256:9b4d1db32a4f1682df1480fd68eb1400235ac8f9ad8932e1624fdb23eb891904", 189 | "sha256:a0a6f3d5063e7fd6662e4773778ad2cb36e598abc6eb171af4a072ca86b441d0", 190 | "sha256:af6a7c956a45ee721e4263f5823e1a3b2e6b21a7e2b3646b3794e000620609d0", 191 | "sha256:b1ff5582bf55e85728119c5a23f695b8e408e15eee7d0f5effe0ee8ad1f8b523", 192 | "sha256:bb997d1631b20745b18674d68dd6f1d9d45db512efd5fe0f162a5d4a6bbdd211", 193 | "sha256:c29496625c61e18d97a6f6c2f2a55759ca8290fc21a751bc57824599c431c0d2", 194 | "sha256:caff7ae6fb6dce2f520b2d46efc801605fa1378fb19bb4580aebc6174eab05a0", 195 | "sha256:cbf9aa926de224af15c974750fecdc7d2c0043428372acaaf61216e202abbf21", 196 | "sha256:cd0223a3a4ddcc0d0e06c6cfeb0adde2bc19c08b4c7fc79d48dac2486a4b115b", 197 | "sha256:daf2030bf18c21bf91fa9cf6a403a765519c9168bd7a91ba1d66d5c7f70ded1e", 198 | "sha256:ed30c5e58e578a2981c67346b2569e04120d1b80fa6906c207fe824d24603313", 199 | "sha256:ed937691f522cc2362c280c903837a4e35195659b9935b598e3cd448db863605" 200 | ], 201 | "markers": "python_version >= '3.7'", 202 | "version": "==1.4.0" 203 | }, 204 | "matplotlib": { 205 | "hashes": [ 206 | "sha256:14334b9902ec776461c4b8c6516e26b450f7ebe0b3ef8703bf5cdfbbaecf774a", 207 | "sha256:2252bfac85cec7af4a67e494bfccf9080bcba8a0299701eab075f48847cca907", 208 | "sha256:2e3484d8455af3fdb0424eae1789af61f6a79da0c80079125112fd5c1b604218", 209 | "sha256:34a1fc29f8f96e78ec57a5eff5e8d8b53d3298c3be6df61e7aa9efba26929522", 210 | "sha256:3e66497cd990b1a130e21919b004da2f1dc112132c01ac78011a90a0f9229778", 211 | "sha256:40e0d7df05e8efe60397c69b467fc8f87a2affeb4d562fe92b72ff8937a2b511", 212 | "sha256:456cc8334f6d1124e8ff856b42d2cc1c84335375a16448189999496549f7182b", 213 | "sha256:506b210cc6e66a0d1c2bb765d055f4f6bc2745070fb1129203b67e85bbfa5c18", 214 | "sha256:53273c5487d1c19c3bc03b9eb82adaf8456f243b97ed79d09dded747abaf1235", 215 | "sha256:577ed20ec9a18d6bdedb4616f5e9e957b4c08563a9f985563a31fd5b10564d2a", 216 | "sha256:6803299cbf4665eca14428d9e886de62e24f4223ac31ab9c5d6d5339a39782c7", 217 | "sha256:68fa30cec89b6139dc559ed6ef226c53fd80396da1919a1b5ef672c911aaa767", 218 | "sha256:6c094e4bfecd2fa7f9adffd03d8abceed7157c928c2976899de282f3600f0a3d", 219 | "sha256:778d398c4866d8e36ee3bf833779c940b5f57192fa0a549b3ad67bc4c822771b", 220 | "sha256:7a350ca685d9f594123f652ba796ee37219bf72c8e0fc4b471473d87121d6d34", 221 | "sha256:87900c67c0f1728e6db17c6809ec05c025c6624dcf96a8020326ea15378fe8e7", 222 | "sha256:8a77906dc2ef9b67407cec0bdbf08e3971141e535db888974a915be5e1e3efc6", 223 | "sha256:8e70ae6475cfd0fad3816dcbf6cac536dc6f100f7474be58d59fa306e6e768a4", 224 | "sha256:abf67e05a1b7f86583f6ebd01f69b693b9c535276f4e943292e444855870a1b8", 225 | "sha256:b04fc29bcef04d4e2d626af28d9d892be6aba94856cb46ed52bcb219ceac8943", 226 | "sha256:b19a761b948e939a9e20173aaae76070025f0024fc8f7ba08bef22a5c8573afc", 227 | "sha256:b2e9810e09c3a47b73ce9cab5a72243a1258f61e7900969097a817232246ce1c", 228 | "sha256:b71f3a7ca935fc759f2aed7cec06cfe10bc3100fadb5dbd9c435b04e557971e1", 229 | "sha256:b8a4fb2a0c5afbe9604f8a91d7d0f27b1832c3e0b5e365f95a13015822b4cd65", 230 | "sha256:bb1c613908f11bac270bc7494d68b1ef6e7c224b7a4204d5dacf3522a41e2bc3", 231 | "sha256:d24e5bb8028541ce25e59390122f5e48c8506b7e35587e5135efcb6471b4ac6c", 232 | "sha256:d70a32ee1f8b55eed3fd4e892f0286df8cccc7e0475c11d33b5d0a148f5c7599", 233 | "sha256:e293b16cf303fe82995e41700d172a58a15efc5331125d08246b520843ef21ee", 234 | "sha256:e2f28a07b4f82abb40267864ad7b3a4ed76f1b1663e81c7efc84a9b9248f672f", 235 | "sha256:e3520a274a0e054e919f5b3279ee5dbccf5311833819ccf3399dab7c83e90a25", 236 | "sha256:e3b6f3fd0d8ca37861c31e9a7cab71a0ef14c639b4c95654ea1dd153158bf0df", 237 | "sha256:e486f60db0cd1c8d68464d9484fd2a94011c1ac8593d765d0211f9daba2bd535", 238 | "sha256:e8c87cdaf06fd7b2477f68909838ff4176f105064a72ca9d24d3f2a29f73d393", 239 | "sha256:edf5e4e1d5fb22c18820e8586fb867455de3b109c309cb4fce3aaed85d9468d1", 240 | "sha256:fe8d40c434a8e2c68d64c6d6a04e77f21791a93ff6afe0dce169597c110d3079" 241 | ], 242 | "index": "pypi", 243 | "version": "==3.5.1" 244 | }, 245 | "matplotlib-inline": { 246 | "hashes": [ 247 | "sha256:a04bfba22e0d1395479f866853ec1ee28eea1485c1d69a6faf00dc3e24ff34ee", 248 | "sha256:aed605ba3b72462d64d475a21a9296f400a19c4f74a31b59103d2a99ffd5aa5c" 249 | ], 250 | "markers": "python_version >= '3.5'", 251 | "version": "==0.1.3" 252 | }, 253 | "nest-asyncio": { 254 | "hashes": [ 255 | "sha256:3fdd0d6061a2bb16f21fe8a9c6a7945be83521d81a0d15cff52e9edee50101d6", 256 | "sha256:f969f6013a16fadb4adcf09d11a68a4f617c6049d7af7ac2c676110169a63abd" 257 | ], 258 | "markers": "python_version >= '3.5'", 259 | "version": "==1.5.4" 260 | }, 261 | "numpy": { 262 | "hashes": [ 263 | "sha256:07a8c89a04997625236c5ecb7afe35a02af3896c8aa01890a849913a2309c676", 264 | "sha256:08d9b008d0156c70dc392bb3ab3abb6e7a711383c3247b410b39962263576cd4", 265 | "sha256:201b4d0552831f7250a08d3b38de0d989d6f6e4658b709a02a73c524ccc6ffce", 266 | "sha256:2c10a93606e0b4b95c9b04b77dc349b398fdfbda382d2a39ba5a822f669a0123", 267 | "sha256:3ca688e1b9b95d80250bca34b11a05e389b1420d00e87a0d12dc45f131f704a1", 268 | "sha256:48a3aecd3b997bf452a2dedb11f4e79bc5bfd21a1d4cc760e703c31d57c84b3e", 269 | "sha256:568dfd16224abddafb1cbcce2ff14f522abe037268514dd7e42c6776a1c3f8e5", 270 | "sha256:5bfb1bb598e8229c2d5d48db1860bcf4311337864ea3efdbe1171fb0c5da515d", 271 | "sha256:639b54cdf6aa4f82fe37ebf70401bbb74b8508fddcf4797f9fe59615b8c5813a", 272 | "sha256:8251ed96f38b47b4295b1ae51631de7ffa8260b5b087808ef09a39a9d66c97ab", 273 | "sha256:92bfa69cfbdf7dfc3040978ad09a48091143cffb778ec3b03fa170c494118d75", 274 | "sha256:97098b95aa4e418529099c26558eeb8486e66bd1e53a6b606d684d0c3616b168", 275 | "sha256:a3bae1a2ed00e90b3ba5f7bd0a7c7999b55d609e0c54ceb2b076a25e345fa9f4", 276 | "sha256:c34ea7e9d13a70bf2ab64a2532fe149a9aced424cd05a2c4ba662fd989e3e45f", 277 | "sha256:dbc7601a3b7472d559dc7b933b18b4b66f9aa7452c120e87dfb33d02008c8a18", 278 | "sha256:e7927a589df200c5e23c57970bafbd0cd322459aa7b1ff73b7c2e84d6e3eae62", 279 | "sha256:f8c1f39caad2c896bc0018f699882b345b2a63708008be29b1f355ebf6f933fe", 280 | "sha256:f950f8845b480cffe522913d35567e29dd381b0dc7e4ce6a4a9f9156417d2430", 281 | "sha256:fade0d4f4d292b6f39951b6836d7a3c7ef5b2347f3c420cd9820a1d90d794802", 282 | "sha256:fdf3c08bce27132395d3c3ba1503cac12e17282358cb4bddc25cc46b0aca07aa" 283 | ], 284 | "index": "pypi", 285 | "version": "==1.22.3" 286 | }, 287 | "packaging": { 288 | "hashes": [ 289 | "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", 290 | "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" 291 | ], 292 | "markers": "python_version >= '3.6'", 293 | "version": "==21.3" 294 | }, 295 | "parso": { 296 | "hashes": [ 297 | "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0", 298 | "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75" 299 | ], 300 | "markers": "python_version >= '3.6'", 301 | "version": "==0.8.3" 302 | }, 303 | "pexpect": { 304 | "hashes": [ 305 | "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937", 306 | "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c" 307 | ], 308 | "markers": "sys_platform != 'win32'", 309 | "version": "==4.8.0" 310 | }, 311 | "pickleshare": { 312 | "hashes": [ 313 | "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca", 314 | "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56" 315 | ], 316 | "version": "==0.7.5" 317 | }, 318 | "pillow": { 319 | "hashes": [ 320 | "sha256:011233e0c42a4a7836498e98c1acf5e744c96a67dd5032a6f666cc1fb97eab97", 321 | "sha256:0f29d831e2151e0b7b39981756d201f7108d3d215896212ffe2e992d06bfe049", 322 | "sha256:12875d118f21cf35604176872447cdb57b07126750a33748bac15e77f90f1f9c", 323 | "sha256:14d4b1341ac07ae07eb2cc682f459bec932a380c3b122f5540432d8977e64eae", 324 | "sha256:1c3c33ac69cf059bbb9d1a71eeaba76781b450bc307e2291f8a4764d779a6b28", 325 | "sha256:1d19397351f73a88904ad1aee421e800fe4bbcd1aeee6435fb62d0a05ccd1030", 326 | "sha256:253e8a302a96df6927310a9d44e6103055e8fb96a6822f8b7f514bb7ef77de56", 327 | "sha256:2632d0f846b7c7600edf53c48f8f9f1e13e62f66a6dbc15191029d950bfed976", 328 | "sha256:335ace1a22325395c4ea88e00ba3dc89ca029bd66bd5a3c382d53e44f0ccd77e", 329 | "sha256:413ce0bbf9fc6278b2d63309dfeefe452835e1c78398efb431bab0672fe9274e", 330 | "sha256:5100b45a4638e3c00e4d2320d3193bdabb2d75e79793af7c3eb139e4f569f16f", 331 | "sha256:514ceac913076feefbeaf89771fd6febde78b0c4c1b23aaeab082c41c694e81b", 332 | "sha256:528a2a692c65dd5cafc130de286030af251d2ee0483a5bf50c9348aefe834e8a", 333 | "sha256:6295f6763749b89c994fcb6d8a7f7ce03c3992e695f89f00b741b4580b199b7e", 334 | "sha256:6c8bc8238a7dfdaf7a75f5ec5a663f4173f8c367e5a39f87e720495e1eed75fa", 335 | "sha256:718856856ba31f14f13ba885ff13874be7fefc53984d2832458f12c38205f7f7", 336 | "sha256:7f7609a718b177bf171ac93cea9fd2ddc0e03e84d8fa4e887bdfc39671d46b00", 337 | "sha256:80ca33961ced9c63358056bd08403ff866512038883e74f3a4bf88ad3eb66838", 338 | "sha256:80fe64a6deb6fcfdf7b8386f2cf216d329be6f2781f7d90304351811fb591360", 339 | "sha256:81c4b81611e3a3cb30e59b0cf05b888c675f97e3adb2c8672c3154047980726b", 340 | "sha256:855c583f268edde09474b081e3ddcd5cf3b20c12f26e0d434e1386cc5d318e7a", 341 | "sha256:9bfdb82cdfeccec50aad441afc332faf8606dfa5e8efd18a6692b5d6e79f00fd", 342 | "sha256:a5d24e1d674dd9d72c66ad3ea9131322819ff86250b30dc5821cbafcfa0b96b4", 343 | "sha256:a9f44cd7e162ac6191491d7249cceb02b8116b0f7e847ee33f739d7cb1ea1f70", 344 | "sha256:b5b3f092fe345c03bca1e0b687dfbb39364b21ebb8ba90e3fa707374b7915204", 345 | "sha256:b9618823bd237c0d2575283f2939655f54d51b4527ec3972907a927acbcc5bfc", 346 | "sha256:cef9c85ccbe9bee00909758936ea841ef12035296c748aaceee535969e27d31b", 347 | "sha256:d21237d0cd37acded35154e29aec853e945950321dd2ffd1a7d86fe686814669", 348 | "sha256:d3c5c79ab7dfce6d88f1ba639b77e77a17ea33a01b07b99840d6ed08031cb2a7", 349 | "sha256:d9d7942b624b04b895cb95af03a23407f17646815495ce4547f0e60e0b06f58e", 350 | "sha256:db6d9fac65bd08cea7f3540b899977c6dee9edad959fa4eaf305940d9cbd861c", 351 | "sha256:ede5af4a2702444a832a800b8eb7f0a7a1c0eed55b644642e049c98d589e5092", 352 | "sha256:effb7749713d5317478bb3acb3f81d9d7c7f86726d41c1facca068a04cf5bb4c", 353 | "sha256:f154d173286a5d1863637a7dcd8c3437bb557520b01bddb0be0258dcb72696b5", 354 | "sha256:f25ed6e28ddf50de7e7ea99d7a976d6a9c415f03adcaac9c41ff6ff41b6d86ac" 355 | ], 356 | "markers": "python_version >= '3.7'", 357 | "version": "==9.0.1" 358 | }, 359 | "prompt-toolkit": { 360 | "hashes": [ 361 | "sha256:30129d870dcb0b3b6a53efdc9d0a83ea96162ffd28ffe077e94215b233dc670c", 362 | "sha256:9f1cd16b1e86c2968f2519d7fb31dd9d669916f515612c269d14e9ed52b51650" 363 | ], 364 | "markers": "python_full_version >= '3.6.2'", 365 | "version": "==3.0.28" 366 | }, 367 | "psutil": { 368 | "hashes": [ 369 | "sha256:072664401ae6e7c1bfb878c65d7282d4b4391f1bc9a56d5e03b5a490403271b5", 370 | "sha256:1070a9b287846a21a5d572d6dddd369517510b68710fca56b0e9e02fd24bed9a", 371 | "sha256:1d7b433519b9a38192dfda962dd8f44446668c009833e1429a52424624f408b4", 372 | "sha256:3151a58f0fbd8942ba94f7c31c7e6b310d2989f4da74fcbf28b934374e9bf841", 373 | "sha256:32acf55cb9a8cbfb29167cd005951df81b567099295291bcfd1027365b36591d", 374 | "sha256:3611e87eea393f779a35b192b46a164b1d01167c9d323dda9b1e527ea69d697d", 375 | "sha256:3d00a664e31921009a84367266b35ba0aac04a2a6cad09c550a89041034d19a0", 376 | "sha256:4e2fb92e3aeae3ec3b7b66c528981fd327fb93fd906a77215200404444ec1845", 377 | "sha256:539e429da49c5d27d5a58e3563886057f8fc3868a5547b4f1876d9c0f007bccf", 378 | "sha256:55ce319452e3d139e25d6c3f85a1acf12d1607ddedea5e35fb47a552c051161b", 379 | "sha256:58c7d923dc209225600aec73aa2c4ae8ea33b1ab31bc11ef8a5933b027476f07", 380 | "sha256:7336292a13a80eb93c21f36bde4328aa748a04b68c13d01dfddd67fc13fd0618", 381 | "sha256:742c34fff804f34f62659279ed5c5b723bb0195e9d7bd9907591de9f8f6558e2", 382 | "sha256:7641300de73e4909e5d148e90cc3142fb890079e1525a840cf0dfd39195239fd", 383 | "sha256:76cebf84aac1d6da5b63df11fe0d377b46b7b500d892284068bacccf12f20666", 384 | "sha256:7779be4025c540d1d65a2de3f30caeacc49ae7a2152108adeaf42c7534a115ce", 385 | "sha256:7d190ee2eaef7831163f254dc58f6d2e2a22e27382b936aab51c835fc080c3d3", 386 | "sha256:8293942e4ce0c5689821f65ce6522ce4786d02af57f13c0195b40e1edb1db61d", 387 | "sha256:869842dbd66bb80c3217158e629d6fceaecc3a3166d3d1faee515b05dd26ca25", 388 | "sha256:90a58b9fcae2dbfe4ba852b57bd4a1dded6b990a33d6428c7614b7d48eccb492", 389 | "sha256:9b51917c1af3fa35a3f2dabd7ba96a2a4f19df3dec911da73875e1edaf22a40b", 390 | "sha256:b2237f35c4bbae932ee98902a08050a27821f8f6dfa880a47195e5993af4702d", 391 | "sha256:c3400cae15bdb449d518545cbd5b649117de54e3596ded84aacabfbb3297ead2", 392 | "sha256:c51f1af02334e4b516ec221ee26b8fdf105032418ca5a5ab9737e8c87dafe203", 393 | "sha256:cb8d10461c1ceee0c25a64f2dd54872b70b89c26419e147a05a10b753ad36ec2", 394 | "sha256:d62a2796e08dd024b8179bd441cb714e0f81226c352c802fca0fd3f89eeacd94", 395 | "sha256:df2c8bd48fb83a8408c8390b143c6a6fa10cb1a674ca664954de193fdcab36a9", 396 | "sha256:e5c783d0b1ad6ca8a5d3e7b680468c9c926b804be83a3a8e95141b05c39c9f64", 397 | "sha256:e9805fed4f2a81de98ae5fe38b75a74c6e6ad2df8a5c479594c7629a1fe35f56", 398 | "sha256:ea42d747c5f71b5ccaa6897b216a7dadb9f52c72a0fe2b872ef7d3e1eacf3ba3", 399 | "sha256:ef216cc9feb60634bda2f341a9559ac594e2eeaadd0ba187a4c2eb5b5d40b91c", 400 | "sha256:ff0d41f8b3e9ebb6b6110057e40019a432e96aae2008951121ba4e56040b84f3" 401 | ], 402 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", 403 | "version": "==5.9.0" 404 | }, 405 | "ptyprocess": { 406 | "hashes": [ 407 | "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", 408 | "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220" 409 | ], 410 | "version": "==0.7.0" 411 | }, 412 | "pure-eval": { 413 | "hashes": [ 414 | "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350", 415 | "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3" 416 | ], 417 | "version": "==0.2.2" 418 | }, 419 | "pycodestyle": { 420 | "hashes": [ 421 | "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20", 422 | "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f" 423 | ], 424 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 425 | "version": "==2.8.0" 426 | }, 427 | "pygments": { 428 | "hashes": [ 429 | "sha256:44238f1b60a76d78fc8ca0528ee429702aae011c265fe6a8dd8b63049ae41c65", 430 | "sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a" 431 | ], 432 | "markers": "python_version >= '3.5'", 433 | "version": "==2.11.2" 434 | }, 435 | "pymdptoolbox": { 436 | "hashes": [ 437 | "sha256:49a4e4653b3baea832b333f8623ae832ee7d572815396d9c57356bd64b18d982", 438 | "sha256:eca66535c25eee8f400dda8d5d1be1d6f728903a18a5a6ffad903254559d8264" 439 | ], 440 | "index": "pypi", 441 | "version": "==4.0b3" 442 | }, 443 | "pyparsing": { 444 | "hashes": [ 445 | "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea", 446 | "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484" 447 | ], 448 | "markers": "python_version >= '3.6'", 449 | "version": "==3.0.7" 450 | }, 451 | "python-dateutil": { 452 | "hashes": [ 453 | "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", 454 | "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" 455 | ], 456 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 457 | "version": "==2.8.2" 458 | }, 459 | "pyzmq": { 460 | "hashes": [ 461 | "sha256:031417b5d450baf645cf9dbf6d156399010505867f0e0db7ce32e50b83c4f4c8", 462 | "sha256:07b4f6f852ded85db1e1939fd9c08cb8b548ad07a386f7237cdebe1b884dffac", 463 | "sha256:099b59e2bdf7bb08599b21425f82e896682642293fe7eddeb0afbe2c79bfa97a", 464 | "sha256:113df7f444c7e60a09f940edc4366d1ba33f374527f9a57096b0eeda731430b9", 465 | "sha256:21529e58514c42598f1ad8ca5551b09e52533e8c13a93d0588b10e9f38b1c045", 466 | "sha256:22581b4b5becf830ab42b36412100eceb412b1dd3367627e67dd4ed8754f5055", 467 | "sha256:226c6a705f33303752bcc7c6979c1cc0db4178c4e7011b8a53398200d49e6c47", 468 | "sha256:232b1511bc81ae0a44002f3b7f42e96813353c2a19b1eeedcb36a0867755606d", 469 | "sha256:2aaa587eb77fce70a5f85fba8711f70a6e8a0c84e5aa75d28f1c47acbbdc3b80", 470 | "sha256:37cfba29611afde16e6f3cc24e6a5c2ef802923f40df4f5ef4cda53dc9ac774a", 471 | "sha256:3b93edc90e6dcca5cdb21a67a92cc593c06b9bc681ffef1665e84c6cc8fc14ff", 472 | "sha256:49300eb7c25046e54459f2e3815a1db430e44f309a28bf70b0c8aedf8c5370a9", 473 | "sha256:4bd5ecf70fd80c0f3debb585412fecace3fecab59665a30437cf9424df5514fe", 474 | "sha256:4dca17b0b27603b2c202b694f440c4b60d1c9c1a4966df9d361cd98b7f41270f", 475 | "sha256:50184458e22ca6e7c18364dc825a177d607a08d8d9bd2bc5577b16169c1f85cd", 476 | "sha256:51e3b39364e069264e451c710b74d46cb1484bc88a17f8ff7c8f8ea2d97c7181", 477 | "sha256:52b1b41488988f0f60c347166e659e9ff530b8f8395896394e177b842ea8835d", 478 | "sha256:532dd70586511bd000671a17b59124d9d599164fc76512ab798fa334522f774c", 479 | "sha256:5ca84bb9f649ee06192ee0a7120b398cc447eaac187e9bc689e9e8ba843fde99", 480 | "sha256:5e4121b525d90330524b6ee7aa8a8c83bf2c1e01709963611d857ebc14f80a3e", 481 | "sha256:656d2a54411c1f204f579c88480641d0a9503eb7eb98517f90ace4cf2897af99", 482 | "sha256:664b7f57330470a8354f248650958c91d1d806408e13fece3d38b545f43e6e3e", 483 | "sha256:6d9025bca175aaecc0f54b2895bef22dc154ca13824a0828f6be4efcdaadefed", 484 | "sha256:7280ecd232e439e040b5cd5ebdd5d5ebaa46cbcd1163e1fd0be236f9871047be", 485 | "sha256:7a5ac470da6bb13f022c5e392d4528f05d5cadb37702ed434c652aa2ef5538c1", 486 | "sha256:81ff0ec9c4d81db3b91d9568c3051ced6e81637ac912bc30d149cf54b1e3cee3", 487 | "sha256:8306f064bf4603381313e4fa66d3b04c50ae8df6888c538d2c1d8072c4c36443", 488 | "sha256:830fd69828931fcd67a283485dc0a9ad1a54c48514a0f68f0d559ab7de1cc7a2", 489 | "sha256:83f8dfbb6711e956a6705e8dbdfc0df32f34bb2aad0f19128bc6abe2fbffe1b2", 490 | "sha256:850032302a9bff470788813389482ad76f83448f2b448b2885ab479d370a9ac3", 491 | "sha256:88786376e7a13dbe37181e6ca079ffdca55186fd80eb44b97ad4d6e5579d5294", 492 | "sha256:8d4cf52e1a2ffe398315c026435dea8a3f09ba12deea88302b3fb5d3527264e1", 493 | "sha256:98f869ff401a1f4c6104fecf44b21ad027b6a94240d565c67528eac96c6a7b4e", 494 | "sha256:9a74e6080b3f76486fe26d35e84c3734081bab729f0124df0b27ae2612cee260", 495 | "sha256:a17befeb4f532b3a80f4befa889b5e6a21c7113a5c145b4dd3a7bb472df0815f", 496 | "sha256:a5cf28f9d566216470357b107147b9ec320025bdc40ca0f0d1d6603a958c3a60", 497 | "sha256:b1495d9d520384c4ac30814943bc3a45d005aee2c9362c91ad536b1db5660ec1", 498 | "sha256:b63605f2ee5c5bca4d762e876c8879760bf046510687de735e28103f072a2d77", 499 | "sha256:bb612af9dc23d80688ace7f005a9ed4e5dae20c988dd197381e7e20d49836c11", 500 | "sha256:c2e1071a11c1bf62888859c761e33a20840ac70819b5c86a55b4ebec3cf8733e", 501 | "sha256:c887bc1a80bef14aa12f1756bd8e976c3f3a4d5fd410ba17454a382a00cfe721", 502 | "sha256:d0a30aac29088a1e11777ce2221bb08f85a9fdb2b386d6fd02f9f36260b48338", 503 | "sha256:d6cced1b564ca1da4ba9e19de88d9cc0422b75ffab869f1bb21ceccd754c6bf5", 504 | "sha256:d8859098ff2bcf3fe2e43d3c6915127a45363a90534d1f2af9487ae87c2920db", 505 | "sha256:e4a189b86adfd0075cc9e41550540cd620a17f74c118d2cf6af0361be07e1d82", 506 | "sha256:e7da43aebe4dc18349f716470f728afbae449d4cfd3945ba6805a563e0ddc1be", 507 | "sha256:f1fc63e7eef23418cdfe8169dbcb0964c36f7c180f60dae122c0f9bb359df2f7", 508 | "sha256:f2c7bf98fdb2f81304921a9aa25ae73b5fdeae0da2fb46d1efec94ba8ffb34d6", 509 | "sha256:f3bbcfde5466c2e3c63d0f77a12daf19308ffa9b03fe0758424bb61b8150abfd", 510 | "sha256:fb9c3747c6516da0b21d4e38d4f433db0216f8e214173bd02a916d8deda68ef2", 511 | "sha256:fd4bf5dfe291611881a19059bcd5b973475f46deaa4fc88fb4357013ed6c4b09" 512 | ], 513 | "markers": "python_version >= '3.6'", 514 | "version": "==23.0.0b1" 515 | }, 516 | "scikit-learn": { 517 | "hashes": [ 518 | "sha256:08ef968f6b72033c16c479c966bf37ccd49b06ea91b765e1cc27afefe723920b", 519 | "sha256:158faf30684c92a78e12da19c73feff9641a928a8024b4fa5ec11d583f3d8a87", 520 | "sha256:16455ace947d8d9e5391435c2977178d0ff03a261571e67f627c8fee0f9d431a", 521 | "sha256:245c9b5a67445f6f044411e16a93a554edc1efdcce94d3fc0bc6a4b9ac30b752", 522 | "sha256:285db0352e635b9e3392b0b426bc48c3b485512d3b4ac3c7a44ec2a2ba061e66", 523 | "sha256:2f3b453e0b149898577e301d27e098dfe1a36943f7bb0ad704d1e548efc3b448", 524 | "sha256:46f431ec59dead665e1370314dbebc99ead05e1c0a9df42f22d6a0e00044820f", 525 | "sha256:55f2f3a8414e14fbee03782f9fe16cca0f141d639d2b1c1a36779fa069e1db57", 526 | "sha256:5cb33fe1dc6f73dc19e67b264dbb5dde2a0539b986435fdd78ed978c14654830", 527 | "sha256:75307d9ea39236cad7eea87143155eea24d48f93f3a2f9389c817f7019f00705", 528 | "sha256:7626a34eabbf370a638f32d1a3ad50526844ba58d63e3ab81ba91e2a7c6d037e", 529 | "sha256:7a93c1292799620df90348800d5ac06f3794c1316ca247525fa31169f6d25855", 530 | "sha256:7d6b2475f1c23a698b48515217eb26b45a6598c7b1840ba23b3c5acece658dbb", 531 | "sha256:80095a1e4b93bd33261ef03b9bc86d6db649f988ea4dbcf7110d0cded8d7213d", 532 | "sha256:85260fb430b795d806251dd3bb05e6f48cdc777ac31f2bcf2bc8bbed3270a8f5", 533 | "sha256:9369b030e155f8188743eb4893ac17a27f81d28a884af460870c7c072f114243", 534 | "sha256:a053a6a527c87c5c4fa7bf1ab2556fa16d8345cf99b6c5a19030a4a7cd8fd2c0", 535 | "sha256:a90b60048f9ffdd962d2ad2fb16367a87ac34d76e02550968719eb7b5716fd10", 536 | "sha256:a999c9f02ff9570c783069f1074f06fe7386ec65b84c983db5aeb8144356a355", 537 | "sha256:b1391d1a6e2268485a63c3073111fe3ba6ec5145fc957481cfd0652be571226d", 538 | "sha256:b54a62c6e318ddbfa7d22c383466d38d2ee770ebdb5ddb668d56a099f6eaf75f", 539 | "sha256:b5870959a5484b614f26d31ca4c17524b1b0317522199dc985c3b4256e030767", 540 | "sha256:bc3744dabc56b50bec73624aeca02e0def06b03cb287de26836e730659c5d29c", 541 | "sha256:d93d4c28370aea8a7cbf6015e8a669cd5d69f856cc2aa44e7a590fb805bb5583", 542 | "sha256:d9aac97e57c196206179f674f09bc6bffcd0284e2ba95b7fe0b402ac3f986023", 543 | "sha256:da3c84694ff693b5b3194d8752ccf935a665b8b5edc33a283122f4273ca3e687", 544 | "sha256:e174242caecb11e4abf169342641778f68e1bfaba80cd18acd6bc84286b9a534", 545 | "sha256:eabceab574f471de0b0eb3f2ecf2eee9f10b3106570481d007ed1c84ebf6d6a1", 546 | "sha256:f14517e174bd7332f1cca2c959e704696a5e0ba246eb8763e6c24876d8710049", 547 | "sha256:fa38a1b9b38ae1fad2863eff5e0d69608567453fdfc850c992e6e47eb764e846", 548 | "sha256:ff3fa8ea0e09e38677762afc6e14cad77b5e125b0ea70c9bba1992f02c93b028", 549 | "sha256:ff746a69ff2ef25f62b36338c615dd15954ddc3ab8e73530237dd73235e76d62" 550 | ], 551 | "markers": "python_version >= '3.7'", 552 | "version": "==1.0.2" 553 | }, 554 | "scipy": { 555 | "hashes": [ 556 | "sha256:011d4386b53b933142f58a652aa0f149c9b9242abd4f900b9f4ea5fbafc86b89", 557 | "sha256:16e09ef68b352d73befa8bcaf3ebe25d3941fe1a58c82909d5589856e6bc8174", 558 | "sha256:31d4f2d6b724bc9a98e527b5849b8a7e589bf1ea630c33aa563eda912c9ff0bd", 559 | "sha256:38aa39b6724cb65271e469013aeb6f2ce66fd44f093e241c28a9c6bc64fd79ed", 560 | "sha256:3d573228c10a3a8c32b9037be982e6440e411b443a6267b067cac72f690b8d56", 561 | "sha256:3d9dd6c8b93a22bf9a3a52d1327aca7e092b1299fb3afc4f89e8eba381be7b59", 562 | "sha256:559a8a4c03a5ba9fe3232f39ed24f86457e4f3f6c0abbeae1fb945029f092720", 563 | "sha256:5e73343c5e0d413c1f937302b2e04fb07872f5843041bcfd50699aef6e95e399", 564 | "sha256:723b9f878095ed994756fa4ee3060c450e2db0139c5ba248ee3f9628bd64e735", 565 | "sha256:87b01c7d5761e8a266a0fbdb9d88dcba0910d63c1c671bdb4d99d29f469e9e03", 566 | "sha256:8f4d059a97b29c91afad46b1737274cb282357a305a80bdd9e8adf3b0ca6a3f0", 567 | "sha256:92b2c2af4183ed09afb595709a8ef5783b2baf7f41e26ece24e1329c109691a7", 568 | "sha256:937d28722f13302febde29847bbe554b89073fbb924a30475e5ed7b028898b5f", 569 | "sha256:a279e27c7f4566ef18bab1b1e2c37d168e365080974758d107e7d237d3f0f484", 570 | "sha256:ad5be4039147c808e64f99c0e8a9641eb5d2fa079ff5894dcd8240e94e347af4", 571 | "sha256:ae3e327da323d82e918e593460e23babdce40d7ab21490ddf9fc06dec6b91a18", 572 | "sha256:bb7088e89cd751acf66195d2f00cf009a1ea113f3019664032d9075b1e727b6c", 573 | "sha256:c17a1878d00a5dd2797ccd73623ceca9d02375328f6218ee6d921e1325e61aff", 574 | "sha256:c2bae431d127bf0b1da81fc24e4bba0a84d058e3a96b9dd6475dfcb3c5e8761e", 575 | "sha256:de2e80ee1d925984c2504812a310841c241791c5279352be4707cdcd7c255039", 576 | "sha256:e6f0cd9c0bd374ef834ee1e0f0999678d49dcc400ea6209113d81528958f97c7", 577 | "sha256:f3720d0124aced49f6f2198a6900304411dbbeed12f56951d7c66ebef05e3df6", 578 | "sha256:f4a6d3b9f9797eb2d43938ac2c5d96d02aed17ef170c8b38f11798717523ddba" 579 | ], 580 | "index": "pypi", 581 | "version": "==1.8.0" 582 | }, 583 | "setuptools": { 584 | "hashes": [ 585 | "sha256:6599055eeb23bfef457d5605d33a4d68804266e6cb430b0fb12417c5efeae36c", 586 | "sha256:782ef48d58982ddb49920c11a0c5c9c0b02e7d7d1c2ad0aa44e1a1e133051c96" 587 | ], 588 | "markers": "python_version >= '3.7'", 589 | "version": "==60.10.0" 590 | }, 591 | "six": { 592 | "hashes": [ 593 | "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", 594 | "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" 595 | ], 596 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 597 | "version": "==1.16.0" 598 | }, 599 | "sklearn": { 600 | "hashes": [ 601 | "sha256:e23001573aa194b834122d2b9562459bf5ae494a2d59ca6b8aa22c85a44c0e31" 602 | ], 603 | "index": "pypi", 604 | "version": "==0.0" 605 | }, 606 | "stack-data": { 607 | "hashes": [ 608 | "sha256:45692d41bd633a9503a5195552df22b583caf16f0b27c4e58c98d88c8b648e12", 609 | "sha256:999762f9c3132308789affa03e9271bbbe947bf78311851f4d485d8402ed858e" 610 | ], 611 | "version": "==0.2.0" 612 | }, 613 | "threadpoolctl": { 614 | "hashes": [ 615 | "sha256:8b99adda265feb6773280df41eece7b2e6561b772d21ffd52e372f999024907b", 616 | "sha256:a335baacfaa4400ae1f0d8e3a58d6674d2f8828e3716bb2802c44955ad391380" 617 | ], 618 | "markers": "python_version >= '3.6'", 619 | "version": "==3.1.0" 620 | }, 621 | "toml": { 622 | "hashes": [ 623 | "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", 624 | "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" 625 | ], 626 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", 627 | "version": "==0.10.2" 628 | }, 629 | "tornado": { 630 | "hashes": [ 631 | "sha256:0a00ff4561e2929a2c37ce706cb8233b7907e0cdc22eab98888aca5dd3775feb", 632 | "sha256:0d321a39c36e5f2c4ff12b4ed58d41390460f798422c4504e09eb5678e09998c", 633 | "sha256:1e8225a1070cd8eec59a996c43229fe8f95689cb16e552d130b9793cb570a288", 634 | "sha256:20241b3cb4f425e971cb0a8e4ffc9b0a861530ae3c52f2b0434e6c1b57e9fd95", 635 | "sha256:25ad220258349a12ae87ede08a7b04aca51237721f63b1808d39bdb4b2164558", 636 | "sha256:33892118b165401f291070100d6d09359ca74addda679b60390b09f8ef325ffe", 637 | "sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791", 638 | "sha256:3447475585bae2e77ecb832fc0300c3695516a47d46cefa0528181a34c5b9d3d", 639 | "sha256:34ca2dac9e4d7afb0bed4677512e36a52f09caa6fded70b4e3e1c89dbd92c326", 640 | "sha256:3e63498f680547ed24d2c71e6497f24bca791aca2fe116dbc2bd0ac7f191691b", 641 | "sha256:548430be2740e327b3fe0201abe471f314741efcb0067ec4f2d7dcfb4825f3e4", 642 | "sha256:6196a5c39286cc37c024cd78834fb9345e464525d8991c21e908cc046d1cc02c", 643 | "sha256:61b32d06ae8a036a6607805e6720ef00a3c98207038444ba7fd3d169cd998910", 644 | "sha256:6286efab1ed6e74b7028327365cf7346b1d777d63ab30e21a0f4d5b275fc17d5", 645 | "sha256:65d98939f1a2e74b58839f8c4dab3b6b3c1ce84972ae712be02845e65391ac7c", 646 | "sha256:66324e4e1beede9ac79e60f88de548da58b1f8ab4b2f1354d8375774f997e6c0", 647 | "sha256:6c77c9937962577a6a76917845d06af6ab9197702a42e1346d8ae2e76b5e3675", 648 | "sha256:70dec29e8ac485dbf57481baee40781c63e381bebea080991893cd297742b8fd", 649 | "sha256:7250a3fa399f08ec9cb3f7b1b987955d17e044f1ade821b32e5f435130250d7f", 650 | "sha256:748290bf9112b581c525e6e6d3820621ff020ed95af6f17fedef416b27ed564c", 651 | "sha256:7da13da6f985aab7f6f28debab00c67ff9cbacd588e8477034c0652ac141feea", 652 | "sha256:8f959b26f2634a091bb42241c3ed8d3cedb506e7c27b8dd5c7b9f745318ddbb6", 653 | "sha256:9de9e5188a782be6b1ce866e8a51bc76a0fbaa0e16613823fc38e4fc2556ad05", 654 | "sha256:a48900ecea1cbb71b8c71c620dee15b62f85f7c14189bdeee54966fbd9a0c5bd", 655 | "sha256:b87936fd2c317b6ee08a5741ea06b9d11a6074ef4cc42e031bc6403f82a32575", 656 | "sha256:c77da1263aa361938476f04c4b6c8916001b90b2c2fdd92d8d535e1af48fba5a", 657 | "sha256:cb5ec8eead331e3bb4ce8066cf06d2dfef1bfb1b2a73082dfe8a161301b76e37", 658 | "sha256:cc0ee35043162abbf717b7df924597ade8e5395e7b66d18270116f8745ceb795", 659 | "sha256:d14d30e7f46a0476efb0deb5b61343b1526f73ebb5ed84f23dc794bdb88f9d9f", 660 | "sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32", 661 | "sha256:d3d20ea5782ba63ed13bc2b8c291a053c8d807a8fa927d941bd718468f7b950c", 662 | "sha256:d3f7594930c423fd9f5d1a76bee85a2c36fd8b4b16921cae7e965f22575e9c01", 663 | "sha256:dcef026f608f678c118779cd6591c8af6e9b4155c44e0d1bc0c87c036fb8c8c4", 664 | "sha256:e0791ac58d91ac58f694d8d2957884df8e4e2f6687cdf367ef7eb7497f79eaa2", 665 | "sha256:e385b637ac3acaae8022e7e47dfa7b83d3620e432e3ecb9a3f7f58f150e50921", 666 | "sha256:e519d64089b0876c7b467274468709dadf11e41d65f63bba207e04217f47c085", 667 | "sha256:e7229e60ac41a1202444497ddde70a48d33909e484f96eb0da9baf8dc68541df", 668 | "sha256:ed3ad863b1b40cd1d4bd21e7498329ccaece75db5a5bf58cd3c9f130843e7102", 669 | "sha256:f0ba29bafd8e7e22920567ce0d232c26d4d47c8b5cf4ed7b562b5db39fa199c5", 670 | "sha256:fa2ba70284fa42c2a5ecb35e322e68823288a4251f9ba9cc77be04ae15eada68", 671 | "sha256:fba85b6cd9c39be262fcd23865652920832b61583de2a2ca907dbd8e8a8c81e5" 672 | ], 673 | "markers": "python_version >= '3.5'", 674 | "version": "==6.1" 675 | }, 676 | "traitlets": { 677 | "hashes": [ 678 | "sha256:059f456c5a7c1c82b98c2e8c799f39c9b8128f6d0d46941ee118daace9eb70c7", 679 | "sha256:2d313cc50a42cd6c277e7d7dc8d4d7fedd06a2c215f78766ae7b1a66277e0033" 680 | ], 681 | "markers": "python_version >= '3.7'", 682 | "version": "==5.1.1" 683 | }, 684 | "wcwidth": { 685 | "hashes": [ 686 | "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784", 687 | "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83" 688 | ], 689 | "version": "==0.2.5" 690 | } 691 | }, 692 | "develop": { 693 | "asttokens": { 694 | "hashes": [ 695 | "sha256:0844691e88552595a6f4a4281a9f7f79b8dd45ca4ccea82e5e05b4bbdb76705c", 696 | "sha256:9a54c114f02c7a9480d56550932546a3f1fe71d8a02f1bc7ccd0ee3ee35cf4d5" 697 | ], 698 | "version": "==2.0.5" 699 | }, 700 | "backcall": { 701 | "hashes": [ 702 | "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e", 703 | "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255" 704 | ], 705 | "version": "==0.2.0" 706 | }, 707 | "debugpy": { 708 | "hashes": [ 709 | "sha256:01e98c594b3e66d529e40edf314f849cd1a21f7a013298df58cd8e263bf8e184", 710 | "sha256:16db27b4b91991442f91d73604d32080b30de655aca9ba821b1972ea8171021b", 711 | "sha256:17a25ce9d7714f92fc97ef00cc06269d7c2b163094990ada30156ed31d9a5030", 712 | "sha256:194f95dd3e84568b5489aab5689a3a2c044e8fdc06f1890b8b4f70b6b89f2778", 713 | "sha256:1ec3a086e14bba6c472632025b8fe5bdfbaef2afa1ebd5c6615ce6ed8d89bc67", 714 | "sha256:23df67fc56d59e386c342428a7953c2c06cc226d8525b11319153e96afb65b0c", 715 | "sha256:26fbe53cca45a608679094791ce587b6e2798acd1d4777a8b303b07622e85182", 716 | "sha256:2b073ad5e8d8c488fbb6a116986858bab0c9c4558f28deb8832c7a5a27405bd6", 717 | "sha256:318f81f37341e4e054b4267d39896b73cddb3612ca13b39d7eea45af65165e1d", 718 | "sha256:3a457ad9c0059a21a6c7d563c1f18e924f5cf90278c722bd50ede6f56b77c7fe", 719 | "sha256:4404a62fb5332ea5c8c9132290eef50b3a0ba38cecacad5529e969a783bcbdd7", 720 | "sha256:5d76a4fd028d8009c3faf1185b4b78ceb2273dd2499447664b03939e0368bb90", 721 | "sha256:70b422c63a833630c33e3f9cdbd9b6971f8c5afd452697e464339a21bbe862ba", 722 | "sha256:82f5f9ce93af6861a0713f804e62ab390bb12a17f113153e47fea8bbb1dfbe36", 723 | "sha256:a2aa64f6d2ca7ded8a7e8a4e7cae3bc71866b09876b7b05cecad231779cb9156", 724 | "sha256:b2df2c373e85871086bd55271c929670cd4e1dba63e94a08d442db830646203b", 725 | "sha256:b5b3157372e0e0a1297a8b6b5280bcf1d35a40f436c7973771c972726d1e32d5", 726 | "sha256:d2b09e91fbd1efa4f4fda121d49af89501beda50c18ed7499712c71a4bf3452e", 727 | "sha256:d876db8c312eeb02d85611e0f696abe66a2c1515e6405943609e725d5ff36f2a", 728 | "sha256:f3a3dca9104aa14fd4210edcce6d9ce2b65bd9618c0b222135a40b9d6e2a9eeb", 729 | "sha256:f73988422b17f071ad3c4383551ace1ba5ed810cbab5f9c362783d22d40a08dc" 730 | ], 731 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 732 | "version": "==1.5.1" 733 | }, 734 | "decorator": { 735 | "hashes": [ 736 | "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330", 737 | "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186" 738 | ], 739 | "markers": "python_version >= '3.5'", 740 | "version": "==5.1.1" 741 | }, 742 | "entrypoints": { 743 | "hashes": [ 744 | "sha256:b706eddaa9218a19ebcd67b56818f05bb27589b1ca9e8d797b74affad4ccacd4", 745 | "sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f" 746 | ], 747 | "markers": "python_version >= '3.6'", 748 | "version": "==0.4" 749 | }, 750 | "executing": { 751 | "hashes": [ 752 | "sha256:c6554e21c6b060590a6d3be4b82fb78f8f0194d809de5ea7df1c093763311501", 753 | "sha256:d1eef132db1b83649a3905ca6dd8897f71ac6f8cac79a7e58a1a09cf137546c9" 754 | ], 755 | "version": "==0.8.3" 756 | }, 757 | "ipykernel": { 758 | "hashes": [ 759 | "sha256:4c3cc8cb359f2ead70c30f5504971c0d285e2c1c699d2ce9af0216fe9c9fb17c", 760 | "sha256:c977cff576b8425a68d3a6916510903833f0f25ed8d5c282a0c51c35de27bd47" 761 | ], 762 | "index": "pypi", 763 | "version": "==6.9.2" 764 | }, 765 | "ipython": { 766 | "hashes": [ 767 | "sha256:6f56bfaeaa3247aa3b9cd3b8cbab3a9c0abf7428392f97b21902d12b2f42a381", 768 | "sha256:8138762243c9b3a3ffcf70b37151a2a35c23d3a29f9743878c33624f4207be3d" 769 | ], 770 | "markers": "python_version >= '3.8'", 771 | "version": "==8.1.1" 772 | }, 773 | "jedi": { 774 | "hashes": [ 775 | "sha256:637c9635fcf47945ceb91cd7f320234a7be540ded6f3e99a50cb6febdfd1ba8d", 776 | "sha256:74137626a64a99c8eb6ae5832d99b3bdd7d29a3850fe2aa80a4126b2a7d949ab" 777 | ], 778 | "markers": "python_version >= '3.6'", 779 | "version": "==0.18.1" 780 | }, 781 | "jupyter-client": { 782 | "hashes": [ 783 | "sha256:4ea61033726c8e579edb55626d8ee2e6bf0a83158ddf3751b8dd46b2c5cd1e96", 784 | "sha256:d56f1c57bef42ff31e61b1185d3348a5b2bcde7c9a05523ae4dbe5ee0871797c" 785 | ], 786 | "markers": "python_full_version >= '3.6.1'", 787 | "version": "==7.1.2" 788 | }, 789 | "jupyter-core": { 790 | "hashes": [ 791 | "sha256:d69baeb9ffb128b8cd2657fcf2703f89c769d1673c851812119e3a2a0e93ad9a", 792 | "sha256:f875e4d27e202590311d468fa55f90c575f201490bd0c18acabe4e318db4a46d" 793 | ], 794 | "markers": "python_version >= '3.6'", 795 | "version": "==4.9.2" 796 | }, 797 | "matplotlib-inline": { 798 | "hashes": [ 799 | "sha256:a04bfba22e0d1395479f866853ec1ee28eea1485c1d69a6faf00dc3e24ff34ee", 800 | "sha256:aed605ba3b72462d64d475a21a9296f400a19c4f74a31b59103d2a99ffd5aa5c" 801 | ], 802 | "markers": "python_version >= '3.5'", 803 | "version": "==0.1.3" 804 | }, 805 | "nest-asyncio": { 806 | "hashes": [ 807 | "sha256:3fdd0d6061a2bb16f21fe8a9c6a7945be83521d81a0d15cff52e9edee50101d6", 808 | "sha256:f969f6013a16fadb4adcf09d11a68a4f617c6049d7af7ac2c676110169a63abd" 809 | ], 810 | "markers": "python_version >= '3.5'", 811 | "version": "==1.5.4" 812 | }, 813 | "parso": { 814 | "hashes": [ 815 | "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0", 816 | "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75" 817 | ], 818 | "markers": "python_version >= '3.6'", 819 | "version": "==0.8.3" 820 | }, 821 | "pexpect": { 822 | "hashes": [ 823 | "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937", 824 | "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c" 825 | ], 826 | "markers": "sys_platform != 'win32'", 827 | "version": "==4.8.0" 828 | }, 829 | "pickleshare": { 830 | "hashes": [ 831 | "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca", 832 | "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56" 833 | ], 834 | "version": "==0.7.5" 835 | }, 836 | "prompt-toolkit": { 837 | "hashes": [ 838 | "sha256:30129d870dcb0b3b6a53efdc9d0a83ea96162ffd28ffe077e94215b233dc670c", 839 | "sha256:9f1cd16b1e86c2968f2519d7fb31dd9d669916f515612c269d14e9ed52b51650" 840 | ], 841 | "markers": "python_full_version >= '3.6.2'", 842 | "version": "==3.0.28" 843 | }, 844 | "psutil": { 845 | "hashes": [ 846 | "sha256:072664401ae6e7c1bfb878c65d7282d4b4391f1bc9a56d5e03b5a490403271b5", 847 | "sha256:1070a9b287846a21a5d572d6dddd369517510b68710fca56b0e9e02fd24bed9a", 848 | "sha256:1d7b433519b9a38192dfda962dd8f44446668c009833e1429a52424624f408b4", 849 | "sha256:3151a58f0fbd8942ba94f7c31c7e6b310d2989f4da74fcbf28b934374e9bf841", 850 | "sha256:32acf55cb9a8cbfb29167cd005951df81b567099295291bcfd1027365b36591d", 851 | "sha256:3611e87eea393f779a35b192b46a164b1d01167c9d323dda9b1e527ea69d697d", 852 | "sha256:3d00a664e31921009a84367266b35ba0aac04a2a6cad09c550a89041034d19a0", 853 | "sha256:4e2fb92e3aeae3ec3b7b66c528981fd327fb93fd906a77215200404444ec1845", 854 | "sha256:539e429da49c5d27d5a58e3563886057f8fc3868a5547b4f1876d9c0f007bccf", 855 | "sha256:55ce319452e3d139e25d6c3f85a1acf12d1607ddedea5e35fb47a552c051161b", 856 | "sha256:58c7d923dc209225600aec73aa2c4ae8ea33b1ab31bc11ef8a5933b027476f07", 857 | "sha256:7336292a13a80eb93c21f36bde4328aa748a04b68c13d01dfddd67fc13fd0618", 858 | "sha256:742c34fff804f34f62659279ed5c5b723bb0195e9d7bd9907591de9f8f6558e2", 859 | "sha256:7641300de73e4909e5d148e90cc3142fb890079e1525a840cf0dfd39195239fd", 860 | "sha256:76cebf84aac1d6da5b63df11fe0d377b46b7b500d892284068bacccf12f20666", 861 | "sha256:7779be4025c540d1d65a2de3f30caeacc49ae7a2152108adeaf42c7534a115ce", 862 | "sha256:7d190ee2eaef7831163f254dc58f6d2e2a22e27382b936aab51c835fc080c3d3", 863 | "sha256:8293942e4ce0c5689821f65ce6522ce4786d02af57f13c0195b40e1edb1db61d", 864 | "sha256:869842dbd66bb80c3217158e629d6fceaecc3a3166d3d1faee515b05dd26ca25", 865 | "sha256:90a58b9fcae2dbfe4ba852b57bd4a1dded6b990a33d6428c7614b7d48eccb492", 866 | "sha256:9b51917c1af3fa35a3f2dabd7ba96a2a4f19df3dec911da73875e1edaf22a40b", 867 | "sha256:b2237f35c4bbae932ee98902a08050a27821f8f6dfa880a47195e5993af4702d", 868 | "sha256:c3400cae15bdb449d518545cbd5b649117de54e3596ded84aacabfbb3297ead2", 869 | "sha256:c51f1af02334e4b516ec221ee26b8fdf105032418ca5a5ab9737e8c87dafe203", 870 | "sha256:cb8d10461c1ceee0c25a64f2dd54872b70b89c26419e147a05a10b753ad36ec2", 871 | "sha256:d62a2796e08dd024b8179bd441cb714e0f81226c352c802fca0fd3f89eeacd94", 872 | "sha256:df2c8bd48fb83a8408c8390b143c6a6fa10cb1a674ca664954de193fdcab36a9", 873 | "sha256:e5c783d0b1ad6ca8a5d3e7b680468c9c926b804be83a3a8e95141b05c39c9f64", 874 | "sha256:e9805fed4f2a81de98ae5fe38b75a74c6e6ad2df8a5c479594c7629a1fe35f56", 875 | "sha256:ea42d747c5f71b5ccaa6897b216a7dadb9f52c72a0fe2b872ef7d3e1eacf3ba3", 876 | "sha256:ef216cc9feb60634bda2f341a9559ac594e2eeaadd0ba187a4c2eb5b5d40b91c", 877 | "sha256:ff0d41f8b3e9ebb6b6110057e40019a432e96aae2008951121ba4e56040b84f3" 878 | ], 879 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", 880 | "version": "==5.9.0" 881 | }, 882 | "ptyprocess": { 883 | "hashes": [ 884 | "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", 885 | "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220" 886 | ], 887 | "version": "==0.7.0" 888 | }, 889 | "pure-eval": { 890 | "hashes": [ 891 | "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350", 892 | "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3" 893 | ], 894 | "version": "==0.2.2" 895 | }, 896 | "pygments": { 897 | "hashes": [ 898 | "sha256:44238f1b60a76d78fc8ca0528ee429702aae011c265fe6a8dd8b63049ae41c65", 899 | "sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a" 900 | ], 901 | "markers": "python_version >= '3.5'", 902 | "version": "==2.11.2" 903 | }, 904 | "python-dateutil": { 905 | "hashes": [ 906 | "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", 907 | "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" 908 | ], 909 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 910 | "version": "==2.8.2" 911 | }, 912 | "pyzmq": { 913 | "hashes": [ 914 | "sha256:031417b5d450baf645cf9dbf6d156399010505867f0e0db7ce32e50b83c4f4c8", 915 | "sha256:07b4f6f852ded85db1e1939fd9c08cb8b548ad07a386f7237cdebe1b884dffac", 916 | "sha256:099b59e2bdf7bb08599b21425f82e896682642293fe7eddeb0afbe2c79bfa97a", 917 | "sha256:113df7f444c7e60a09f940edc4366d1ba33f374527f9a57096b0eeda731430b9", 918 | "sha256:21529e58514c42598f1ad8ca5551b09e52533e8c13a93d0588b10e9f38b1c045", 919 | "sha256:22581b4b5becf830ab42b36412100eceb412b1dd3367627e67dd4ed8754f5055", 920 | "sha256:226c6a705f33303752bcc7c6979c1cc0db4178c4e7011b8a53398200d49e6c47", 921 | "sha256:232b1511bc81ae0a44002f3b7f42e96813353c2a19b1eeedcb36a0867755606d", 922 | "sha256:2aaa587eb77fce70a5f85fba8711f70a6e8a0c84e5aa75d28f1c47acbbdc3b80", 923 | "sha256:37cfba29611afde16e6f3cc24e6a5c2ef802923f40df4f5ef4cda53dc9ac774a", 924 | "sha256:3b93edc90e6dcca5cdb21a67a92cc593c06b9bc681ffef1665e84c6cc8fc14ff", 925 | "sha256:49300eb7c25046e54459f2e3815a1db430e44f309a28bf70b0c8aedf8c5370a9", 926 | "sha256:4bd5ecf70fd80c0f3debb585412fecace3fecab59665a30437cf9424df5514fe", 927 | "sha256:4dca17b0b27603b2c202b694f440c4b60d1c9c1a4966df9d361cd98b7f41270f", 928 | "sha256:50184458e22ca6e7c18364dc825a177d607a08d8d9bd2bc5577b16169c1f85cd", 929 | "sha256:51e3b39364e069264e451c710b74d46cb1484bc88a17f8ff7c8f8ea2d97c7181", 930 | "sha256:52b1b41488988f0f60c347166e659e9ff530b8f8395896394e177b842ea8835d", 931 | "sha256:532dd70586511bd000671a17b59124d9d599164fc76512ab798fa334522f774c", 932 | "sha256:5ca84bb9f649ee06192ee0a7120b398cc447eaac187e9bc689e9e8ba843fde99", 933 | "sha256:5e4121b525d90330524b6ee7aa8a8c83bf2c1e01709963611d857ebc14f80a3e", 934 | "sha256:656d2a54411c1f204f579c88480641d0a9503eb7eb98517f90ace4cf2897af99", 935 | "sha256:664b7f57330470a8354f248650958c91d1d806408e13fece3d38b545f43e6e3e", 936 | "sha256:6d9025bca175aaecc0f54b2895bef22dc154ca13824a0828f6be4efcdaadefed", 937 | "sha256:7280ecd232e439e040b5cd5ebdd5d5ebaa46cbcd1163e1fd0be236f9871047be", 938 | "sha256:7a5ac470da6bb13f022c5e392d4528f05d5cadb37702ed434c652aa2ef5538c1", 939 | "sha256:81ff0ec9c4d81db3b91d9568c3051ced6e81637ac912bc30d149cf54b1e3cee3", 940 | "sha256:8306f064bf4603381313e4fa66d3b04c50ae8df6888c538d2c1d8072c4c36443", 941 | "sha256:830fd69828931fcd67a283485dc0a9ad1a54c48514a0f68f0d559ab7de1cc7a2", 942 | "sha256:83f8dfbb6711e956a6705e8dbdfc0df32f34bb2aad0f19128bc6abe2fbffe1b2", 943 | "sha256:850032302a9bff470788813389482ad76f83448f2b448b2885ab479d370a9ac3", 944 | "sha256:88786376e7a13dbe37181e6ca079ffdca55186fd80eb44b97ad4d6e5579d5294", 945 | "sha256:8d4cf52e1a2ffe398315c026435dea8a3f09ba12deea88302b3fb5d3527264e1", 946 | "sha256:98f869ff401a1f4c6104fecf44b21ad027b6a94240d565c67528eac96c6a7b4e", 947 | "sha256:9a74e6080b3f76486fe26d35e84c3734081bab729f0124df0b27ae2612cee260", 948 | "sha256:a17befeb4f532b3a80f4befa889b5e6a21c7113a5c145b4dd3a7bb472df0815f", 949 | "sha256:a5cf28f9d566216470357b107147b9ec320025bdc40ca0f0d1d6603a958c3a60", 950 | "sha256:b1495d9d520384c4ac30814943bc3a45d005aee2c9362c91ad536b1db5660ec1", 951 | "sha256:b63605f2ee5c5bca4d762e876c8879760bf046510687de735e28103f072a2d77", 952 | "sha256:bb612af9dc23d80688ace7f005a9ed4e5dae20c988dd197381e7e20d49836c11", 953 | "sha256:c2e1071a11c1bf62888859c761e33a20840ac70819b5c86a55b4ebec3cf8733e", 954 | "sha256:c887bc1a80bef14aa12f1756bd8e976c3f3a4d5fd410ba17454a382a00cfe721", 955 | "sha256:d0a30aac29088a1e11777ce2221bb08f85a9fdb2b386d6fd02f9f36260b48338", 956 | "sha256:d6cced1b564ca1da4ba9e19de88d9cc0422b75ffab869f1bb21ceccd754c6bf5", 957 | "sha256:d8859098ff2bcf3fe2e43d3c6915127a45363a90534d1f2af9487ae87c2920db", 958 | "sha256:e4a189b86adfd0075cc9e41550540cd620a17f74c118d2cf6af0361be07e1d82", 959 | "sha256:e7da43aebe4dc18349f716470f728afbae449d4cfd3945ba6805a563e0ddc1be", 960 | "sha256:f1fc63e7eef23418cdfe8169dbcb0964c36f7c180f60dae122c0f9bb359df2f7", 961 | "sha256:f2c7bf98fdb2f81304921a9aa25ae73b5fdeae0da2fb46d1efec94ba8ffb34d6", 962 | "sha256:f3bbcfde5466c2e3c63d0f77a12daf19308ffa9b03fe0758424bb61b8150abfd", 963 | "sha256:fb9c3747c6516da0b21d4e38d4f433db0216f8e214173bd02a916d8deda68ef2", 964 | "sha256:fd4bf5dfe291611881a19059bcd5b973475f46deaa4fc88fb4357013ed6c4b09" 965 | ], 966 | "markers": "python_version >= '3.6'", 967 | "version": "==23.0.0b1" 968 | }, 969 | "setuptools": { 970 | "hashes": [ 971 | "sha256:6599055eeb23bfef457d5605d33a4d68804266e6cb430b0fb12417c5efeae36c", 972 | "sha256:782ef48d58982ddb49920c11a0c5c9c0b02e7d7d1c2ad0aa44e1a1e133051c96" 973 | ], 974 | "markers": "python_version >= '3.7'", 975 | "version": "==60.10.0" 976 | }, 977 | "six": { 978 | "hashes": [ 979 | "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", 980 | "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" 981 | ], 982 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 983 | "version": "==1.16.0" 984 | }, 985 | "stack-data": { 986 | "hashes": [ 987 | "sha256:45692d41bd633a9503a5195552df22b583caf16f0b27c4e58c98d88c8b648e12", 988 | "sha256:999762f9c3132308789affa03e9271bbbe947bf78311851f4d485d8402ed858e" 989 | ], 990 | "version": "==0.2.0" 991 | }, 992 | "tornado": { 993 | "hashes": [ 994 | "sha256:0a00ff4561e2929a2c37ce706cb8233b7907e0cdc22eab98888aca5dd3775feb", 995 | "sha256:0d321a39c36e5f2c4ff12b4ed58d41390460f798422c4504e09eb5678e09998c", 996 | "sha256:1e8225a1070cd8eec59a996c43229fe8f95689cb16e552d130b9793cb570a288", 997 | "sha256:20241b3cb4f425e971cb0a8e4ffc9b0a861530ae3c52f2b0434e6c1b57e9fd95", 998 | "sha256:25ad220258349a12ae87ede08a7b04aca51237721f63b1808d39bdb4b2164558", 999 | "sha256:33892118b165401f291070100d6d09359ca74addda679b60390b09f8ef325ffe", 1000 | "sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791", 1001 | "sha256:3447475585bae2e77ecb832fc0300c3695516a47d46cefa0528181a34c5b9d3d", 1002 | "sha256:34ca2dac9e4d7afb0bed4677512e36a52f09caa6fded70b4e3e1c89dbd92c326", 1003 | "sha256:3e63498f680547ed24d2c71e6497f24bca791aca2fe116dbc2bd0ac7f191691b", 1004 | "sha256:548430be2740e327b3fe0201abe471f314741efcb0067ec4f2d7dcfb4825f3e4", 1005 | "sha256:6196a5c39286cc37c024cd78834fb9345e464525d8991c21e908cc046d1cc02c", 1006 | "sha256:61b32d06ae8a036a6607805e6720ef00a3c98207038444ba7fd3d169cd998910", 1007 | "sha256:6286efab1ed6e74b7028327365cf7346b1d777d63ab30e21a0f4d5b275fc17d5", 1008 | "sha256:65d98939f1a2e74b58839f8c4dab3b6b3c1ce84972ae712be02845e65391ac7c", 1009 | "sha256:66324e4e1beede9ac79e60f88de548da58b1f8ab4b2f1354d8375774f997e6c0", 1010 | "sha256:6c77c9937962577a6a76917845d06af6ab9197702a42e1346d8ae2e76b5e3675", 1011 | "sha256:70dec29e8ac485dbf57481baee40781c63e381bebea080991893cd297742b8fd", 1012 | "sha256:7250a3fa399f08ec9cb3f7b1b987955d17e044f1ade821b32e5f435130250d7f", 1013 | "sha256:748290bf9112b581c525e6e6d3820621ff020ed95af6f17fedef416b27ed564c", 1014 | "sha256:7da13da6f985aab7f6f28debab00c67ff9cbacd588e8477034c0652ac141feea", 1015 | "sha256:8f959b26f2634a091bb42241c3ed8d3cedb506e7c27b8dd5c7b9f745318ddbb6", 1016 | "sha256:9de9e5188a782be6b1ce866e8a51bc76a0fbaa0e16613823fc38e4fc2556ad05", 1017 | "sha256:a48900ecea1cbb71b8c71c620dee15b62f85f7c14189bdeee54966fbd9a0c5bd", 1018 | "sha256:b87936fd2c317b6ee08a5741ea06b9d11a6074ef4cc42e031bc6403f82a32575", 1019 | "sha256:c77da1263aa361938476f04c4b6c8916001b90b2c2fdd92d8d535e1af48fba5a", 1020 | "sha256:cb5ec8eead331e3bb4ce8066cf06d2dfef1bfb1b2a73082dfe8a161301b76e37", 1021 | "sha256:cc0ee35043162abbf717b7df924597ade8e5395e7b66d18270116f8745ceb795", 1022 | "sha256:d14d30e7f46a0476efb0deb5b61343b1526f73ebb5ed84f23dc794bdb88f9d9f", 1023 | "sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32", 1024 | "sha256:d3d20ea5782ba63ed13bc2b8c291a053c8d807a8fa927d941bd718468f7b950c", 1025 | "sha256:d3f7594930c423fd9f5d1a76bee85a2c36fd8b4b16921cae7e965f22575e9c01", 1026 | "sha256:dcef026f608f678c118779cd6591c8af6e9b4155c44e0d1bc0c87c036fb8c8c4", 1027 | "sha256:e0791ac58d91ac58f694d8d2957884df8e4e2f6687cdf367ef7eb7497f79eaa2", 1028 | "sha256:e385b637ac3acaae8022e7e47dfa7b83d3620e432e3ecb9a3f7f58f150e50921", 1029 | "sha256:e519d64089b0876c7b467274468709dadf11e41d65f63bba207e04217f47c085", 1030 | "sha256:e7229e60ac41a1202444497ddde70a48d33909e484f96eb0da9baf8dc68541df", 1031 | "sha256:ed3ad863b1b40cd1d4bd21e7498329ccaece75db5a5bf58cd3c9f130843e7102", 1032 | "sha256:f0ba29bafd8e7e22920567ce0d232c26d4d47c8b5cf4ed7b562b5db39fa199c5", 1033 | "sha256:fa2ba70284fa42c2a5ecb35e322e68823288a4251f9ba9cc77be04ae15eada68", 1034 | "sha256:fba85b6cd9c39be262fcd23865652920832b61583de2a2ca907dbd8e8a8c81e5" 1035 | ], 1036 | "markers": "python_version >= '3.5'", 1037 | "version": "==6.1" 1038 | }, 1039 | "traitlets": { 1040 | "hashes": [ 1041 | "sha256:059f456c5a7c1c82b98c2e8c799f39c9b8128f6d0d46941ee118daace9eb70c7", 1042 | "sha256:2d313cc50a42cd6c277e7d7dc8d4d7fedd06a2c215f78766ae7b1a66277e0033" 1043 | ], 1044 | "markers": "python_version >= '3.7'", 1045 | "version": "==5.1.1" 1046 | }, 1047 | "wcwidth": { 1048 | "hashes": [ 1049 | "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784", 1050 | "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83" 1051 | ], 1052 | "version": "==0.2.5" 1053 | } 1054 | } 1055 | } 1056 | --------------------------------------------------------------------------------