///|
/// Connects language operations, enumeration, and scheduling to one session.
pub struct Reducer[P] {
priv session : ReductionSession[P]
priv schedule : OperationSchedule[P]
priv mut search : Enumeration[P]?
}
///|
/// `better(candidate, incumbent)` orders programs without interpreting their cost.
pub fn[P] Reducer::new(
initial : P,
evidence : @contracts.Assessment,
predicate : @contracts.FailurePredicate,
id~ : String,
limit~ : Int32,
better~ : (P, P) -> Bool,
valid~ : (P) -> Bool,
operations~ : Array[(P) -> Array[P]],
) -> Result[Reducer[P], ReductionStartError] {
let session = match
ReductionSession::new(
initial,
evidence,
id~,
limit~,
valid~,
accepts=(current, candidate) => better(candidate, current),
better=(best, candidate) => better(candidate, best),
predicate=assessment => match_failure(predicate, assessment),
) {
Ok(session) => session
Err(error) => return Err(error)
}
Ok({ session, schedule: OperationSchedule::new(operations), search: None, })
}
///|
pub fn[P] Reducer::next(self : Reducer[P]) -> ReductionRequest[P]? {
if self.session.pending() is Some(request) {
return Some(request)
}
while self.session.stop_reason() is None {
if self.search is Some(search) && search.next() is Some(candidate) {
match self.session.offer(candidate) {
Evaluate(request) => return Some(request)
Declined(_) => continue
Pending => return self.session.pending()
Stopped(_) => return None
}
}
match self.schedule.next() {
Some(operation) =>
self.search = Some(Enumeration::new(operation(self.session.current())))
None => {
ignore(self.session.finish())
return None
}
}
} nobreak {
None
}
}
///|
pub fn[P] Reducer::observe(
self : Reducer[P],
id : CandidateId,
evidence : @contracts.Assessment,
) -> Bool {
if self.session.observe(id, evidence) is Some(Accepted) {
self.schedule.restart()
self.search = None
true
} else {
false
}
}
///|
pub fn[P] Reducer::result(self : Reducer[P]) -> P {
self.session.result()
}
///|
pub fn[P] Reducer::attempts(self : Reducer[P]) -> Int32 {
self.session.attempts()
}
///|
pub fn[P] Reducer::stop_reason(self : Reducer[P]) -> ReductionStop? {
self.session.stop_reason()
}