Skip to content

iraikov/array-morphisms

Repository files navigation

Array Morphisms

Chicken Scheme

A unified backend for numerical computing in Chicken Scheme, combining fusion-based lazy evaluation, Mathematics of Arrays (MoA) index transformations, and automatic memory reuse.

Features

  • Lazy Evaluation: Operations build expression trees that are materialized on demand
  • Zero-Copy Views: Structural operations (reshape, transpose, slice) via MoA affine index functions
  • Memory Reuse: Automatic buffer planning with graph coloring for optimal allocation
  • BLAS Integration: Transparent dispatch to optimized linear algebra kernels
  • Type Safety: Multiple element types (f64, f32, s64, s32, u32, u64)
  • Category-Theoretic Foundation: Array morphisms as structure-preserving transformations

Installation

# Install array-morphisms
chicken-install array-morphisms

Or clone from GitHub:

git clone https://github.com/iraikov/array-morphisms.git
cd array-morphisms
chicken-install .

Quick Start

(import array-morphisms-core
        array-morphisms-basic-ops
        array-morphisms-structural-ops
        array-morphisms-realization)

;; Create concrete arrays
(define x (morph-from-list '(1.0 2.0 3.0 4.0 5.0) '(5) 'f64))
(define y (morph-from-list '(2.0 4.0 6.0 8.0 10.0) '(5) 'f64))

;; Build lazy computation (no allocation yet!)
(define z (morph+ (morph-map (lambda (a) (* a a)) x) y))

;; Materialize when needed
(define result (realize z))  ; Returns concrete array
(morph->list result)          ; Convert to Scheme list

;; Chain structural operations (all zero-copy views)
(define matrix (morph-reshape x #(2 3)))   ; Reshape to 2x3
(define transposed (morph-transpose matrix)) ; Transpose
(define slice (morph-slice transposed '(0 0) '(2 2))) ; Extract submatrix

Core Concepts

Morphisms vs Arrays

In array-morphisms, computation is represented as morphisms - structure-preserving transformations between arrays. There are two types:

  • Concrete Arrays: Materialized data with shape, dtype, and strides
  • Abstract Morphisms: Deferred computations represented as expression trees
;; Concrete array - data is stored
(define concrete (morph-from-list '(1.0 2.0 3.0) '(3) 'f64))

;; Abstract morphism - represents computation
(define abstract (morph+ concrete concrete))

;; Realization materializes the morphism
(define result (realize abstract))  ; Now concrete

Index Functions

Array morphisms use index functions to describe transformations algebraically:

  • Affine Index Functions: Pure transformations (reshape, transpose, slice)
  • Compute Index Functions: Element-wise arithmetic operations
  • Window Index Functions: Convolution and pooling operations
  • Reduction Index Functions: Aggregate operations (sum, mean, max)
;; Affine: stride-2 slice
(define downsampled (morph-slice x '(0) '(16) 2))

;; Compute: element-wise multiplication
(define scaled (morph* x (morph-from-list '(2.0) '(1) 'f64)))

;; Reduction: sum all elements
(define total (morph-reduce 'sum x))

Zero-Copy Structural Operations

Structural operations manipulate array views without copying data:

(define x (morph-from-list '(0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0) '(8) 'f64))

;; Non-contiguous slice (stride 2)
(define strided (morph-slice x '(0) '(8) 2))  ; (0.0 2.0 4.0 6.0)

;; Reshape works even on non-contiguous views
(define as-2x2 (morph-reshape strided #(2 2)))  ; ((0.0 2.0) (4.0 6.0))

;; Transpose
(define transposed (morph-transpose as-2x2 '(1 0)))  ; ((0.0 4.0) (2.0 6.0))

Basic Operations

Array Creation

(morph-from-list '(1.0 2.0 3.0) '(3) 'f64)  ; From list
(make-morphism data-vector shape 'f64)        ; From typed vector

Arithmetic

(morph+ a b)    (morph- a b)    (morph* a b)    (morph/ a b)
(morph-pow a b)

;; Unary operations
(morph-negate a)  (morph-abs a)  (morph-sqrt a)
(morph-exp a)     (morph-log a)  (morph-sin a)   (morph-cos a)

Comparison

(morph> a b)  (morph< a b)  (morph= a b)  (morph>= a b)  (morph<= a b)
;; Returns 1.0 for true, 0.0 for false

Structural Operations

;; Reshape (supports -1 for automatic dimension inference)
(morph-reshape m #(2 3))      ; Reshape to 2x3
(morph-reshape m '(2 -1))     ; Infer second dimension

;; Transpose
(morph-transpose m)           ; Reverse all axes
(morph-transpose m '(1 0))    ; 2D transpose
(morph-transpose m '(0 2 1))  ; Swap last two axes

;; Slice
(morph-slice m '(0) '(10))      ; Elements 0 to 9
(morph-slice m '(0) '(10) 2)    ; Every other element

;; Stack/Concat
(morph-stack (list m1 m2 m3) 0)   ; Stack along new axis
(morph-concat (list m1 m2) 0)      ; Concatenate along existing axis

Functional Operations

;; Map applies function element-wise
(morph-map (lambda (x) (* x x)) arr)

;; Reduce aggregates over specified axes
(morph-reduce 'sum arr)           ; Sum all elements
(morph-reduce 'mean arr '(0))     ; Mean along axis 0
(morph-reduce 'max arr '(1 2))    ; Max along axes 1 and 2

;; Fold and scan (batch operations)
(batch-fold fn init batched-m)
(batch-scan fn init batched-m)

Memory Reuse with Execution Context

For repeated computations, use execution contexts to enable buffer reuse:

(import array-morphisms-context)

;; Create context for memory planning
(define ctx (make-morphism-context))

;; Trace phase: record allocations
(realize/ctx ctx morphism)
(finalize-context! ctx)

;; Replay phase: reuse buffers
(reset-context! ctx)
(realize/ctx ctx morphism)  ; Uses pre-allocated buffers

Type System

Type Description Size
'f64 Double float 64-bit
'f32 Single float 32-bit
's64 64-bit signed int 64-bit
's32 32-bit signed int 32-bit
'u64 64-bit unsigned int 64-bit
'u32 32-bit unsigned int 32-bit

Type promotion rules:

  • Mixed operations promote to the higher precision type
  • Transcendental functions promote integers to floating point
  • Reductions preserve dtype (mean promotes to float)

Performance Tips

  1. Laziness is your friend - Build expression trees, materialize once
  2. Zero-copy views - Structural operations are essentially free
  3. Use contexts - For repeated computations, enable buffer reuse
  4. Batch operations - Process multiple arrays together efficiently
;; Good: Chain operations, materialize once
(define result (realize (morph-sqrt (morph+ (morph* a b) c))))

;; Good: Use contexts for repeated inference
(define ctx (make-morphism-context))
(realize/ctx ctx model-output)  ; First run traces
(finalize-context! ctx)
;; ... later ...
(realize/ctx ctx model-output)  ; Reuses buffers

;; Bad: Materializing intermediate results
(define temp1 (realize (morph* a b)))
(define temp2 (realize (morph+ temp1 c)))
(define result (realize (morph-sqrt temp2)))

Comparison with Fusion Arrays

Feature Fusion Arrays Array Morphisms
Core abstraction Fusion arrays Array morphisms
Structural ops Copy on non-contiguous Zero-copy via MoA
Memory reuse Manual Automatic (context-based)
Index functions Hidden First-class, composable
Batch operations Limited First-class combinators
BLAS integration No Yes (GEMM, GEMV, DOT)

Examples

Layer Normalization

(define (layer-norm x eps)
  (let* ((mean (morph-reduce 'mean x '(0)))
         (centered (morph- x mean))
         (variance (morph-reduce 'mean 
                               (morph* centered centered) 
                               '(0)))
         (std (morph-sqrt (morph+ variance 
                                  (morph-from-list 
                                    (make-list (vector-ref 
                                                (get-morphism-shape x) 1) 
                                               eps)
                                    (list (vector-ref 
                                           (get-morphism-shape x) 1))
                                    'f64)))))
    (morph/ centered std)))

Signal Downsampling Pipeline

(define (downsample-pipeline signal)
  ;; Polyphase downsampling via composed slices
  (let* ((even (morph-slice signal '(0) (get-morphism-shape signal) 2))
         (quarter (morph-slice even '(0) (get-morphism-shape even) 2)))
    ;; Both slices are zero-copy views
    ;; Final realization computes in single pass
    (realize quarter)))

Batched Matrix Operations

(import array-morphisms-batch-ops)

;; Stack matrices into batch
(define batch (morph-stack (list m1 m2 m3) 0))

;; Apply operation to each batch element
(define doubled (batch-map 
                   (lambda (m) (morph-map (lambda (x) (* x 2)) m))
                   batch))

;; Reduce across batch dimension
(define summed (batch-reduce 'sum batch))

Requirements

  • CHICKEN Scheme 5.0+
  • Dependencies: datatype, matchable, srfi-1, srfi-4, srfi-69
  • Optional: BLAS library for accelerated linear algebra

API Reference

See CHICKEN Scheme Wiki for full documentation.

Key modules:

  • array-morphisms-core - Core data types and utilities
  • array-morphisms-basic-ops - Arithmetic and transcendental operations
  • array-morphisms-structural-ops - Reshape, transpose, slice, stack
  • array-morphisms-realization - Materialization and execution
  • array-morphisms-context - Memory reuse contexts
  • array-morphisms-batch-ops - Batch operations and combinators

License

LGPL-3

Acknowledgments

  • Inspired by the Mathematics of Arrays (MoA) formalism by Lenore Mullin
  • Category-theoretic foundation from functional programming research
  • Memory reuse patterns from stream fusion and buffer optimization literature