Envision Language Server - Envision Prelude

The prelude contains the currently used definition of some Envision process.

//////////////////////////////////////////////////////////////////
/// abs
//////////////////////////////////////////////////////////////////
def autodiff const pure abs(n : number) as "abs" with
  return if n < 0 then -n else n

def const pure abs(n : long) as "abs(long)" with
  return if n < to.long(0) then -n else n
  
def const pure abs(n : double) as "abs(dbl)" with
  return if n < to.double(0) then -n else n

//////////////////////////////////////////////////////////////////
/// isnan
//////////////////////////////////////////////////////////////////

def const pure isnan(n : number) as "isnan(num)" with
  return n != n

def const pure isnan(n : double) as "isnan(dbl)" with
  return n != n

//////////////////////////////////////////////////////////////////
/// gradControl (temporary)
//////////////////////////////////////////////////////////////////

def autodiff pure gradControl(x : number, y : number) as "gradControl" with 
  return noGrad(x)

//////////////////////////////////////////////////////////////////
/// format
//////////////////////////////////////////////////////////////////

def const pure format(m : month, format : text) as "format(mnth)" with
  return format(monthStart(m), format)

def const pure format(m : week, format : text) as "format(week)" with
  return format(monday(m), format)

//////////////////////////////////////////////////////////////////
/// loggamma
//////////////////////////////////////////////////////////////////

def autodiff pure logGamma(n : number) as "logGamma" with
  // Log Gamma Function continued fractions NIST Handbook of Mathematical Functions see:
  // https://univ.jeanpaulcalvi.com/Posters/ConfAuchWeb/abramovitz2.pdf

  x = n + 1

  // A & S eq. 6.1.48 (continuing fraction)
  a0 = 1.0 / 12
  a1 = 1.0 / 30
  a2 = 53.0 / 210
  a3 = 195.0 / 371
  a4 = 22999.0 / 22737
  // a5 = 29944523.0 / 19733142 // -> 1.5174736491532874
  // a5 = 29944524.0 / 19733142 //  approximated -> 1.5174736976623535
  a5 = 1.5174736976623535
  // a6 = 109535241009.0 / 48264275462 -> 2.26948902978545
  // a6 = 109535240192.0 / 48264273920 // approximated -> 2.269489049911499
  a6 = 2.269489049911499
  
  t6 = a6 / x
  t5 = a5 / (x + t6)
  t4 = a4 / (x + t5)
  t3 = a3 / (x + t4)
  t2 = a2 / (x + t3)
  t1 = a1 / (x + t2)
  t0 = a0 / (x + t1)

  // Ln2Pi_2 = Math.Log(2.0*Math.PI)/2.0
  // Ln2Pi_2 = 0.9189385332
  Ln2Pi_2 = 0.9189385

  // Numeric shift to improve accuracy (cost +1 'Log').
  // logGamma(x) = logGamma(x + 1) - log(x)
  return -log(n) + t0 - x + (x - 0.5) * log(x) + Ln2Pi_2

//////////////////////////////////////////////////////////////////
/// loglikelihood.normal
//////////////////////////////////////////////////////////////////

def autodiff const pure loglikelihood_normal(mu : number, sigma : number, x : number) as "loglikelihood-normal" with
  // return -0.9189385332 /* -Ln2Pi_2 */ - log(sigma) - (x - mu)^2 / (2 * sigma^2)
  return -0.9189385 /* -Ln2Pi_2 */ - log(sigma) - (x - mu)^2 / (2 * sigma^2)

//////////////////////////////////////////////////////////////////
/// loglikelihood.poisson
//////////////////////////////////////////////////////////////////

def autodiff pure loglikelihood_poisson(lambda : number, k : number) as "loglikelihood-poisson" with
  return k * log(lambda) - lambda - logGamma(k + 1)

//////////////////////////////////////////////////////////////////
/// loglikelihood.negativeBinomial
//////////////////////////////////////////////////////////////////

def autodiff pure loglikelihood_negativebinomial(mean : number, dispersion : number, k : number) as "loglikelihood-negativebinomial" with
  y = 0
  if dispersion >= 1.001
    r = mean / (dispersion - 1)
    p = 1 - 1 / dispersion
    y = logGamma(k + r) - logGamma(k + 1) - logGamma(r) + k * log(p) + r * log(1 - p)
  else
    y = loglikelihood.poisson(mean, k)
  return y

//////////////////////////////////////////////////////////////////
/// loglikelihood.zeroInflatedNegativeBinomial
//////////////////////////////////////////////////////////////////

def autodiff pure loglikelihood_negativebinomial(mean : number, dispersion : number, zeroInflation : number, k : number) as "loglikelihood-inflatednegativebinomial" with
  y = 0
  alpha = 0
  if zeroInflation < 0
    alpha = 0
  else 
    if zeroInflation > 0.999
      alpha = 0.999
    else
      alpha = zeroInflation
  if dispersion >= 1.001
    r = mean / (dispersion - 1)
    p = 1 - 1 / dispersion
    if k == 0
      y = log(alpha + (1-alpha) * (1-p)^r)
    else        
      y = logGamma(k + r) - logGamma(k + 1) - logGamma(r) + k * log(p) + r * log(1 - p) + log(1-alpha)
  else
    if k == 0
      y = log(alpha + (1-alpha) * exp(-mean))
    else        
      y = loglikelihood.poisson(mean, k)+log(1-alpha)
  return y

