Skip to content

Commit

Permalink
DIRTY [skip ci]
Browse files Browse the repository at this point in the history
  • Loading branch information
tstelzer committed May 4, 2024
1 parent cc7850a commit 3ee432d
Show file tree
Hide file tree
Showing 19 changed files with 537 additions and 563 deletions.
23 changes: 12 additions & 11 deletions workspace/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import * as PT from '@creative-introvert/prediction-testing';
import * as P from './prelude.js';

export type Config<I = unknown, O = unknown, T = unknown> = {
testSuite: PT.TestSuite<I, O, T>;
testSuite: PT.Test.TestSuite<I, O, T>;
dirPath: string;
filePostfix: string;
testSuiteName: string;
displayConfig?: Partial<PT.Show.DisplayConfig> | undefined;
displayConfig?: Partial<PT.DisplayConfig.DisplayConfig> | undefined;
showInput?: undefined | ((input: I) => string);
showExpected?: undefined | ((expected: T) => string);
showResult?: undefined | ((result: O, expected: T) => string);
Expand Down Expand Up @@ -38,13 +38,13 @@ const labels = Options.text('labels').pipe(

const createFilterLabel =
(maybeLables: P.O.Option<readonly PT.Classify.Label[]>) =>
(tr: PT.TestResult<unknown, unknown, unknown>) =>
(tr: PT.Test.TestResult<unknown, unknown, unknown>) =>
P.O.match(maybeLables, {
onNone: () => true,
onSome: labels => labels.includes(tr.label),
});

const TestRunSchema = P.Schema.parseJson(PT.TestRunSchema);
const TestRunSchema = P.Schema.parseJson(PT.Test.TestRunSchema);

const readPreviousTestRun = P.E.gen(function* () {
const {testSuiteName, dirPath, filePostfix} = yield* Config;
Expand All @@ -67,9 +67,9 @@ const summarize = Command.make('summarize', {labels}, ({labels}) =>

const filterLabel = createFilterLabel(labels);
const previousTestRun = yield* readPreviousTestRun;
const testRun = yield* PT.testAll(testSuite).pipe(
const testRun = yield* PT.Test.all(testSuite).pipe(
P.Stream.filter(filterLabel),
PT.runFoldEffect,
PT.Test.runFoldEffect,
);

if (testRun.testResultIds.length === 0) {
Expand Down Expand Up @@ -114,7 +114,7 @@ const diff = Command.make('diff', {ci}, ({ci}) =>

const previousTestRun = yield* readPreviousTestRun;

const testRun = yield* PT.testAll(testSuite).pipe(
const testRun = yield* PT.Test.all(testSuite).pipe(
P.Stream.filter(next =>
P.pipe(
P.O.flatMap(previousTestRun, prevTestRun =>
Expand All @@ -128,7 +128,7 @@ const diff = Command.make('diff', {ci}, ({ci}) =>
P.O.getOrElse(() => true),
),
),
PT.runFoldEffect,
PT.Test.runFoldEffect,
);

if (testRun.testResultIds.length === 0) {
Expand All @@ -145,8 +145,7 @@ const diff = Command.make('diff', {ci}, ({ci}) =>
}),
'',
PT.Show.diff({
testRun,
diff: PT.diff({testRun, previousTestRun}),
diff: PT.Test.diff({testRun, previousTestRun}),
}),
].join('\n'),
);
Expand All @@ -164,7 +163,9 @@ const write = Command.make('write', {}, () =>

yield* fs.makeDirectory(dirPath, {recursive: true});

const testRun = yield* PT.testAll(testSuite).pipe(PT.runFoldEffect);
const testRun = yield* PT.Test.all(testSuite).pipe(
PT.Test.runFoldEffect,
);
const filePath = `${dirPath}/${testSuiteName}.${filePostfix}.json`;
yield* fs.writeFileString(filePath, JSON.stringify(testRun, null, 2));
yield* P.Console.log(`Wrote to "${filePath}"`);
Expand Down
103 changes: 4 additions & 99 deletions workspace/core/src/Classify.ts
Original file line number Diff line number Diff line change
@@ -1,109 +1,14 @@
import * as P from './prelude.js';
import * as internal from './internal/Classify.js';

export const Label = {
TN: 'TN',
TP: 'TP',
FP: 'FP',
FN: 'FN',
} as const;
export type Label = 'TP' | 'TN' | 'FP' | 'FN';

export type Label = (typeof Label)[keyof typeof Label];

export const LabelSchema: P.Schema.Schema<Label> = P.Schema.Literal(
'TP',
'TN',
'FP',
'FN',
);

export const defaultIsNil = <I>(x: I): boolean => x === null || x === undefined;
export const values = internal.values;

export type Classify<O, T> = (output: O, expected: T) => Label;

export const make =
<O, T>(
isEqual: (output: O, expected: T) => boolean,
isOutputNil: (output: O) => boolean = defaultIsNil,
isExpectedNil: (expected: T) => boolean = defaultIsNil,
): Classify<O, T> =>
(output, expected) => {
const eq = isEqual(output, expected);
const oNil = isOutputNil(output);
const eNil = isExpectedNil(expected);

if (oNil && eNil) {
return Label.TN;
}

if (!oNil && !eNil && eq) {
return Label.TP;
}

if ((!oNil && eNil) || (!oNil && !eNil && !eq)) {
return Label.FP;
}

return Label.FN;
};

export type Stats = Record<Label, number> & {
precision: number;
recall: number;
};

export const StatsSchema: P.Schema.Schema<Stats> = P.Schema.Struct({
TP: P.Schema.Number,
TN: P.Schema.Number,
FP: P.Schema.Number,
FN: P.Schema.Number,
precision: P.Schema.Number,
recall: P.Schema.Number,
});

export const Stats = {
empty: (): Stats => ({
TP: 0,
TN: 0,
FP: 0,
FN: 0,
precision: 0,
recall: 0,
}),
};

export const precision = (m: Stats): number => {
const r = m.TP / (m.TP + m.FP);
return isNaN(r) ? 0 : r;
};

export const recall = (m: Stats): number => {
const r = m.TP / (m.TP + m.FN);
return isNaN(r) ? 0 : r;
};

export const min = (xs: number[]): number =>
xs.reduce((min, x) => (x < min ? x : min), Infinity);

export const max = (xs: number[]): number =>
xs.reduce((max, x) => (x > max ? x : max), -Infinity);

export const mean = (xs: number[]): number | undefined => {
if (xs.length === 0) {
return undefined;
}

return xs.reduce((a, b) => a + b, 0) / xs.length;
};

export const median = (xs: number[]): number | undefined => {
if (xs.length === 0) {
return undefined;
}

const sorted = xs.slice().sort((a, b) => a - b);
const index = Math.floor(sorted.length / 2);

return sorted.length % 2 === 0
? (sorted[index - 1] + sorted[index]) / 2
: sorted[index];
};
export const LabelSchema = internal.LabelSchema;
21 changes: 21 additions & 0 deletions workspace/core/src/DisplayConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as internal from './internal/DisplayConfig.js';

export type DisplayConfig = {
/** @default true */
colorize: boolean;
/** @default 2 */
columnPadding: number;
corner: string;
cornerLeft: string;
cornerRight: string;
cornerTop: string;
cornerTopLeft: string;
cornerTopRight: string;
cornerBottomLeft: string;
cornerBottomRight: string;
cornerBottom: string;
horizontal: string;
vertical: string;
};

export const makeDefault = internal.makeDefault;
2 changes: 0 additions & 2 deletions workspace/core/src/Json.ts

This file was deleted.

73 changes: 69 additions & 4 deletions workspace/core/src/Show.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,69 @@
export {summarize} from './Show/summarize.js';
export {diff} from './Show/diff.js';
export {stats} from './Show/stats.js';
export {DisplayConfig} from './Show/DisplayConfig.js';
import type {Stats} from './Classify.js';
import type {Diff} from './Test.js';
import type {TestRun} from './internal/Test.js';
import type * as P from './prelude.js';

export {summarize} from './internal/summarize.js';
export {diff} from './internal/diff.js';
export {stats} from './internal/stats.js';

export type DiffContext = {
diff: Diff;
};

export type DiffColumnNames =
| 'TP'
| 'TN'
| 'FP'
| 'FN'
| 'precision'
| 'recall';

export type DiffColumn = {
name: DiffColumnNames;
label: string;
make: (ctx: DiffContext) => string[];
};

export type StatsContext = {
stats: Stats;
};

export type StatsColumnNames =
| 'TP'
| 'TN'
| 'FP'
| 'FN'
| 'precision'
| 'recall';

export type StatsColumn = {
name: StatsColumnNames;
label: string;
make: (ctx: StatsContext) => string[];
};

export type SummarizeContext = {
i: number;
ids: string[];
testRun: TestRun;
previousTestRun: P.O.Option<TestRun>;
};

export type SummarizeColumnNames =
| 'index'
| 'hash'
| 'input'
| 'tags'
| 'label'
| 'expected'
| 'result'
| 'result_diff'
| 'prev_result'
| 'prev_result_diff';

export type SummarizeColumn = {
name: SummarizeColumnNames;
label: string;
make: (ctx: SummarizeContext) => string[];
};
35 changes: 0 additions & 35 deletions workspace/core/src/Show/DisplayConfig.ts

This file was deleted.

Loading

0 comments on commit 3ee432d

Please sign in to comment.