from dataclasses import dataclass
import numpy as np
from matplotlib import pyplot as plt
from smart_cruise.jit import compute
#: Default weight budget.
W0 = 26000.0
#: Default time budget.
T0 = 26000.0
#: Default backoff for changing speed.
BACKOFF = 9
#: Default discretization of the Pareto front of individual states.
PARETO_MAX = 30
[docs]
class Trajectories:
"""
Handler class for optimal trajectories.
Parameters
----------
trajs: :class:`~numpy.ndarray`
:math:`n_t \\times n_d` array of :math:`(h, s, w, t)` states.
n_h: :class:`int`
Number of heights (for normalization).
n_s: :class:`int`
Number of speeds (for normalization).
"""
def __init__(self, trajs, n_h, n_s):
self.trajs = trajs
self.n_h = n_h
self.n_s = n_s
[docs]
def get_traj(self, i):
"""
Get trajectory profile.
Parameters
----------
i: :class:`int`
Index of trajectory.
Returns
-------
h: :class:`~numpy.ndarray`
s: :class:`~numpy.ndarray`
w: :class:`~numpy.ndarray`
t: :class:`~numpy.ndarray`
"""
row = self.trajs[i, :]
h = np.array([state[0] for state in row]) / self.n_h
s = np.array([state[1] for state in row]) / self.n_s
w = np.array([state[2] for state in row]) / self.trajs[0, 0][2]
t = np.array([state[3] for state in row]) / self.trajs[0, 0][3]
return h, s, w, t
[docs]
def plot_traj(self, i):
"""
Display trajectory profile.
Parameters
----------
i: :class:`int`
Index of trajectory.
Returns
-------
None
"""
h, s, w, t = self.get_traj(i)
plt.plot(h, label="Height")
plt.plot(s, label="Speed")
plt.plot(w, label="Remaining Energy")
plt.plot(t, label="Spare Time")
plt.ylim([0, 1])
plt.xlim([0, len(h) - 1])
plt.legend()
plt.show()
[docs]
def get_front(self):
"""
Get Pareto front.
Returns
-------
w: :class:`~numpy.ndarray`
t: :class:`~numpy.ndarray`
"""
last = self.trajs[:, -1]
w = np.array([state[2] for state in last], dtype=float)
t = np.array([state[3] for state in last], dtype=float)
return w, t
[docs]
def plot_front(self):
"""
Display Pareto front.
Returns
-------
None
"""
w, t = self.get_front()
plt.plot(w, t)
plt.xlabel("Remaining energy")
plt.ylabel("Spare time")
plt.xlim([0, None])
plt.ylim([0, None])
plt.show()
[docs]
@dataclass
class CruiseParameters:
"""
Attributes
----------
backoff: :class:`int`, default=BACKOFF
Timer to change speed.
pareto_max: :class:`int`, default=PARETO_MAX
Max number of pareto-optimal points per state.
"""
backoff: int = BACKOFF
pareto_max: int = PARETO_MAX
[docs]
class Cruise:
"""
Parameters
----------
model: :class:`~smart_cruise.models.CostModel`
The cost model.
parameters: :class:`~smart_cruise.smart_cruise.CruiseParameters`
Simulation parameters.
Examples
--------
>>> from smart_cruise import CostRandom
>>> model = CostRandom(n_d=100, seed=42)
>>> cruise = Cruise(model)
>>> cruise.parameters.pareto_max = 5
>>> cruise.compute()
>>> w, t = cruise.trajectories.get_front()
Weight optimal values:
>>> f"Weight: {w[0]:.2f}, time: {t[0]:.2f}"
'Weight: 23160.79, time: 21102.36'
Time optimal values:
>>> f"Weight: {w[-1]:.2f}, time: {t[-1]:.2f}"
'Weight: 20938.41, time: 22734.91'
"""
def __init__(self, model=None, parameters=None):
self.model = model
if parameters is None:
parameters = CruiseParameters()
self.parameters = parameters
self.trajectories = None
def compute(self, w0=W0, t0=T0):
trajectories = compute(
[(w0, t0)],
backoff=self.parameters.backoff,
pareto_max=self.parameters.pareto_max,
**self.model.dict,
)
self.trajectories = Trajectories(
trajectories,
n_s=len(self.model.timings),
n_h=self.model.cruise_matrix.shape[1],
)