homotopy-continuation-chann.../python/hccd/path_tracker.py

85 lines
2.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import numpy as np
import typing
import scipy
def _sign(val):
return -1 * (val < 0) + 1 * (val >= 0)
class PathTracker:
"""
Path trakcer for the homotopy continuation method. Uses a
predictor-corrector scheme to trace a path defined by a homotopy.
References:
[1] T. Chen and T.-Y. Li, “Homotopy continuation method for solving
systems of nonlinear and polynomial equations,” Communications in
Information and Systems, vol. 15, no. 2, pp. 119307, 2015
"""
def __init__(self, Homotopy, euler_step_size=0.05, euler_max_tries=10, newton_max_iter=5,
newton_convergence_threshold=0.001, sigma=1):
self.Homotopy = Homotopy
self._euler_step_size = euler_step_size
self._euler_max_tries = euler_max_tries
self._newton_max_iter = newton_max_iter
self._newton_convergence_threshold = newton_convergence_threshold
self._sigma = sigma
def step(self, y):
"""Perform one predictor-corrector step."""
return self.transparent_step(y)[0]
def transparent_step(self, y) -> typing.Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray,]:
"""Perform one predictor-corrector step, returning intermediate results."""
for i in range(self._euler_max_tries):
step_size = self._euler_step_size / (1 << i)
y_hat, y_prime = self._perform_euler_predictor_step(y, step_size)
y_hat_n = self._perform_newtown_corrector_step(y_hat)
return y, y_prime, y_hat, y_hat_n
raise RuntimeError("Newton corrector did not converge")
def _perform_euler_predictor_step(self, y, step_size) -> typing.Tuple[np.ndarray, np.ndarray]:
# Obtain y_prime
DH = self.Homotopy.evaluate_DH(y)
ns = scipy.linalg.null_space(DH)
y_prime = ns[:, 0] * self._sigma
# Q, R = np.linalg.qr(np.transpose(DH), mode="complete")
# y_prime = Q[:, 2]
#
# if _sign(np.linalg.det(Q)*np.linalg.det(R[:2, :])) != _sign(self._sigma):
# y_prime = -y_prime
# Perform prediction
y_hat = y + step_size*y_prime
return y_hat, y_prime
def _perform_newtown_corrector_step(self, y) -> np.ndarray:
prev_y = y
for _ in range(self._newton_max_iter):
# Perform correction
DH = self.Homotopy.evaluate_DH(y)
DH_pinv = np.linalg.pinv(DH)
y = y - DH_pinv @ self.Homotopy.evaluate_H(y)
# Check stopping criterion
if np.linalg.norm(y - prev_y) < self._newton_convergence_threshold:
return y
prev_y = y
raise RuntimeError("Newton corrector did not converge")