//////////////////////////////////////////////////////////////////
/// loglikelihood.loglogistic
//////////////////////////////////////////////////////////////////

def autodiff pure loglikelihood_loglogistic(alpha : number, beta : number, x : number) as "loglikelihood-loglogistic" with
  logAlpha = log(alpha)
  return log(beta) - logAlpha + (beta - 1)*(log(x)-logAlpha)-2*log(1+(x/alpha)^beta)

//////////////////////////////////////////////////////////////////
/// loglikelihood.loglogistic (with lowerbound option)
//////////////////////////////////////////////////////////////////

def autodiff pure loglikelihood_loglogistic(alpha : number, beta : number, x : number, isLowerBound : boolean) as "loglikelihood-loglogistic-lowerbound" with
  y = 0
  if not isLowerBound
    y = loglikelihood.logLogistic(alpha, beta, x)
  else
    y = log(1-1/(1+(alpha/x)^beta))
  return y

//////////////////////////////////////////////////////////////////
/// square
//////////////////////////////////////////////////////////////////

def const pure square(n : number) as "square(num)" with
  return n * n

//////////////////////////////////////////////////////////////////
/// weekDayNum
//////////////////////////////////////////////////////////////////

def const pure weekDayNum(d : date) as "weekDayNum" with 
  return d - monday(d) + 1


//////////////////////////////////////////////////////////////
/// Regularization Term
//////////////////////////////////////////////////////////////

def autodiff pure regularizationTerm(
    /// the positive quantity that aims to impact parameters gradients
    penalty: number, 
    /// The original loss, without any regularization terms
    loss : number, 
    /// The scaling factor, intended to be between 0 (no impact) and 1 (regularization as important as original loss)
    alpha : number) as "regularizationTerm" with

  /// The penalty is scaled between 0 and 1 with a gradient that does not converge to 0
  /// If the penalty is under 1.8 (magic number, after this value, tanh gradient is too small), one uses tanh
  /// After this limit one uses the rest of the floor function.
  /// Note that noGrad is used as the floor's gradient is hand coded as 1.

  /// To make computation faster:
  /// 1 - tanh(1.8)^2 = 0.10355837
  /// tanh(1.8) = 0.94680601
  
  scaledPenalty = if penalty < 1.8 then tanh(penalty) else 0.10355837*(penalty - floor(noGrad(penalty)/1.8) * 1.8) + 0.94680601
  /// The scaled penalty (between 0 and 1) is then scaled by the original loss, used without impacting gradient.
  return alpha * noGrad(loss) * scaledPenalty


//////////////////////////////////////////////////////////////////
/// single
//////////////////////////////////////////////////////////////////

def process single(a: number) as "single{num}" default 0 with
  if not argfirst()
    b = assertfail("'single()': called with more than one element.")
  return a

def process single(a: text) as "single{text}" default "" with
  if not argfirst()
    b = assertfail("'single()': called with more than one element.")
  return a

def process single(a: date) as "single{date}" default date(2001,1,1) with
  if not argfirst()
    b = assertfail("'single()': called with more than one element.")
  return a

def process single(a: boolean) as "single{bool}" default false with
  if not argfirst()
    b = assertfail("'single()': called with more than one element.")
  return a

def process single(a: ranvar) as "single{dist}" default (dirac(0)) with
  if not argfirst()
    b = assertfail("'single()': called with more than one element.")
  return a

def process single(a: zedfunc) as "single{fun}" default (linear(0)) with
  if not argfirst()
    b = assertfail("'single()': called with more than one element.")
  return a

def process single(a: double) as "single{dbl}" default (to.double(0)) with
  if not argfirst()
    b = assertfail("'single()': called with more than one element.")
  return a

def process single(a: long) as "single{long}" default (to.long(0)) with
  if not argfirst()
    b = assertfail("'single()': called with more than one element.")
  return a

def process single(a: week) as "single{week}" default (week(date(2001, 1, 1))) with
  if not argfirst()
    b = assertfail("'single()': called with more than one element.")
  return a

def process single(a: month) as "single{mnth}" default (month(date(2001, 1, 1))) with
  if not argfirst()
    b = assertfail("'single()': called with more than one element.")
  return a

def process single(a: flagset) as "single{flag}" default (emptySet()) with
  if not argfirst()
    b = assertfail("'single()': called with more than one element.")
  return a

def process single(a: ordinal) as "single{ord}" default (bad_ord__()) with
  if not argfirst()
    b = assertfail("'single()': called with more than one element.")
  return a

def process single(a: embedding) as "single{emb}" default (bad_emb__()) with
  if not argfirst()
    b = assertfail("'single()': called with more than one element.")
  return a

//////////////////////////////////////////////////////////////////
/// Sum/Product
//////////////////////////////////////////////////////////////////
def process sum(n : double) as "sum{dbl}" default (to.double(0)) with
  keep accum = to.double(0)
  accum = accum + n
  return accum

def process sum(n : long) as "sum{long}" default (to.long(0)) with
  keep accum = to.long(0)
  accum = accum + n
  return accum

def process sum(n : number) as "sum{num}" default 0 with
  return to.number(sum(to.double(n)))

def process fastsum(n: number) as "fastsum{num}" default 0 with 
  keep accum = 0
  accum = accum + n
  return accum

def process product(n : number) as "product{num}" default 1 with
  keep accum = to.double(1)
  accum = accum * to.double(n)
  return to.number(accum)

