tla-ts 0.0.3-dev.79f7ed7 → 0.0.3-dev.b74f28c

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tla-ts",
3
- "version": "0.0.3-dev.79f7ed7",
3
+ "version": "0.0.3-dev.b74f28c",
4
4
  "description": "A TLA+ interpreter and model checker in TypeScript, 2× faster than TLC",
5
5
  "keywords": [
6
6
  "formal verification",
package/src/symmetry.ts CHANGED
@@ -9,6 +9,7 @@ import {
9
9
  isEnumerable,
10
10
  isFunctionValue,
11
11
  isModelValue,
12
+ isSameValue,
12
13
  isSetValue,
13
14
  toFiniteFunction,
14
15
  toFiniteSet,
@@ -163,7 +164,10 @@ const permuteValue = (value: Value, permutation: Permutation): Value => {
163
164
  if (size === 0 || size > CACHED_SIZE_LIMIT) return computePermutedValue(value, permutation);
164
165
  const cached = permutation.cache.get(value);
165
166
  if (cached !== undefined) return cached;
166
- const permuted = computePermutedValue(value, permutation);
167
+ const computed = computePermutedValue(value, permutation);
168
+ // A permutation often maps a value to an equal one. Keeping the original lets the comparison
169
+ // with the smallest state so far stop at identity.
170
+ const permuted = computed !== value && isSameValue(computed, value) ? value : computed;
167
171
  if (permutation.cacheSize >= permutation.cacheLimit) {
168
172
  permutation.cache = new WeakMap();
169
173
  permutation.cacheSize = 0;
@@ -184,7 +188,15 @@ const computePermutedValue = (value: ObjectValue, permutation: Permutation) => {
184
188
  const domain = permuteElements(functionValue.domain, permutation);
185
189
  const range = permuteElements(functionValue.range, permutation) ?? functionValue.range;
186
190
  if (domain) {
187
- return createFunction(domain.map((key, index): [Value, Value] => [key, range[index]]));
191
+ const permuted = createFunction(
192
+ domain.map((key, index): [Value, Value] => [key, range[index]]),
193
+ );
194
+ // A permutation often maps the domain to itself, such as a function over the symmetric set.
195
+ // Sharing the original domain array lets comparisons with other images skip the domain.
196
+ const isSameDomain = permuted.domain.every(
197
+ (key, index) => key === functionValue.domain[index],
198
+ );
199
+ return isSameDomain ? createSortedFunction(functionValue.domain, permuted.range) : permuted;
188
200
  }
189
201
  return range === functionValue.range
190
202
  ? functionValue
package/src/values.ts CHANGED
@@ -5,6 +5,7 @@ export interface ModelValue {
5
5
  kind: "ModelValue";
6
6
  name: string;
7
7
  type: string | undefined;
8
+ rank: number;
8
9
  }
9
10
 
10
11
  export interface SetValue {
@@ -264,6 +265,7 @@ const stringOrder = { ranks: Object.create(null) as Record<string, number>, size
264
265
  export const setStringOrder = (texts: Iterable<string>) => {
265
266
  stringOrder.ranks = Object.create(null);
266
267
  stringOrder.size = 0;
268
+ modelValues.clear();
267
269
  for (const text of texts) rankString(text);
268
270
  };
269
271
 
@@ -353,7 +355,7 @@ export const compareValues = (left: Value, right: Value): number => {
353
355
  if (left.type !== undefined && right.type !== undefined) {
354
356
  checkModelValueTypes(left, right, false);
355
357
  }
356
- return compareStrings(left.name, right.name);
358
+ return left.rank - right.rank;
357
359
  }
358
360
  if (leftKind === "ModelValue" || rightKind === "ModelValue") {
359
361
  checkModelValueTypes(left, right, false);
@@ -385,14 +387,15 @@ export const compareValues = (left: Value, right: Value): number => {
385
387
 
386
388
  const modelValues = new Map<string, ModelValue>();
387
389
 
390
+ // A check ranks every model value's name when it creates the value, and creates its own values.
388
391
  export const createModelValue = (name: string): ModelValue => {
389
- rankString(name);
390
392
  const known = modelValues.get(name);
391
393
  if (known) return known;
392
394
  const value: ModelValue = {
393
395
  kind: "ModelValue",
394
396
  name,
395
397
  type: name.length > 2 && name[1] === "_" ? name[0] : undefined,
398
+ rank: getStringRank(name),
396
399
  };
397
400
  modelValues.set(name, value);
398
401
  return value;
@@ -562,7 +565,7 @@ const equalsModelValueWith = (modelValue: ModelValue, other: Value) => {
562
565
 
563
566
  const compareModelValue = (left: ModelValue, right: Value) => {
564
567
  const type = getModelValueType(left);
565
- if (type === undefined) return isModelValue(right) ? compareStrings(left.name, right.name) : -1;
568
+ if (type === undefined) return isModelValue(right) ? left.rank - right.rank : -1;
566
569
  if (!isModelValue(right)) {
567
570
  throw new TlaEvaluationError(
568
571
  `Attempted to compare the typed model value ${formatValue(left)} and non-model value\n${formatValue(right)}`,
@@ -574,7 +577,7 @@ const compareModelValue = (left: ModelValue, right: Value) => {
574
577
  `Attempted to compare the differently-typed model values ${formatValue(left)} and ${formatValue(right)}`,
575
578
  );
576
579
  }
577
- return compareStrings(left.name, right.name);
580
+ return left.rank - right.rank;
578
581
  };
579
582
 
580
583
  const equalsModelValue = (left: ModelValue, right: Value) => {