Optimise numeric type bounds with a single instruction - #970
Conversation
|
|
1 similar comment
|
|
There was a problem hiding this comment.
2 issues found across 21 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="test/evaluator/evaluator_2019_09.json">
<violation number="1" location="test/evaluator/evaluator_2019_09.json:11237">
P2: The exhaustive trace for type_number_bounded_exclusive_maximum is missing the type and minimum assertions. The schema has type:number, minimum:1 and exclusiveMaximum:3, and exhaustive mode is meant to preserve unfused behaviour (the sibling type_number_bounded/integer_lower_bound cases and the fused fast trace prove the type check runs first). As written the test claims exhaustive mode emits only AssertionLess, which contradicts that intent and either masks a coverage regression in exhaustive mode or is an incomplete/incorrect expectation that will mislead when the suite fails. Add the missing AssertionTypeStrictAny /type (and AssertionGreaterEqual /minimum) to pre, post and descriptions.</violation>
</file>
<file name="test/evaluator/evaluator_draft6.json">
<violation number="1" location="test/evaluator/evaluator_draft6.json:3501">
P3: The fused `AssertionType*Bounded` instruction replaces distinct per-keyword diagnostics with one generic message, so when the instance is the wrong JSON type (e.g. a string, or a number when `integer` is expected) the trace no longer explains the actual type mismatch (previously "expected to be of type integer but it was of type string/number"). This reduces the quality of evaluator trace output (e.g. `validate --trace`) for the most common numeric failures. If preserving type-aware messages matters, consider making `describe_numeric_bounds` append the offending instance type when the value is not a number/integral.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| }, | ||
| "exhaustive": { | ||
| "pre": [ | ||
| [ "AssertionLess", "/exclusiveMaximum", "#/exclusiveMaximum", "" ] |
There was a problem hiding this comment.
P2: The exhaustive trace for type_number_bounded_exclusive_maximum is missing the type and minimum assertions. The schema has type:number, minimum:1 and exclusiveMaximum:3, and exhaustive mode is meant to preserve unfused behaviour (the sibling type_number_bounded/integer_lower_bound cases and the fused fast trace prove the type check runs first). As written the test claims exhaustive mode emits only AssertionLess, which contradicts that intent and either masks a coverage regression in exhaustive mode or is an incomplete/incorrect expectation that will mislead when the suite fails. Add the missing AssertionTypeStrictAny /type (and AssertionGreaterEqual /minimum) to pre, post and descriptions.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At test/evaluator/evaluator_2019_09.json, line 11237:
<comment>The exhaustive trace for type_number_bounded_exclusive_maximum is missing the type and minimum assertions. The schema has type:number, minimum:1 and exclusiveMaximum:3, and exhaustive mode is meant to preserve unfused behaviour (the sibling type_number_bounded/integer_lower_bound cases and the fused fast trace prove the type check runs first). As written the test claims exhaustive mode emits only AssertionLess, which contradicts that intent and either masks a coverage regression in exhaustive mode or is an incomplete/incorrect expectation that will mislead when the suite fails. Add the missing AssertionTypeStrictAny /type (and AssertionGreaterEqual /minimum) to pre, post and descriptions.</comment>
<file context>
@@ -11171,5 +11171,157 @@
+ },
+ "exhaustive": {
+ "pre": [
+ [ "AssertionLess", "/exclusiveMaximum", "#/exclusiveMaximum", "" ]
+ ],
+ "post": [
</file context>
| "The integer value 50 was expected to be less than or equal to the integer 100", | ||
| "The integer value 50 was expected to be greater than or equal to the integer 0", | ||
| "The value was expected to be of type integer" | ||
| "The value was expected to be an integer within the given range" |
There was a problem hiding this comment.
P3: The fused AssertionType*Bounded instruction replaces distinct per-keyword diagnostics with one generic message, so when the instance is the wrong JSON type (e.g. a string, or a number when integer is expected) the trace no longer explains the actual type mismatch (previously "expected to be of type integer but it was of type string/number"). This reduces the quality of evaluator trace output (e.g. validate --trace) for the most common numeric failures. If preserving type-aware messages matters, consider making describe_numeric_bounds append the offending instance type when the value is not a number/integral.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At test/evaluator/evaluator_draft6.json, line 3501:
<comment>The fused `AssertionType*Bounded` instruction replaces distinct per-keyword diagnostics with one generic message, so when the instance is the wrong JSON type (e.g. a string, or a number when `integer` is expected) the trace no longer explains the actual type mismatch (previously "expected to be of type integer but it was of type string/number"). This reduces the quality of evaluator trace output (e.g. `validate --trace`) for the most common numeric failures. If preserving type-aware messages matters, consider making `describe_numeric_bounds` append the offending instance type when the value is not a number/integral.</comment>
<file context>
@@ -3504,19 +3492,13 @@
- "The integer value 50 was expected to be less than or equal to the integer 100",
- "The integer value 50 was expected to be greater than or equal to the integer 0",
- "The value was expected to be of type integer"
+ "The value was expected to be an integer within the given range"
]
},
</file context>
906572e to
0e01413
Compare
There was a problem hiding this comment.
1 issue found across 3 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="ports/javascript/index.mjs">
<violation number="1" location="ports/javascript/index.mjs:1377">
P3: When `target` is `NaN`, all comparison operators (`<`, `>`, `<=`, `>=`) return `false`. The `withinNumericBounds` function checks `target < minimum` and `target > maximum` — both evaluate to `false` for `NaN`, so neither guard triggers and the function returns `true`. This means `AssertionTypeNumberBounded` would accept `NaN` as a valid number within bounds, because `typeof NaN === 'number'` passes the type check and `withinNumericBounds` never rejects it.
`NaN` does not arise from `JSON.parse`, so this only affects programmatic API usage. However, the existing `AssertionTypeIntegerBounded` correctly filters `NaN` via `Number.isInteger(NaN) === false` before reaching `withinNumericBounds`. For consistency and defensive correctness, add a `Number.isNaN` guard.
Add `if (Number.isNaN(target)) return false;` at the top of `withinNumericBounds` to reject NaN early.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| return __result; | ||
| }; | ||
|
|
||
| function withinNumericBounds(target, range) { |
There was a problem hiding this comment.
P3: When target is NaN, all comparison operators (<, >, <=, >=) return false. The withinNumericBounds function checks target < minimum and target > maximum — both evaluate to false for NaN, so neither guard triggers and the function returns true. This means AssertionTypeNumberBounded would accept NaN as a valid number within bounds, because typeof NaN === 'number' passes the type check and withinNumericBounds never rejects it.
NaN does not arise from JSON.parse, so this only affects programmatic API usage. However, the existing AssertionTypeIntegerBounded correctly filters NaN via Number.isInteger(NaN) === false before reaching withinNumericBounds. For consistency and defensive correctness, add a Number.isNaN guard.
Add if (Number.isNaN(target)) return false; at the top of withinNumericBounds to reject NaN early.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At ports/javascript/index.mjs, line 1377:
<comment>When `target` is `NaN`, all comparison operators (`<`, `>`, `<=`, `>=`) return `false`. The `withinNumericBounds` function checks `target < minimum` and `target > maximum` — both evaluate to `false` for `NaN`, so neither guard triggers and the function returns `true`. This means `AssertionTypeNumberBounded` would accept `NaN` as a valid number within bounds, because `typeof NaN === 'number'` passes the type check and `withinNumericBounds` never rejects it.
`NaN` does not arise from `JSON.parse`, so this only affects programmatic API usage. However, the existing `AssertionTypeIntegerBounded` correctly filters `NaN` via `Number.isInteger(NaN) === false` before reaching `withinNumericBounds`. For consistency and defensive correctness, add a `Number.isNaN` guard.
Add `if (Number.isNaN(target)) return false;` at the top of `withinNumericBounds` to reject NaN early.</comment>
<file context>
@@ -1373,20 +1374,34 @@ function AssertionDivisible(instruction, instance, depth, template, evaluator) {
return __result;
};
+function withinNumericBounds(target, range) {
+ const minimum = range[0];
+ const maximum = range[1];
</file context>
|
@jviotti , The PR structurally reduces three common evaluator instructions to one in fast mode, creating a clear opportunity for lower dispatch and resolution overhead. It does not claim a specific measured percentage improvement. |
|
@HarshPopat23 I like the idea but I wonder if the single instruction for all cases is too complex. Some questions from me before we judge how to proceed:
My main concern is not your implementation, which looks good, but the layer of indirection in the |
|
Hi @jviotti, Thank you for the thoughtful feedback! That makes complete sense. I analyzed our 1. Integer vs Real distribution (
|
|
Awesome research! And exactly. Seems like the vast majority, by far, are integers with integer bounds only, so let's target one initial instruction on that specifically? Then the instruction will be tailor made and we should see a bigger perf difference |
|
@HarshPopat23 Note that I also sent you an invite as an external collaborator to this project. Once you accepted, can you send PRs through the repo directly and not through a fork? The result is the same, but our GitHub Action automation for displaying performance benchmarks on PRs does not work on forks for silly reasons... |
249825c to
7cd061b
Compare
Signed-off-by: HarshPopat23 <musichk61@gmail.com>
7cd061b to
bab9b5d
Compare
|
Thanks @jviotti for inviting ! |
Summary
type: number | integerwithminimum,maximum,exclusiveMinimum, andexclusiveMaximuminto a single bounded instruction in fast mode.AssertionTypeNumberBoundedand support optional/exclusive numeric bounds.This reduces common numeric schemas from multiple evaluator instructions to one bounded instruction.
Validation
blaze.compilerpassed.blaze.evaluator_trace_suitepassed.Closes #111