Skip to content

egoughnour/complexity-hints

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

51 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Complexity Analysis System

First-class algorithmic complexity analysis for .NET β€” powered by Roslyn, the Master Theorem, and Akra-Bazzi.

See Big-O time and space complexity directly in your editor, backed by a rigorous five-phase analysis pipeline that extracts recurrences from C# source code and solves them symbolically.

VS Code CodeLens showing O(n) amortized time complexity and O(n) space complexity with 85% confidence, including amortized analysis explanation

CodeLens annotations show time complexity, space complexity, confidence scores, and explanatory tooltips β€” all computed from static analysis of your C# code.


Features

  • Automatic Big-O extraction from C# source via Roslyn AST/CFG analysis
  • Recurrence solving using the Master Theorem, Akra-Bazzi Theorem, and characteristic polynomial method
  • 150+ .NET BCL methods pre-mapped with documented complexities (List, Dictionary, LINQ, String, etc.)
  • Real-time IDE integration β€” VS Code CodeLens hints with debounced incremental analysis
  • Amortized, parallel, probabilistic, and memory complexity analysis
  • Hardware calibration β€” micro-benchmarking with curve fitting to verify theoretical predictions
  • Confidence scoring β€” every result carries a confidence level so you know when to trust it
  • 752 passing tests across unit, integration, and theorem-specific suites

Quick Start

using ComplexityAnalysis.Roslyn.Analysis;
using Microsoft.CodeAnalysis.CSharp;

// Parse your code
var tree = CSharpSyntaxTree.ParseText(sourceCode);
var compilation = CSharpCompilation.Create("Analysis", new[] { tree }, references);

// Analyze
var extractor = new RoslynComplexityExtractor(compilation.GetSemanticModel(tree));
var complexity = extractor.AnalyzeMethod(methodDeclaration);

Console.WriteLine($"Complexity: {complexity.ToBigONotation()}");
// => "Complexity: O(n log n)"

VS Code Extension

cd src/ComplexityAnalysis.IDE/vscode
npm install && npm run compile && npm run package
# Install the .vsix via "Extensions: Install from VSIX..."

Open any C# file and complexity annotations appear above each method signature.

Running Tests

cd src
dotnet test
# 752 passed, 42 skipped

Architecture

The system operates as a five-phase pipeline, each phase building on the previous to produce increasingly refined complexity estimates:

Source Code
    β”‚
    β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Phase A β€” Static Extraction                        β”‚
β”‚  Roslyn AST/CFG analysis, loop bounds, call graph,  β”‚
β”‚  BCL method lookup, mutual recursion detection       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Phase B β€” Recurrence Solving                       β”‚
β”‚  Master Theorem, Akra-Bazzi, linear recurrence      β”‚
β”‚  (characteristic polynomial), SymPy fallback         β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Phase C β€” Refinement                               β”‚
β”‚  Slack variable optimization, perturbation           β”‚
β”‚  expansion, numerical induction, confidence scoring  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Phase D β€” Speculative / IDE Integration            β”‚
β”‚  Incremental parsing, incomplete code tolerance,     β”‚
β”‚  stub detection, real-time CodeLens hints             β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Phase E β€” Hardware Calibration                     β”‚
β”‚  Micro-benchmarks, curve fitting, constant factor    β”‚
β”‚  estimation, hardware profiling                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    β”‚
    β–Ό
ComplexityExpression + ConfidenceScore

Component Libraries

Library Purpose
ComplexityAnalysis.Core Expression type hierarchy, recurrence types, variables, visitor pattern
ComplexityAnalysis.Roslyn Roslyn-based extractors, loop analysis, call graph, BCL mappings, speculative analysis
ComplexityAnalysis.Solver Theorem applicability, critical exponent solver, integral evaluator, refinement engine
ComplexityAnalysis.Calibration Micro-benchmarks, curve fitting, constant factor estimation, calibration persistence
ComplexityAnalysis.Engine Pipeline orchestration
ComplexityAnalysis.IDE VS Code extension (TypeScript) + .NET CLI tool

Theoretical Foundations

The solver implements three complementary approaches to recurrence solving. This section covers the mathematics behind each.

Master Theorem

For standard divide-and-conquer recurrences of the form:

$$T(n) = a \cdot T!\left(\frac{n}{b}\right) + f(n)$$

where a β‰₯ 1 subproblems of size n/b are created and f(n) is the non-recursive work. Let d = logb(a) be the critical exponent. The three cases are:

