I'm trying to minimize a custom cost function (see below) using the python gekko library but seem to be encountering issues with the dtype being set by the library. Attempts to cast the variables to np.int_ result in a ValueError as well. Is there a way to make the MINLP solver of the GEKKO library allow for using its variables as indexers? Or is there potentially a way to minimize this cost function with another library?
def find_optimal_path(
self,
p0: npt.NDArray[np.int_],
correlation_matrix: npt.NDArray[np.float64],
euclidean_distance_matrix: npt.NDArray[np.float64],
lags: npt.NDArray[np.int_],
) -> np.float64:
r"""
Finds the optimal path for the provided correlation matrix of size
M x N, euclidean distance matrix of size M and N and lags vector of size Mx1
where M is the shift distance and N is the number of
rolling windows. The cost function is defined as:
.. math::
cost(\textbf{p}) = 1 - \frac{1}{N}\sum_{i=0}^{N}{C[p_i,i]} +
\frac{\alpha}{N}\sum_{i=0}^{N}{E[p_i,i]} +
\frac{\beta}{N}|\sum_{i=0}^{N}{\textbf{l}[p_i]}| +
\frac{\gamma}{N}\sum_{i=0}^{N}{|\textbf{l}[p_i]-\textbf{l}[p_{i-1}]|+|\textbf{l}[p_i]-\textbf{l}[p_{i+1}]|}
"""
def previous_and_next(some_iterable):
prevs, items, nexts = tee(some_iterable, 3)
prevs = chain([None], prevs)
nexts = chain(islice(nexts, 1, None), [None])
return zip(prevs, items, nexts)
# TODO: Tune these
alpha = beta = gamma = 0.1
N = len(p0)
def obj(path):
return (
1
- 1 / N * np.sum(correlation_matrix[path, np.arange(len(path))])
+ alpha
/ N
* np.sum(euclidean_distance_matrix[path, np.arange(len(path))])
+ beta / N * abs(np.sum([lags[y] for y in path]))
+ gamma
/ N
* np.sum(
[
abs(lags[y] - lags[p]) + abs(lags[y] - lags[n])
for p, y, n in previous_and_next(path)
]
)
)
# Instantiate local MINLP solver
m = GEKKO(remote=False)
# Add path variable
path = m.Array(m.Var, N, lb=0, ub=correlation_matrix.shape[0] - 1, integer=True)
for i in range(N):
path[i].value = p0[i]
# Add objective
m.Minimize(obj(path))
# Solve
m.solve(disp=True)
return path
If I run the above function I get an IndexError from numpy which I think comes from the fact that the path variable has dtype=object
:
IndexError: arrays used as indices must be of integer (or boolean) type
If I attempt to cast the path variable inside my obj
function like so path = np.asarray(path, dtype=np.int_)
I get the following python ValueError:
ValueError: setting an array element with a sequence.