///|
fn write_json_string(builder : StringBuilder, value : String) -> Unit {
builder.write_char('"')
for character in value.iter() {
match character {
'"' => builder.write("\\\"")
'\\' => builder.write("\\\\")
'\n' => builder.write("\\n")
'\r' => builder.write("\\r")
'\t' => builder.write("\\t")
'\u{0008}' => builder.write("\\b")
'\u{000c}' => builder.write("\\f")
_ => builder.write_char(character)
}
}
builder.write_char('"')
}
///|
fn write_int_array(builder : StringBuilder, values : Array[Int]) -> Unit {
builder.write_char('[')
for index, value in values {
if index > 0 {
builder.write_char(',')
}
builder.write(value)
}
builder.write_char(']')
}
///|
fn write_int_matrix(
builder : StringBuilder,
values : Array[Array[Int]],
) -> Unit {
builder.write_char('[')
for index, row in values {
if index > 0 {
builder.write_char(',')
}
write_int_array(builder, row)
}
builder.write_char(']')
}
///|
/// Produces a stable line-oriented dataset audit report.
pub fn dataset_profile_text(profile : DatasetProfile) -> String {
let builder = StringBuilder()
builder.write("dataset: \{profile.name()}\n")
builder.write("rows: \{profile.row_count()}\n")
builder.write("features: \{profile.feature_count()}\n")
builder.write("classes: \{profile.class_count()}\n")
builder.write("minimum_squared_norm: \{profile.minimum_squared_norm()}\n")
builder.write("maximum_squared_norm: \{profile.maximum_squared_norm()}\n")
builder.write("mean_squared_norm: \{profile.mean_squared_norm()}\n")
for feature in profile.features() {
builder.write(
"feature \{feature.feature_index()}: minimum=\{feature.minimum()}, maximum=\{feature.maximum()}, mean=\{feature.mean()}, variance=\{feature.variance()}, standard_deviation=\{feature.standard_deviation()}, constant=\{feature.is_constant()}\n",
)
}
for class_profile in profile.classes() {
builder.write(
"class \{class_profile.label()}: count=\{class_profile.count()}, proportion=\{class_profile.proportion()}\n",
)
}
builder.to_string()
}
///|
/// Produces deterministic JSON for a dataset profile.
pub fn dataset_profile_json(profile : DatasetProfile) -> String {
let builder = StringBuilder()
builder.write("{\"name\":")
write_json_string(builder, profile.name())
builder.write(",\"row_count\":\{profile.row_count()}")
builder.write(",\"feature_count\":\{profile.feature_count()}")
builder.write(",\"class_count\":\{profile.class_count()}")
builder.write(",\"minimum_squared_norm\":\{profile.minimum_squared_norm()}")
builder.write(",\"maximum_squared_norm\":\{profile.maximum_squared_norm()}")
builder.write(",\"mean_squared_norm\":\{profile.mean_squared_norm()}")
builder.write(",\"centroid\":[")
for index, value in profile.centroid() {
if index > 0 {
builder.write_char(',')
}
builder.write(value)
}
builder.write("],\"feature_profiles\":[")
for index, feature in profile.features() {
if index > 0 {
builder.write_char(',')
}
builder.write("{\"feature_index\":\{feature.feature_index()}")
builder.write(",\"minimum\":\{feature.minimum()}")
builder.write(",\"maximum\":\{feature.maximum()}")
builder.write(",\"mean\":\{feature.mean()}")
builder.write(",\"variance\":\{feature.variance()}")
builder.write(",\"standard_deviation\":\{feature.standard_deviation()}")
builder.write(",\"constant\":\{feature.is_constant()}}")
}
builder.write("],\"class_profiles\":[")
for index, class_profile in profile.classes() {
if index > 0 {
builder.write_char(',')
}
builder.write("{\"label\":\{class_profile.label()}")
builder.write(",\"count\":\{class_profile.count()}")
builder.write(",\"proportion\":\{class_profile.proportion()}}")
}
builder.write("]}")
builder.to_string()
}
///|
/// Produces a stable human-readable classification report.
pub fn classification_metrics_text(metrics : ClassificationMetrics) -> String {
let builder = StringBuilder()
builder.write("observations: \{metrics.observation_count()}\n")
builder.write("accuracy: \{metrics.accuracy()}\n")
builder.write("error_rate: \{metrics.error_rate()}\n")
builder.write("balanced_accuracy: \{metrics.balanced_accuracy()}\n")
builder.write("macro_precision: \{metrics.macro_precision()}\n")
builder.write("macro_recall: \{metrics.macro_recall()}\n")
builder.write("macro_f1: \{metrics.macro_f1()}\n")
builder.write("micro_precision: \{metrics.micro_precision()}\n")
builder.write("micro_recall: \{metrics.micro_recall()}\n")
builder.write("micro_f1: \{metrics.micro_f1()}\n")
builder.write("weighted_precision: \{metrics.weighted_precision()}\n")
builder.write("weighted_recall: \{metrics.weighted_recall()}\n")
builder.write("weighted_f1: \{metrics.weighted_f1()}\n")
for class_metric in metrics.per_class() {
builder.write(
"class \{class_metric.label()}: support=\{class_metric.support()}, true_positives=\{class_metric.true_positives()}, false_positives=\{class_metric.false_positives()}, false_negatives=\{class_metric.false_negatives()}, precision=\{class_metric.precision()}, recall=\{class_metric.recall()}, f1=\{class_metric.f1()}\n",
)
}
builder.to_string()
}
///|
/// Produces deterministic JSON including confusion and per-class evidence.
pub fn classification_metrics_json(metrics : ClassificationMetrics) -> String {
let builder = StringBuilder()
builder.write("{\"observation_count\":\{metrics.observation_count()}")
builder.write(",\"accuracy\":\{metrics.accuracy()}")
builder.write(",\"error_rate\":\{metrics.error_rate()}")
builder.write(",\"balanced_accuracy\":\{metrics.balanced_accuracy()}")
builder.write(",\"macro_precision\":\{metrics.macro_precision()}")
builder.write(",\"macro_recall\":\{metrics.macro_recall()}")
builder.write(",\"macro_f1\":\{metrics.macro_f1()}")
builder.write(",\"micro_precision\":\{metrics.micro_precision()}")
builder.write(",\"micro_recall\":\{metrics.micro_recall()}")
builder.write(",\"micro_f1\":\{metrics.micro_f1()}")
builder.write(",\"weighted_precision\":\{metrics.weighted_precision()}")
builder.write(",\"weighted_recall\":\{metrics.weighted_recall()}")
builder.write(",\"weighted_f1\":\{metrics.weighted_f1()}")
builder.write(",\"classes\":")
write_int_array(builder, metrics.classes())
builder.write(",\"confusion_matrix\":")
write_int_matrix(builder, metrics.confusion_matrix())
builder.write(",\"per_class\":[")
for index, class_metric in metrics.per_class() {
if index > 0 {
builder.write_char(',')
}
builder.write("{\"label\":\{class_metric.label()}")
builder.write(",\"support\":\{class_metric.support()}")
builder.write(",\"true_positives\":\{class_metric.true_positives()}")
builder.write(",\"false_positives\":\{class_metric.false_positives()}")
builder.write(",\"false_negatives\":\{class_metric.false_negatives()}")
builder.write(",\"precision\":\{class_metric.precision()}")
builder.write(",\"recall\":\{class_metric.recall()}")
builder.write(",\"f1\":\{class_metric.f1()}}")
}
builder.write("]}")
builder.to_string()
}
///|
/// Produces stable binary support-vector and convergence evidence.
pub fn binary_diagnostics_text(
diagnostics : BinaryModelDiagnostics,
convergence : ConvergenceReport,
) -> String {
let builder = StringBuilder()
builder.write("support_vectors: \{diagnostics.support_vectors()}\n")
builder.write(
"negative_support_vectors: \{diagnostics.negative_support_vectors()}\n",
)
builder.write(
"positive_support_vectors: \{diagnostics.positive_support_vectors()}\n",
)
builder.write("minimum_alpha: \{diagnostics.minimum_alpha()}\n")
builder.write("maximum_alpha: \{diagnostics.maximum_alpha()}\n")
builder.write("mean_alpha: \{diagnostics.mean_alpha()}\n")
builder.write("iterations: \{convergence.iterations()}\n")
builder.write("pair_updates: \{convergence.pair_updates()}\n")
builder.write("maximum_kkt_violation: \{convergence.max_kkt_violation()}\n")
builder.write("dual_objective: \{convergence.dual_objective()}\n")
builder.write("converged: \{convergence.converged()}\n")
builder.to_string()
}
///|
/// Produces deterministic JSON for binary model diagnostics.
pub fn binary_diagnostics_json(
diagnostics : BinaryModelDiagnostics,
convergence : ConvergenceReport,
) -> String {
let builder = StringBuilder()
builder.write("{\"support_vectors\":\{diagnostics.support_vectors()}")
builder.write(
",\"negative_support_vectors\":\{diagnostics.negative_support_vectors()}",
)
builder.write(
",\"positive_support_vectors\":\{diagnostics.positive_support_vectors()}",
)
builder.write(",\"minimum_alpha\":\{diagnostics.minimum_alpha()}")
builder.write(",\"maximum_alpha\":\{diagnostics.maximum_alpha()}")
builder.write(",\"mean_alpha\":\{diagnostics.mean_alpha()}")
builder.write(",\"iterations\":\{convergence.iterations()}")
builder.write(",\"pair_updates\":\{convergence.pair_updates()}")
builder.write(",\"maximum_kkt_violation\":\{convergence.max_kkt_violation()}")
builder.write(",\"dual_objective\":\{convergence.dual_objective()}")
builder.write(",\"converged\":\{convergence.converged()}}")
builder.to_string()
}
///|
/// Produces a line-oriented threshold report with confusion evidence.
pub fn threshold_analysis_text(analysis : BinaryThresholdAnalysis) -> String {
let builder = StringBuilder()
builder.write("positive_count: \{analysis.positive_count()}\n")
builder.write("negative_count: \{analysis.negative_count()}\n")
builder.write("roc_auc: \{analysis.roc_auc()}\n")
builder.write("average_precision: \{analysis.average_precision()}\n")
for point in analysis.points() {
builder.write(
"threshold \{point.threshold()}: true_positives=\{point.true_positives()}, false_positives=\{point.false_positives()}, true_negatives=\{point.true_negatives()}, false_negatives=\{point.false_negatives()}, true_positive_rate=\{point.true_positive_rate()}, false_positive_rate=\{point.false_positive_rate()}, precision=\{point.precision()}, recall=\{point.recall()}\n",
)
}
builder.to_string()
}
///|
/// Produces deterministic JSON for ROC and precision-recall points.
pub fn threshold_analysis_json(analysis : BinaryThresholdAnalysis) -> String {
let builder = StringBuilder()
builder.write("{\"positive_count\":\{analysis.positive_count()}")
builder.write(",\"negative_count\":\{analysis.negative_count()}")
builder.write(",\"roc_auc\":\{analysis.roc_auc()}")
builder.write(",\"average_precision\":\{analysis.average_precision()}")
builder.write(",\"points\":[")
for index, point in analysis.points() {
if index > 0 {
builder.write_char(',')
}
builder.write("{\"threshold\":\{point.threshold()}")
builder.write(",\"true_positives\":\{point.true_positives()}")
builder.write(",\"false_positives\":\{point.false_positives()}")
builder.write(",\"true_negatives\":\{point.true_negatives()}")
builder.write(",\"false_negatives\":\{point.false_negatives()}")
builder.write(",\"true_positive_rate\":\{point.true_positive_rate()}")
builder.write(",\"false_positive_rate\":\{point.false_positive_rate()}")
builder.write(",\"precision\":\{point.precision()}")
builder.write(",\"recall\":\{point.recall()}}")
}
builder.write("]}")
builder.to_string()
}
///|
/// Produces stable repeated-validation summary text.
pub fn repeated_validation_text(report : RepeatedValidationReport) -> String {
let builder = StringBuilder()
builder.write("repetitions: \{report.repetition_count()}\n")
builder.write("folds_per_repetition: \{report.fold_count()}\n")
builder.write("mean_accuracy: \{report.mean_accuracy()}\n")
builder.write("minimum_accuracy: \{report.minimum_accuracy()}\n")
builder.write("maximum_accuracy: \{report.maximum_accuracy()}\n")
builder.write(
"accuracy_standard_deviation: \{report.accuracy_standard_deviation()}\n",
)
builder.write("mean_macro_f1: \{report.mean_macro_f1()}\n")
builder.write("minimum_macro_f1: \{report.minimum_macro_f1()}\n")
builder.write("maximum_macro_f1: \{report.maximum_macro_f1()}\n")
builder.write(
"macro_f1_standard_deviation: \{report.macro_f1_standard_deviation()}\n",
)
for index, round in report.reports() {
builder.write(
"round \{index}: accuracy=\{round.metrics().accuracy()}, macro_f1=\{round.metrics().macro_f1()}, observations=\{round.observation_count()}\n",
)
}
builder.to_string()
}
///|
/// Produces deterministic JSON for repeated validation variability.
pub fn repeated_validation_json(report : RepeatedValidationReport) -> String {
let builder = StringBuilder()
builder.write("{\"repetitions\":\{report.repetition_count()}")
builder.write(",\"folds_per_repetition\":\{report.fold_count()}")
builder.write(",\"mean_accuracy\":\{report.mean_accuracy()}")
builder.write(",\"minimum_accuracy\":\{report.minimum_accuracy()}")
builder.write(",\"maximum_accuracy\":\{report.maximum_accuracy()}")
builder.write(
",\"accuracy_standard_deviation\":\{report.accuracy_standard_deviation()}",
)
builder.write(",\"mean_macro_f1\":\{report.mean_macro_f1()}")
builder.write(",\"minimum_macro_f1\":\{report.minimum_macro_f1()}")
builder.write(",\"maximum_macro_f1\":\{report.maximum_macro_f1()}")
builder.write(
",\"macro_f1_standard_deviation\":\{report.macro_f1_standard_deviation()}",
)
builder.write(",\"rounds\":[")
for index, round in report.reports() {
if index > 0 {
builder.write_char(',')
}
builder.write("{\"index\":\{index}")
builder.write(",\"accuracy\":\{round.metrics().accuracy()}")
builder.write(",\"macro_f1\":\{round.metrics().macro_f1()}")
builder.write(",\"observations\":\{round.observation_count()}}")
}
builder.write("]}")
builder.to_string()
}