predictSequence.frink

Download or view predictSequence.frink in plain text format


use functionUtils.frink

/** This program contains routines to predict a sequence.  These are generally
    achieved by finding the differences or quotients of terms, but there are
    other techniques that, say, try to force a polynomial fit onto the data.
*/

fit[list, numAdditionalTerms=1, debug=false] :=
{
   level = 0
   do
   {
      [result, perfectFit, nextRowPoly, symbolic, polyFunc] = polynomialFit[list, numAdditionalTerms-level, debug, true]
      if perfectFit
         return polyFunc
      else
      {
         println["nextRowPoly is $nextRowPoly"]
         [result, perfectFit, nextRowQuot, symbolic, quotFunc] = quotientFit[nextRowPoly, numAdditionalTerms-level-1, debug, true]
         if perfectFit
            return polyFunc[quotFunc[x]]
      }
      
      [result, perfectFit, nextRowQuot, symbolic, quotFunc] = quotientFit[list, numAdditionalTerms-level, debug, true]
      if perfectFit
         return quotFunc
      else
      {
         println["nextRowQuot is $nextRowQuot"]
         [result, perfectFit, nextRowPoly, symbolic, polyFunc] = polynomialFit[nextRowQuot, numAdditionalTerms-level-1, debug, true]
         if perfectFit
            return quotFunc[polyFunc[x]]
      }

      level = level + 1
   } while level < numAdditionalTerms

   return "match not found"
}

/** This is one version that forces a polynomial fit onto the data.  See
    http://extremelearning.com.au/a-simple-formula-for-sequences-and-series/

    although it's not clear from the article that it's fitting a polynomial
    onto the data and that it won't work for geometric terms, or a Fibonacci
    sequence, or whatever.
*/

polynomialFit[list, numAdditionalTerms=10, debug=false, returnExtra=false] :=
{
   list2 = deepCopy[list]
   first = new array
   first@0 = list2@0
   
   origlen = length[list]
   var nextRow
   var symbolic
   level = 0

   LEVEL:
   while (len = length[list2]) >= 2
   {
      diffs = new array
      allZero = true
      for i=0 to len-2
      {
         diff = list2@(i+1) - list2@i
         diffs@i = diff
         if (diff != 0)
            allZero = false
      }

      if debug
         println[diffs]
      
      first.push[diffs@0]
      list2 = diffs
      if returnExtra and level==0
         nextRow = diffs
      
      if allZero == true or len <= 2
      {
         if debug
            println["first is " + first]
         result = new array
         for n = 0 to origlen + numAdditionalTerms - 1
         {
            Tn = 0
            symbolic = 0
            for i = rangeOf[first]
            {
               Tn = Tn + first@i * binomial[n, i]
               symbolic = symbolic + first@i * binomialSymbolic[n,i]
            }
            result.push[Tn]
            if debug
               println["Symbolic is $symbolic"]
         }
         if returnExtra == false
            return result
         else
            return [result, allZero, nextRow, symbolic, toFunction[noEval[n], symbolic]]
       }
       level = level + 1
   }
}

/** This tries the quotient of terms to try and predict a series.
*/

quotientFit[list, numAdditionalTerms=10, debug=false, returnExtra=false] :=
{
   list2 = deepCopy[list]
   first = new array
   first@0 = list2@0
   
   difftri = new array
   difftri.push[list2]
   
   origlen = length[list]

   level:
   while (len = length[list2]) >= 2
   {
      diffs = new array
      allone = true
      for i=0 to len-2
      {
         diff = list2@(i+1) / list2@i
         diffs@i = diff
         if (diff != 1)
            allone = false
      }

      difftri.push[diffs]
      
      if debug
         println[diffs]
      
      first.push[diffs@0]
      list2 = diffs
      
      if allone == true or len <= 2
      {
         if debug
            println["first is " + first]
         if debug
            println["difftri is\n" + join["\n", difftri]]
         result = deepCopy[list]
         for n = 1 to numAdditionalTerms
         {
            // copy last entry in difftri
            lastRow = difftri@(length[difftri] - 1)
            lastRow.push[lastRow@(length[lastRow]-1)]

//            if debug
//               println["New sorta difftri is $difftri"]
            for i=length[difftri]-2 to 0 step -1
            {
               row     = difftri@i
               nextRow = difftri@(i+1)
               row.push[row@(length[row]-1) * nextRow@(length[nextRow]-1)]
            }

            if debug
               println["New difftri is " + difftri]
         }
        
         if returnExtra == false
            return difftri@0
         else
         {
            symbolic = list@0 * (list@1/list@0) ^ noEval[n]
            return [difftri@0, allone, difftri@1, symbolic, toFunction[noEval[n], symbolic]]
         }
      }
   }
}

binomialSymbolic[n,k] :=
{
   if (k<=0 or k>=n)
      return 1
   
   if (n - k) > k
      k = (n-k)

   product = 1 / (n-k)!
   
   for i = 0 to n-k-1
      product = product * (noEval[n] - i)
   return product 
}

toFunction[symbol, symbolic] :=
{
   return constructExpression["AnonymousFunction", [[makeSymbol[symbol]], symbolic]]
}


Download or view predictSequence.frink in plain text format


This is a program written in the programming language Frink.
For more information, view the Frink Documentation or see More Sample Frink Programs.

Alan Eliasen was born 20139 days, 7 hours, 35 minutes ago.