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 CHANGED
@@ -1,60 +1,65 @@
1
1
  # RecursiveSet
2
2
 
3
- > Mutable, recursive set implementation for TypeScript – inspired by Cantor's and ZFC set theory.
4
-
5
- Supports arbitrary nesting, detects cycles (Foundation axiom), and includes all classic set operations (union, intersection, difference, powerset etc.).
3
+ > **High-Performance ZFC Set Implementation for TypeScript**
4
+ >
5
+ > Mutable, strictly typed, and optimized for cache locality.
6
6
 
7
7
  [![MIT License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
8
8
  [![npm version](https://img.shields.io/npm/v/recursive-set.svg)](https://www.npmjs.com/package/recursive-set)
9
9
 
10
10
  ---
11
11
 
12
- ## Features
12
+ ## 🚀 What is this?
13
13
 
14
- **Mutable, recursive sets** with arbitrary depth
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
- ## Implementation Details
21
+ ---
26
22
 
27
- This library enforces strict **ZFC Set Theory** semantics, differing from native JavaScript `Set`s:
23
+ ## Features
28
24
 
29
- - **Extensionality:** Two sets are considered equal if they contain the same elements, regardless of object reference identity.
30
- - Example: `new RecursiveSet(1).equals(new RecursiveSet(1))` is `true`.
31
- - Native `Set` would treat them as distinct objects.
32
- - **Foundation Axiom:** The library performs cycle detection to prevent sets from containing themselves (recursively).
33
- - **NaN Handling:** In strict ZFC semantics, `NaN` is not a valid element. Adding `NaN` will explicitly throw an error.
34
- - **Performance:** Internally powered by **Functional Red-Black Trees** (via `functional-red-black-tree`).
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
- const q0 = "q0", q1 = "q1";
52
- const eqClass = new RecursiveSet(q0, q1); // {q0, q1}
53
- const classes = new RecursiveSet(eqClass);
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
- classes.add(new RecursiveSet("q2", "q3")); // {{q0, q1}, {q2, q3}}
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
- console.log(classes.toString()); // {{q0, q1}, {q2, q3}}
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
- new RecursiveSet<T>(...elements: Array<T | RecursiveSet<T>>)
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
- - `add(element: T | RecursiveSet<T>): this` – Add element (chainable). **Throws if element is NaN.**
74
- - `remove(element: T | RecursiveSet<T>): this` – Remove element (chainable)
75
- - `clear(): this` – Remove all elements (chainable)
76
-
77
- **Snapshot:**
78
- - `clone(): RecursiveSet<T>` – Creates a shallow copy in **O(1)** time (Copy-on-Write).
79
-
80
- **Set Operations:**
81
- - `union(other: RecursiveSet<T>): RecursiveSet<T>` – A B
82
- - `intersection(other: RecursiveSet<T>): RecursiveSet<T>` – A ∩ B
83
- - `difference(other: RecursiveSet<T>): RecursiveSet<T>` – A \ B
84
- - `symmetricDifference(other: RecursiveSet<T>): RecursiveSet<T>` – A △ B
85
-
86
- **Advanced Operations:**
87
- - `powerset(): RecursiveSet<RecursiveSet<T>>`𝒫(A)
88
- - `cartesianProduct<U>(other: RecursiveSet<U>): RecursiveSet<RecursiveSet<T | U>>` A × B
89
-
90
- **Predicates:**
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
- - `size: number` – Cardinality |A|
99
- - `toString(): string` – Pretty print with and {}
101
+ * `size: number` – Cardinality.
102
+ * `hashCode: number` – The cached hash of the set.
100
103
 
101
104
  ---
102
105
 
103
- ## Examples
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
- const state = new RecursiveSet("init");
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
- // Create a checkpoint (O(1))
123
- const checkpoint = state.clone();
124
-
125
- state.add("newState");
126
- // If this path fails, simply revert:
127
- // state = checkpoint; (conceptually)
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
- ### Power Set
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
- ## Use Cases
122
+ ## Breaking Changes in v4.0
162
123
 
163
- - **Finite State Machine (FSM) minimization**: Equivalence classes of states
164
- - **Set theory algorithms**: Implement mathematical proofs and algorithms
165
- - **Graph algorithms**: Represent node sets and partitions
166
- - **Compiler design**: Symbol tables, scope analysis
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
- ## Development
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
- # Install dependencies
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
- - Cantor's set theory
209
- - Zermelo-Fraenkel set theory with the Axiom of Choice (ZFC)
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