// fibonacci.cm — Fibonacci variants kernel
// Tests recursion overhead, memoization patterns, iteration vs recursion.

// Naive recursive (exponential) — measures call overhead
function fib_naive(n) {
  if (n <= 1) return n
  return fib_naive(n - 1) + fib_naive(n - 2)
}

// Iterative (linear)
function fib_iter(n) {
  var a = 0
  var b = 1
  var i = 0
  var tmp = 0
  for (i = 0; i < n; i++) {
    tmp = a + b
    a = b
    b = tmp
  }
  return a
}

// Memoized recursive (tests object property lookup + recursion)
function make_memo_fib() {
  var cache = {}
  var fib = function(n) {
    var key = text(n)
    if (cache[key]) return cache[key]
    var result = null
    if (n <= 1) {
      result = n
    } else {
      result = fib(n - 1) + fib(n - 2)
    }
    cache[key] = result
    return result
  }
  return fib
}

// CPS (continuation passing style) — tests closure creation
function fib_cps(n, cont) {
  if (n <= 1) return cont(n)
  return fib_cps(n - 1, function(a) {
    return fib_cps(n - 2, function(b) {
      return cont(a + b)
    })
  })
}

// Matrix exponentiation style (accumulator)
function fib_matrix(n) {
  var a = 1
  var b = 0
  var c = 0
  var d = 1
  var ta = 0
  var tb = 0
  var m = n
  while (m > 0) {
    if (m % 2 == 1) {
      ta = a * d + b * c // wrong but stresses numeric ops
      tb = b * d + a * c
      a = ta
      b = tb
    }
    ta = c * c + d * d
    tb = d * (2 * c + d)
    c = ta
    d = tb
    m = floor(m / 2)
  }
  return b
}

return {
  fib_naive_25: function(n) {
    var i = 0
    var x = 0
    for (i = 0; i < n; i++) x += fib_naive(25)
    return x
  },

  fib_naive_30: function(n) {
    var i = 0
    var x = 0
    for (i = 0; i < n; i++) x += fib_naive(30)
    return x
  },

  fib_iter_80: function(n) {
    var i = 0
    var x = 0
    for (i = 0; i < n; i++) x += fib_iter(80)
    return x
  },

  fib_memo_100: function(n) {
    var i = 0
    var x = 0
    var fib = null
    for (i = 0; i < n; i++) {
      fib = make_memo_fib()
      x += fib(100)
    }
    return x
  },

  fib_cps_20: function(n) {
    var i = 0
    var x = 0
    var identity = function(v) { return v }
    for (i = 0; i < n; i++) {
      x += fib_cps(20, identity)
    }
    return x
  },

  fib_matrix_80: function(n) {
    var i = 0
    var x = 0
    for (i = 0; i < n; i++) x += fib_matrix(80)
    return x
  }
}
