///|
fn report_percent(numerator : Int, denominator : Int) -> String {
if denominator <= 0 {
"0.00%"
} else {
let basis_points = numerator * 10000 / denominator
(basis_points / 100).to_string() +
"." +
(basis_points % 100 / 10).to_string() +
(basis_points % 10).to_string() +
"%"
}
}
///|
fn markdown_escape(value : String) -> String {
value
.replace(old="\\", new="\\\\")
.replace(old="|", new="\\|")
.replace(old="\n", new=" ")
.replace(old="\r", new=" ")
}
///|
fn event_name(kind : CampaignEventKind) -> String {
match kind {
Generated => "generated"
Mutated(strategy) => "mutated:" + mutation_name(strategy)
Crossed => "crossed"
Admitted(_) => "admitted"
RejectedInput(_) => "rejected"
FailureFound(_) => "failure"
MutationSkipped => "mutation-skipped"
}
}
///|
fn mutation_name(strategy : MutationStrategy) -> String {
match strategy {
RegenerateSubtree => "regenerate-subtree"
DeleteRepeatedChild => "delete-repeated-child"
ToggleOptional => "toggle-optional"
ReplaceIntegerBoundary => "replace-integer-boundary"
ReplaceDictionaryEntry => "replace-dictionary-entry"
DuplicateRepeatedChild => "duplicate-repeated-child"
}
}
///|
fn origin_name(origin : CorpusOrigin) -> String {
match origin {
Seeded(_) => "seeded"
Generated(_) => "generated"
Mutated(_, _) => "mutated"
Crossed(_, _) => "crossed"
Reduced(_) => "reduced"
Replayed => "replayed"
}
}
///|
pub fn CampaignResult::markdown_report(
self : CampaignResult,
title? : String = "MoonGrammata Campaign Report",
) -> String {
let stats = self.statistics
let lines : Array[String] = [
"# " + title,
"",
"## Summary",
"",
"| Metric | Value |",
"| --- | ---: |",
"| Executions | " + stats.completed_executions.to_string() + " |",
"| Corpus entries | " + stats.final_corpus.entries.to_string() + " |",
"| Unique feedback signatures | " +
stats.final_corpus.unique_signatures.to_string() +
" |",
"| Unique features | " +
stats.final_corpus.unique_features.to_string() +
" |",
"| Unique failures | " + stats.unique_failures.to_string() + " |",
"| Admission rate | " +
report_percent(stats.admitted_inputs, stats.completed_executions) +
" |",
"| Mutation inputs | " + stats.mutated_inputs.to_string() + " |",
"| Crossover inputs | " + stats.crossed_inputs.to_string() + " |",
"| Generated inputs | " + stats.generated_inputs.to_string() + " |",
"| Corpus bytes | " + stats.final_corpus.total_bytes.to_string() + " |",
"",
"## Retained Corpus",
"",
"| ID | Origin | Bytes | Nodes | Features | Failure |",
"| ---: | --- | ---: | ---: | ---: | --- |",
]
for entry in self.corpus {
let failure = match entry.failure {
None => ""
Some(value) => markdown_escape(value.value())
}
lines.push(
"| " +
entry.id.to_string() +
" | " +
origin_name(entry.origin) +
" | " +
entry.tree.byte_length().to_string() +
" | " +
entry.tree.node_count().to_string() +
" | " +
entry.observation.feature_count().to_string() +
" | " +
failure +
" |",
)
}
lines.push("")
lines.push("## Failures")
lines.push("")
if self.failures.is_empty() {
lines.push("No unique failures were observed.")
} else {
for index, replay in self.failures {
let fingerprint = replay.failure_fingerprint.unwrap().value()
lines.push(
(index + 1).to_string() +
". `" +
markdown_escape(fingerprint) +
"` — " +
replay.input.length().to_string() +
" bytes, seed `" +
replay.seed.to_string() +
"`.",
)
}
}
lines.join("\n") + "\n"
}
///|
fn corpus_entry_json(entry : CorpusEntry) -> String {
let failure = match entry.failure {
None => "null"
Some(value) => replay_json_quote(value.value())
}
"{" +
"\"id\":" +
entry.id.to_string() +
",\"origin\":" +
replay_json_quote(origin_name(entry.origin)) +
",\"bytes\":" +
entry.tree.byte_length().to_string() +
",\"nodes\":" +
entry.tree.node_count().to_string() +
",\"depth\":" +
entry.tree.depth().to_string() +
",\"feature_count\":" +
entry.observation.feature_count().to_string() +
",\"feedback_signature\":" +
replay_json_quote(entry.signature.value()) +
",\"failure_fingerprint\":" +
failure +
"}"
}
///|
fn campaign_stats_json(stats : CampaignStatistics) -> String {
"{" +
"\"requested_executions\":" +
stats.requested_executions.to_string() +
",\"completed_executions\":" +
stats.completed_executions.to_string() +
",\"generated_inputs\":" +
stats.generated_inputs.to_string() +
",\"mutated_inputs\":" +
stats.mutated_inputs.to_string() +
",\"crossed_inputs\":" +
stats.crossed_inputs.to_string() +
",\"admitted_inputs\":" +
stats.admitted_inputs.to_string() +
",\"rejected_inputs\":" +
stats.rejected_inputs.to_string() +
",\"unique_failures\":" +
stats.unique_failures.to_string() +
",\"mutation_failures\":" +
stats.mutation_failures.to_string() +
",\"final_corpus\":{" +
"\"entries\":" +
stats.final_corpus.entries.to_string() +
",\"failures\":" +
stats.final_corpus.failures.to_string() +
",\"total_bytes\":" +
stats.final_corpus.total_bytes.to_string() +
",\"unique_features\":" +
stats.final_corpus.unique_features.to_string() +
",\"unique_signatures\":" +
stats.final_corpus.unique_signatures.to_string() +
",\"unique_failures\":" +
stats.final_corpus.unique_failures.to_string() +
"}}"
}
///|
fn event_json(event : CampaignEvent) -> String {
"{" +
"\"execution\":" +
event.execution.to_string() +
",\"input_bytes\":" +
event.input_bytes.to_string() +
",\"corpus_entries\":" +
event.corpus_entries.to_string() +
",\"kind\":" +
replay_json_quote(event_name(event.kind)) +
"}"
}
///|
pub fn CampaignResult::json_report(self : CampaignResult) -> String {
let corpus : Array[String] = []
for entry in self.corpus {
corpus.push(corpus_entry_json(entry))
}
let failures : Array[String] = []
for replay in self.failures {
failures.push(replay.encode_json())
}
let events : Array[String] = []
for event in self.events {
events.push(event_json(event))
}
"{" +
"\"schema_version\":1," +
"\"statistics\":" +
campaign_stats_json(self.statistics) +
",\"corpus\":[" +
corpus.join(",") +
"],\"failures\":[" +
failures.join(",") +
"],\"events\":[" +
events.join(",") +
"]}"
}
///|
pub(all) struct StrategyEvidence {
name : String
executions : Int
unique_features : Int
unique_signatures : Int
unique_failures : Int
corpus_entries : Int
} derive(Debug, Eq)
///|
pub fn CampaignResult::strategy_evidence(
self : CampaignResult,
name : String,
) -> StrategyEvidence {
{
name,
executions: self.statistics.completed_executions,
unique_features: self.statistics.final_corpus.unique_features,
unique_signatures: self.statistics.final_corpus.unique_signatures,
unique_failures: self.statistics.unique_failures,
corpus_entries: self.statistics.final_corpus.entries,
}
}
///|
pub fn compare_strategies(values : Array[StrategyEvidence]) -> String {
let lines : Array[String] = [
"| Strategy | Executions | Features | Signatures | Failures | Corpus |", "| --- | ---: | ---: | ---: | ---: | ---: |",
]
for value in values {
lines.push(
"| " +
markdown_escape(value.name) +
" | " +
value.executions.to_string() +
" | " +
value.unique_features.to_string() +
" | " +
value.unique_signatures.to_string() +
" | " +
value.unique_failures.to_string() +
" | " +
value.corpus_entries.to_string() +
" |",
)
}
lines.join("\n") + "\n"
}