
.10.dp.source-code.fit.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core_2.10 Show documentation
Show all versions of core_2.10 Show documentation
Core drx utilities that have no other dependencies other than the core scala lib
The newest version!
/*
Copyright 2010 Aaron J. Radke
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cc.drx
import scala.collection.Iterable
trait Fitter[T]{
def fit[A](proto:T, ds:Iterable[A], f:A=>(Double,Double)):T
}
/*
trait Univariate[T]{
def apply(x:Double):Double //evaluate
def grad(x:Double):T //define the gradient
def coefs:ListMap[Symbol,Double]
//--derived
def toKson:String = coefs map {(k,v) => s"$k:$v"} mkString " "
def fromCoefArray(coefs:Array[Double]):T = new T()
def coefArray:Array[Double] = coeffs
}
*/
//TODO add an implicit fitting function here using Chomsky decomposition and forward/backward solving. For now use external libs wrappers like drx.Math._ that wraps apache commons
// object Fitter{
// implicit object FitterPolynomial extends cc.drx.Fitter[Polynomial]{
// def fit[A](proto:Polynomial, ds:Iterable[A], f:A=>(Double,Double)):Polynomial = ???
// }
// }
case class FirstOrderStep(a:Double, w:Double){
def apply(x:Double):Double = a*(1.0 - math.exp(-w*x))
override def toString = f"$a*(1 - e^(-$w*x))"
def toKson = f"FirstOrderStep a:$a w:$w"
def fit[A](ds:Iterable[A])(implicit f:A=>(Double,Double), fitter:Fitter[FirstOrderStep]):FirstOrderStep = fitter.fit(this,ds,f) //if A = (Double,Double) then use the implicit Predef.identity to pluck out x and y values
}
case class Exponential(b:Double, a:Double, k:Double, t:Double){
def apply(x:Double):Double = b + a*math.exp(k*(x-t))
override def toString = f"$b + $a e^($k (x-$t))"
def toKson = f"Exponential: b:$b a:$a k:$k t:$t"
def fit[A](ds:Iterable[A])(implicit f:A=>(Double,Double), fitter:Fitter[Exponential]):Exponential = fitter.fit(this,ds,f) //if A = (Double,Double) then use the implicit Predef.identity to pluck out x and y values
}
object Polynomial{
def apply(coeffs:Double*):Polynomial = Polynomial(coeffs.toArray)
def order(n:Int) = Polynomial(Array.fill[Double](n+1)(1))
}
case class Polynomial(coeff:Array[Double]){
def order = coeff.size-1
//def apply(x:Double) = coeff.zipWithIndex.foldLeft(0.0){case (a,(c,i)) => a + c*(math.pow(x,i))}
def apply(x:Double) = coeff.foldLeft(0.0->1.0){case ((a,xi),c) => a + c*xi -> xi*x}._1
def toKson = "Polynomial coefs:" + (coeff mkString " ")
override def toString = coeff.zipWithIndex.foldLeft(""){case (a,(c,i)) =>
if(i==0) f"$c" else {
val exp = if(i>1) "^"+i else ""
val sign = if(c < 0) "-" else "+"
f"$a $sign ${c.abs} x$exp"
}
}
def fit[A](ds:Iterable[A])(implicit f:A=>(Double,Double), fitter:Fitter[Polynomial]):Polynomial = fitter.fit(this,ds,f) //if A = (Double,Double) then use the implicit Predef.identity to pluck out x and y values
}
object Logistic{
def apply():Logistic = Logistic(k=1,m=1,b=1, q=1,a=1,n=1) //reasonably well starting conditions for fitting problems
def ones = Logistic(k=1,m=1,b=1, q=1,a=1,n=1) //reasonably well starting conditions for fitting problems
}
case class Logistic(k:Double, //ending value: asymptote to \inf (or -\inf if b<0)
m:Double, //start time: (of max derivative)
b:Double, //growth rate
q:Double, //pos of curve (related to apply(0))
a:Double, //starting value: lower asymptote
n:Double //\nu pos of max growth ( >0 )
){
require(n > 0)
require(k >= a)
private val kMinusA = k - a
private val nInv = 1.0/n
def apply(x:Double) = a + kMinusA / math.pow(1.0 + q * math.exp(b * (m-x)), nInv)
override def toString = f"$a + $kMinusA / (1 + $q * e^($b * ($m-x)))^$nInv";
def toKson = f"Logistic k:$k m:$m b:$b q:$q a:$a n:$n"
def fit[A](ds:Iterable[A])(implicit f:A=>(Double,Double), fitter:Fitter[Logistic]):Logistic = fitter.fit(this,ds,f)
def shift(x:Double) = copy(m = m+x)
}