| @ -0,0 +1,11 @@ | |||
| import numpy as np | |||
| # A, B로 나뉘어진 현시시간을 (4현시) 세부현시시간(5현시)로 바꾸는 코드 | |||
| durs_A = np.array([37, 55, 45, 23]) | |||
| durs_B = np.array([37, 55, 28, 40]) | |||
| cums_A = durs_A.cumsum() | |||
| cums_B = durs_B.cumsum() | |||
| cycle = durs_A.sum() | |||
| detailed_cums = [] | |||
| combined_row = np.unique(np.concatenate((cums_A, cums_B))) | |||
| detailed_durations = np.concatenate(([combined_row[0]], np.diff(combined_row))) | |||
| print(detailed_durations) | |||
| @ -0,0 +1,24 @@ | |||
| import numpy as np | |||
| # 두 개의 배열 생성 | |||
| durs_A = np.array([37, 55, 45, 23]) | |||
| durs_B = np.array([37, 55, 28, 40]) | |||
| # 두 배열의 누적합 계산 | |||
| cums_A = durs_A.cumsum() | |||
| cums_B = durs_B.cumsum() | |||
| # durs_A의 합계를 cycle에 저장 | |||
| cycle = durs_A.sum() | |||
| # 빈 리스트 생성 | |||
| detailed_cums = [] | |||
| # cums_A와 cums_B의 고유한 요소들을 결합 | |||
| combined_row = np.unique(np.concatenate((cums_A, cums_B))) | |||
| # combined_row의 각 요소 간 차이 계산 | |||
| detailed_durations = np.concatenate(([combined_row[0]], np.diff(combined_row))) | |||
| # 결과 출력 | |||
| print(detailed_durations) | |||
| @ -0,0 +1,189 @@ | |||
| import os | |||
| import sys | |||
| import numpy as np | |||
| from sumolib import checkBinary | |||
| from args import Args | |||
| class Env: | |||
| '''This class is responsible for handling the traffic light optimization environment.''' | |||
| def __init__(self, infos, path_config, name=0): | |||
| ''' | |||
| Initializes the environment with given information, | |||
| configuration path and initial state path. | |||
| ''' | |||
| self.path_config = path_config | |||
| self.infos = infos | |||
| self.node_ids = Args.node_ids | |||
| assert list(self.node_ids) == list(self.infos) | |||
| self.path_init_state = f'data/init_state_{name}' | |||
| assert not os.path.exists(self.path_init_state) | |||
| self.gui = Args.gui | |||
| self.e2_length = Args.e2_length | |||
| self.yellow_length = Args.yellow_length | |||
| self.step_length = Args.step_length | |||
| self.rest_length = self.step_length - self.yellow_length | |||
| self.episode_length = Args.episode_length | |||
| self.episode_step = Args.episode_step | |||
| self.name = name | |||
| def _start(self): | |||
| ''' | |||
| Starts the simulation. | |||
| https://sumo.dlr.de/docs/TraCI/Interfacing_TraCI_from_Python.html#importing_traci_in_a_script | |||
| ''' | |||
| import traci | |||
| if 'SUMO_HOME' in os.environ: | |||
| tools = os.path.join(os.environ['SUMO_HOME'], 'tools') | |||
| sys.path.append(tools) | |||
| else: | |||
| sys.exit("please declare environment variable 'SUMO_HOME'") | |||
| sumo_binary = checkBinary('sumo-gui' if self.gui else 'sumo') | |||
| cmd = [sumo_binary, '-c', self.path_config] | |||
| traci.start(cmd, label=self.name) | |||
| self.conn = traci.getConnection(self.name) | |||
| def close(self): | |||
| '''Closes the simulation.''' | |||
| self.conn.close() | |||
| if os.path.exists(self.path_init_state): | |||
| os.remove(self.path_init_state) | |||
| def _save(self): | |||
| ''' | |||
| Saves the current state of the simulation. | |||
| https://sumo.dlr.de/docs/TraCI/Change_Simulation_State.html | |||
| ''' | |||
| self.conn.simulation.saveState(self.path_init_state) | |||
| def _load(self): | |||
| ''' | |||
| Loads the saved state of the simulation. | |||
| https://sumo.dlr.de/docs/TraCI/Change_Simulation_State.html | |||
| ''' | |||
| self.conn.simulation.loadState(self.path_init_state) | |||
| def _step(self, step_length): | |||
| '''Advances the simulation by a given number of steps.''' | |||
| for _ in range(step_length): | |||
| self.conn.simulationStep() | |||
| def _get_occupancy(self, detector_id): | |||
| ''' | |||
| Returns the occupancy of a given detector. | |||
| https://sumo.dlr.de/docs/TraCI/Lane_Area_Detector_Value_Retrieval.html | |||
| ''' | |||
| return self.conn.lanearea.getLastStepOccupancy(detector_id) / 100 | |||
| def _get_queue(self, detector_id): | |||
| ''' | |||
| Returns the queue length at a given detector. | |||
| https://sumo.dlr.de/docs/TraCI/Lane_Area_Detector_Value_Retrieval.html | |||
| ''' | |||
| return self.conn.lanearea.getJamLengthMeters(detector_id) / self.e2_length | |||
| def _get_values(self): | |||
| '''Retrieves the occupancy, queue and phase for each node.''' | |||
| node2values = {} | |||
| for node_id, info in self.infos.items(): | |||
| values = {} | |||
| values['occupancy'] = [self._get_occupancy(d) for d in info['detectors']] | |||
| values['queue'] = [self._get_queue(d) for d in info['detectors']] | |||
| values['phase'] = [self.prev_phase_indexes[node_id]] | |||
| node2values[node_id] = values | |||
| states, rewards = [], [] | |||
| global_reward = 0 | |||
| for node_id, info in self.infos.items(): | |||
| occupancy = [node2values[node_id]['occupancy']] | |||
| queue = [node2values[node_id]['queue']] | |||
| phase = [node2values[node_id]['phase']] | |||
| reward = -np.sum(node2values[node_id]['queue']) | |||
| global_reward -= np.sum(node2values[node_id]['queue']) | |||
| for nnode_id in info['neighbors']: | |||
| occupancy.append(node2values[nnode_id]['occupancy']) | |||
| queue.append(node2values[nnode_id]['queue']) | |||
| phase.append(node2values[nnode_id]['phase']) | |||
| reward -= np.sum(node2values[nnode_id]['queue']) * 0.5 | |||
| states.append(np.concatenate(occupancy + queue + phase, dtype=np.float32)) | |||
| rewards.append(reward) | |||
| return states, rewards, global_reward | |||
| def _set_yellows(self, actions): | |||
| '''Sets the yellow phase for nodes based on the given actions.''' | |||
| for node_id, action in zip(self.node_ids, actions): | |||
| if action == 0: | |||
| continue | |||
| info = self.infos[node_id] | |||
| prev_idx = self.prev_phase_indexes[node_id] | |||
| idx = (prev_idx + 1) % len(info['phases']['green']) | |||
| self.prev_phase_indexes[node_id] = idx | |||
| y = info['phases']['yellow'][prev_idx] | |||
| self._set_phase(node_id, y) | |||
| def _set_greens(self): | |||
| '''Sets the green phase for each node.''' | |||
| for node_id, info in self.infos.items(): | |||
| idx = self.prev_phase_indexes[node_id] | |||
| g = info['phases']['green'][idx] | |||
| self._set_phase(node_id, g) | |||
| def _set_phase(self, node_id, phase): | |||
| '''Sets the phase for a specific node.''' | |||
| if self.prev_phases.get(node_id) != phase: | |||
| self.conn.trafficlight.setRedYellowGreenState(node_id, phase) | |||
| self.prev_phases[node_id] = phase | |||
| def step(self, actions): | |||
| '''Performs a step in the simulation based on the given actions.''' | |||
| self._set_yellows(actions) | |||
| self._step(self.yellow_length) | |||
| self._set_greens() | |||
| self._step(self.rest_length) | |||
| self.curr_step += 1 | |||
| states, rewards, global_reward = self._get_values() | |||
| done = self.curr_step >= self.episode_step | |||
| return states, rewards, done, global_reward | |||
| def reset(self): | |||
| '''Resets the simulation to its initial state.''' | |||
| # Initialize simulation | |||
| if not os.path.exists(self.path_init_state): | |||
| self._start() | |||
| self._save() | |||
| self._load() | |||
| self.curr_step = 0 | |||
| self.prev_phases = {n:'none' for n in self.node_ids} | |||
| self.prev_phase_indexes = {n:0 for n in self.node_ids} | |||
| self._set_greens() | |||
| self._step(1) | |||
| states, _, _ = self._get_values() | |||
| return states | |||
| @ -0,0 +1,171 @@ | |||
| # uncompyle6 version 3.9.0 | |||
| # Python bytecode version base 3.8.0 (3413) | |||
| # Decompiled from: Python 3.8.10 (tags/v3.8.10:3d8993a, May 3 2021, 11:48:03) [MSC v.1928 64 bit (AMD64)] | |||
| # Embedded file name: .\env.py | |||
| # Compiled at: 2024-01-10 13:34:11 | |||
| # Size of source mod 2**32: 6588 bytes | |||
| import os, sys, numpy as np | |||
| from sumolib import checkBinary | |||
| from args import Args | |||
| class Env: | |||
| __doc__ = 'This class is responsible for handling the traffic light optimization environment.' | |||
| def __init__(self, infos, path_config, name=0): | |||
| """ | |||
| Initializes the environment with given information, | |||
| configuration path and initial state path. | |||
| """ | |||
| self.path_config = path_config | |||
| self.infos = infos | |||
| self.node_ids = Args.node_ids | |||
| assert list(self.node_ids) == list(self.infos) | |||
| self.path_init_state = f"data/init_state_{name}" | |||
| assert not os.path.exists(self.path_init_state) | |||
| self.gui = Args.gui | |||
| self.e2_length = Args.e2_length | |||
| self.yellow_length = Args.yellow_length | |||
| self.step_length = Args.step_length | |||
| self.rest_length = self.step_length - self.yellow_length | |||
| self.episode_length = Args.episode_length | |||
| self.episode_step = Args.episode_step | |||
| self.name = name | |||
| def _start(self): | |||
| """ | |||
| Starts the simulation. | |||
| https://sumo.dlr.de/docs/TraCI/Interfacing_TraCI_from_Python.html#importing_traci_in_a_script | |||
| """ | |||
| import traci | |||
| if 'SUMO_HOME' in os.environ: | |||
| tools = os.path.join(os.environ['SUMO_HOME'], 'tools') | |||
| sys.path.append(tools) | |||
| else: | |||
| sys.exit("please declare environment variable 'SUMO_HOME'") | |||
| sumo_binary = checkBinary('sumo-gui' if self.gui else 'sumo') | |||
| cmd = [sumo_binary, '-c', self.path_config] | |||
| traci.start(cmd, label=(self.name)) | |||
| self.conn = traci.getConnection(self.name) | |||
| def close(self): | |||
| """Closes the simulation.""" | |||
| self.conn.close() | |||
| if os.path.exists(self.path_init_state): | |||
| os.remove(self.path_init_state) | |||
| def _save(self): | |||
| """ | |||
| Saves the current state of the simulation. | |||
| https://sumo.dlr.de/docs/TraCI/Change_Simulation_State.html | |||
| """ | |||
| self.conn.simulation.saveState(self.path_init_state) | |||
| def _load(self): | |||
| """ | |||
| Loads the saved state of the simulation. | |||
| https://sumo.dlr.de/docs/TraCI/Change_Simulation_State.html | |||
| """ | |||
| self.conn.simulation.loadState(self.path_init_state) | |||
| def _step(self, step_length): | |||
| """Advances the simulation by a given number of steps.""" | |||
| for _ in range(step_length): | |||
| self.conn.simulationStep() | |||
| def _get_occupancy(self, detector_id): | |||
| """ | |||
| Returns the occupancy of a given detector. | |||
| https://sumo.dlr.de/docs/TraCI/Lane_Area_Detector_Value_Retrieval.html | |||
| """ | |||
| return self.conn.lanearea.getLastStepOccupancy(detector_id) / 100 | |||
| def _get_queue(self, detector_id): | |||
| """ | |||
| Returns the queue length at a given detector. | |||
| https://sumo.dlr.de/docs/TraCI/Lane_Area_Detector_Value_Retrieval.html | |||
| """ | |||
| return self.conn.lanearea.getJamLengthMeters(detector_id) / self.e2_length | |||
| def _get_values(self): | |||
| """Retrieves the occupancy, queue and phase for each node.""" | |||
| node2values = {} | |||
| for node_id, info in self.infos.items(): | |||
| values = {} | |||
| values['occupancy'] = [self._get_occupancy(d) for d in info['detectors']] | |||
| values['queue'] = [self._get_queue(d) for d in info['detectors']] | |||
| values['phase'] = [self.prev_phase_indexes[node_id]] | |||
| node2values[node_id] = values | |||
| else: | |||
| states, rewards = [], [] | |||
| global_reward = 0 | |||
| for node_id, info in self.infos.items(): | |||
| occupancy = [ | |||
| node2values[node_id]['occupancy']] | |||
| queue = [node2values[node_id]['queue']] | |||
| phase = [node2values[node_id]['phase']] | |||
| reward = -np.sum(node2values[node_id]['queue']) | |||
| global_reward -= np.sum(node2values[node_id]['queue']) | |||
| for nnode_id in info['neighbors']: | |||
| occupancy.append(node2values[nnode_id]['occupancy']) | |||
| queue.append(node2values[nnode_id]['queue']) | |||
| phase.append(node2values[nnode_id]['phase']) | |||
| reward -= np.sum(node2values[nnode_id]['queue']) * 0.5 | |||
| else: | |||
| states.append(np.concatenate((occupancy + queue + phase), dtype=(np.float32))) | |||
| rewards.append(reward) | |||
| else: | |||
| return ( | |||
| states, rewards, global_reward) | |||
| def _set_yellows(self, actions): | |||
| """Sets the yellow phase for nodes based on the given actions.""" | |||
| for node_id, action in zip(self.node_ids, actions): | |||
| if action == 0: | |||
| pass | |||
| else: | |||
| info = self.infos[node_id] | |||
| prev_idx = self.prev_phase_indexes[node_id] | |||
| idx = (prev_idx + 1) % len(info['phases']['green']) | |||
| self.prev_phase_indexes[node_id] = idx | |||
| y = info['phases']['yellow'][prev_idx] | |||
| self._set_phase(node_id, y) | |||
| def _set_greens(self): | |||
| """Sets the green phase for each node.""" | |||
| for node_id, info in self.infos.items(): | |||
| idx = self.prev_phase_indexes[node_id] | |||
| g = info['phases']['green'][idx] | |||
| self._set_phase(node_id, g) | |||
| def _set_phase(self, node_id, phase): | |||
| """Sets the phase for a specific node.""" | |||
| if self.prev_phases.get(node_id) != phase: | |||
| self.conn.trafficlight.setRedYellowGreenState(node_id, phase) | |||
| self.prev_phases[node_id] = phase | |||
| def step(self, actions): | |||
| """Performs a step in the simulation based on the given actions.""" | |||
| self._set_yellows(actions) | |||
| self._step(self.yellow_length) | |||
| self._set_greens() | |||
| self._step(self.rest_length) | |||
| self.curr_step += 1 | |||
| states, rewards, global_reward = self._get_values() | |||
| done = self.curr_step >= self.episode_step | |||
| return (states, rewards, done, global_reward) | |||
| def reset(self): | |||
| """Resets the simulation to its initial state.""" | |||
| if not os.path.exists(self.path_init_state): | |||
| self._start() | |||
| self._save() | |||
| self._load() | |||
| self.curr_step = 0 | |||
| self.prev_phases = {n: 'none' for n in self.node_ids} | |||
| self.prev_phase_indexes = {n: 0 for n in self.node_ids} | |||
| self._set_greens() | |||
| self._step(1) | |||
| states, _, _ = self._get_values() | |||
| return states | |||
| # okay decompiling .\env.cpython-38.pyc | |||
| @ -0,0 +1,122 @@ | |||
| { | |||
| "cells": [ | |||
| { | |||
| "cell_type": "markdown", | |||
| "metadata": {}, | |||
| "source": [ | |||
| "`node_id = '11053'`는 총 4현시로 구성되어 있고, 1현시와 2현시에서 오버랩이 일어난다.\n", | |||
| "\n", | |||
| "#### single ring\n", | |||
| "\n", | |||
| "3현시는 오버랩현시에 포함되지 않으므로\n", | |||
| "$a_3=b_3$\n", | |||
| "이어야 한다. (단, $a_3$은 A링 3현시의 현시시간.)\n", | |||
| "그런데\n", | |||
| "\\begin{align*}\n", | |||
| "a_3&=ag_3+ar_3+ay_3\\\\\n", | |||
| "b_3&=bg_3+br_3+by_3\n", | |||
| "\\end{align*}\n", | |||
| "에서\n", | |||
| "\\begin{align*}\n", | |||
| "ag_3+ar_3+ay_3 &= bg_3+br_3+by_3\\\\\n", | |||
| "ag_3 - bg_3 &= -ar_3+br_3 -ay_3+by_3\\\\\n", | |||
| "\\begin{bmatrix}0\\\\0\\\\1\\\\0\\\\0\\\\0\\\\-1\\\\0\\end{bmatrix}^T\n", | |||
| "\\begin{bmatrix}ag_1\\\\ag_2\\\\ag_3\\\\ag_4\\\\bg_1\\\\bg_2\\\\bg_3\\\\bg_4\\end{bmatrix}\n", | |||
| "&= (-1)((ar_3+ay_3)-(br_3+by_3))\\tag{$*$}\n", | |||
| "\\end{align*}\n", | |||
| "이어야 한다.\n", | |||
| "한편\n", | |||
| "\\begin{align*}\n", | |||
| "\\texttt{loss\\_lst}\n", | |||
| "&= \\texttt{r\\_lst} + \\texttt{y\\_loss\\_lst} + \\texttt{y\\_lst}\\\\\n", | |||
| "&=\\begin{bmatrix}ar_1\\\\ar_2\\\\ar_3\\\\ar_4\\\\br_1\\\\br_2\\\\br_3\\\\br_4\\end{bmatrix}\n", | |||
| "+\\begin{bmatrix}0.3 \\\\0.3 \\\\0.3 \\\\0.3 \\\\0.3 \\\\0.3 \\\\0.3 \\\\0.3 \\end{bmatrix}\n", | |||
| "+\\begin{bmatrix}ay_1\\\\ay_2\\\\ay_3\\\\ay_4\\\\by_1\\\\by_2\\\\by_3\\\\by_4\\end{bmatrix}\n", | |||
| "\\end{align*}\n", | |||
| "이다. ($\\texttt{y\\_loss\\_lst}$는 편의상 0.3으로 이루어진 벡터로 표현함.)\n", | |||
| "따라서 식 $(*)$의 우변은\n", | |||
| "$$\n", | |||
| "(-1)((ar_3+ay_3)-(br_3+by_3))\n", | |||
| "=(-1)\\begin{bmatrix}0\\\\0\\\\1\\\\0\\\\0\\\\0\\\\-1\\\\0\\end{bmatrix}^T\\texttt{loss\\_lst}\n", | |||
| "$$\n", | |||
| "으로 쓸 수 있고, 따라서 식 $(*)$은 \n", | |||
| "\n", | |||
| "$$\n", | |||
| "\\begin{bmatrix}0\\\\0\\\\1\\\\0\\\\0\\\\0\\\\-1\\\\0\\end{bmatrix}^T\n", | |||
| "\\begin{bmatrix}ag_1\\\\ag_2\\\\ag_3\\\\ag_4\\\\bg_1\\\\bg_2\\\\bg_3\\\\bg_4\\end{bmatrix}\n", | |||
| " = (-1)\\begin{bmatrix}0\\\\0\\\\1\\\\0\\\\0\\\\0\\\\-1\\\\0\\end{bmatrix}^T\\texttt{loss\\_lst}\n", | |||
| "$$\n", | |||
| "\n", | |||
| "이다.\n", | |||
| "A링과 B링의 황색/적색시간이 같으면 ($ar_i=br_i$, $ay_i=by_i$ ; 대부분의 경우에 이것이 성립한다.) 위 식의 우변은 0이다.\n", | |||
| "이것은 $ag_3=bg_3$이라는 의미이다.\n", | |||
| "\n", | |||
| "\n", | |||
| "이상이 `evaluation_green_time_ratio.py`의 368, 369번째 줄의 의미이다." | |||
| ] | |||
| }, | |||
| { | |||
| "cell_type": "markdown", | |||
| "metadata": {}, | |||
| "source": [ | |||
| "#### dual ring\n", | |||
| "\n", | |||
| "1현시와 2현시는 오버랩되므로\n", | |||
| "$a_1+a_2=b_1+b_2$\n", | |||
| "이어야 한다.\n", | |||
| "그러면\n", | |||
| "\\begin{align*}\n", | |||
| "ag_1+ar_1+ay_1+ag_2+ar_2+ay_2 &= bg_1+br_1+by_1+bg_2+br_2+by_2\\\\\n", | |||
| "ag_1 + ag_2 - bg_1 - bg_2 &= -ar_1-ay_1-ar_2-ay_2+br_1+by_1+br_2+by_2\\\\\n", | |||
| "\\begin{bmatrix}1\\\\1\\\\0\\\\0\\\\-1\\\\-1\\\\0\\\\0\\end{bmatrix}^T\n", | |||
| "\\begin{bmatrix}ag_1\\\\ag_2\\\\ag_3\\\\ag_4\\\\bg_1\\\\bg_2\\\\bg_3\\\\bg_4\\end{bmatrix}\n", | |||
| "&= (-1)((ar_1+ay_1+ar_2+ay_2)-(br_1+by_1+br_2+by_2))\\tag{$**$}\n", | |||
| "\\end{align*}\n", | |||
| "이어야 한다.\n", | |||
| "한편\n", | |||
| "\\begin{align*}\n", | |||
| "\\texttt{loss\\_lst}\n", | |||
| "&= \\texttt{r\\_lst} + \\texttt{y\\_loss\\_lst} + \\texttt{y\\_lst}\\\\\n", | |||
| "&=\\begin{bmatrix}ar_1\\\\ar_2\\\\ar_3\\\\ar_4\\\\br_1\\\\br_2\\\\br_3\\\\br_4\\end{bmatrix}\n", | |||
| "+\\begin{bmatrix}0.3 \\\\0.3 \\\\0.3 \\\\0.3 \\\\0.3 \\\\0.3 \\\\0.3 \\\\0.3 \\end{bmatrix}\n", | |||
| "+\\begin{bmatrix}ay_1\\\\ay_2\\\\ay_3\\\\ay_4\\\\by_1\\\\by_2\\\\by_3\\\\by_4\\end{bmatrix}\n", | |||
| "\\end{align*}\n", | |||
| "에서 식 $(**)$의 우변은\n", | |||
| "$$\n", | |||
| "(-1)((ar_1+ay_1+ar_2+ay_2)-(br_1+by_1+br_2+by_2))\n", | |||
| "=(-1)\\begin{bmatrix}1\\\\1\\\\0\\\\0\\\\-1\\\\-1\\\\0\\\\0\\end{bmatrix}^T\\texttt{loss\\_lst}\n", | |||
| "$$\n", | |||
| "으로 쓸 수 있고, 따라서 식 $(*)$은 \n", | |||
| "\n", | |||
| "$$\n", | |||
| "\\begin{bmatrix}1\\\\1\\\\0\\\\0\\\\-1\\\\-1\\\\0\\\\0\\end{bmatrix}^T\n", | |||
| "\\begin{bmatrix}ag_1\\\\ag_2\\\\ag_3\\\\ag_4\\\\bg_1\\\\bg_2\\\\bg_3\\\\bg_4\\end{bmatrix}\n", | |||
| " = (-1)\\begin{bmatrix}1\\\\1\\\\0\\\\0\\\\-1\\\\-1\\\\0\\\\0\\end{bmatrix}^T\\texttt{loss\\_lst}\n", | |||
| "$$\n", | |||
| "\n", | |||
| "이다. 이것이 `evaluation_green_time_ratio.py`의 380, 381번째 줄의 의미이다." | |||
| ] | |||
| } | |||
| ], | |||
| "metadata": { | |||
| "kernelspec": { | |||
| "display_name": "sts", | |||
| "language": "python", | |||
| "name": "sts" | |||
| }, | |||
| "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" | |||
| } | |||
| }, | |||
| "nbformat": 4, | |||
| "nbformat_minor": 2 | |||
| } | |||
| @ -0,0 +1,87 @@ | |||
| `node_id = '11053'`는 총 4현시로 구성되어 있고, 1현시와 2현시에서 오버랩이 일어난다. | |||
| #### single ring | |||
| 3현시는 오버랩현시에 포함되지 않으므로 | |||
| $a_3=b_3$ | |||
| 이어야 한다. (단, $a_3$은 A링 3현시의 현시시간.) | |||
| 그런데 | |||
| \begin{align*} | |||
| a_3&=ag_3+ar_3+ay_3\\ | |||
| b_3&=bg_3+br_3+by_3 | |||
| \end{align*} | |||
| 에서 | |||
| \begin{align*} | |||
| ag_3+ar_3+ay_3 &= bg_3+br_3+by_3\\ | |||
| ag_3 - bg_3 &= -ar_3+br_3 -ay_3+by_3\\ | |||
| \begin{bmatrix}0\\0\\1\\0\\0\\0\\-1\\0\end{bmatrix}^T | |||
| \begin{bmatrix}ag_1\\ag_2\\ag_3\\ag_4\\bg_1\\bg_2\\bg_3\\bg_4\end{bmatrix} | |||
| &= (-1)((ar_3+ay_3)-(br_3+by_3))\tag{$*$} | |||
| \end{align*} | |||
| 이어야 한다. | |||
| 한편 | |||
| \begin{align*} | |||
| \texttt{loss\_lst} | |||
| &= \texttt{r\_lst} + \texttt{y\_loss\_lst} + \texttt{y\_lst}\\ | |||
| &=\begin{bmatrix}ar_1\\ar_2\\ar_3\\ar_4\\br_1\\br_2\\br_3\\br_4\end{bmatrix} | |||
| +\begin{bmatrix}0.3 \\0.3 \\0.3 \\0.3 \\0.3 \\0.3 \\0.3 \\0.3 \end{bmatrix} | |||
| +\begin{bmatrix}ay_1\\ay_2\\ay_3\\ay_4\\by_1\\by_2\\by_3\\by_4\end{bmatrix} | |||
| \end{align*} | |||
| 이다. ($\texttt{y\_loss\_lst}$는 편의상 0.3으로 이루어진 벡터로 표현함.) | |||
| 따라서 식 $(*)$의 우변은 | |||
| $$ | |||
| (-1)((ar_3+ay_3)-(br_3+by_3)) | |||
| =(-1)\begin{bmatrix}0\\0\\1\\0\\0\\0\\-1\\0\end{bmatrix}^T\texttt{loss\_lst} | |||
| $$ | |||
| 으로 쓸 수 있고, 따라서 식 $(*)$은 | |||
| $$ | |||
| \begin{bmatrix}0\\0\\1\\0\\0\\0\\-1\\0\end{bmatrix}^T | |||
| \begin{bmatrix}ag_1\\ag_2\\ag_3\\ag_4\\bg_1\\bg_2\\bg_3\\bg_4\end{bmatrix} | |||
| = (-1)\begin{bmatrix}0\\0\\1\\0\\0\\0\\-1\\0\end{bmatrix}^T\texttt{loss\_lst} | |||
| $$ | |||
| 이다. | |||
| A링과 B링의 황색/적색시간이 같으면 ($ar_i=br_i$, $ay_i=by_i$ ; 대부분의 경우에 이것이 성립한다.) 위 식의 우변은 0이다. | |||
| 이것은 $ag_3=bg_3$이라는 의미이다. | |||
| 이상이 `evaluation_green_time_ratio.py`의 368, 369번째 줄의 의미이다. | |||
| #### dual ring | |||
| 1현시와 2현시는 오버랩되므로 | |||
| $a_1+a_2=b_1+b_2$ | |||
| 이어야 한다. | |||
| 그러면 | |||
| \begin{align*} | |||
| ag_1+ar_1+ay_1+ag_2+ar_2+ay_2 &= bg_1+br_1+by_1+bg_2+br_2+by_2\\ | |||
| ag_1 + ag_2 - bg_1 - bg_2 &= -ar_1-ay_1-ar_2-ay_2+br_1+by_1+br_2+by_2\\ | |||
| \begin{bmatrix}1\\1\\0\\0\\-1\\-1\\0\\0\end{bmatrix}^T | |||
| \begin{bmatrix}ag_1\\ag_2\\ag_3\\ag_4\\bg_1\\bg_2\\bg_3\\bg_4\end{bmatrix} | |||
| &= (-1)((ar_1+ay_1+ar_2+ay_2)-(br_1+by_1+br_2+by_2))\tag{$**$} | |||
| \end{align*} | |||
| 이어야 한다. | |||
| 한편 | |||
| \begin{align*} | |||
| \texttt{loss\_lst} | |||
| &= \texttt{r\_lst} + \texttt{y\_loss\_lst} + \texttt{y\_lst}\\ | |||
| &=\begin{bmatrix}ar_1\\ar_2\\ar_3\\ar_4\\br_1\\br_2\\br_3\\br_4\end{bmatrix} | |||
| +\begin{bmatrix}0.3 \\0.3 \\0.3 \\0.3 \\0.3 \\0.3 \\0.3 \\0.3 \end{bmatrix} | |||
| +\begin{bmatrix}ay_1\\ay_2\\ay_3\\ay_4\\by_1\\by_2\\by_3\\by_4\end{bmatrix} | |||
| \end{align*} | |||
| 에서 식 $(**)$의 우변은 | |||
| $$ | |||
| (-1)((ar_1+ay_1+ar_2+ay_2)-(br_1+by_1+br_2+by_2)) | |||
| =(-1)\begin{bmatrix}1\\1\\0\\0\\-1\\-1\\0\\0\end{bmatrix}^T\texttt{loss\_lst} | |||
| $$ | |||
| 으로 쓸 수 있고, 따라서 식 $(*)$은 | |||
| $$ | |||
| \begin{bmatrix}1\\1\\0\\0\\-1\\-1\\0\\0\end{bmatrix}^T | |||
| \begin{bmatrix}ag_1\\ag_2\\ag_3\\ag_4\\bg_1\\bg_2\\bg_3\\bg_4\end{bmatrix} | |||
| = (-1)\begin{bmatrix}1\\1\\0\\0\\-1\\-1\\0\\0\end{bmatrix}^T\texttt{loss\_lst} | |||
| $$ | |||
| 이다. 이것이 `evaluation_green_time_ratio.py`의 380, 381번째 줄의 의미이다. | |||