///|
/// Ranked consensus record for repeated model evaluation.
pub(all) struct ConsensusRecord {
inlier_count : Int
score : Double
residual_sum : Double
} derive(Debug, Eq)
///|
pub(all) struct ConsensusTable {
threshold : Double
records : Array[ConsensusRecord]
}
///|
pub fn ConsensusTable::new(threshold~ : Double) -> ConsensusTable {
{ threshold: threshold.max(0.0), records: [] }
}
///|
pub fn ConsensusTable::observe(
table : ConsensusTable,
residuals : ArrayView[Double],
) -> Unit {
let mut count = 0
let mut score = 0.0
let mut sum = 0.0
for residual in residuals {
let error = @core.abs(residual)
sum += error
if error <= table.threshold {
count += 1
score += table.threshold - error
}
}
table.records.push({ inlier_count: count, score, residual_sum: sum })
}
///|
pub fn ConsensusTable::evaluated_models(table : ConsensusTable) -> Int {
table.records.length()
}
///|
pub fn ConsensusTable::best_inlier_count(table : ConsensusTable) -> Int {
let mut best = 0
for record in table.records {
best = best.max(record.inlier_count)
}
best
}
///|
pub fn ConsensusTable::best_score(table : ConsensusTable) -> Double {
let mut best = 0.0
for record in table.records {
best = best.max(record.score)
}
best
}
///|
pub fn ConsensusTable::best_record(table : ConsensusTable) -> ConsensusRecord? {
if table.records.length() == 0 {
return None
}
let mut best = table.records[0]
for record in table.records[1:] {
if record.inlier_count > best.inlier_count ||
(record.inlier_count == best.inlier_count && record.score > best.score) {
best = record
}
}
Some(best)
}
///|
pub fn ConsensusTable::clear(table : ConsensusTable) -> Unit {
table.records.clear()
}
///|
pub fn consensus_mask(
residuals : ArrayView[Double],
threshold : Double,
) -> Array[Bool] {
let result : Array[Bool] = []
for residual in residuals {
result.push(@core.abs(residual) <= threshold)
}
result
}