@ -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번째 줄의 의미이다. |