//////////////////////////////////////////////////////////////////
/// Average
//////////////////////////////////////////////////////////////////
def process avg(n : double) as "avg{dbl}" default to.double(0) with
  return sum(n) / to.double(enumerate() + 1)

def process avg(n : long) as "avg{long}" default to.long(0) with
  return sum(n) / to.long(enumerate() + 1)

def process avg(n : number) as "avg{num}" default 0 with
  return to.number(avg(to.double(n)))

////////////////////////////////////////////////////////////////
/// any
////////////////////////////////////////////////////////////////
def process any(v : boolean) as "any{bool}" default false with
  keep seen = false
  seen = seen or v
  return seen

////////////////////////////////////////////////////////////////
/// ratio
////////////////////////////////////////////////////////////////
def process ratio(val : number) as "ratio{num}" default 1 with
  return count(val != 0) / (enumerate() + 1)

def process ratio(val : text) as "ratio{text}" default 1 with
  return count(val != "") / (enumerate() + 1)

def process ratio(val : boolean) as "ratio{bool}" default 1 with
  return count(val) / (enumerate() + 1)

////////////////////////////////////////////////////////////////
/// Set union and intersection
////////////////////////////////////////////////////////////////

def process union(n : flagset) as "union{flag}" default emptySet() with 
  keep acc = emptySet()
  acc = union(acc, n)
  return acc

def process intersection(n : flagset) as "intersection{flag}" default complement(emptySet()) with 
  keep acc = complement(emptySet())
  acc = intersection(acc, n)
  return acc

////////////////////////////////////////////////////////////////
/// all
////////////////////////////////////////////////////////////////
def process all(v : boolean) as "all{bool}" default true with
  keep seen = true
  seen = seen and v
  return seen

//////////////////////////////////////////////////////////////////
/// enumerations
//////////////////////////////////////////////////////////////////

def process argfirst() as "is_first{}" default false with
  keep isFirst = true
  if isFirst
    isFirst = false
    return true
  else
    return false

def process argfirst(cond : boolean) as "is_first{bool}" default false with
  keep answer = false
  keep marked = true
  if marked
    if cond
      marked = false
      answer = true
  else
    answer = false

  return answer

def process enumerate() as "enumerate{}" default 0 with
  keep value = to.long(-1)
  value = to.long(1) + value
  return to.number(value)

def process rank() as "rank{}" default 0 with
  keep value = to.long(0)
  value = to.long(1) + value
  return to.number(value)

def process rankrev() as "rev_enumerate{}" default 0 with
  return groupsize() - enumerate()

//////////////////////////////////////////////////////////////////
/// Min (all versions)
//////////////////////////////////////////////////////////////////
def process min(a : number) as "min{num}" default 0 with
  keep mini = 0
  if argfirst()
    mini = a
  else if a < mini
    mini = a

  return mini

def process min(a : long) as "min{long}" default to.long(0) with
  keep mini = to.long(0)
  if argfirst()
    mini = a
  else if a < mini
    mini = a

  return mini


def process min(a : double) as "min{dbl}" default to.double(0) with
  keep mini = to.double(0)
  if argfirst()
    mini = a
  else if a < mini
    mini = a

  return mini

def process min(a : date) as "min{date}" default (date(2001, 1, 1)) with
  keep mini = date(2001, 1, 1)
  if argfirst()
    mini = a
  else if a < mini
    mini = a

  return mini

def process min(a : week) as "min{week}" default (week(date(2001, 1, 1))) with
  keep mini = week(date(2001, 1, 1))
  if argfirst()
    mini = a
  else if a < mini
    mini = a

  return mini

def process min(a : month) as "min{mnth}" default (month(date(2001, 1, 1))) with
  keep mini = month(date(2001, 1, 1))
  if argfirst()
    mini = a
  else if a < mini
    mini = a

  return mini

def process min(a : text) as "min{text}" default "" with
  keep mini = ""
  if argfirst()
    mini = a
  else if a < mini
    mini = a

  return mini

def process min(a : ranvar) as "min{ranv}" default (dirac(0)) with
  keep mini = dirac(0)
  if argfirst()
    mini = a
  else
    mini = min(mini, a)

  return mini

//////////////////////////////////////////////////////////////////
/// Max (all versions)
//////////////////////////////////////////////////////////////////
def process max(a : number) as "max{num}" default 0 with
  keep maxi = 0
  if argfirst()
    maxi = a
  else if a > maxi
    maxi = a

  return maxi

def process max(a : long) as "max{long}" default to.long(0) with
  keep maxi = to.long(0)
  if argfirst()
    maxi = a
  else if a > maxi
    maxi = a

  return maxi


def process max(a : double) as "max{dbl}" default to.double(0) with
  keep maxi = to.double(0)
  if argfirst()
    maxi = a
  else if a > maxi
    maxi = a

  return maxi

def process max(a : date) as "max{date}" default (date(2001, 1, 1)) with
  keep maxi = date(2001, 1, 1)
  if argfirst()
    maxi = a
  else if a > maxi
    maxi = a

  return maxi

def process max(a : week) as "max{week}" default (week(date(2001, 1, 1))) with
  keep maxi = week(date(2001, 1, 1))
  if argfirst()
    maxi = a
  else if a > maxi
    maxi = a

  return maxi

def process max(a : month) as "max{mnth}" default (month(date(2001, 1, 1))) with
  keep maxi = month(date(2001, 1, 1))
  if argfirst()
    maxi = a
  else if a > maxi
    maxi = a

  return maxi

