Skip to content

Time Complexity Analysis

Sinbad Adjuik edited this page Oct 7, 2025 · 3 revisions

Time Complexity Analysis

System Overview

The Cetamura Photo Processing System is designed to batch process archaeological photo archives, converting JPG files to TIFF format, pairing them with XML metadata, and packaging them into ZIP archives with validation.

Overall Time Complexity

Total System Complexity: O(N × M) where:

  • N = number of files in directory tree
  • M = average image size (for image processing operations)

Phase-by-Phase Analysis

Phase 1: Photo Set Discovery

Function: find_photo_sets_enhanced()

Complexity: O(N) where N = total files in directory tree

Operations:

  1. Recursive File Search - find_all_files_recursive()

    • O(N): Single depth-first traversal of directory tree
    • Max depth limit: 5 levels (prevents excessive recursion)
    • Filters files by extension (.jpg, .xml, .ini)
  2. File Grouping - group_files_by_directory()

    • O(N): Single pass through all discovered files
    • Uses defaultdict for O(1) insertion per file
    • Groups by parent directory using hash-based lookup
  3. Hierarchical Set Detection - find_hierarchical_sets()

    • O(K × L) where K = manifest files, L = avg subdirectories
    • Typically K << N (few manifest files)
    • Finds parent-child relationships between manifests and photos
  4. Photo Set Validation - validate_photo_set()

    • O(P) per photo set, where P = files in set
    • Validates XML-JPG matching by filename
    • Checks for orphaned files
    • Total: O(N) across all sets (each file validated once)

Optimizations:

  • Early termination on validation failure
  • Dictionary-based lookups (O(1) average)
  • Single-pass algorithms throughout
  • Duplicate detection via set membership (O(1))

Phase 2: Pre-Flight Validation

Function: pre_flight_checks()

Complexity: O(P + D) where P = photo sets, D = disk check operations

Operations:

  1. Disk Space Check

    • O(1): Single system call to shutil.disk_usage()
    • Estimates required space: P × average_zip_size
  2. Orphaned File Detection

    • O(N): Scans staging directory for leftover TIFF/XML files
    • Hash-based set operations for duplicate detection
  3. Photo Set Validation

    • O(P × F) where F = average files per set
    • Validates each photo set structure
    • Checks XML-JPG pairing consistency

Space Complexity: O(P) for storing photo set metadata


Phase 3: Batch Processing

Function: batch_process_with_safety_nets()

Complexity: O(N × M) where N = files, M = image processing operations

Per-Item Processing Pipeline:

  1. IID Extraction - extract_iid_from_xml()

    • O(X) where X = XML file size
    • XML parsing with ElementTree (linear parse)
    • XPath navigation: O(depth) typically O(log X)
  2. Image Loading & EXIF Processing

    • O(M) where M = image dimensions (width × height)
    • PIL Image.open(): O(M) to read pixel data
    • EXIF tag reading: O(E) where E = EXIF data size (typically << M)
    • Orientation detection: O(1) tag lookup
  3. Image Rotation (if needed)

    • O(M): Full pixel array transformation
    • Operations: transpose, rotate (90°, 180°, 270°)
    • In-place when possible (PIL optimizations)
  4. TIFF Conversion - convert_jpg_to_tiff()

    • O(M): Read entire image + write TIFF
    • Compression: LZW (O(M) with constant factor)
    • Color space conversion: O(M) if needed
    • TIFF tag writing: O(1)
  5. ZIP Archive Creation

    • O(T + X + I) where T = TIFF size, X = XML size, I = manifest size
    • ZIP compression: O(T) with LZW/Deflate
    • Typically T ≈ M (TIFF size proportional to image size)
  6. File Cleanup

    • O(1) per file deletion
    • 2-3 operations: delete JPG, delete temp TIFF

Total Per-Item: O(X + M + T) ≈ O(M) since M ≫ X and T ≈ M

Batch Processing: N items × O(M) = O(N × M)


Phase 4: Post-Processing Validation

Function: validate_batch_output()

Complexity: O(Z × F) where Z = ZIP files, F = files per ZIP

Operations:

  1. ZIP File Discovery

    • O(Z): List all .zip files in output directory
  2. ZIP Content Validation - verify_zip_contents()

    • O(F) per ZIP: Read ZIP directory structure
    • Validates: TIFF + XML + manifest.ini present
    • Total: O(Z × F)O(Z) since F is constant (3)
  3. CSV Reconciliation

    • O(C) where C = CSV rows
    • Single-pass CSV parsing
    • Count SUCCESS/ERROR rows
  4. Discrepancy Detection

    • O(Z): Compare counts (input XML vs output ZIPs)
    • Set operations for finding orphaned files: O(N)

Total Validation: O(Z + C + N)O(N) since Z ≤ N and C ≈ N


Space Complexity Analysis

Memory Usage: O(N + M)

Persistent Storage:

  • O(N): File path metadata for all discovered files
  • O(P): Photo set structures (P << N)
  • O(Z): ZIP file validation results

Temporary Storage:

  • O(M): Single image loaded in memory at a time
  • O(T): TIFF buffer during conversion (T ≈ M)
  • O(X): XML DOM tree (X << M, typically KB not MB)

Optimizations:

  • Sequential processing: Only one image in memory at a time
  • Streaming ZIP: Files written directly to ZIP (no full buffering)
  • Generator patterns: File discovery uses iterators where possible

Performance Characteristics

