Source code for foxes_opt.problems.layout.geom_layouts.derivatives

import numpy as np
from iwopy import Problem
from scipy.spatial.distance import cdist


[docs] def layout_data( problem: Problem, vars_int: np.ndarray, vars_float: np.ndarray, var: int, ) -> tuple[np.ndarray, np.ndarray, np.ndarray] | None: """Return layout points, validity, and one Jacobian column.""" derivative = getattr(problem, "layout_derivative", None) if not callable(derivative): return None points, valid = problem.apply_individual(vars_int, vars_float) return points, valid, derivative(vars_int, vars_float, var)
def _common_derivative(values: list[float]) -> float: """Return a common active derivative, or NaN when branches disagree.""" derivatives = np.asarray(values, dtype=np.float64) if not len(derivatives) or np.any(np.isnan(derivatives)): return np.nan return float(derivatives[0]) if np.allclose(derivatives, derivatives[0]) else np.nan def _distance_derivative(delta: np.ndarray, point_derivative: np.ndarray) -> float: """Differentiate one point-to-fixed-point distance.""" distance = np.linalg.norm(delta) if distance > 0.0: return float(np.dot(delta / distance, point_derivative)) return 0.0 if not np.any(point_derivative) else np.nan
[docs] def maximin_distance_derivative( probes: np.ndarray, points: np.ndarray, valid: np.ndarray, point_derivatives: np.ndarray, ) -> float: """Differentiate the largest probe-to-nearest-point distance.""" valid_indices = np.flatnonzero(valid) if not len(valid_indices): return np.nan distances = cdist(probes, points[valid_indices]) nearest_distances = np.min(distances, axis=1) active_probes = np.flatnonzero( np.isclose(nearest_distances, np.max(nearest_distances)) ) probe_derivatives = [] for probe in active_probes: active_points = np.flatnonzero( np.isclose(distances[probe], nearest_distances[probe]) ) derivatives = [ _distance_derivative( points[valid_indices[point]] - probes[probe], point_derivatives[valid_indices[point]], ) for point in active_points ] probe_derivatives.append(_common_derivative(derivatives)) return _common_derivative(probe_derivatives)
[docs] def nearest_distance_derivatives( points: np.ndarray, point_derivatives: np.ndarray, scale: float, ) -> tuple[np.ndarray, np.ndarray]: """Calculate nearest-neighbour distances and one derivative column.""" distances = cdist(points, points) np.fill_diagonal(distances, np.inf) nearest = np.min(distances, axis=1) derivatives = np.zeros(len(points), dtype=np.float64) for point in range(len(points)): neighbours = np.flatnonzero(np.isclose(distances[point], nearest[point])) candidates = [ _distance_derivative( points[point] - points[neighbour], point_derivatives[point] - point_derivatives[neighbour], ) for neighbour in neighbours ] derivatives[point] = _common_derivative(candidates) return nearest / scale, derivatives / scale
[docs] def extreme_derivative( values: np.ndarray, derivatives: np.ndarray, maximize: bool ) -> float: """Differentiate a minimum or maximum across active scalar branches.""" extreme = np.max(values) if maximize else np.min(values) active = np.flatnonzero(np.isclose(values, extreme)) return _common_derivative(derivatives[active].tolist())