def process max(a : text) as "max{text}" default "" with
  keep maxi = ""
  if argfirst()
    maxi = a
  else if a > maxi
    maxi = a

  return maxi

def process max(a : ranvar) as "max{ranv}" default (dirac(0)) with
  keep maxi = dirac(0)
  if argfirst()
    maxi = a
  else
    maxi = max(maxi, a)

  return maxi

//////////////////////////////////////////////////////////////////
/// count
//////////////////////////////////////////////////////////////////

def process count(n : boolean) as "count{bool}" default 0 with
  keep c = to.long(0)
  if n
    c = c + to.long(1)
  return to.number(c)

//////////////////////////////////////////////////////////////////
/// distinct
//////////////////////////////////////////////////////////////////
def process distinct(b : boolean) as "distinct{bool}" default 0 with
  keep hasTrue = false
  keep hasFalse = false

  if b
    hasTrue = true
  else
    hasFalse = true

  return((if hasTrue then 1 else 0) + (if hasFalse then 1 else 0))

//////////////////////////////////////////////////////////////////
/// mode
//////////////////////////////////////////////////////////////////
def process mode(b : boolean) as "mode{bool}" default false with
  keep trueCount = to.long(0)
  keep falseCount = to.long(0)

  if b
    trueCount = trueCount + to.long(1)
  else
    falseCount = falseCount + to.long(1)

  return trueCount > falseCount

//////////////////////////////////////////////////////////////////
/// areSame
//////////////////////////////////////////////////////////////////
def process areSame(a : number) as "areSame{num}" default true with
  keep value = 0
  if argfirst()
    value = a
  return all(a == value)

def process areSame(a : double) as "areSame{dbl}" default true with
  keep value = to.double(0)
  if argfirst()
    value = a
  return all(a == value)

def process areSame(a : long) as "areSame{long}" default true with
  keep value = to.long(0)
  if argfirst()
    value = a
  return all(a == value)

def process areSame(a : ordinal) as "areSame{ord}" default true with
  keep value = bad_ord__()
  if argfirst()
    value = a
  return all(a == value)

def process areSame(a : boolean) as "areSame{bool}" default true with
  keep value = false
  if argfirst()
    value = a
  return all(value == a)

def process areSame(a : date) as "areSame{date}" default true with
  keep value = date(2001, 1, 1)
  if argfirst()
    value = a
  return all(value == a)

def process areSame(a : week) as "areSame{week}" default true with
  keep value = week(date(2001, 1, 1))
  if argfirst()
    value = a
  return all(value == a)

def process areSame(a : month) as "areSame{mnth}" default true with
  keep value = month(date(2001, 1, 1))
  if argfirst()
    value = a
  return all(value == a)

// we don't use all, to avoid extra comparison that are not
// cheap for text, ranvar and zedfunc
def process areSame(a : text) as "areSame{text}" default true with
  keep areSame = true
  keep value = ""
  if argfirst()
    value = a
  else if value != a
    areSame = false

  return areSame

def process areSame(a : ranvar) as "areSame{dist}" default true with
  keep areSame = true
  keep value = dirac(0)
  if argfirst()
    value = a
  else if value != a
    areSame = false

  return areSame

def process areSame(a : zedfunc) as "areSame{fun}" default true with
  keep areSame = true
  keep value = linear(0)
  if argfirst()
    value = a
  else if value != a
    areSame = false

  return areSame

def process areSame(a : embedding) as "areSame{emb}" default true with
  keep areSame = true
  keep value = bad_emb__()
  if argfirst()
    value = a
  else if value != a
    areSame = false

  return areSame

//////////////////////////////////////////////////////////////////
/// same (it's the same)
//////////////////////////////////////////////////////////////////

def process same(a: number) as "same{num}" default 0 with
  keep fst = 0
  if argfirst()
    fst = a
  else if fst != a
    b = assertfail("'same()': found different values '\{fst}' and '\{a}'.")
  return a

def process same(a: ordinal) as "same{ord}" default (bad_ord__()) with
  keep fst = bad_ord__()
  if argfirst()
    fst = a
  else if fst != a
    fstStr = text(fst)
    aStr = text(a)
    b = assertfail("'same()': found different values '\{fstStr}' and '\{aStr}'.")
  return a

def process same(a: date) as "same{date}" default date(2001,1,1) with
  keep fst = date(2001,1,1)
  if argfirst()
    fst = a
  else if fst != a
    b = assertfail("'same()': found different values '\{fst}' and '\{a}'.")
  return a

def process same(a: boolean) as "same{bool}" default false with
  keep fst = false
  if argfirst()
    fst = a
  else if fst != a
    b = assertfail("'same()': found different values '\{fst}' and '\{a}'.")
  return a

def process same(a: double) as "same{dbl}" default to.double(0) with
  keep fst = to.double(0)
  if argfirst()
    fst = a
  else if fst != a
    b = assertfail("'same()': found different values '\{fst}' and '\{a}'.")
  return a

def process same(a: long) as "same{long}" default to.long(0) with
  keep fst = to.long(0)
  if argfirst()
    fst = a
  else if fst != a
    b = assertfail("'same()': found different values '\{fst}' and '\{a}'.")
  return a

def process same(a: flagset) as "same{flag}" default emptySet() with
  keep fst = emptySet()
  if argfirst()
    fst = a
  else if fst != a
    b = assertfail("'same()': found different values.")
  return a

