diff --git a/.jules/bolt.md b/.jules/bolt.md index 7b58f99..64cf4d1 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -2,14 +2,14 @@ **Learning:** Found nested loops inside the `OverviewTab` render cycle where `.find()` was being used inside a `.map()` to lookup nodes from a graph diff, turning it into an O(N*M) lookup. **Action:** Always verify if `.find()` or `.filter()` inside loops can be hoisted or converted into an O(1) hash map or `Map` using `useMemo` when looking up state in lists. -## 2024-03-30 - Deferred Value for Tree Filtering -**Learning:** In highly nested or complex recursive component structures (like `SmartFileExplorer` which recursively filters a repository file tree), real-time filtering tied to user input blocks the main React rendering thread, leading to noticeable typing latency. -**Action:** Use React's `useDeferredValue` hook on the search input query. This allows React to process the keystroke updates synchronously while rendering the expensive filtered list at a lower priority, keeping UI interactions snappy. - ## 2023-11-10 - [O(N*M) Loop Optimization in AnalysisTab] **Learning:** Found nested loops inside the `AnalysisTab` render cycle where `.find()` was being used inside a `.map()` to lookup nodes from a graph diff, turning it into an O(N*M) lookup. **Action:** Replaced `.find()` inside loops with an O(1) `Map` lookup using `useMemo` to create a `nodeById` map mapping node IDs to nodes. This is a recurring pattern in the visualization codebase. +## 2024-03-30 - Deferred Value for Tree Filtering +**Learning:** In highly nested or complex recursive component structures (like `SmartFileExplorer` which recursively filters a repository file tree), real-time filtering tied to user input blocks the main React rendering thread, leading to noticeable typing latency. +**Action:** Use React's `useDeferredValue` hook on the search input query. This allows React to process the keystroke updates synchronously while rendering the expensive filtered list at a lower priority, keeping UI interactions snappy. + ## 2024-11-20 - [O(N*M) Loop Optimization in LearningPathTab] **Learning:** Found nested loops inside the `LearningPathTab` render cycle event handlers (`onKeyDown`, `onClick`) where array `.find()` was being used inside a `.map()` to lookup target node IDs, turning it into an O(N*M) time complexity bottleneck for large codebases. **Action:** Replaced `.find()` inside the `.map()` loop with an O(1) `Map` lookup by pre-computing a `nodeById` map mapping node IDs to node IDs using `useMemo` at the component level. This reinforces the pattern of using memoized Hash Maps for list lookups in React components. @@ -26,3 +26,7 @@ **Action:** Replace multiple `.filter()` passes with a single `for` loop pass over the array utilizing a mutable tally counter struct, reducing iteration overhead and allocations to $O(N)$ exactly. - In backend data processing pipelines, avoid nested O(N) array operations (like `.find()` inside `.filter()`). Pre-compute a `Map` keyed by unique identifiers (e.g., `path`) for O(1) lookups to optimize performance and prevent O(N*M) bottlenecks. For example, converting array lookups inside incremental indexing mapping logic. + +## 2024-11-20 - [O(N*M) Loop Optimization in groupDependencies] +**Learning:** Found nested loops inside the `groupDependencies` algorithm where array `.filter()` was being used inside a `for` loop to match `scopedDependencies` to `dependencies` based on a composite string key, creating an O(N*M) time complexity bottleneck for large codebases and dependency trees. +**Action:** Replaced `.filter()` inside the loop with an O(1) `Map` lookup by pre-computing a map grouping `scopedDependencies` by their keys. This eliminates the inner O(M) loop, speeding it up significantly (reducing time complexity to O(N+M)). diff --git a/server/services/dependency-health.ts b/server/services/dependency-health.ts index a4c2593..945e494 100644 --- a/server/services/dependency-health.ts +++ b/server/services/dependency-health.ts @@ -53,6 +53,21 @@ function groupDependencies( ): readonly DependencyGroup[] { const grouped = new Map(); + // Performance Optimization (Bolt): + // Pre-compute a Map of scoped dependencies grouped by dependencyKey. + // This eliminates the need for an O(M) .filter() array lookup inside the + // O(N) loop below, reducing time complexity from O(N*M) to O(N+M). + const scopedByDepKey = new Map(); + for (const scoped of scopedDependencies) { + const key = dependencyKey(scoped); + let arr = scopedByDepKey.get(key); + if (!arr) { + arr = []; + scopedByDepKey.set(key, arr); + } + arr.push(scoped); + } + for (const dependency of dependencies) { const key = dependencyKey(dependency); const existing = grouped.get(key); @@ -60,7 +75,7 @@ function groupDependencies( grouped.set(key, { dependency, - scopedDependencies: scopedDependencies.filter((scopedDependency) => dependencyKey(scopedDependency) === key), + scopedDependencies: scopedByDepKey.get(key) || [], }); }