mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
Cross-tabulates the properties that fired against the human verdict, one cell per implementation, over a sweep whose implementations all passed their own generated tests. An implementation that failed to build, has no usable run, or carries no filed verdict is listed as missing data rather than counted as a clean cell. Landing the package in one commit because the intermediate splits would not link.
170 lines
5.7 KiB
Go
170 lines
5.7 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"maps"
|
|
"slices"
|
|
"strconv"
|
|
"strings"
|
|
"text/tabwriter"
|
|
)
|
|
|
|
// labelledMatrix is one row of a printed matrix: the whole sample, or one model.
|
|
type labelledMatrix struct {
|
|
Label string
|
|
Value clauseMatrix
|
|
Excluded int
|
|
}
|
|
|
|
func writeReport(outcome result, out io.Writer) {
|
|
fmt.Fprintln(out, "unit: implementation whose own suite passed, scored on whether a property fired and on the reviewer's overall verdict")
|
|
fmt.Fprintln(out, "an implementation with no cell is missing data and is listed separately, never counted as a clean run")
|
|
fmt.Fprintln(out)
|
|
writeTable(out, []string{"group", "scored", "true pos", "false pos", "false neg", "true neg", "precision", "recall", "no cell"},
|
|
func(add func(...string)) {
|
|
for _, row := range implementationRows(outcome) {
|
|
add(
|
|
row.Label,
|
|
strconv.Itoa(row.Value.Scored),
|
|
strconv.Itoa(row.Value.TruePositive),
|
|
strconv.Itoa(row.Value.FalsePositive),
|
|
strconv.Itoa(row.Value.FalseNegative),
|
|
strconv.Itoa(row.Value.TrueNegative),
|
|
formatRatio(row.Value.Precision),
|
|
formatRatio(row.Value.Recall),
|
|
strconv.Itoa(row.Excluded),
|
|
)
|
|
}
|
|
})
|
|
|
|
fmt.Fprintln(out)
|
|
fmt.Fprintln(out, "clause pairs are an implementation against one of R1 to R20, scored through the declared property-to-clause mapping")
|
|
fmt.Fprintln(out, "cannot tell is the reviewer's specification-error answer and is evidence neither way")
|
|
fmt.Fprintln(out, "unevaluated is a clause whose every covering property a never-located surface left unrunnable: a portability miss, not a cell")
|
|
writeTable(out, []string{"group", "scored", "true pos", "false pos", "false neg", "true neg",
|
|
"precision", "recall", "cannot tell", "unevaluated", "uncovered", "uncovered false neg"},
|
|
func(add func(...string)) {
|
|
for _, row := range clauseRows(outcome) {
|
|
add(
|
|
row.Label,
|
|
strconv.Itoa(row.Value.Scored),
|
|
strconv.Itoa(row.Value.TruePositive),
|
|
strconv.Itoa(row.Value.FalsePositive),
|
|
strconv.Itoa(row.Value.FalseNegative),
|
|
strconv.Itoa(row.Value.TrueNegative),
|
|
formatRatio(row.Value.Precision),
|
|
formatRatio(row.Value.Recall),
|
|
strconv.Itoa(row.Value.CannotTell),
|
|
strconv.Itoa(row.Value.UnevaluatedSurfaceMissed),
|
|
strconv.Itoa(row.Value.UncoveredScored),
|
|
strconv.Itoa(row.Value.UncoveredFalseNegative),
|
|
)
|
|
}
|
|
})
|
|
|
|
fmt.Fprintln(out)
|
|
writeTable(out, []string{"implementation", "model", "cell", "usable runs", "fired", "violated clauses", "cannot tell"},
|
|
func(add func(...string)) {
|
|
for _, row := range outcome.Outcomes {
|
|
add(
|
|
row.Implementation,
|
|
row.Model,
|
|
row.Cell,
|
|
strconv.Itoa(row.RunsUsable),
|
|
joinOrDash(row.FiredProperties),
|
|
joinOrDash(row.ViolatedClauses),
|
|
strconv.Itoa(len(row.CannotTellClauses)),
|
|
)
|
|
}
|
|
})
|
|
|
|
if len(outcome.Excluded) > 0 {
|
|
fmt.Fprintf(out, "\n%d implementation(s) carry no cell: missing data, never a clean run\n", len(outcome.Excluded))
|
|
writeTable(out, []string{"implementation", "model", "reason", "detail"}, func(add func(...string)) {
|
|
for _, entry := range outcome.Excluded {
|
|
add(entry.Implementation, orDash(entry.Model), entry.Reason, orDash(entry.Detail))
|
|
}
|
|
})
|
|
}
|
|
|
|
fmt.Fprintf(out, "\nspecification portability over the %d scored implementation(s): %d needed a locating adaptation\n",
|
|
outcome.Portability.Scored, outcome.Portability.WithUnlocatableSurface)
|
|
if len(outcome.Portability.BySurface) > 0 {
|
|
writeTable(out, []string{"surface never located", "implementations"}, func(add func(...string)) {
|
|
for _, surface := range slices.Sorted(maps.Keys(outcome.Portability.BySurface)) {
|
|
add(surface, strconv.Itoa(outcome.Portability.BySurface[surface]))
|
|
}
|
|
})
|
|
}
|
|
if len(outcome.Portability.SurfacesReadAsInconclusive) > 0 {
|
|
fmt.Fprintf(out, "a miss on %s cannot be told from that surface being legitimately absent, so neither counts against portability\n",
|
|
strings.Join(outcome.Portability.SurfacesReadAsInconclusive, ", "))
|
|
}
|
|
|
|
fmt.Fprintf(out, "\nclause coverage: %d mapped propert(ies) cover %d of %d clauses\n",
|
|
outcome.Coverage.MappedProperties, len(outcome.Coverage.ClausesCovered), clauseCount)
|
|
if len(outcome.Coverage.ClausesUncovered) > 0 {
|
|
fmt.Fprintf(out, "no property covers %s\n", strings.Join(outcome.Coverage.ClausesUncovered, ", "))
|
|
}
|
|
fmt.Fprintf(out, "review cost over the scored implementations: %d minutes\n", outcome.ReviewMinutes)
|
|
|
|
for _, note := range outcome.Notes {
|
|
fmt.Fprintf(out, "\nnote: %s\n", note)
|
|
}
|
|
}
|
|
|
|
func implementationRows(outcome result) []labelledMatrix {
|
|
rows := []labelledMatrix{{
|
|
Label: "all",
|
|
Value: clauseMatrix{matrix: outcome.Implementations},
|
|
Excluded: len(outcome.Excluded),
|
|
}}
|
|
for _, model := range outcome.ByModel {
|
|
rows = append(rows, labelledMatrix{
|
|
Label: model.Model,
|
|
Value: clauseMatrix{matrix: model.Implementations},
|
|
Excluded: model.Excluded,
|
|
})
|
|
}
|
|
return rows
|
|
}
|
|
|
|
func clauseRows(outcome result) []labelledMatrix {
|
|
rows := []labelledMatrix{{Label: "all", Value: outcome.Clauses}}
|
|
for _, model := range outcome.ByModel {
|
|
rows = append(rows, labelledMatrix{Label: model.Model, Value: model.Clauses})
|
|
}
|
|
return rows
|
|
}
|
|
|
|
func writeTable(out io.Writer, header []string, rows func(add func(...string))) {
|
|
writer := tabwriter.NewWriter(out, 0, 0, 2, ' ', 0)
|
|
fmt.Fprintln(writer, strings.Join(header, "\t"))
|
|
rows(func(cells ...string) {
|
|
fmt.Fprintln(writer, strings.Join(cells, "\t"))
|
|
})
|
|
writer.Flush()
|
|
}
|
|
|
|
func formatRatio(value *float64) string {
|
|
if value == nil {
|
|
return "n/a"
|
|
}
|
|
return strconv.FormatFloat(*value, 'f', 3, 64)
|
|
}
|
|
|
|
func joinOrDash(values []string) string {
|
|
if len(values) == 0 {
|
|
return "-"
|
|
}
|
|
return strings.Join(values, " ")
|
|
}
|
|
|
|
func orDash(value string) string {
|
|
if value == "" {
|
|
return "-"
|
|
}
|
|
return value
|
|
}
|