Case Condition Result
1 f(n) = O(nd βˆ’ Ξ΅) for some Ξ΅ > 0 Θ(nd)
2 f(n) = Θ(nd · logk n) Θ(nd · logk+1 n)
3 f(n) = Ω(nd + Ρ) with regularity Θ(f(n))

Case 3 requires the regularity condition: a Β· f(n/b) ≀ c Β· f(n) for some c < 1. The solver verifies this numerically by sampling at multiple input sizes.

Example: Merge sort's recurrence T(n) = 2T(n/2) + n falls into Case 2 with d = 1, k = 0, yielding Θ(n log n).

Limitations

The Master Theorem cannot handle recurrences with multiple recursive terms, variable a or b, or driving functions that fall between cases (e.g., nd / log n). For these, the system falls back to Akra-Bazzi.

Akra-Bazzi Theorem

The Akra-Bazzi theorem generalizes the Master Theorem to multi-term recurrences:

$$T(n) = \sum_{i=1}^{k} a_i \cdot T(b_i \cdot n + h_i(n)) + g(n)$$

where ai > 0, 0 < bi < 1, and |hi(n)| = O(n / logΒ² n).

Solving procedure:

  1. Find the unique critical exponent p satisfying:

$$\sum_{i=1}^{k} a_i \cdot b_i^{,p} = 1$$

The solver uses Newton-Raphson iteration with Brent's method as a fallback, bracketing the search interval for robust convergence.

  1. Evaluate the integral to obtain the closed-form solution:

$$T(n) = \Theta!\left(n^p \cdot \left(1 + \int_1^n \frac{g(u)}{u^{p+1}},du\right)\right)$$

For common forms of g(n), the integral has a closed-form result. When g(n) = nk: if k < p the integral is O(1); if k = p it gives O(log n); if k > p it contributes O(nk βˆ’ p).

Example: The recurrence T(n) = T(n/3) + T(2n/3) + n cannot be solved by the Master Theorem (two different subproblem sizes), but Akra-Bazzi yields p = 1 and the solution Θ(n log n).

Linear Recurrences (Characteristic Polynomial)

For subtract-style recurrences common in dynamic programming and backtracking:

$$T(n) = \sum_{i=1}^{k} a_i \cdot T(n - i) + f(n)$$

The solver forms the characteristic polynomial xk βˆ’ a₁xkβˆ’1 βˆ’ β‹― βˆ’ ak = 0 and finds its roots. The dominant root determines the asymptotic growth:

Root type Contribution
Distinct real root r c Β· rn
Repeated root r (multiplicity m) (cβ‚€ + c₁n + β‹― + cmβˆ’1nmβˆ’1) Β· rn
Complex conjugates Ξ± Β± Ξ²i rn Β· (c₁ cos(nΞΈ) + cβ‚‚ sin(nΞΈ))

For order-2 recurrences the solver uses the quadratic formula directly; for higher orders it uses companion matrix eigenvalue decomposition.

Example: The Fibonacci recurrence T(n) = T(n βˆ’ 1) + T(n βˆ’ 2) has characteristic equation xΒ² βˆ’ x βˆ’ 1 = 0, with dominant root Ο† = (1 + √5)/2 β‰ˆ 1.618, giving Θ(Ο†n).

Key Distinction: Subtract vs. Divide

This distinction is critical and a common source of confusion:

Subtract (T(n βˆ’ k)) Divide (T(n/b))
Typical growth Exponential Polynomial
Solving method Characteristic roots Critical exponent
Algorithms DP, backtracking Merge sort, binary search
Example T(n) = 2T(n βˆ’ 1) β†’ Θ(2n) T(n) = 2T(n/2) β†’ Θ(n)

Expression Type System

Complexity is represented using a rich expression tree hierarchy rooted at ComplexityExpression:

ComplexityExpression
β”œβ”€β”€ ConstantComplexity          O(1)
β”œβ”€β”€ LinearComplexity            O(n)
β”œβ”€β”€ PolynomialComplexity        O(n^k)
β”œβ”€β”€ LogarithmicComplexity       O(log n)
β”œβ”€β”€ PolyLogComplexity           O(n^k Β· log^j n)
β”œβ”€β”€ ExponentialComplexity       O(2^n)
β”œβ”€β”€ FactorialComplexity         O(n!)
β”œβ”€β”€ RecurrenceComplexity        T(n) = aT(n/b) + f(n)
β”œβ”€β”€ AmortizedComplexity         amortized vs. worst-case
β”œβ”€β”€ ParallelComplexity          work / span model
β”œβ”€β”€ ProbabilisticComplexity     expected vs. worst-case
β”œβ”€β”€ MemoryComplexity            stack / heap / auxiliary space
└── BinaryOperationComplexity   +, Γ—, max, min

