anchor.diff:    // end moving window functions
   
     // Helps create an expanding window calculation
  -  //   minObs is the minimum number of observations 
  +  //   winSz is the minimum window size
     //   fupdate takes the current state and incoming observation to the next state
     //   ftransf takes the current state to the current output
     let internal expandingWindowFn winSz initState fupdate ftransf (source: seq<_>) =
       source 
       |> Seq.scan fupdate initState 
  -    |> Seq.skip winSz
       |> Seq.map ftransf 
   
     // Knuth/Welford algorithm for online stats updating
  -  // ref: http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#On-line_algorithm            
  +  // see: http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#On-line_algorithm            
     type Moments = { 
       nobs : float 
       sum  : float 
  
positive.code: 
  [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]    
  module Stats =
    // -- Experimental window logic 
    // - TODO: 
    //    -- still to do, possibly: prod, min, max, median, quantile, corr, cov
  
    let internal applySeriesProj keyProj (denseProj:float seq -> float seq) (sparseProj:float option seq -> float option seq) 
      (series:Series<'K, float>) : Series<'K, float> =
      
      let newKeys = series.Index.Keys |> keyProj
      
      let makeOptionalSeries x = 
        let newVals = x |> Seq.map OptionalValue.asOption |> sparseProj
        Series(Index.ofKeys newKeys, Vector.ofOptionalValues newVals, series.VectorBuilder, series.IndexBuilder)
  
      let makeSeries x =
        let newVals = x |> denseProj
        Series(Index.ofKeys newKeys, Vector.ofValues newVals, series.VectorBuilder, series.IndexBuilder)
  
      match series.Vector.Data with
      | VectorData.DenseList x  -> makeSeries x
      | VectorData.SparseList x -> makeOptionalSeries x
      | VectorData.Sequence x   -> makeOptionalSeries x
      
    // moving window functions:
  
    // Helps create a moving window calculation
    // nb. adopted from Seq.windowed in F# code base
    //   finit takes the first fully populated window array to an initial state
    //   fupdate takes the current state, incoming observation, and out-going observation to the next state
    //   ftransf takes the current state to the current output
    let internal movingWindowFn winSz finit fupdate ftransf (source: seq<_>) =
      seq {
         let arr = Array.zeroCreate winSz 
         let r = ref (winSz - 1)
  
negative.code:     | Some x -> updateMoments state x
      | None   -> state
  
    let internal applyExpandingStatsTransform minObs (proj: Moments -> float) series =
      if minObs < 1 then invalidArg "minObs" "minObs must be at least 1"
      let proj' s = if (int s.nobs) >= minObs then proj s else nan
      let filtProj s = if (int s.nobs) >= minObs then Some(proj s) else None
      let initState = {nobs = 0.0; sum = 0.0; M1 = 0.0; M2 = 0.0; M3 = 0.0; M4 = 0.0 }
      let calcDense = expandingWindowFn minObs initState updateMoments proj' 
      let calcSparse = expandingWindowFn minObs initState updateMomentsSparse filtProj
      applySeriesProj calcDense calcSparse series
  
    // expanding window functions
  
    let expandingCount minObs (series:Series<'K, float>) : Series<'K, float> =
      applyExpandingStatsTransform minObs (fun w -> w.nobs) series
  
    let expandingSum minObs (series:Series<'K, float>) : Series<'K, float> =
      applyExpandingStatsTransform minObs (fun w -> w.sum) series
  
    let expandingMean minObs (series:Series<'K, float>) : Series<'K, float> =
      applyExpandingStatsTransform minObs (fun w -> w.M1) series
  
    let expandingVariance minObs (series:Series<'K, float>) : Series<'K, float> =
      let toVar w = w.M2 / (w.nobs - 1.0)
      applyExpandingStatsTransform minObs toVar series
  
    let expandingStdDev minObs (series:Series<'K, float>) : Series<'K, float> =
      let toStdDev w = w.M2 / (w.nobs - 1.0) |> sqrt
      applyExpandingStatsTransform minObs toStdDev series
  
    let expandingSkew minObs (series:Series<'K, float>) : Series<'K, float> =
      // population -> sample estimate    
      let toEstSkew w = 
        if w.nobs < 3.0 then nan else
          let adjust = (sqrt (w.nobs * (w.nobs - 1.0))) / (w.nobs - 2.0)
          adjust * (sqrt w.nobs) * w.M3 / (w.M2 ** 1.5) 
      applyExpandingStatsTransform minObs toEstSkew series
  
    let expandingKurt minObs (series:Series<'K, float>) : Series<'K, float> =
      // population -> sample estimate
      let toEstKurt w = 
        if w.nobs < 4.0 then nan else
          let adjust p = (6.0 + p * (w.nobs + 1.0)) * (w.nobs - 1.0) / ((w.nobs - 2.0) * (w.nobs - 3.0))
          adjust ((w.nobs * w.M4) / (w.M2 * w.M2) - 3.0)
      applyExpandingStatsTransform minObs toEstKurt series
  
    // end expanding window functions
  
  