///|
/// Shared candidate selection helper.
///|
pub fn[T, U] select_untried_candidates(
pool : Array[T],
rounds : Array[RoundSummary],
candidate_limit : Int,
to_candidate : (T) -> ImprovementCandidate[U],
) -> Array[ImprovementCandidate[U]] {
if candidate_limit <= 0 {
return []
}
let tried : Map[String, Bool] = {}
for round in rounds {
for id in round.result_ids {
tried.set(id, true)
}
}
let out : Array[ImprovementCandidate[U]] = []
for item in pool {
let candidate = to_candidate(item)
if tried.contains(candidate.id) {
continue
}
out.push(candidate)
if out.length() >= candidate_limit {
break
}
}
out
}
///|
pub fn[T, TMetrics] create_metric_symbol(
baseline_input : T,
coerce_candidate : (Json) -> Result[T, String],
evaluate_candidate : (T) -> Result[TMetrics, String],
pick_metric : (TMetrics, String) -> Result[Double, String],
cache : Map[String, TMetrics],
cache_key : (T) -> String,
) -> (RLMExternalSymbolCall) -> Result[Json, String] {
fn(call) {
let args_row = harness_json_object_or_empty(call.args)
let metric_key = match harness_json_get_string(args_row, "metricKey") {
Some(v) => v
None => return Err("metricKey must be string")
}
let candidate = match args_row.get("candidate") {
Some(v) =>
match coerce_candidate(v) {
Ok(parsed) => parsed
Err(message) => return Err(message)
}
None =>
match call.input {
Some(v) =>
match coerce_candidate(v) {
Ok(parsed) => parsed
Err(message) => return Err(message)
}
None => baseline_input
}
}
let key = cache_key(candidate)
let metrics = match cache.get(key) {
Some(v) => v
None => {
let computed = match evaluate_candidate(candidate) {
Ok(v) => v
Err(message) => return Err(message)
}
cache.set(key, computed)
computed
}
}
let value = match pick_metric(metrics, metric_key) {
Ok(v) => v
Err(message) => return Err(message)
}
Ok(Json::number(value))
}
}
///|
fn harness_json_object_or_empty(input : Json?) -> Map[String, Json] {
match input {
Some(Json::Object(v)) => v
_ => {}
}
}
///|
fn harness_json_get_string(row : Map[String, Json], key : String) -> String? {
match row.get(key) {
Some(Json::String(v)) => Some(v)
_ => None
}
}