///|
pub struct OptimizationResult {
parameters : Array[Double]
objective : Double
iterations : Int
converged : Bool
} derive(Debug, Eq)
///|
pub fn finite_difference_gradient(
objective : (Array[Double]) -> Double,
parameters : Array[Double],
step : Double,
) -> Array[Double] {
let gradient : Array[Double] = []
for i in 0.. Double,
initial : Array[Double],
learning_rate : Double,
iterations : Int,
) -> OptimizationResult {
let parameters = initial.copy()
let mut completed = 0
for _ in 0.. sum + value * value).sqrt() <
1.0e-8 {
break
}
}
{
parameters,
objective: objective(parameters),
iterations: completed,
converged: completed < iterations.max(0) || iterations <= 0,
}
}
///|
pub fn grid_search_1d(
objective : (Double) -> Double,
lower : Double,
upper : Double,
samples : Int,
) -> (Double, Double) {
let mut best_x = lower
let mut best_value = objective(lower)
for i in 0.. Double {
if values.length() != weights.length() {
1.0e30
} else {
let normalized = normalize_weights(weights)
let mut total = 0.0
for i in 0.. (Double, Double) {
if radii.length() < 2 {
(0.0, 0.0)
} else {
let mut best = radii[0]
let mut cost = 1.0e30
for radius in radii {
let value = circular_speed(mu, radius)
if value < cost {
cost = value
best = radius
}
}
(best, cost)
}
}
///|
pub fn pareto_front(
values : Array[(Double, Double)],
) -> Array[(Double, Double)] {
let result : Array[(Double, Double)] = []
for candidate in values {
let dominated = values.any(other => {
other.0 <= candidate.0 &&
other.1 <= candidate.1 &&
(other.0 < candidate.0 || other.1 < candidate.1)
})
if !dominated {
result.push(candidate)
}
}
result
}
///|
pub fn normalize_parameter(
value : Double,
lower : Double,
upper : Double,
) -> Double {
clamp(inverse_lerp(lower, upper, value), 0.0, 1.0)
}
///|
pub fn denormalize_parameter(
value : Double,
lower : Double,
upper : Double,
) -> Double {
lerp_scalar(lower, upper, clamp(value, 0.0, 1.0))
}
///|
pub fn objective_orbit_altitude(
mu : Double,
elements : ClassicalElements,
target_altitude_km : Double,
) -> Double {
let actual = elements.semi_major_axis_km - earth_radius_km
(actual - target_altitude_km).abs() +
elements.eccentricity * 100.0 +
orbital_period(mu, elements.semi_major_axis_km) * 1.0e-5
}
///|
pub fn select_best_candidate(
candidates : Array[DesignCandidate],
) -> DesignCandidate? {
let feasible = feasible_designs(candidates)
let ranked = rank_designs(feasible)
if ranked.length() == 0 {
None
} else {
Some(ranked[0])
}
}