///|
fn write_double_array(builder : StringBuilder, values : Array[Double]) -> Unit {
builder.write_char('[')
for index, value in values {
if index > 0 {
builder.write_char(',')
}
builder.write(value)
}
builder.write_char(']')
}
///|
/// Produces a stable row-level prediction audit report.
pub fn prediction_audit_text(audit : PredictionAudit) -> String {
let builder = StringBuilder()
builder.write("observations: \{audit.observation_count()}\n")
builder.write("correct: \{audit.correct_count()}\n")
builder.write("incorrect: \{audit.incorrect_count()}\n")
builder.write("accuracy: \{audit.accuracy()}\n")
builder.write("minimum_winning_margin: \{audit.minimum_winning_margin()}\n")
builder.write("maximum_winning_margin: \{audit.maximum_winning_margin()}\n")
builder.write("mean_winning_margin: \{audit.mean_winning_margin()}\n")
for profile in audit.class_score_profiles() {
builder.write(
"class \{profile.class_label()}: positives=\{profile.positive_count()}, negatives=\{profile.negative_count()}, positive_minimum=\{profile.minimum_positive_score()}, positive_maximum=\{profile.maximum_positive_score()}, positive_mean=\{profile.positive_mean_score()}, negative_minimum=\{profile.minimum_negative_score()}, negative_maximum=\{profile.maximum_negative_score()}, negative_mean=\{profile.negative_mean_score()}, separation=\{profile.score_separation()}\n",
)
}
for observation in audit.observations() {
builder.write(
"row \{observation.row_index()}: actual=\{observation.actual_class()}, predicted=\{observation.predicted_class()}, winning_score=\{observation.winning_score()}, second_class=\{observation.second_class()}, second_score=\{observation.second_score()}, margin=\{observation.winning_margin()}, correct=\{observation.is_correct()}\n",
)
}
builder.to_string()
}
///|
/// Produces deterministic JSON for row-level prediction evidence.
pub fn prediction_audit_json(audit : PredictionAudit) -> String {
let builder = StringBuilder()
builder.write("{\"observation_count\":\{audit.observation_count()}")
builder.write(",\"correct_count\":\{audit.correct_count()}")
builder.write(",\"incorrect_count\":\{audit.incorrect_count()}")
builder.write(",\"accuracy\":\{audit.accuracy()}")
builder.write(",\"minimum_winning_margin\":\{audit.minimum_winning_margin()}")
builder.write(",\"maximum_winning_margin\":\{audit.maximum_winning_margin()}")
builder.write(",\"mean_winning_margin\":\{audit.mean_winning_margin()}")
builder.write(",\"class_score_profiles\":[")
for index, profile in audit.class_score_profiles() {
if index > 0 {
builder.write_char(',')
}
builder.write("{\"class_label\":\{profile.class_label()}")
builder.write(",\"positive_count\":\{profile.positive_count()}")
builder.write(",\"negative_count\":\{profile.negative_count()}")
builder.write(",\"positive_minimum\":\{profile.minimum_positive_score()}")
builder.write(",\"positive_maximum\":\{profile.maximum_positive_score()}")
builder.write(",\"positive_mean\":\{profile.positive_mean_score()}")
builder.write(",\"negative_minimum\":\{profile.minimum_negative_score()}")
builder.write(",\"negative_maximum\":\{profile.maximum_negative_score()}")
builder.write(",\"negative_mean\":\{profile.negative_mean_score()}")
builder.write(",\"score_separation\":\{profile.score_separation()}}")
}
builder.write("],\"observations\":[")
for index, observation in audit.observations() {
if index > 0 {
builder.write_char(',')
}
builder.write("{\"row_index\":\{observation.row_index()}")
builder.write(",\"actual_class\":\{observation.actual_class()}")
builder.write(",\"predicted_class\":\{observation.predicted_class()}")
builder.write(",\"winning_score\":\{observation.winning_score()}")
builder.write(",\"second_class\":\{observation.second_class()}")
builder.write(",\"second_score\":\{observation.second_score()}")
builder.write(",\"winning_margin\":\{observation.winning_margin()}")
builder.write(",\"correct\":\{observation.is_correct()}")
builder.write(",\"scores\":")
write_double_array(builder, observation.scores())
builder.write_char('}')
}
builder.write("]}")
builder.to_string()
}
///|
/// Produces a stable ranked permutation-importance report.
pub fn permutation_importance_text(
importance : PermutationImportance,
) -> String {
let builder = StringBuilder()
builder.write("baseline_accuracy: \{importance.baseline_accuracy()}\n")
builder.write("feature_count: \{importance.feature_count()}\n")
for feature in importance.ranked_features() {
builder.write(
"feature \{feature.feature_index()}: baseline_accuracy=\{feature.baseline_accuracy()}, permuted_accuracy=\{feature.permuted_accuracy()}, accuracy_drop=\{feature.accuracy_drop()}\n",
)
}
builder.to_string()
}
///|
/// Produces deterministic JSON for ranked feature importance.
pub fn permutation_importance_json(
importance : PermutationImportance,
) -> String {
let builder = StringBuilder()
builder.write("{\"baseline_accuracy\":\{importance.baseline_accuracy()}")
builder.write(",\"feature_count\":\{importance.feature_count()}")
builder.write(",\"ranked_features\":[")
for index, feature in importance.ranked_features() {
if index > 0 {
builder.write_char(',')
}
builder.write("{\"feature_index\":\{feature.feature_index()}")
builder.write(",\"baseline_accuracy\":\{feature.baseline_accuracy()}")
builder.write(",\"permuted_accuracy\":\{feature.permuted_accuracy()}")
builder.write(",\"accuracy_drop\":\{feature.accuracy_drop()}}")
}
builder.write("]}")
builder.to_string()
}
///|
/// Produces stable aggregate diagnostics for an OvR model.
pub fn multiclass_diagnostics_text(
diagnostics : MulticlassModelDiagnostics,
) -> String {
let builder = StringBuilder()
builder.write("class_count: \{diagnostics.class_count()}\n")
builder.write(
"total_support_vectors: \{diagnostics.total_support_vectors()}\n",
)
builder.write("all_converged: \{diagnostics.all_converged()}\n")
let counts = diagnostics.support_counts()
let reports = diagnostics.convergence_reports()
for index, count in counts {
let report = reports[index]
builder.write(
"model \{index}: support_vectors=\{count}, iterations=\{report.iterations()}, pair_updates=\{report.pair_updates()}, maximum_kkt_violation=\{report.max_kkt_violation()}, dual_objective=\{report.dual_objective()}, converged=\{report.converged()}\n",
)
}
builder.to_string()
}
///|
/// Produces deterministic JSON for every OvR convergence report.
pub fn multiclass_diagnostics_json(
diagnostics : MulticlassModelDiagnostics,
) -> String {
let builder = StringBuilder()
builder.write("{\"class_count\":\{diagnostics.class_count()}")
builder.write(
",\"total_support_vectors\":\{diagnostics.total_support_vectors()}",
)
builder.write(",\"all_converged\":\{diagnostics.all_converged()}")
builder.write(",\"support_counts\":")
write_int_array(builder, diagnostics.support_counts())
builder.write(",\"convergence_reports\":[")
for index, report in diagnostics.convergence_reports() {
if index > 0 {
builder.write_char(',')
}
builder.write("{\"iterations\":\{report.iterations()}")
builder.write(",\"pair_updates\":\{report.pair_updates()}")
builder.write(",\"support_vectors\":\{report.support_vectors()}")
builder.write(",\"maximum_kkt_violation\":\{report.max_kkt_violation()}")
builder.write(",\"dual_objective\":\{report.dual_objective()}")
builder.write(",\"converged\":\{report.converged()}}")
}
builder.write("]}")
builder.to_string()
}
///|
/// Produces a stable summary of positive sample-weight concentration.
pub fn weight_profile_text(profile : WeightProfile) -> String {
let builder = StringBuilder()
builder.write("count: \{profile.count()}\n")
builder.write("minimum: \{profile.minimum()}\n")
builder.write("maximum: \{profile.maximum()}\n")
builder.write("total: \{profile.total()}\n")
builder.write("mean: \{profile.mean()}\n")
builder.write("effective_sample_size: \{profile.effective_sample_size()}\n")
builder.to_string()
}
///|
/// Produces deterministic JSON for positive sample-weight evidence.
pub fn weight_profile_json(profile : WeightProfile) -> String {
let builder = StringBuilder()
builder.write("{\"count\":\{profile.count()}")
builder.write(",\"minimum\":\{profile.minimum()}")
builder.write(",\"maximum\":\{profile.maximum()}")
builder.write(",\"total\":\{profile.total()}")
builder.write(",\"mean\":\{profile.mean()}")
builder.write(
",\"effective_sample_size\":\{profile.effective_sample_size()}}",
)
builder.to_string()
}
///|
/// Produces stable range and symmetry evidence for a kernel matrix.
pub fn kernel_diagnostics_text(diagnostics : KernelDiagnostics) -> String {
let builder = StringBuilder()
builder.write("entry_count: \{diagnostics.entry_count()}\n")
builder.write("minimum: \{diagnostics.minimum()}\n")
builder.write("maximum: \{diagnostics.maximum()}\n")
builder.write("mean: \{diagnostics.mean()}\n")
builder.write("diagonal_mean: \{diagnostics.diagonal_mean()}\n")
builder.write(
"maximum_symmetry_error: \{diagnostics.maximum_symmetry_error()}\n",
)
builder.to_string()
}
///|
/// Produces deterministic JSON for kernel matrix diagnostics.
pub fn kernel_diagnostics_json(diagnostics : KernelDiagnostics) -> String {
let builder = StringBuilder()
builder.write("{\"entry_count\":\{diagnostics.entry_count()}")
builder.write(",\"minimum\":\{diagnostics.minimum()}")
builder.write(",\"maximum\":\{diagnostics.maximum()}")
builder.write(",\"mean\":\{diagnostics.mean()}")
builder.write(",\"diagonal_mean\":\{diagnostics.diagonal_mean()}")
builder.write(
",\"maximum_symmetry_error\":\{diagnostics.maximum_symmetry_error()}}",
)
builder.to_string()
}