def process same(a: week) as "same{week}" default week(date(2001,1,1)) with
  keep fst = week(date(2001,1,1))
  if argfirst()
    fst = a
  else if fst != a
    b = assertfail("'same()': found different values '\{fst}' and '\{a}'.")
  return a

def process same(a: month) as "same{mnth}" default month(date(2001,1,1)) with
  keep fst = month(date(2001,1,1))
  if argfirst()
    fst = a
  else if fst != a
    b = assertfail("'same()': found different values '\{fst}' and '\{a}'.")
  return a

def process same(a: ranvar) as "same{dist}" default dirac(0) with
  keep fst = dirac(0)
  if argfirst()
    fst = a
  else if fst != a
    fstSpark = spark(fst)
    aSpark = spark(a)
    b = assertfail("'same()': found different values '\{fstSpark}' and '\{aSpark}'.")
  return a

def process same(a: zedfunc) as "same{fun}" default linear(0) with
  keep fst = linear(0)
  if argfirst()
    fst = a
  else if fst != a
    fstSpark = spark(fst)
    aSpark = spark(a)
    b = assertfail("'same()': found different values '\{fstSpark}' and '\{aSpark}'.")
  return a
  
def process same(a: text) as "same{text}" default "" with
  keep fst = ""
  if argfirst()
    fst = a
  else if fst != a
    b = assertfail("'same()': found different values '\{fst}' and '\{a}'.")
  return a

def process same(a: embedding) as "same{emb}" default bad_emb__() with
  keep fst = bad_emb__()
  if argfirst()
    fst = a
  else if fst != a
    fstSpark = spark(fst)
    aSpark = spark(a)
    b = assertfail("'same()': found different values '\{fstSpark}' and '\{aSpark}'.")
  return a

//////////////////////////////////////////////////////////////////
/// argmin/max (all versions)
//////////////////////////////////////////////////////////////////

def process argmin(score: number, val: number) as "argmin{num,num}" default 0 with
  keep minScore = 0
  keep mini = 0
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    mini = val
    minScore = score

  return mini
    
def process argmax(score: number, val: number) as "argmax{num,num}" default 0 with
  keep maxScore = 0
  keep maxi = 0
  if argfirst()
    maxScore = score
    maxi = val
  else if score > maxScore
    maxi = val
    maxScore = score

  return maxi
    
def process argmin(score: number, val: boolean) as "argmin{num,bool}" default false with
  keep minScore = 0
  keep mini = false
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    mini = val
    minScore = score

  return mini
    
def process argmax(score: number, val: boolean) as "argmax{num,bool}" default false with
  keep maxScore = 0
  keep maxi = false
  if argfirst()
    maxScore = score
    maxi = val
  else if score > maxScore
    maxi = val
    maxScore = score

  return maxi
    
def process argmin(score: number, val: text) as "argmin{num,txt}" default "" with
  keep minScore = 0
  keep mini = ""
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    mini = val
    minScore = score

  return mini
    
def process argmax(score: number, val: text) as "argmax{num,txt}" default "" with
  keep maxScore = 0
  keep maxi = ""
  if argfirst()
    maxScore = score
    maxi = val
  else if score > maxScore
    maxi = val
    maxScore = score

  return maxi
    
def process argmin(score: number, val: date) as "argmin{num,date}" default (date(2001,1,1)) with
  keep minScore = 0
  keep mini = date(2001,1,1)
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    mini = val
    minScore = score

  return mini
    
def process argmax(score: number, val: date) as "argmax{num,date}" default (date(2001,1,1)) with
  keep maxScore = 0
  keep maxi = date(2001,1,1)
  if argfirst()
    maxScore = score
    maxi = val
  else if score > maxScore
    maxi = val
    maxScore = score

  return maxi

def process argmin(score: number, val: ordinal) as "argmin{num,ord}" default (bad_ord__()) with
  keep minScore = 0
  keep mini = bad_ord__()
  if argfirst() or score < minScore
    minScore = score
    mini = val
  return mini
    
def process argmax(score: number, val: ordinal) as "argmax{num,ord}" default (bad_ord__()) with
  keep maxScore = 0
  keep maxi = bad_ord__()
  if argfirst() or score > maxScore
    maxScore = score
    maxi = val
  return maxi
    
def process argmin(score: number, val: ranvar) as "argmin{num,dist}" default (dirac(0)) with
  keep minScore = 0
  keep mini = dirac(0)
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    mini = val
    minScore = score

  return mini
    
def process argmax(score: number, val: ranvar) as "argmax{num,dist}" default (dirac(0)) with
  keep maxScore = 0
  keep maxi = dirac(0)
  if argfirst()
    maxScore = score
    maxi = val
  else if score > maxScore
    maxi = val
    maxScore = score

  return maxi
    
def process argmin(score: number, val: zedfunc) as "argmin{num,fun}" default (linear(0)) with
  keep minScore = 0
  keep mini = linear(0)
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    mini = val
    minScore = score

  return mini
    
def process argmax(score: number, val: zedfunc) as "argmax{num,fun}" default (linear(0)) with
  keep maxScore = 0
  keep maxi = linear(0)
  if argfirst()
    maxScore = score
    maxi = val
  else if score > maxScore
    maxi = val
    maxScore = score

  return maxi

