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