Best Case Scenario

Conditions:

  • All photos have correct orientation (no rotation needed)
  • Clean directory structure (no orphaned files)
  • Sufficient disk space
  • Fast I/O (SSD storage)

Complexity: O(N × M) with minimal constant factors

Worst Case Scenario

Conditions:

  • All photos need 90° rotation (full pixel transformation)
  • Complex hierarchical directory structure
  • Slow I/O (network drive)
  • Many validation failures requiring retries

Complexity: Still O(N × M) but with higher constant factors

Average Case (Real-World)

Based on 76-file test dataset:

  • Processing time: ~2-3 seconds per image
  • Dominated by:
    1. Image I/O (reading JPG, writing TIFF): ~60%
    2. Image processing (rotation, conversion): ~30%
    3. ZIP compression: ~8%
    4. Validation: ~2%

Scalability Analysis

Linear Scaling: O(N)

Scales linearly with:

  • Number of photo sets
  • Number of files per set
  • Total files in directory tree

Example:

  • 76 files: ~3 minutes
  • 760 files: ~30 minutes (10× increase)
  • 7,600 files: ~5 hours (100× increase)

Image-Size Scaling: O(M)

Scales with image dimensions:

  • 4 MP (2048×2048): ~2 seconds/image
  • 16 MP (4096×4096): ~8 seconds/image (4× increase)
  • 64 MP (8192×8192): ~32 seconds/image (16× increase)

Parallelization Potential

Currently: Sequential processing (one image at a time)

Potential Improvements:

  • Thread-based: Limited by Python GIL for CPU-bound operations
  • Process-based: Good parallelization potential
    • Independent file processing (no shared state)
    • Can achieve near-linear speedup with P processes
    • Improved complexity: O((N × M) / P)

Recommended for: N > 1000 files


Bottleneck Analysis

Primary Bottlenecks (by time %)

  1. TIFF Conversion (40-50%)

    • Image decompression (JPG → RGB)
    • Image compression (RGB → TIFF/LZW)
    • Mitigation: Use faster compression or RAW TIFF
  2. Disk I/O (30-40%)

    • Reading JPG files
    • Writing TIFF files
    • Writing ZIP archives
    • Mitigation: SSD storage, disk caching
  3. Image Rotation (10-20%) - when needed

    • Full pixel array transformation
    • Mitigation: Process at reduced resolution for previews
  4. ZIP Compression (5-10%)

    • Deflate algorithm on TIFF + XML
    • Mitigation: Lower compression level
  5. Validation (<5%)

    • Negligible impact
    • Pre-flight checks: O(1) disk operations
    • Post-processing: O(N) file listing

Optimization Recommendations

Current Optimizations (Implemented)

Single-pass directory traversal Hash-based file lookups Sequential processing (memory-efficient) Early termination on errors Streaming ZIP writes Efficient XML parsing (ElementTree)

Future Optimizations Plans (Not Implemented)

1. Parallel Processing

Impact: 4-8× speedup on modern CPUs

# Multiprocessing pool
from multiprocessing import Pool
with Pool(processes=8) as pool:
    results = pool.map(process_single_item, file_pairs)

Complexity: O((N × M) / P) where P = processes

2. Incremental Processing

Impact: Resume from checkpoint, avoid reprocessing

# Track processed files in database
if iid in processed_set:
    continue  # Skip already processed

Complexity: Same O(N × M), but reduced N on reruns

3. Batch ZIP Creation

Impact: Reduce I/O overhead

# Write multiple TIFFs to single ZIP
with ZipFile('batch.zip', 'w') as zf:
    for item in batch:
        zf.write(item)

Complexity: Same, but reduced I/O operations

4. Caching Layer

Impact: Faster validation on repeated runs

# Cache file metadata (sizes, hashes)
cache[file_path] = {
    'size': size,
    'mtime': mtime,
    'hash': md5
}

Complexity: O(1) lookup instead of O(M) reprocessing


Comparison with Alternatives

Sequential Processing (Current)

  • Time: O(N × M)
  • Space: O(N + M)
  • Pros: Simple, memory-efficient, reliable
  • Cons: Slow for large batches

Parallel Processing (Proposed)

  • Time: O((N × M) / P)
  • Space: O(N + P×M) - P images in memory
  • Pros: 4-8× faster
  • Cons: More complex, higher memory usage

Streaming Pipeline (Alternative)

  • Time: O(N × M) but with better latency
  • Space: O(M) - constant memory
  • Pros: Start seeing results immediately
  • Cons: More complex error handling

Conclusion

At the moment The Cetamura Photo Processing System has O(N × M) time complexity, which is optimal for this type of batch image processing task. Every file must be read, processed, and written, making O(N × M) the theoretical minimum.

Key Insights:

  1. Linear scalability in number of files (N)
  2. Linear scalability in image size (M)
  3. Dominated by I/O, not computation
  4. Memory-efficient design (O(N + M))
  5. Good optimization potential through parallelization

Performance Profile:

  • Small batches (<100 files): ~5-10 minutes
  • Medium batches (100-1000 files): ~30 minutes - 2 hours
  • Large batches (>1000 files): Consider parallel processing

Validation Overhead:

  • Pre-flight checks: O(N) - negligible
  • Post-processing validation: O(N) - negligible
  • Total validation: <5% of processing time

Related Documentation


Last Updated: October 7, 2025
Version: v2025.10.06

Clone this wiki locally