def process argmin(score: date, val: boolean) as "argmin{date,bool}" default false with
  keep minScore = date(2001, 1, 1)
  keep mini = false
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: date, val: boolean) as "argmax{date,bool}" default false with
  keep minScore = date(2001, 1, 1)
  keep mini = false
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: date, val: number) as "argmin{date,num}" default 0 with
  keep minScore = date(2001, 1, 1)
  keep mini = 0
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: date, val: number) as "argmax{date,num}" default 0 with
  keep minScore = date(2001, 1, 1)
  keep mini = 0
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: date, val: ordinal) as "argmin{date,ord}" default (bad_ord__()) with
  keep minScore = date(2001, 1, 1)
  keep mini = (bad_ord__())
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: date, val: ordinal) as "argmax{date,ord}" default (bad_ord__()) with
  keep minScore = date(2001, 1, 1)
  keep mini = (bad_ord__())
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: date, val: ranvar) as "argmin{date,dist}" default (dirac(0)) with
  keep minScore = date(2001, 1, 1)
  keep mini = dirac(0)
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: date, val: ranvar) as "argmax{date,dist}" default (dirac(0)) with
  keep minScore = date(2001, 1, 1)
  keep mini = dirac(0)
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: date, val: text) as "argmin{date,txt}" default "" with
  keep minScore = date(2001, 1, 1)
  keep mini = ""
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: date, val: text) as "argmax{date,txt}" default "" with
  keep minScore = date(2001, 1, 1)
  keep mini = ""
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: date, val: zedfunc) as "argmin{date,fun}" default (linear(0)) with
  keep minScore = date(2001, 1, 1)
  keep mini = linear(0)
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: date, val: zedfunc) as "argmax{date,fun}" default (linear(0)) with
  keep minScore = date(2001, 1, 1)
  keep mini = linear(0)
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: week, val: boolean) as "argmin{week,bool}" default false with
  keep minScore = week(date(2001, 1, 1))
  keep mini = false
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: week, val: boolean) as "argmax{week,bool}" default false with
  keep minScore = week(date(2001, 1, 1))
  keep mini = false
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: week, val: number) as "argmin{week,num}" default 0 with
  keep minScore = week(date(2001, 1, 1))
  keep mini = 0
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: week, val: number) as "argmax{week,num}" default 0 with
  keep minScore = week(date(2001, 1, 1))
  keep mini = 0
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: week, val: ordinal) as "argmin{week,ord}" default (bad_ord__()) with
  keep minScore = week(date(2001, 1, 1))
  keep mini = (bad_ord__())
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: week, val: ordinal) as "argmax{week,ord}" default (bad_ord__()) with
  keep minScore = week(date(2001, 1, 1))
  keep mini = (bad_ord__())
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: week, val: ranvar) as "argmin{week,dist}" default (dirac(0)) with
  keep minScore = week(date(2001, 1, 1))
  keep mini = dirac(0)
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: week, val: ranvar) as "argmax{week,dist}" default (dirac(0)) with
  keep minScore = week(date(2001, 1, 1))
  keep mini = dirac(0)
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: week, val: text) as "argmin{week,txt}" default "" with
  keep minScore = week(date(2001, 1, 1))
  keep mini = ""
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: week, val: text) as "argmax{week,txt}" default "" with
  keep minScore = week(date(2001, 1, 1))
  keep mini = ""
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: week, val: zedfunc) as "argmin{week,fun}" default (linear(0)) with
  keep minScore = week(date(2001, 1, 1))
  keep mini = linear(0)
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: week, val: zedfunc) as "argmax{week,fun}" default (linear(0)) with
  keep minScore = week(date(2001, 1, 1))
  keep mini = linear(0)
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: month, val: boolean) as "argmin{mnth,bool}" default false with
  keep minScore = month(date(2001, 1, 1))
  keep mini = false
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: month, val: boolean) as "argmax{mnth,bool}" default false with
  keep minScore = month(date(2001, 1, 1))
  keep mini = false
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: month, val: number) as "argmin{mnth,num}" default 0 with
  keep minScore = month(date(2001, 1, 1))
  keep mini = 0
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: month, val: number) as "argmax{mnth,num}" default 0 with
  keep minScore = month(date(2001, 1, 1))
  keep mini = 0
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: month, val: ordinal) as "argmin{mnth,ord}" default (bad_ord__()) with
  keep minScore = month(date(2001, 1, 1))
  keep mini = (bad_ord__())
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: month, val: ordinal) as "argmax{mnth,ord}" default (bad_ord__()) with
  keep minScore = month(date(2001, 1, 1))
  keep mini = (bad_ord__())
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: month, val: ranvar) as "argmin{mnth,dist}" default (dirac(0)) with
  keep minScore = month(date(2001, 1, 1))
  keep mini = dirac(0)
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: month, val: ranvar) as "argmax{mnth,dist}" default (dirac(0)) with
  keep minScore = month(date(2001, 1, 1))
  keep mini = dirac(0)
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: month, val: text) as "argmin{mnth,txt}" default "" with
  keep minScore = month(date(2001, 1, 1))
  keep mini = ""
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: month, val: text) as "argmax{mnth,txt}" default "" with
  keep minScore = month(date(2001, 1, 1))
  keep mini = ""
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: month, val: zedfunc) as "argmin{mnth,fun}" default (linear(0)) with
  keep minScore = month(date(2001, 1, 1))
  keep mini = linear(0)
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: month, val: zedfunc) as "argmax{mnth,fun}" default (linear(0)) with
  keep minScore = month(date(2001, 1, 1))
  keep mini = linear(0)
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: text, val: boolean) as "argmin{txt,bool}" default false with
  keep minScore = ""
  keep mini = false
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: text, val: boolean) as "argmax{txt,bool}" default false with
  keep minScore = ""
  keep mini = false
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: text, val: number) as "argmin{txt,num}" default 0 with
  keep minScore = ""
  keep mini = 0
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: text, val: number) as "argmax{txt,num}" default 0 with
  keep minScore = ""
  keep mini = 0
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: text, val: ordinal) as "argmin{txt,ord}" default (bad_ord__()) with
  keep minScore = ""
  keep mini = (bad_ord__())
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: text, val: ordinal) as "argmax{txt,ord}" default (bad_ord__()) with
  keep minScore = ""
  keep mini = (bad_ord__())
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: text, val: ranvar) as "argmin{txt,dist}" default (dirac(0)) with
  keep minScore = ""
  keep mini = dirac(0)
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: text, val: ranvar) as "argmax{txt,dist}" default (dirac(0)) with
  keep minScore = ""
  keep mini = dirac(0)
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: text, val: text) as "argmin{txt,txt}" default "" with
  keep minScore = ""
  keep mini = ""
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: text, val: text) as "argmax{txt,txt}" default "" with
  keep minScore = ""
  keep mini = ""
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: text, val: zedfunc) as "argmin{txt,fun}" default (linear(0)) with
  keep minScore = ""
  keep mini = linear(0)
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    minScore = score
    mini = val

  return mini