Expressions compose algebraically (addition, multiplication, max, min) and support a visitor pattern for traversal.

Variables

Complexity can be parameterized over multiple input dimensions: InputSize (n), VertexCount (V), EdgeCount (E), TreeHeight (h), StringLength, and more.


Advanced Analysis Capabilities

Amortized Analysis

Detects and annotates amortized costs for patterns like dynamic array resizing (List<T>.Add β†’ O(1) amortized), hash table rehashing, and union-find with path compression (O(Ξ±(n)) amortized).

Parallel Complexity

Uses the work/span model to analyze Parallel.For, Parallel.ForEach, PLINQ, Task.WhenAll/Task.WhenAny, and async/await patterns, reporting both total work and critical-path span.

Probabilistic Complexity

Tracks expected vs. worst-case complexity for randomized algorithms, with factory methods for common patterns: QuickSort-like (E[O(n log n)], W[O(nΒ²)]), hash table lookup (E[O(1)], W[O(n)]), randomized selection, skip lists, and Bloom filters.

Memory / Space Complexity

Analyzes stack depth from recursion, heap allocations, tail-call optimization eligibility, and in-place algorithm detection.


BCL Complexity Mappings

Over 150 .NET BCL methods are pre-mapped with complexity information and confidence-level attribution:

Collection Key Operations
List<T> Add O(1)*, Contains O(n), Sort O(n log n), BinarySearch O(log n)
Dictionary<K,V> Add O(1), TryGetValue O(1), ContainsKey O(1)*
HashSet<T> Add O(1), Contains O(1)
SortedSet<T> Add O(log n), Contains O(log n)
LINQ Where O(n), OrderBy O(n log n), GroupBy O(n)
String Contains O(nΒ·m), IndexOf O(nΒ·m)

* amortized

Confidence levels: Documented (MSDN), Attested (CLRS), Empirical (benchmarked), Inferred (code-derived), Heuristic (conservative estimate).


Hardware Calibration

Phase E can micro-benchmark your machine to verify theoretical complexity predictions and estimate constant factors in nanoseconds:

var calibrator = new BCLCalibrator();
var results = await calibrator.RunFullCalibration(BenchmarkOptions.Standard);

// Results include:
// - Constant factor per operation (ns)
// - RΒ² goodness-of-fit scores
// - Hardware profile (CPU, memory, OS, runtime)

Calibration data is persisted as JSON for reuse across sessions.


Project Structure

ComplexityAnalysis.sln
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ ComplexityAnalysis.Core/          # Type system, recurrences, variables
β”‚   β”œβ”€β”€ ComplexityAnalysis.Roslyn/        # Roslyn extractors, BCL mappings, speculative analysis
β”‚   β”œβ”€β”€ ComplexityAnalysis.Solver/        # Theorem solving, critical exponent, refinement
β”‚   β”œβ”€β”€ ComplexityAnalysis.Calibration/   # Micro-benchmarks, curve fitting
β”‚   β”œβ”€β”€ ComplexityAnalysis.Engine/        # Pipeline orchestration
β”‚   β”œβ”€β”€ ComplexityAnalysis.IDE/
β”‚   β”‚   β”œβ”€β”€ vscode/                       # VS Code extension (TypeScript)
β”‚   β”‚   └── Cli/                          # .NET CLI tool
β”‚   └── ComplexityAnalysis.Tests/         # 752 tests (xUnit)
β”œβ”€β”€ docs/articles/                        # Technical documentation
└── assets/
    └── vscode-codelens.png

Technology Stack

  • .NET 8.0 β€” target framework
  • Roslyn (Microsoft.CodeAnalysis) β€” C# syntax and semantic analysis
  • MathNet.Numerics β€” root finding, numerical methods
  • xUnit β€” test framework
  • TypeScript β€” VS Code extension
  • SymPy (optional) β€” symbolic integral evaluation for advanced recurrences
  • DocFX β€” API documentation generation

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Run tests: cd src && dotnet test
  4. Submit a pull request

See PHASES_AND_MILESTONES.md for current implementation status, test inventory, and upcoming work.


License

MIT

About

VS Code Extension with per-method asymptotic complexity hints via CodeLens

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors