route-explainer / utils /util_calc.py
daisuke.kikuta
first commit
719d0db
raw
history blame
4.02 kB
import numpy as np
import torch
from torchmetrics.classification import ConfusionMatrix
def calc_tour_length(tour, coords):
tour_length = []
for i in range(len(tour) - 1):
path_length = np.linalg.norm(coords[tour[i]] - coords[tour[i + 1]])
tour_length.append(path_length)
tour_length = np.sum(tour_length)
return tour_length
class TemporalConfusionMatrix():
def __init__(self, num_classes: int, seq_length: int, device: str):
if num_classes == 2:
task = "binary"
elif num_classes > 2:
task = "multiclass"
else:
assert False, "Invalid num_classes. It should be more than 2"
self.num_classes = num_classes
self.seq_length = seq_length
self.temp_confmat = [ConfusionMatrix(task=task, num_classes=num_classes).to(device) for _ in range(seq_length)]
def update(self,
preds: torch.Tensor,
labels: torch.Tensor,
mask: torch.Tensor):
"""
Parameters
----------
preds: predicted labels [batch_size x max_seq_length]
label: ground truth labels [batch_size x max_seq_length]
mask: mask of padding [batch_size x max_seq_length]
"""
batch_mask = (mask.sum(-1) == self.seq_length) # [batch_size]
preds = preds[batch_mask] # [fixed_batch_size x max_seq_length]
labels = labels[batch_mask] # [fixed_batch_size x max_seq_length]
for i in range(self.seq_length):
self.temp_confmat[i](preds[:, i], labels[:, i])
def compute(self, device="cpu"):
return [confmat.compute().to(device) for confmat in self.temp_confmat]
def calc_route_length(routes: list, coords: np.array):
route_length = []
num_vehicles = get_num_vehicles(routes)
for vehicle_id in range(num_vehicles):
route = routes[vehicle_id]
for i in range(len(route) - 1):
edge_length = np.linalg.norm(coords[route[i]] - coords[route[i + 1]])
route_length.append(edge_length)
route_length = np.sum(route_length)
return route_length
def get_num_vehicles(routes: list):
return len(routes)
def calc_class_ratio(labels: torch.Tensor, routes: list):
"""
Parameters
----------
lables: torch.Tensor [num_vehicles, max_seq_length]
routes: 2d list [num_vehicles, seq_length]
"""
if isinstance(labels, torch.Tensor):
num_classes = 3 # labels.max().item() + 1
class_list = [0 for _ in range(num_classes)]
print(labels, routes)
for vehicle_id in range(get_num_vehicles(routes)):
for step in range(len(routes[vehicle_id])-1):
class_list[labels[vehicle_id, step].item()] += 1
else:
if len(labels) > 1:
num_classes = np.max(np.max(labels)) + 1
else:
num_classes = np.max(labels) + 1
class_list = [0 for _ in range(num_classes)]
for vehicle_id in range(get_num_vehicles(routes)):
for step in range(len(routes[vehicle_id])-1):
class_list[labels[vehicle_id][step]] += 1
class_list = np.array(class_list)
return class_list / np.sum(class_list)
def calc_feasible_ratio(routes: list, coords: np.array):
return len(np.unique(routes)) / len(coords)
def calc_total_prizes(routes: list, prizes: np.array):
total_prizes = 0.
num_vehicles = get_num_vehicles(routes)
for vehicle_id in range(num_vehicles):
route = routes[vehicle_id]
for i in range(len(route) - 1):
total_prizes += prizes[route[i]]
return total_prizes
def calc_total_penlties(routes: list, penalities: np.array):
total_penalites = 0.
num_nodes = len(penalities)
node_ids = np.arange(num_nodes)
visited_node_ids = np.unique(routes)
unvisited_node_ids = np.setdiff1d(node_ids, visited_node_ids)
for unvisited_node_id in unvisited_node_ids:
total_penalites += penalities[unvisited_node_id]
return total_penalites