def process argmax(score: text, val: zedfunc) as "argmax{txt,fun}" default (linear(0)) with
  keep minScore = ""
  keep mini = linear(0)
  if argfirst()
    minScore = score
    mini = val
  else if score > minScore
    minScore = score
    mini = val

  return mini

def process argmin(score: text, val: date) as "argmin{txt,date}" default (date(2001,1,1)) with
  keep minScore = ""
  keep mini = date(2001,1,1)
  if argfirst()
    minScore = score
    mini = val
  else if score < minScore
    mini = val
    minScore = score

  return mini
    
def process argmax(score: text, val: date) as "argmax{txt,date}" default (date(2001,1,1)) with
  keep maxScore = ""
  keep maxi = date(2001,1,1)
  if argfirst()
    maxScore = score
    maxi = val
  else if score > maxScore
    maxi = val
    maxScore = score

  return maxi

//////////////////////////////////////////////////////////////
/// Last of simple value only (complex would induce a copy
/// we don't want that)
//////////////////////////////////////////////////////////////
def process last(v : number) as "last{num}" default 0 with
  return v

def process last(v : double) as "last{dbl}" default to.double(0) with
  return v

def process last(v : long) as "last{long}" default to.long(0) with
  return v

def process last(v : flagset) as "last{flag}" default emptySet() with
  return v

def process last(v : date) as "last{date}" default date(2001,1,1) with
  return v

def process last(v : month) as "last{mnth}" default month(date(2001,1,1)) with
  return v

def process last(v : week) as "last{week}" default week(date(2001,1,1)) with
  return v

def process last(v : boolean) as "last{bool}" default false with
  return v

def process last(v : embedding) as "last{emb}" default bad_emb__() with
  return v

// this could be, but not done due to the large performance impact
// keeping them in IL allows us to skip copy!
//
// def process last(v : text) as "last{text}" default "" with
//   return v
// 
// def process last(v : ranvar) as "last{dist}" default (dirac(0)) with
//   return v
// 
// def process last(v : zedfunc) as "last{fun}" default (linear(0)) with
//   return v

//////////////////////////////////////////////////////////////
/// Whichever/first, whichever come first
//////////////////////////////////////////////////////////////

def process first(a: flagset) as "first{flag}" default emptySet() with
  keep first = emptySet()
  if argfirst()
    first = a
  return first

def process first(a: number) as "first{num}" default 0 with
  keep first = 0
  if argfirst()
    first = a
  return first

def process first(a: ordinal) as "first{ord}" default bad_ord__() with
  keep first = bad_ord__()
  if argfirst()
    first = a
  return first

def process first(a: text) as "first{text}" default "" with
  keep first = ""
  if argfirst()
    first = a
  return first

def process first(a: date) as "first{date}" default (date(2001, 1, 1)) with
  keep first = date(2001, 1, 1)
  if argfirst()
    first = a
  return first

def process first(a: month) as "first{mnth}" default (month(date(2001, 1, 1))) with
  keep first = month(date(2001, 1, 1))
  if argfirst()
    first = a
  return first

def process week(a: week) as "first{week}" default (week(date(2001, 1, 1))) with
  keep first = week(date(2001, 1, 1))
  if argfirst()
    first = a
  return first

def process first(a: boolean) as "first{bool}" default false with
  keep first = false
  if argfirst()
    first = a
  return first

def process first(a: ranvar) as "first{dist}" default (dirac(0)) with
  keep first = dirac(0)
  if argfirst()
    first = a
  return first

def process first(a: zedfunc) as "first{fun}" default (linear(0)) with
  keep first = linear(0)
  if argfirst()
    first = a
  return first

def process first(a: double) as "first{dbl}" default (to.double(0)) with
  keep first = to.double(0)
  if argfirst()
    first = a
  return first

def process first(a: long) as "first{long}" default (to.long(0)) with
  keep first = to.long(0)
  if argfirst()
    first = a
  return first

def process first(a: embedding) as "first{emb}" default bad_emb__() with
  keep first = bad_emb__()
  if argfirst()
    first = a
  return first

