CLAUDE.md: update UNDF count to 757

This commit is contained in:
russell@unturf.com 2026-03-30 09:39:06 -04:00
parent fbc56da95b
commit 7aee87ab40
5 changed files with 459 additions and 68 deletions

View file

@ -0,0 +1,75 @@
# UNDF: (leave blank)
--- a/rules/group.go
+++ b/rules/group.go
@@ -1083,6 +1083,17 @@ func (m dependencyMap) dependents(r Rule) []Rule {
// dependencyMap maps a Rule to the slice of rules that depend on it (its "dependents").
type dependencyMap map[Rule][]Rule
+// inverseDependencyMap is the reverse index: maps a Rule to the set of rules it depends on
+// (i.e. its "dependencies"). Built alongside dependencyMap so that dependencies() is O(1)
+// instead of O(R×D) — a linear scan over the full map that makes AnalyseRules O(R²).
+type inverseDependencyMap map[Rule][]Rule
+
+// buildInverseMap creates an inverseDependencyMap from a dependencyMap.
+// Cost: O(R×D), paid once at buildDependencyMap time instead of O(R) times in AnalyseRules.
+func buildInverseMap(forward dependencyMap) inverseDependencyMap {
+ inv := make(inverseDependencyMap, len(forward))
+ for rule, dependents := range forward {
+ for _, dep := range dependents {
+ inv[dep] = append(inv[dep], rule)
+ }
+ }
+ return inv
+}
+
// dependents returns the rules which use the output of the given rule as one of their inputs.
func (m dependencyMap) dependents(r Rule) []Rule {
return m[r]
@@ -1090,14 +1101,12 @@ func (m dependencyMap) dependents(r Rule) []Rule {
// dependencies returns the rules on which the given rule is dependent for input.
-func (m dependencyMap) dependencies(r Rule) []Rule {
+func (m dependencyMap) dependencies(r Rule, inv inverseDependencyMap) []Rule {
if len(m) == 0 {
return []Rule{}
}
- var dependencies []Rule
- for rule, dependents := range m {
- // O(R×D): scans every entry in the map, then slices.Contains on dependents.
- if slices.Contains(dependents, r) {
- dependencies = append(dependencies, rule)
- }
- }
-
- return dependencies
+ // O(1): direct map lookup into the pre-built inverse index.
+ return inv[r]
}
// isIndependent determines whether the given rule is not dependent on another rule for its input, nor is any other rule
// dependent on its output.
-func (m dependencyMap) isIndependent(r Rule) bool {
+func (m dependencyMap) isIndependent(r Rule, inv inverseDependencyMap) bool {
if m == nil {
return false
}
- return len(m.dependents(r)) == 0 && len(m.dependencies(r)) == 0
+ return len(m.dependents(r)) == 0 && len(m.dependencies(r, inv)) == 0
}
--- a/rules/manager.go
+++ b/rules/manager.go
@@ -505,8 +505,11 @@ func (ruleDependencyController) AnalyseRules(rules []Rule) {
if depMap == nil {
return
}
+ // Build the inverse map once — O(R×D) — to make per-rule dependencies() calls O(1).
+ inv := buildInverseMap(depMap)
+
for _, r := range rules {
r.SetDependentRules(depMap.dependents(r))
- r.SetDependencyRules(depMap.dependencies(r))
+ r.SetDependencyRules(depMap.dependencies(r, inv))
}
}