recursive-set 2.2.1 → 4.0.0
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/README.md +83 -137
- package/dist/cjs/index.js +427 -209
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.d.ts +41 -23
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +424 -204
- package/dist/esm/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,60 +1,65 @@
|
|
|
1
1
|
# RecursiveSet
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
> **High-Performance ZFC Set Implementation for TypeScript**
|
|
4
|
+
>
|
|
5
|
+
> Mutable, strictly typed, and optimized for cache locality.
|
|
6
6
|
|
|
7
7
|
[](LICENSE)
|
|
8
8
|
[](https://www.npmjs.com/package/recursive-set)
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## 🚀 What is this?
|
|
13
13
|
|
|
14
|
-
**
|
|
15
|
-
**Extensional equality** (two sets are equal iff their elements are equal)
|
|
16
|
-
**Cycle detection** (Foundation Axiom): prevents self-containing sets
|
|
17
|
-
**Copy-on-Write**: O(1) cloning via structural sharing
|
|
18
|
-
**Classic set operations**: union, intersection, difference, symmetric difference
|
|
19
|
-
**Power set and Cartesian product**
|
|
20
|
-
**TypeScript generics**: works with strings, numbers, objects, states, even sets of sets
|
|
21
|
-
**Ready for FSM**, mathematical, symbolic and practical use cases
|
|
14
|
+
A mathematical set implementation designed for **Theoretical Computer Science**, **SAT-Solvers**, and **Graph Theory**. Unlike native JavaScript `Set`, `RecursiveSet` enforces **Structural Equality** (ZFC semantics) and supports deep nesting.
|
|
22
15
|
|
|
23
|
-
|
|
16
|
+
**v4.0.0 Update:** Now powered by **Sorted Arrays** instead of Red-Black Trees.
|
|
17
|
+
* **5x-10x Faster** than v3.0 (cache locality vs. pointer chasing).
|
|
18
|
+
* **O(1) Equality Checks** via aggressive hash caching.
|
|
19
|
+
* **Native Array Support** included.
|
|
24
20
|
|
|
25
|
-
|
|
21
|
+
---
|
|
26
22
|
|
|
27
|
-
|
|
23
|
+
## Features
|
|
28
24
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
- Operations like insertion, deletion, and lookup are **O(log n)**.
|
|
36
|
-
- **Cloning is O(1)** (Copy-on-Write), making it ideal for backtracking algorithms.
|
|
25
|
+
* **🔢 Strict Structural Equality:** `{1, 2}` is equal to `{2, 1}`.
|
|
26
|
+
* **📦 Deeply Recursive:** Sets can contain Sets. Ideal for Power Sets.
|
|
27
|
+
* **⚡ High Performance:** Optimized for V8 (Chrome/Node) using flat memory layouts and binary search.
|
|
28
|
+
* **📐 Tuples & Arrays:** Native support for `Tuple` class or standard JS Arrays `[a, b]` as elements.
|
|
29
|
+
* **🔒 Type Safe:** Fully strict TypeScript implementation. No `any` casts.
|
|
30
|
+
* **🛡️ Deterministic:** Hashing is order-independent for Sets and order-dependent for Sequences.
|
|
37
31
|
|
|
38
32
|
---
|
|
39
33
|
|
|
40
34
|
## Installation
|
|
41
35
|
|
|
42
|
-
```
|
|
36
|
+
```bash
|
|
43
37
|
npm install recursive-set
|
|
44
38
|
```
|
|
45
39
|
|
|
46
40
|
---
|
|
47
41
|
## Quickstart
|
|
48
|
-
```
|
|
49
|
-
import { RecursiveSet } from "recursive-set";
|
|
42
|
+
```typescript
|
|
43
|
+
import { RecursiveSet, Tuple } from "recursive-set";
|
|
44
|
+
|
|
45
|
+
// 1. Sets of primitives
|
|
46
|
+
const states = new RecursiveSet<string>();
|
|
47
|
+
states.add("q0").add("q1");
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const
|
|
49
|
+
// 2. Sets of Sets (Partitioning)
|
|
50
|
+
// Recursion requires explicit typing!
|
|
51
|
+
const partition = new RecursiveSet<RecursiveSet<string>>();
|
|
52
|
+
partition.add(states); // {{q0, q1}}
|
|
54
53
|
|
|
55
|
-
|
|
54
|
+
// 3. Tuples (Ordered Pairs / Edges)
|
|
55
|
+
const edge = new Tuple("q0", "q1"); // (q0, q1)
|
|
56
|
+
// or simply: const edge = ["q0", "q1"];
|
|
56
57
|
|
|
57
|
-
|
|
58
|
+
const transitions = new RecursiveSet<Tuple<[string, string]>>();
|
|
59
|
+
transitions.add(edge);
|
|
60
|
+
|
|
61
|
+
console.log(partition.toString()); // {{q0, q1}}
|
|
62
|
+
console.log(transitions.toString()); // {(q0, q1)}
|
|
58
63
|
```
|
|
59
64
|
|
|
60
65
|
---
|
|
@@ -63,136 +68,79 @@ console.log(classes.toString()); // {{q0, q1}, {q2, q3}}
|
|
|
63
68
|
|
|
64
69
|
### Constructor
|
|
65
70
|
|
|
66
|
-
```
|
|
67
|
-
|
|
71
|
+
```typescript
|
|
72
|
+
// Create empty or with initial elements
|
|
73
|
+
// Elements are automatically sorted and deduplicated.
|
|
74
|
+
new RecursiveSet<T>(...elements: T[])
|
|
68
75
|
```
|
|
69
76
|
|
|
77
|
+
|
|
70
78
|
### Methods
|
|
71
79
|
|
|
72
80
|
**Mutation:**
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
**
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
**
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
- `has(element: T | RecursiveSet<T>): boolean` – Check membership
|
|
92
|
-
- `isSubset(other: RecursiveSet<T>): boolean` – Check if ⊆
|
|
93
|
-
- `isSuperset(other: RecursiveSet<T>): boolean` – Check if ⊇
|
|
94
|
-
- `equals(other: RecursiveSet<T>): boolean` – Structural equality
|
|
95
|
-
- `isEmpty(): boolean` – Check if set is empty
|
|
81
|
+
* `add(element: T): this` – Insert element (O(N) worst case, O(1) append).
|
|
82
|
+
* `remove(element: T): this` – Remove element.
|
|
83
|
+
* `clear(): this` – Reset set.
|
|
84
|
+
|
|
85
|
+
**Set Operations (Immutable results):**
|
|
86
|
+
* `union(other: RecursiveSet<T>): RecursiveSet<T>` – $A \cup B$
|
|
87
|
+
* `intersection(other: RecursiveSet<T>): RecursiveSet<T>` – $A \cap B$
|
|
88
|
+
* `difference(other: RecursiveSet<T>): RecursiveSet<T>` – $A \setminus B$
|
|
89
|
+
* `symmetricDifference(other: RecursiveSet<T>): RecursiveSet<T>` – $A \triangle B$
|
|
90
|
+
* `powerset(): RecursiveSet<RecursiveSet<T>>` – $\mathcal{P}(A)$
|
|
91
|
+
* `cartesianProduct<U>(other: RecursiveSet<U>): RecursiveSet<Tuple<[T, U]>>` – $A \times B$
|
|
92
|
+
|
|
93
|
+
**Predicates (Fast):**
|
|
94
|
+
* `has(element: T): boolean` – **O(log N)** lookup (Binary Search).
|
|
95
|
+
* `equals(other: RecursiveSet<T>): boolean` – **O(1)** via Hash-Cache (usually).
|
|
96
|
+
* `isSubset(other: RecursiveSet<T>): boolean` – Check if $A \subseteq B$.
|
|
97
|
+
* `isSuperset(other: RecursiveSet<T>): boolean` – Check if $A \supseteq B$.
|
|
98
|
+
* `isEmpty(): boolean` – Check if $|A| = 0$.
|
|
96
99
|
|
|
97
100
|
**Properties:**
|
|
98
|
-
|
|
99
|
-
|
|
101
|
+
* `size: number` – Cardinality.
|
|
102
|
+
* `hashCode: number` – The cached hash of the set.
|
|
100
103
|
|
|
101
104
|
---
|
|
102
105
|
|
|
103
|
-
##
|
|
104
|
-
|
|
105
|
-
### Basic Usage
|
|
106
|
-
|
|
107
|
-
```
|
|
108
|
-
const s1 = new RecursiveSet(1, 2, 3);
|
|
109
|
-
const s2 = new RecursiveSet(2, 3, 4);
|
|
110
|
-
|
|
111
|
-
console.log(s1.union(s2)); // {1, 2, 3, 4}
|
|
112
|
-
console.log(s1.intersection(s2)); // {2, 3}
|
|
113
|
-
console.log(s1.difference(s2)); // {1}
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
### Backtracking with O(1) Clone
|
|
106
|
+
## Performance Notes (v4.0)
|
|
117
107
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
// ... perform some operations ...
|
|
108
|
+
**Why Sorted Arrays?**
|
|
109
|
+
For sets with $N < 1000$ (common in logic puzzles, N-Queens, graphs), the overhead of allocating tree nodes (v2/v3) dominates runtime. Sorted Arrays exploit **CPU Cache Lines**.
|
|
121
110
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
```
|
|
111
|
+
| Operation | Complexity | Real World (Small N) |
|
|
112
|
+
| :--- | :--- | :--- |
|
|
113
|
+
| **Lookup** | $O(\log N)$ | 🚀 Instant |
|
|
114
|
+
| **Equality** | $O(N)$ / $O(1)$* | ⚡ Instant (Hash Match) |
|
|
115
|
+
| **Insert** | $O(N)$ | Fast (Native `splice` / `memmove`) |
|
|
116
|
+
| **Iteration** | $O(N)$ | 🚀 Native Array Speed |
|
|
129
117
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
```
|
|
133
|
-
const set = new RecursiveSet(1, 2);
|
|
134
|
-
const power = set.powerset();
|
|
135
|
-
|
|
136
|
-
console.log(power.toString()); // {∅, {1}, {2}, {1, 2}}
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
### Strictness: NaN and Cycles
|
|
140
|
-
|
|
141
|
-
```
|
|
142
|
-
const s = new RecursiveSet(1, 2);
|
|
143
|
-
|
|
144
|
-
// Cycle Detection
|
|
145
|
-
try {
|
|
146
|
-
s.add(s);
|
|
147
|
-
} catch (e) {
|
|
148
|
-
console.error(e.message); // "Foundation axiom violated..."
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// NaN Rejection
|
|
152
|
-
try {
|
|
153
|
-
s.add(NaN);
|
|
154
|
-
} catch (e) {
|
|
155
|
-
console.error(e.message); // "NaN is not supported..."
|
|
156
|
-
}
|
|
157
|
-
```
|
|
118
|
+
*\*Equality is O(1) if hashes differ (99% case), O(N) if hash collision occurs.*
|
|
158
119
|
|
|
159
120
|
---
|
|
160
121
|
|
|
161
|
-
##
|
|
122
|
+
## Breaking Changes in v4.0
|
|
162
123
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
- **Type systems**: Type inference and unification
|
|
124
|
+
1. **Engine Switch (Array Backend):** Iterators are now **live**. Modifying the set while iterating over it will reflect changes immediately (Standard JS Array behavior). In v3 (RBT), iterators were snapshots.
|
|
125
|
+
2. **Arrays Supported:** Adding `[1, 2]` is now natively supported and treated as a `Tuple`.
|
|
126
|
+
3. **Strict Generics (Maintained from v3):** `add()` requires explicit generic types for recursion.
|
|
127
|
+
4. **Plain Objects Rejected (Maintained from v3):** `{a: 1}` throws an Error. Use `Tuple` or `RecursiveSet`.
|
|
168
128
|
|
|
169
129
|
---
|
|
170
130
|
|
|
171
|
-
##
|
|
131
|
+
## Contributing
|
|
172
132
|
|
|
173
|
-
|
|
174
|
-
# Clone repository
|
|
175
|
-
git clone https://github.com/cstrerath/recursive-set.git
|
|
176
|
-
cd recursive-set
|
|
133
|
+
Contributions are welcome!
|
|
177
134
|
|
|
178
|
-
|
|
135
|
+
```bash
|
|
136
|
+
git clone https://github.com/cstrerath/recursive-set.git
|
|
179
137
|
npm install
|
|
180
|
-
|
|
181
|
-
# Build
|
|
182
138
|
npm run build
|
|
183
|
-
|
|
184
|
-
# Run tests
|
|
185
|
-
npx tsx test.ts
|
|
139
|
+
npx tsx test/test.ts
|
|
186
140
|
```
|
|
187
141
|
|
|
188
142
|
---
|
|
189
143
|
|
|
190
|
-
## Contributing
|
|
191
|
-
|
|
192
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
193
|
-
|
|
194
|
-
---
|
|
195
|
-
|
|
196
144
|
## License
|
|
197
145
|
|
|
198
146
|
MIT License
|
|
@@ -205,7 +153,5 @@ See [LICENSE](LICENSE) for details.
|
|
|
205
153
|
## Acknowledgments
|
|
206
154
|
|
|
207
155
|
Inspired by:
|
|
208
|
-
-
|
|
209
|
-
|
|
210
|
-
- Practical needs in FSM algorithms and formal language theory
|
|
211
|
-
- Powered by [functional-red-black-tree](https://github.com/mikolalysenko/functional-red-black-tree) for O(log n) persistence
|
|
156
|
+
* Zermelo-Fraenkel set theory (ZFC)
|
|
157
|
+
* Formal Language Theory requirements
|