//////////////////////////////////////////////////////////////
/// smudge
//////////////////////////////////////////////////////////////

def process smudge(val : boolean, present: boolean) as "smudge{bool,bool}" default false with
  keep tmp = false
  if present
    tmp = val
  return tmp

def process smudge(val : number, present: boolean) as "smudge{num,bool}" default 0 with
  keep tmp = 0
  if present
    tmp = val
  return tmp

def process smudge(val : date, present: boolean) as "smudge{date,bool}" default date(2001,1,1) with
  keep tmp = date(2001,1,1)
  if present
    tmp = val
  return tmp

def process smudge(val : text, present: boolean) as "smudge{text,bool}" default "" with
  keep tmp = ""
  if present
    tmp = val
  return tmp


//////////////////////////////////////////////////////////////
/// expsmooth
//////////////////////////////////////////////////////////////
def process expsmooth(src: number, factor: number; init: number) as "expsmooth{num,num;num}" default 0 with
  keep prev = init
  prev = factor * src + (1 - factor) * prev
  return prev
    
//////////////////////////////////////////////////////////////
/// partition
//////////////////////////////////////////////////////////////

def process partition(max: number) as "partition{num}" default 1 with 
  keep prev = 0
  prev = if prev >= max then 1 else prev + 1
  return prev

//////////////////////////////////////////////////////////////
/// rgb
//////////////////////////////////////////////////////////////

def pure rgb(r : number, g : number, b : number) as "rgb" with
  if r < 0 or r > 1 or g < 0 or g > 1 or b < 0 or b > 1
    _ = assertfail("Color components must be in [0, 1].")
  rr = to.long(r * 255)
  gg = to.long(g * 255)
  bb = to.long(b * 255)
  return "#\{rr:X2}\{gg:X2}\{bb:X2}"

//////////////////////////////////////////////////////////////
/// dispersion
//////////////////////////////////////////////////////////////

def pure dispersion(r : ranvar) as "dispersion" with
  mean = mean(r)
  variance = variance(r)
  if mean <= 0 
    _ = assertfail("Mean must be strictly greater than 0.")
  return variance/mean

//////////////////////////////////////////////////////////////
/// Year start and end dates defined by a month primitive 
/// object and a year number.
//////////////////////////////////////////////////////////////

def pure yearStart(y: number) as "yearStart(num)" with
  return date(y, 1, 1)

def pure yearStart(m: month) as "yearStart(mnth)" with
  return yearStart(date(m, 1))

def pure yearEnd(y: number) as "yearEnd(num)" with
  return date(y, 12, 31)
    
def pure yearEnd(m: month) as "yearEnd(mnth)" with
  return yearEnd(date(m, 1))

//////////////////////////////////////////////////////////////
/// sliceUrl overload.
//////////////////////////////////////////////////////////////

def pure sliceUrl(slice : ordinal, tab : text) as "sliceurl(ord,txt)" with
  return concat(sliceUrl(slice),"&t=\{tab}")

//////////////////////////////////////////////////////////////
/// fieldCount function.
//////////////////////////////////////////////////////////////

def pure fieldCount(haystack : text, sep : text) as "fieldCount(txt,txt)" with
  return if strlen(haystack) == 0 then 0 else containsCount(haystack, sep) + 1

//////////////////////////////////////////////////////////////
// changed function.
//////////////////////////////////////////////////////////////

def process changed(next: number) as "changed{num}" default false with
  keep prev = 0
  changed = prev != next
  prev = next
  return argfirst() or changed

def process changed(next: date) as "changed{date}" default false with
  keep prev = date(2001,1,1)
  changed = prev != next
  prev = next
  return argfirst() or changed

def process changed(next: week) as "changed{week}" default false with
  keep prev = week(2001,1)
  changed = prev != next
  prev = next
  return argfirst() or changed

def process changed(next: month) as "changed{mnth}" default false with
  keep prev = month(2001,1)
  changed = prev != next
  prev = next
  return argfirst() or changed

def process changed(next: ranvar) as "changed{dist}" default false with
  keep prev = dirac(0)
  changed = prev != next
  prev = next
  return argfirst() or changed

def process changed(next: zedfunc) as "changed{fun}" default false with
  keep prev = linear(0)
  changed = prev != next
  prev = next
  return argfirst() or changed

def process changed(next: double) as "changed{dbl}" default false with
  keep prev = to.double(0)
  changed = prev != next
  prev = next
  return argfirst() or changed

def process changed(next: ordinal) as "changed{ord}" default false with
  keep prev = bad_ord__()
  changed = prev != next
  prev = next
  return argfirst() or changed

def process changed(next: text) as "changed{text}" default false with
  keep prev = ""
  changed = prev != next
  prev = next
  return argfirst() or changed

def process changed(next: boolean) as "changed{bool}" default false with
  keep prev = false
  changed = prev != next
  prev = next
  return argfirst() or changed

def process changed(next: long) as "changed{long}" default false with
  keep prev = to.long(0)
  changed = prev != next
  prev = next
  return argfirst() or changed
  
//////////////////////////////////////////////////////////////
/// consume function
//////////////////////////////////////////////////////////////

def process consume(qtyAvailable: number; qtyRequested: number) as "consume{number;number}" with
  keep leftRequested = qtyRequested
  qtyConsumed = min(qtyAvailable, leftRequested)
  leftRequested = leftRequested - qtyConsumed
  return qtyConsumed