Additional optimisation options
[modiphy.git] / src / main / scala / org / modiphy / math / ActorModel.scala
blob204a014985071c50807a7fb8a7a5b8e9a7b5da2b
1 package org.modiphy.math
2 import EnhancedMatrix._
3 import org.modiphy.tree._
4 import org.modiphy.tree.DataParse.Tree
5 import org.modiphy.sequence._
6 import scala.collection.immutable.{Map,IntMap}
7 import scala.actors.Actor
8 import scala.actors.Actor._
9 import scala.actors.OutputChannel
10 import tlf.Logging
12 object ParamScheduler extends scala.actors.scheduler.ForkJoinScheduler(10,400,true,false)
14 trait ParamActor extends Actor{
15 override def scheduler = ParamScheduler
17 abstract class ActorModelComponent extends ParamActor with Logging
19 trait SimpleActorModelComponent extends ActorModelComponent{
20 def params:List[ActorParamComponent]
21 def rec1:Option[Actor]
22 lazy val numParams = params.length
23 lazy val paramNames=params.map{_.name}
24 lazy val pActorMap=paramNames.zip(params).foldLeft(Map[ParamName,ActorParamComponent]()){_+_}
25 var pMap:Map[ParamName,ParamChanged[_]]=null
26 override def start={
27 debug{"Setup start" + this}
28 params.foreach{p=>
29 p addActor this
31 pMap = params.map{p=>
32 var x = (p !? (4000,RequestParam))
33 while (x.isEmpty){
34 debug{"LOOP"}
35 x = (p !? (4000,RequestParam))
37 x.get
38 }.map{_.asInstanceOf[ParamChanged[_]]}.map{p=>(p.name,p)}.foldLeft(Map[ParamName,ParamChanged[_]]()){_+_}
39 pMap.map{_._2}.foreach{updateParam}
40 if (rec1.isDefined){rec1.get.start}
41 debug{"Setup " + this}
42 super.start
44 def act{
45 loop{
46 react{myHandler.orElse {
47 case a:Any =>
48 if (rec1.isDefined){
49 rec1.get forward a
50 }else {
51 println(self + " received unexpected message" + a)
57 def matReq[A <: BioEnum](m:MatReq[A]):MatReq[A]
58 def updateParam(p:ParamChanged[_])
60 def sendUnclean(p:ParamName)={
61 if (rec1.isDefined){ rec1.get forward Unclean(pActorMap(p))}
62 else {reply(Unclean(pActorMap(p)))}
64 /**
65 called when a downstream component has a parameter changed
67 def unclean:Unit
68 def myHandler = handlers
69 lazy val handlers = {
71 val mainHandler:PartialFunction[Any,Unit]={
72 case m:QMatReq[BioEnum]=>
73 val ans = matReq(m.toMatReq).toQMatReq
74 if (rec1.isDefined){
75 rec1.get forward ans
77 else {sender ! ans}
78 case m:MatReq[BioEnum]=>
79 val ans = matReq(m)
80 if (rec1.isDefined){rec1.get forward ans}
81 else {sender ! ans}
82 case Unclean(a)=>
83 unclean
84 if (rec1.isDefined){rec1.get forward Unclean(a)}
85 else {reply(Unclean(a))}
87 paramNames.map{p=>
89 case ParamChanged(`p`,param)=>
90 sendUnclean(p)
91 updateParam(ParamChanged(`p`,param))
92 }:PartialFunction[Any,Unit]
93 }.foldLeft(mainHandler){_ orElse _}
96 def problem(s:String)={
97 warning{s}
103 sealed trait NMessage{
104 def n:Int
107 case class SwitchingRate(val n:Int) extends NMessage
111 case class Params(list:List[ActorParamComponent])
112 object GetParams extends Params(Nil)
113 class MatBuilder(m:Option[Map[Node[_],Matrix]])
114 case class Unclean(sender:Actor)
115 case object RequestOpt
116 object RequestParam
117 sealed trait ParamName
118 trait ConcreteParamName extends ParamName{
119 def i:Int
121 case class Pi(i:Int) extends ConcreteParamName
122 case class S(i:Int) extends ConcreteParamName
123 case class BranchLengths(i:Int) extends ConcreteParamName
124 case class Alpha(i:Int) extends ConcreteParamName
125 case class InvarPrior(i:Int) extends ConcreteParamName
126 case class Sigma(i:Int) extends ConcreteParamName
127 case class SingleParam(p:ParamName) extends ParamName
128 case class JoinedParam(p:List[ParamName]) extends ParamName
131 trait ParamMatcher extends ParamName{
132 def matches(p2:ParamName):Boolean
134 case class All(p:ConcreteParamName) extends ParamMatcher{
135 def matches(p2:ParamName)={
136 p2!=null && (p2.getClass==p.getClass)
139 case class AllMatches(p:ConcreteParamName,f:Int=>Boolean) extends ParamMatcher{
140 def matches(p2:ParamName)={
141 p2!=null && (p2.getClass==p.getClass) && f(p2.asInstanceOf[ConcreteParamName].i)
144 //This doesn't seem ideal and may be improved...
145 case class AllSingle(p:ConcreteParamName) extends ParamMatcher{
146 def matches(p2:ParamName)={
147 p2!=null && (p2.getClass==p.getClass)
151 object LazyP{
152 type PFact={def apply(i:Int):ConcreteParamName}
153 implicit def lazymaker(p:PFact)=p(0)
156 case class ParamUpdate[A](d:A)
157 case class ParamChanged[A](name:ParamName,param:A){
158 def toParamUpdate = ParamUpdate(param)
161 object Lower
162 object Upper
166 Optimiser may have different view of params (log of real params, for example)
168 case class OptUpdate(d:Array[Double])
170 class BasicActorModel(piParam:ActorPiComponent,sParam:ActorSComponent,rec:Actor) extends ActorModelComponent with SimpleActorModelComponent{
171 val params = piParam :: sParam :: Nil
172 val piName = piParam.name
173 val sName = sParam.name
174 val rec1 = Some(rec)
175 var pi:Vector = null
176 var sMat:Matrix = null
177 var mat:Option[Matrix]=None
178 def updateParam(p:ParamChanged[_]){
179 p match {
180 case ParamChanged(`piName`,v:Vector)=>
181 pi = v
182 unclean
183 case ParamChanged(`sName`,m:Matrix) =>
184 sMat = m
185 unclean
188 def unclean{mat=None}
189 def matReq[A <: BioEnum](m:MatReq[A])={
190 val myMat = if (mat.isDefined){
191 mat.get
192 }else {
193 mat = Some(sMat.sToQ(pi))
194 mat.get
196 MatReq(m.n,Some(myMat),Some(pi))
199 class NormaliserActorModel(rec:Actor) extends SimpleActorModelComponent{
200 val params = Nil
201 val rec1 = Some(rec)
202 var mat:Option[Matrix]=None
203 def updateParam(p:ParamChanged[_]){
205 def unclean{mat=None}
206 def matReq[A <: BioEnum](m:MatReq[A])={
207 if (mat.isDefined){
208 MatReq(m.n,mat,m.pi)
209 }else {
210 mat = Some(m.m.get.normalize(m.pi.get))
211 MatReq(m.n,mat,m.pi)
216 class THMMActorModel(sigmaParam:ActorFullSComponent,numClasses:Int,rec:Actor) extends SimpleActorModelComponent{
217 val sigmaName = sigmaParam.name
218 val params = sigmaParam :: Nil
219 val rec1 = Some(rec)
220 var mat:Option[Matrix]=None
221 var switchingRate:Option[Double]=None
222 var sigma:Matrix = null
223 def updateParam(p:ParamChanged[_]){
224 p match {
225 case ParamChanged(`sigmaName`,m:Matrix)=>
226 sigma = m
227 unclean
230 def unclean{ mat=None }
232 pi must be the new length, m is pi.length - numAA
234 def applyMat(m:Matrix,pi:Vector,sigma:Matrix):(Matrix,Double)={
235 val qStart = m.copy
236 val numAlpha = m.rows / numClasses
237 var switching = 0.0
238 for (i <- 0 until numClasses){
239 for (j <- i+1 until numClasses){
240 for (x <- 0 until numAlpha){
241 qStart(i * numAlpha + x, j * numAlpha + x) = sigma(i,j) * pi(j * numAlpha + x) // i->j transition
242 qStart(j * numAlpha + x, i * numAlpha + x) = sigma(i,j) * pi(i * numAlpha + x) // j->i transition
243 switching = switching + sigma(i,j) * pi(j * numAlpha + x) * pi(i * numAlpha + x) * 2
247 qStart.fixDiag
248 (qStart,switching)
251 def matReq[A <: BioEnum](m:MatReq[A])={
252 m match {
253 case MatReq(n,Some(m),Some(pi))=>
254 if (mat.isDefined){mat}
255 else {
256 val (myMat,switch) = applyMat(m,pi,sigma)
257 mat = Some(myMat)
258 switchingRate=Some(switch)
260 MatReq(n,mat,Some(pi))
261 case m:MatReq[_]=>
262 problem(m + " is not defined")
266 override def myHandler = {
267 val h:PartialFunction[Any,Unit]={
268 case SwitchingRate(n) =>
269 reply(switchingRate)
271 h orElse (super.myHandler)
279 class InvarActorModel(priorParam:ActorProbComponent,piParam:ActorPiComponent,numClasses:Int,rec:Actor) extends SimpleActorModelComponent{
280 val priorName=priorParam.name
281 val piName = piParam.name
282 val params = priorParam :: piParam :: Nil
283 var rec1=Some(rec)
284 var processedPi:Option[Vector]=None
285 var mat:Option[Matrix]=None
286 var prior:Double = 0.0D
287 var pi:Vector = null
289 def updateParam(p:ParamChanged[_]){
290 p match {
291 case ParamChanged(`priorName`,d:Double)=>
292 prior = d
293 unclean
294 case ParamChanged(`piName`,v:Vector)=>
295 pi=v
296 unclean
299 def unclean{
300 processedPi = None
301 mat = None
304 pi must be the new length, m is pi.length - numAA
306 def applyMat(m:Matrix,pi:Vector):Matrix={
307 val newMatSize = pi.size
308 val mat = Matrix(newMatSize,newMatSize)
309 mat.viewPart(0,0,m.rows,m.rows).assign(m)
312 def applyPi(oldPi:Vector):Vector={
313 val newPi = Vector(oldPi.size + pi.size)
314 newPi.viewPart(0,oldPi.size).assign(oldPi * (1.0D-prior))
315 newPi.viewPart(oldPi.size,pi.size).assign(pi * prior)
316 newPi
319 def matReq[A <: BioEnum](m:MatReq[A])={
320 m match{
321 case MatReq(n,Some(m),Some(p))=>
322 val myPi = if (processedPi.isDefined){
323 processedPi.get
324 }else{
325 processedPi=Some(applyPi(p))
326 processedPi.get
328 val myMat = if (mat.isDefined){
329 mat.get
330 }else {
331 mat = Some(applyMat(m,myPi))
332 mat.get
334 MatReq(n,mat,processedPi)
335 case m:MatReq[_] =>
336 problem(m + " not completely defined")
342 class GammaActorModel(shape:ActorGammaComponent,numClasses:Int,rec:Actor) extends SimpleActorModelComponent{
343 val rec1 = Some(rec)
344 val shapeName = shape.name
345 val params = shape :: Nil
346 val gamma = new Gamma(numClasses)
347 var alpha = 1.0
348 var mat:Option[Matrix] = None
349 var processedPi:Option[Vector] = None
351 def applyMat(m:Matrix,alpha:Double,pi:Vector):Matrix={
352 val r = gamma(alpha)
353 debug{"GAMMA " + alpha + " " + r.mkString(" ")}
354 val myMat = Matrix(m.rows*numClasses,m.columns * numClasses)
355 val numAlpha = m.rows
356 (0 until numClasses).foreach{i=>
357 myMat.viewPart(i * numAlpha,i * numAlpha,numAlpha,numAlpha).assign(m) * r(i)
359 myMat
362 def matReq[A <: BioEnum](m:MatReq[A])=m match{
363 case MatReq(n,Some(m),Some(p)) =>
364 if (mat.isEmpty){
365 mat = Some(applyMat(m,alpha,p))
367 if (processedPi.isEmpty){
368 processedPi = Some(applyPi(p))
370 MatReq(n,mat,processedPi)
371 case m:MatReq[A]=>
372 problem("Unfilled " + m)
376 def unclean{
377 mat = None
378 processedPi = None
380 def updateParam(p:ParamChanged[_]){
381 p match {
382 case ParamChanged(`shapeName`,d:Double) =>
383 alpha=d
384 unclean
388 def applyPi(pi:Vector):Vector={
389 val numAlpha = pi.size
390 val myPi = Vector(numAlpha * numClasses)
391 val postVals = pi / numClasses.toDouble
392 (0 until numClasses).foreach{i=>
393 myPi.viewPart(i*numAlpha,numAlpha).assign(postVals)
395 myPi
399 class ForkActor[A <: BioEnum](tree:Tree[A],rec1Map:Map[Int,Actor]) extends ActorModelComponent{
400 val rec = rec1Map.values.toList.removeDuplicates
401 val numRec = rec.length
402 override def start={
403 rec1Map.values.foreach{v=>
404 v.start
406 super.start
409 def act{
410 loop{
411 react{
412 case Params(l)=>
413 rec.foreach{v=>
414 v ! Params(l)
416 getListReplies(sender,numRec,Nil)
417 case Unclean(a:ActorParamComponent) =>
418 rec.foreach{v=>
419 v !? Unclean(self)
421 reply(Unclean(a))
422 case QMatReq(n,m,p)=>
423 if (rec1Map contains n.id){
424 rec1Map(n.id) forward QMatReq(n,m,p)
425 }else {
426 warning{"Map does not contain " + n.id + " " + n}
427 sender ! QMatReq(n,m,p)
429 case MatReq(n,m,p)=>
430 if(rec1Map contains n.id){
431 rec1Map(n.id) forward MatReq(n,m,p)
432 }else {
433 if (! n.isRoot){warning{"Map does not contain " + n.id + " " + n}}
434 sender ! MatReq(n,m,p)
436 case m:NMessage=>
437 if (rec1Map contains m.n){
438 rec1Map(m.n) forward m
439 }else {
440 println(self + " received unexpected message " + m)
442 case a:Any=>
443 println(self + " received unexpected message " + a)
448 def getListReplies(output:OutputChannel[Any],toDo:Int,l:List[ActorParamComponent]){
449 if (toDo==0){
450 output ! Params(l)
453 react{
454 case Params(l2) =>
455 getListReplies(output,toDo-1,l2++l)
459 def getCleanReplies(output:Actor,toDo:Int,me:Actor){
460 if (toDo==0){
461 output ! Unclean(output)
464 react{
465 case Unclean(`me`) =>
466 getCleanReplies(output,toDo-1,me)
473 class BasicSingleExpActorModel[A <: BioEnum](tree:Tree[A],branchLengthParams:ActorTreeComponent[A],rec1:Option[Actor]) extends ActorModelComponent{
474 val blName = branchLengthParams.name
475 val nodes = tree.descendentNodes.toArray //root has no length
477 override def start={
478 branchLengthParams addActor this
479 if (rec1.isDefined){rec1.get.start}
480 super.start
482 var eigen:MatrixExponential=null
484 def act{
485 main(None,nodes.foldLeft(Map[Int,Double]()){(m,n)=>m+((n.id,n.lengthTo))})
487 def main(eigen:Option[MatrixExponential],lengths:Map[Int,Double]){
488 case class ExpReq[A <: BioEnum](n:Node[A],e:MatrixExponential,lengthTo:Double,pi:Vector)
489 react{
490 case q:QMatReq[_] =>
491 sender ! q
492 main(eigen,lengths)
493 case MatReq(n,Some(m),Some(pi)) =>
494 if (n.isRoot){//don't need exp(qt)
495 if (rec1.isDefined){rec1.get forward MatReq(n,None,Some(pi))}
496 else { sender ! MatReq(n,None,Some(pi))}
497 main(eigen,lengths)
499 val myEigen = if (eigen.isEmpty){
500 val ans = new MatExpNormal(m,pi,None)
502 }else {
503 eigen.get
505 new Actor{
506 def act{
507 react{
508 case ExpReq(n,e,lengthTo,pi)=>
509 val ans = e.exp(lengthTo)
510 if (rec1.isDefined){rec1.get forward MatReq(n,Some(ans),Some(pi))}
511 else { sender ! MatReq(n,Some(ans),Some(pi)) }
512 exit
515 }.start forward ExpReq(n,myEigen,lengths(n.id),pi)
516 main(Some(myEigen),lengths)
517 case Unclean(a)=>
518 if (rec1.isDefined){rec1.get forward Unclean(a)} else {
519 reply(Unclean(a))
521 main(None,lengths)
522 case ParamChanged(`blName`,a:Array[Double])=>
523 if (rec1.isDefined){rec1.get forward Unclean(branchLengthParams)} else {reply(Unclean(branchLengthParams))}
524 val nodeMap = nodes.zip(a).foldLeft(Map[Int,Double]()){(m,t)=>m + ((t._1.id,t._2))}
525 main(eigen,nodeMap)
530 trait ActorParamComponent extends ParamActor{
531 def name:ParamName
532 var modelComp:List[Actor]=Nil
533 def addActor(l:Actor){
534 modelComp = l::modelComp
539 case class SingleParamWrapper(p:ActorParamComponent) extends ActorParamComponent{
540 start
541 val name = SingleParam(p.name)
542 def act{
543 val mainParam = (p !? RequestOpt).asInstanceOf[Array[Double]]
544 main(Array.make(mainParam.length,mainParam(0)))
546 def lower = (p !? Lower).asInstanceOf[Array[Double]](0)
547 def upper = (p !? Upper).asInstanceOf[Array[Double]](0)
549 def main(param:Array[Double]){
550 react{
551 case RequestParam=>
552 reply(ParamChanged(name,param(0)))
553 main(param)
554 case ParamUpdate(x:Array[Double])=>
555 val newParam = Array.make(param.length,x(0))
556 p forward OptUpdate(newParam)
557 main(newParam)
558 case OptUpdate(x:Array[Double]) =>
559 val newParam = Array.make(param.length,x(0))
560 p forward OptUpdate(newParam)
561 main(newParam)
562 case RequestOpt =>
563 reply(Array(param(0)))
564 main(param)
565 case Lower =>
566 reply(Array(lower))
567 main(param)
568 case Upper =>
569 reply(Array(upper))
570 main(param)
576 object JoinedParamWrapper{
577 def apply(pList:List[ActorParamComponent])={
578 val x = new JoinedParamWrapper(pList)
579 x.start
583 class JoinedParamWrapper private(pList:List[ActorParamComponent]) extends ActorParamComponent{
584 override def start ={
585 super.start
587 val name = JoinedParam(pList.map{_.name})
588 lazy val paramArray=getParam2D.toArray
589 lazy val numParams =paramArray.map{_.size}
590 def getParam2D= pList.map{p=>(p !? RequestOpt).asInstanceOf[Array[Double]]}
591 def flatten(a:Array[Array[Double]]):Array[Double]={
592 flatten(a.toList)
594 def flatten(a:List[Array[Double]]):Array[Double]={
595 //jeez this is lazy - but it probably isn't going to slow things down too much
596 a.map{_.toList}.flatten[Double].toArray
598 def setParam(from:Array[Double],to:Array[Array[Double]])={
599 val iter = from.elements
600 for (i<-0 until to.length){
601 for (j<-0 until to(i).length){
602 to(i)(j)=iter.next
606 lazy val lower = pList.map{p=>(p !? Lower).asInstanceOf[Array[Double]].toList}.flatten[Double].toArray
607 lazy val upper = pList.map{p=>(p !? Upper).asInstanceOf[Array[Double]].toList}.flatten[Double].toArray
608 def act{
609 loop{
610 react{
611 case RequestParam=>
612 reply(ParamChanged(name,flatten(getParam2D)))
613 case ParamUpdate(x:Array[Double])=>
614 val to = paramArray.map{i=>new Array[Double](i.size)}.toArray
615 setParam(x,to)
616 pList.elements.zip(to.elements).foreach{t=>
617 val (pActor,pArray)=t
618 pActor forward OptUpdate(pArray)
620 case OptUpdate(x:Array[Double]) =>
621 val to = paramArray.map{i=>new Array[Double](i.size)}
622 setParam(x,to)
623 pList.elements.zip(to.elements).foreach{t=>
624 val (pActor,pArray)=t
625 pActor forward OptUpdate(pArray)
627 case RequestOpt =>
628 reply(flatten(getParam2D))
629 case Lower =>
630 reply(lower)
631 case Upper =>
632 reply(upper)
637 case class JoinedParamWrapper(p:List[ActorParamComponent]) extends ActorParamComponent{
638 start
639 val name = JoinedParam(p)
640 def act{
641 val current = p.map{p2 => (p2 !? RequestOpt).asInstanceOf[Array[Double]].toList}.flatten[Double].toArray
646 case class ReadSerial(x:Seq[Double])
647 case object WriteSerial
649 abstract class AbstractActorParam[A] extends ActorParamComponent with Logging{
650 override def !?(msg:Any)={
651 debug{this + " !? "+ msg}
652 val ans = super.!?(msg)
653 debug{this + " finished" }
654 ans
657 type Param = {
658 def getParams:Array[Double]
659 def setParams(a:Array[Double]):Unit
661 def internal:Param
662 def myParam:A
663 override def toString={
664 name.toString + " = " + internal.getParams.toList.mkString(",")
667 def readSerial(x:Seq[Double])=internal setParams x.toArray
668 def writeSerial:Seq[Double]=internal.getParams
670 def lower:Double
671 def upper:Double
672 def lowerArray = Array.make(internal.getParams.length,lower)
673 def upperArray = Array.make(internal.getParams.length,upper)
674 //override this if raw params are different!
675 def setRaw(p:Array[Double]){internal setParams p}
676 /*def waitOn(i:Int,o:OutputChannel[Any]){
677 finest{super.toString + " WAITING ON " + i + ":::" + this}
678 react{
679 case Unclean(_)=>
680 finest{"GOT " + i}
681 if (i==1){
682 o ! 'ok
684 }else {
685 waitOn(i-1,o)
689 private val myHandler:PartialFunction[Any,Unit] = {
690 case RequestParam=>
691 reply(ParamChanged(name,myParam))
692 case ParamUpdate(x:Array[Double])=>
693 setRaw(x)
694 modelComp.foreach{c=>
695 c !? ParamChanged(name,myParam)
697 reply('ok)
698 // waitOn(modelComp.length,sender)
699 case ParamUpdate(v:Vector)=>
700 debug{"ParamUpdate 1"}
701 setRaw(v.toArray)
702 debug{"ParamUpdate 2"}
703 modelComp.foreach{c=>
704 debug{"ParamUpdate c"}
705 c !? ParamChanged(name,myParam)
707 debug{"ParamUpdate 3"}
708 reply('ok)
709 case OptUpdate(x)=>
710 internal setParams x
711 modelComp.foreach{c=>
712 c !? ParamChanged(name,myParam)
714 reply('ok)
715 case RequestOpt=>
716 reply(internal.getParams)
717 case Lower=>
718 reply(lowerArray)
719 case Upper=>
720 reply(upperArray)
721 case ReadSerial(s) =>
722 readSerial(s)
723 reply('ok)
724 case WriteSerial =>
725 reply(writeSerial)
727 def handler:PartialFunction[Any,Unit]= {
728 myHandler
731 def act{
732 loop{
733 react{handler}
737 class ActorPiComponent(pi:Vector,val name:ParamName) extends AbstractActorParam[Vector]{
739 override def handler:PartialFunction[Any,Unit]={
740 super.handler
744 class PiParam(pi:Vector){
746 var medianIndex=0
747 def fromFit(array:Array[Double],medianIndex:Int)={
748 val exponentiated = array.map{i=>Math.exp(i)}
749 val total = (0.0D /: exponentiated){_+_} + Math.exp(0.0D)
750 ((0 to medianIndex-1 ).map{i=> exponentiated(i)/total}.toList ++ List(Math.exp(0.0D)/total) ++ (medianIndex to array.length-1).map{i=> exponentiated(i)/total}).toArray
753 def toFit(pi:Vector):(List[Double],Int)={
754 val t = (pi.toList.zipWithIndex.toList.sort{_._1<_._1})(pi.size/2)
755 medianIndex = t._2
756 def toFitness={i:Int=>Math.log(pi(i)/pi(medianIndex))}
757 ((0 to medianIndex-1).map{toFitness}.toList ++ (medianIndex+1 to pi.size-1).map{toFitness}.toList,
758 medianIndex)
761 def setParams(a:Array[Double]){pi assign fromFit(a,medianIndex)}
762 def getParams={
763 val (l,m)=toFit(pi)
764 medianIndex=m
765 l.toArray
767 def view=pi.copy
768 def setPi(p:Array[Double]){pi assign p}
772 val internal = new PiParam(pi)
774 def lower = -10 // this is log-odds scaled prob
775 def upper = 10
776 def myParam = pi
777 override def setRaw(p:Array[Double]){
778 internal setPi p
780 override def toString=name.toString + " = " + internal.view.toArray.mkString(",")
781 override def writeSerial = internal.view.toList
782 override def readSerial(x:Seq[Double])=internal.setPi(x.toArray)
784 class ActorSComponent(s:Matrix,val name:ParamName) extends AbstractActorParam[Matrix] with SMatUtil{
785 class SMatParam(s:Matrix) extends SMatUtil{
786 var cache:Option[Array[Double]]=None
787 def getParams={ if (cache.isEmpty){cache = Some(linearSMat(s).toArray)}; cache.get}
788 def setParams(a:Array[Double]) = setSMat(a,s)
790 val internal = new SMatParam(s)
791 def myParam = s
792 def lower = 0.0
793 def upper = 200
794 private val myHandler:PartialFunction[Any,Unit]={
795 case ParamUpdate(m:Matrix)=>
796 setRaw(linearSMatFull(m).toArray)
797 modelComp.foreach{c=>
798 c !? ParamChanged(name,myParam)
800 //waitOn(modelComp.length,sender)
801 reply('ok)
803 override def handler={
804 myHandler orElse (super.handler)
808 class ActorFullSComponent(s:Matrix,val name:ParamName) extends AbstractActorParam[Matrix] with SMatUtil{
809 class FullSMatParam(s:Matrix) extends SMatUtil{
810 var cache:Option[Array[Double]]=None
811 def getParams={ if (cache.isEmpty){cache = Some(linearSMatFull(s).toArray)}; cache.get}
812 def setParams(a:Array[Double]) = {setSMat(a,s);cache=None}
814 val internal = new FullSMatParam(s)
815 def lower = 0.0D
816 def upper = 200
817 def myParam = s
818 private val myHandler:PartialFunction[Any,Unit]={
819 case RequestParam=>
820 reply(ParamChanged(name,myParam))
821 case ParamUpdate(m:Matrix)=>
822 setRaw(linearSMatFull(m).toArray)
823 modelComp.foreach{c=>
824 c !? ParamChanged(name,myParam)
826 //waitOn(modelComp.length,sender)
827 reply('ok)
829 override def handler={
830 myHandler orElse (super.handler)
835 class ActorTreeComponent[B <: BioEnum](tree:Tree[B],name:ParamName) extends ActorArrayComponent(tree.getBranchLengths.toArray,name,0.0,100.0)
836 class ActorDoubleComponent(param:Double,val name:ParamName,val lower:Double,val upper:Double) extends AbstractActorParam[Double]{
837 class DoubleParam{
838 var myP:Double=param
839 def getParams=Array(myP)
840 def setParams(a:Array[Double]){myP=a(0)}
842 val internal = new DoubleParam
843 def myParam = internal.getParams(0)
845 private val myHandler:PartialFunction[Any,Unit]={
846 case ParamUpdate(x:Double)=>
847 internal.myP=x
848 modelComp.foreach{c=>
849 c !? ParamChanged(name,myParam)
851 // waitOn(modelComp.length,sender)
852 reply('ok)
854 override def handler={
855 myHandler orElse (super.handler)
858 class ActorArrayComponent(param:Array[Double],val name:ParamName,val lower:Double, val upper:Double) extends AbstractActorParam[Array[Double]]{
859 class ArrayParam{
860 var myP=param
861 def getParams = myP.toArray
862 def setParams(a:Array[Double]){Array.copy(a,0,myP,0,Math.min(a.length,myP.length))}
864 val internal = new ArrayParam
865 def myParam = internal.getParams
867 class ActorProbComponent(prob:Double,name:ParamName,min:Double,max:Double) extends ActorDoubleComponent(prob,name,min,max){
868 def this(prob:Double,name:ParamName)=this(prob,name,0,0.9)
870 class ActorGammaComponent(alpha:Double,name:ParamName) extends ActorDoubleComponent(alpha,name,0.01,1000)
871 object SimpleModel{
872 def apply[A <: BioEnum](tree:Tree[A])={
873 val pi = new ActorPiComponent(WAG.pi,Pi(0))
874 val s = new ActorSComponent(WAG.S,S(0))
875 val branchLength = new ActorTreeComponent(tree,BranchLengths(0))
876 val components = new BasicActorModel(pi,s, new NormaliserActorModel(new BasicSingleExpActorModel(tree,branchLength,None)))
877 val pList = List(pi,s,branchLength)
878 val pMap = pList.map{p => (p.name,p)}.foldLeft(Map[ParamName,ActorParamComponent]()){_+_}
879 new ActorModel(tree,components,pMap)
882 object GammaModel{
883 def apply[A <: BioEnum](tree:Tree[A])={
884 val pi = new ActorPiComponent(WAG.pi,Pi(0))
885 val s = new ActorSComponent(WAG.S,S(0))
886 val branchLength = new ActorTreeComponent(tree,BranchLengths(0))
887 val alpha = new ActorGammaComponent(0.5D,Alpha(0))
888 val components = new BasicActorModel(pi,s,
889 new GammaActorModel(alpha,tree.alphabet.numClasses,
890 new NormaliserActorModel(
891 new BasicSingleExpActorModel(tree,branchLength,None))))
892 val pList = List(pi,s,branchLength,alpha)
893 val pMap = pList.map{p => (p.name,p)}.foldLeft(Map[ParamName,ActorParamComponent]()){_+_}
894 new ActorModel(tree,components,pMap)
897 object InvarGammaModel{
898 def apply[A <: BioEnum](tree:Tree[A])={
899 val pi = new ActorPiComponent(WAG.pi,Pi(0))
900 val s = new ActorSComponent(WAG.S,S(0))
901 val branchLength = new ActorTreeComponent(tree,BranchLengths(0))
902 val alpha = new ActorGammaComponent(0.5D,Alpha(0))
903 val invarPrior = new ActorProbComponent(0.2D,InvarPrior(0))
904 val components = new BasicActorModel(pi,s,
905 new GammaActorModel(alpha,tree.alphabet.numClasses-1,
906 new InvarActorModel(invarPrior,pi,tree.alphabet.numClasses,
907 new NormaliserActorModel(
908 new BasicSingleExpActorModel(tree,branchLength,None)))))
909 val pList = List(pi,s,branchLength,alpha,invarPrior)
910 val pMap = pList.map{p => (p.name,p)}.foldLeft(Map[ParamName,ActorParamComponent]()){_+_}
911 new ActorModel(tree,components,pMap)
915 object InvarThmmModel{
916 def apply[A <: BioEnum](tree:Tree[A])={
917 val numClasses = tree.alphabet.numClasses
918 val pi = new ActorPiComponent(WAG.pi,Pi(0))
919 val s = new ActorSComponent(WAG.S,S(0))
920 val branchLength = new ActorTreeComponent(tree,BranchLengths(0))
921 val alpha = new ActorGammaComponent(0.5D,Alpha(0))
922 val invarPrior = new ActorProbComponent(0.2D,InvarPrior(0))
923 val sigma = new ActorFullSComponent(Matrix(numClasses,numClasses),Sigma(0))
924 val components = new BasicActorModel(pi,s,
925 new GammaActorModel(alpha,numClasses-1,
926 new InvarActorModel(invarPrior,pi,numClasses,
927 new NormaliserActorModel(
928 new THMMActorModel(sigma,numClasses,
929 new BasicSingleExpActorModel(tree,branchLength,None))))))
930 val pList = List(pi,s,branchLength,alpha,invarPrior,sigma)
931 val pMap = pList.map{p => (p.name,p)}.foldLeft(Map[ParamName,ActorParamComponent]()){_+_}
932 new ActorModel(tree,components,pMap)
936 object BranchSpecificThmmModel{
937 def apply[A <: BioEnum](tree:Tree[A]):ActorModel[A]={
938 val nodeMap=tree.descendentNodes.foldLeft[Map[Int,Int]](IntMap[Int]()){(m,n)=>
939 m + ((n.id,n.id))
941 apply(tree,nodeMap)
943 def apply[A <: BioEnum](tree:Tree[A],map:Map[Int,Int]):ActorModel[A]={
944 val numClasses = tree.alphabet.numClasses
945 val pi = new ActorPiComponent(WAG.pi,Pi(0))
946 val s = new ActorSComponent(WAG.S,S(0))
947 val branchLength = new ActorTreeComponent(tree,BranchLengths(0))
948 val alpha = new ActorGammaComponent(0.5D,Alpha(0))
949 val invarPrior = new ActorProbComponent(0.2D,InvarPrior(0))
950 var pList:List[ActorParamComponent] = List(pi,s,branchLength,alpha,invarPrior)
951 val modelNums = map.values.toList.removeDuplicates
952 val modelMapTmp = modelNums.map{a=>
953 val sigma = new ActorFullSComponent(Matrix(numClasses,numClasses),Sigma(a))
954 pList = sigma :: pList
955 val ans = new THMMActorModel(sigma,numClasses, new BasicSingleExpActorModel(tree,branchLength,None))
956 (a,ans)
957 }.foldLeft[Map[Int,Actor]](IntMap[Actor]()){_+_}
959 val pMap = pList.map{p => (p.name,p)}.foldLeft(Map[ParamName,ActorParamComponent]()){_+_}
961 val modelMap = (map.keys).map{id=> (id,modelMapTmp(map(id)))}.foldLeft[Map[Int,Actor]](IntMap[Actor]()){_+_}
962 val components = new BasicActorModel(pi,s,
963 new GammaActorModel(alpha,numClasses-1,
964 new InvarActorModel(invarPrior,pi,numClasses,
965 new NormaliserActorModel(
966 new ForkActor(tree,modelMap)))))
967 //modelMap(1))))
970 new ActorModel(tree,components,pMap)
974 def apply[A <: BioEnum](tree:Tree[A],l:List[Int]):ActorModel[A]={
975 apply(tree,(tree::tree.descendentNodes).map{n => (n.id,if (l contains n.id){1}else{0})}.foldLeft(Map[Int,Int]()){_+_})
978 class BadParameterException(s:String) extends Exception(s)
980 trait PSetter[A]{
981 def internal:ActorParamComponent
982 def update(x:Seq[Double]){
983 x.elements.zipWithIndex.foreach{t=>
984 update(t._2,t._1)
988 def readSerial(x:Seq[Double]){internal !? ReadSerial(x)}
989 def writeSerial = {internal !? WriteSerial}.asInstanceOf[Seq[Double]]
990 def update(i:Int,x:Double) { throw new BadParameterException("Can't accept 1D parameter location")}
991 def update(i:Int,j:Int,x:Double) { throw new BadParameterException("Can't accept 2D parameter location")}
992 def apply(i:Int):Double = throw new BadParameterException("Can't accept 1D parameter location")
993 def apply(i:Int,j:Int):Double = throw new BadParameterException("Can't accept 2D parameter location")
994 def apply():Double = throw new BadParameterException("Can't accept 0D parameter location")
995 def toList:List[Double]
996 def update(x:Double) { throw new BadParameterException("Can't accept 0D parameter location")}
997 def <<[B](other:PSetter[B]){apply[B](other.getP)}
998 def apply[B](a:B)={internal !? ParamUpdate(a)}
999 def getP:A
1000 def name:ParamName
1001 override def toString = name + " : " + paramString
1002 def paramString:String
1004 trait OptPSetter {
1005 def lower:Array[Double]
1006 def upper:Array[Double]
1007 def numArguments:Int
1008 def length = numArguments
1009 def apply(d:Array[Double])
1010 def currentArgs:Array[Double]
1011 def latestArgs:Array[Double]
1012 lazy val random = new org.apache.commons.math.random.MersenneTwister
1013 def randomise{
1014 apply(
1015 lower.zip(upper).map{t=>
1016 random.nextDouble * (t._2-t._1) + t._1
1017 }.toArray
1020 def randomise(lowerX:Double,upperX:Double){
1021 apply(
1022 lower.zip(upper).map{t=> ((t._1 max lowerX),(t._2 min upperX))}.map{t=>
1023 random.nextDouble * (t._2-t._1) + t._1
1024 }.toArray
1028 def shuffle{
1029 val prevArgs = currentArgs
1030 val newArgs = prevArgs.map{i=>
1031 prevArgs(random nextInt currentArgs.length)
1033 apply(newArgs)
1039 class ActorModel[A <: BioEnum](t:Tree[A],components:ActorModelComponent,val paramMap:Map[ParamName,ActorParamComponent]) extends Logging{
1041 val tree = t.splitAln(6)
1042 tree.foreach{_.start}
1043 val params = paramMap.keys.toList
1044 paramMap.values.foreach{_.start}
1045 components.start
1048 def rawReq(a:Any)={
1049 Actor.actor{
1050 receive{
1051 case a:Any=>
1052 components ! a
1053 var a2:Any=null
1054 receive{
1055 case b:Any=>
1056 a2=b
1058 reply(a2)
1059 exit
1061 } !? a
1064 def qMat(i:Int)={
1065 case class GetQ(i:Int)
1068 val actor = Actor.actor{
1069 receive{
1070 case GetQ(i)=>
1071 val baseTree = tree(0)
1072 components ! QMatReq(baseTree(i),None,None)
1073 var matrix:Matrix=null
1074 receive{
1075 case QMatReq(node,Some(m),Some(pi))=>
1076 matrix = m
1078 reply(matrix)
1079 exit
1082 (actor !? GetQ(i)).asInstanceOf[Matrix]
1085 def eMat(i:Int)={
1086 case class GetQ(i:Int)
1089 val actor = Actor.actor{
1090 receive{
1091 case GetQ(i)=>
1092 val baseTree = tree(0)
1093 components ! MatReq(baseTree(i),None,None)
1094 var matrix:Matrix=null
1095 receive{
1096 case MatReq(node,Some(m),Some(pi))=>
1097 matrix = m
1099 reply(matrix)
1100 exit
1103 (actor !? GetQ(i)).asInstanceOf[Matrix]
1106 debug{"Param Map " + paramMap}
1107 def getParam(p:ParamName):ActorParamComponent={
1108 val ans = p match {
1109 case SingleParam(p2)=>SingleParamWrapper(getParam(p2))
1110 case JoinedParam(p2)=>JoinedParamWrapper(p2.map{getParam})
1111 case m:AllSingle => {
1112 JoinedParamWrapper( paramMap.filter{m matches _._1}.map{t=>SingleParamWrapper(t._2)}.toList)
1114 case m:ParamMatcher => {
1115 JoinedParamWrapper( paramMap.filter{m matches _._1}.map{_._2}.toList)
1117 case p => paramMap(p)
1122 def setParamsFrom(other:ActorModel[A]){
1123 other.paramMap.foreach{t=> val (k,v)=t
1124 if (paramMap.contains(k) && !k.isInstanceOf[BranchLengths]){
1125 debug{"Setting " + k + " " + v}
1126 val p = (v !? RequestParam).asInstanceOf[ParamChanged[_]]
1127 debug{"Param " + p}
1128 this(k)=p
1133 def from(other:ActorModel[A])={
1134 this << other
1135 apply(BranchLengths(0)) << other(BranchLengths(0))
1136 this
1140 def from(other:String)={
1141 val pLookup = paramMap.map{t=>(t._1.toString,t._1)}.foldLeft(Map[String,ParamName]()){_+_}
1142 other.lines.foreach{s=>
1143 val p = s.split("=").map{_.trim}
1144 val name=pLookup.get(p(0))
1145 if (name.isDefined){
1146 apply(name.get) readSerial p(1).split(",").map(_.toDouble)
1147 }else {
1148 warning{"Ignoring apparent Parameter " + p(0)}
1151 this
1154 def <<(other:ActorModel[A]){setParamsFrom(other)}
1156 val paramLengthMap = paramMap.keys.map{t=>(t,optGet(t).length)}.foldLeft(Map[ParamName,Int]()){(m,p)=>m+((p._1,p._2))}
1158 def update(p:ParamName,x:Array[Double]) {
1159 getParam(p) !? ParamUpdate[Array[Double]](x)
1161 def update(p:ParamName,x:Double) {
1162 getParam(p) !? ParamUpdate(Array(x))
1164 def update(p:ParamName,x:Vector) {
1165 getParam(p) !? ParamUpdate(x.toArray)
1167 def update(p:ParamName,x:Matrix) {
1168 getParam(p) !? ParamUpdate(x)
1170 def update[B](p:ParamName,pc:ParamChanged[B]){
1171 getParam(p) !? pc.toParamUpdate
1173 def optUpdate(p:ParamName,x:Array[Double]){getParam(p) !? OptUpdate(x)}
1174 def optGet(p:ParamName):Array[Double]={getParam(p) !? RequestOpt}.asInstanceOf[Array[Double]]
1175 def optUpdate(pList:List[ParamName])(x:Array[Double]){
1176 val iter = x.elements
1177 pList.foreach{p=>
1178 optUpdate(p,iter.take(paramLengthMap(p)).toList.toArray)
1181 def optGet(p:List[ParamName]):Array[Double]={
1182 //this is a crappy implementation
1183 //but how often is this really going to be called?
1184 p.map{optGet(_).toList}.flatten[Double].toArray
1186 def optSetter(p:ParamName):OptPSetter={
1187 new OptPSetter{
1188 val param = getParam(p)
1189 lazy val lower = (param !? Lower).asInstanceOf[Array[Double]]
1190 lazy val upper = (param !? Upper).asInstanceOf[Array[Double]]
1191 lazy val numArguments=lower.length
1192 lazy val currentArgs=(param !? RequestOpt).asInstanceOf[Array[Double]]
1193 def latestArgs={
1194 val latestArgs=(param !? RequestOpt).asInstanceOf[Array[Double]]
1195 Array.copy(latestArgs,0,currentArgs,0,currentArgs.length)
1196 latestArgs
1198 def apply(d:Array[Double])={
1199 if (d.zip(currentArgs).foldLeft(false){(bool,t)=> bool || t._1!=t._2}){
1200 Array.copy(d,0,currentArgs,0,d.length)
1201 param !? OptUpdate(d)
1204 def paramString=latestArgs.mkString(" ")
1205 override def toString = p + " : (" +paramString+")"
1208 def optSetter(p:List[ParamName]):OptPSetter={
1209 new OptPSetter{
1210 val numSub=p.length
1211 val sub = p.map{optSetter}
1212 val lower = sub.map{_.lower.toList}.flatten[Double].toArray
1213 val upper = sub.map{_.upper.toList}.flatten[Double].toArray
1214 val subLengths = sub.map{_.numArguments}
1215 val numArguments=subLengths.foldLeft(0){_+_}
1217 val currentArgs = sub.map{_.currentArgs.toList}.flatten[Double].toArray
1218 def latestArgs={
1219 val latestArgs = sub.map{_.latestArgs.toList}.flatten[Double].toArray
1220 Array.copy(latestArgs,0,currentArgs,0,currentArgs.length)
1221 latestArgs
1224 def apply(d:Array[Double])={
1225 var pointer =0
1226 val subIter = sub.elements
1227 val lenIter=subLengths.elements
1228 for (i<- 0 until numSub){
1229 val len = lenIter.next
1230 val s = subIter.next
1231 s(d.slice(pointer,pointer + len).toArray)
1232 pointer = pointer + len
1235 override def toString = sub.map{_.toString}.mkString(" ")
1240 def paramSetterVector(p:ActorParamComponent)(startParam:Vector)={
1241 class APSetter extends PSetter[Vector]{
1242 val internal=p
1243 def getP={(p !? RequestParam).asInstanceOf[ParamChanged[Vector]].param}
1244 override def update(i:Int,x:Double){
1245 val array=getP
1246 array(i)=x
1247 p !? ParamUpdate(array)
1249 override def apply(i:Int):Double={
1250 val array = getP
1251 array(i)
1253 def toList = getP.toList
1254 def name = p.name
1255 def paramString = getP.toString
1258 new APSetter
1260 //Separate array type necessary otherwise casting back to [A] seems to give a
1261 //java array rather than scala array - maybe this is something that changes
1262 //in Scala 2.8?
1263 def paramSetterArray(p:ActorParamComponent)(startParam:Array[Double])={
1264 class APSetter extends PSetter[Array[Double]]{
1265 def getP={(p !? RequestParam).asInstanceOf[ParamChanged[Array[Double]]].param}
1266 val internal=p
1267 override def update(i:Int,x:Double){
1268 val array = getP
1269 array(i)=x
1270 p !? ParamUpdate(array)
1272 override def apply(i:Int):Double={
1273 val array = getP
1274 array(i)
1276 def toList = getP.toList
1277 def name = p.name
1278 def paramString = getP.mkString(" ")
1280 new APSetter
1284 def paramSetterMatrix(p:ActorParamComponent)(startParam:Matrix)={
1285 class APSetter extends PSetter[Matrix]{
1286 val internal=p
1287 def getP=(p !? RequestParam).asInstanceOf[ParamChanged[Matrix]].param
1288 override def update(i:Int,j:Int,x:Double){
1289 val array = getP
1290 array(i,j)=x
1291 p !? ParamUpdate(array)
1293 override def apply(i:Int,j:Int):Double={
1294 val ans = getP(i,j)
1297 def toList = getP.toList
1298 def name = p.name
1299 def paramString = getP.toString
1301 new APSetter
1303 def paramSetterDouble(p:ActorParamComponent)(startParam:Double)={
1304 class APSetter extends PSetter[Double]{
1305 val internal=p
1306 def getP=(p !? RequestParam).asInstanceOf[ParamChanged[Double]].param
1307 override def update(x:Double){
1308 p !? ParamUpdate(x)
1310 override def apply():Double={
1311 val ans = getP
1314 override def update(i:Int,x:Double)={
1315 assert(i==0)
1316 update(x)
1318 def toList = getP :: Nil
1319 def name = p.name
1320 def paramString = getP.toString
1322 new APSetter
1326 //model(Pi(0))(S)=0.03
1327 def apply(p:ParamName)={
1328 val param = getParam(p)
1329 val start = param !? RequestParam
1330 start match {
1331 case ParamChanged(_,a:Array[Double])=>paramSetterArray(param)(a)
1332 case ParamChanged(_,a:Vector)=>paramSetterVector(param)(a)
1333 case ParamChanged(_,a:Matrix)=>paramSetterMatrix(param)(a)
1334 case ParamChanged(_,a:Double)=>paramSetterDouble(param)(a)
1335 case _ => null//TODO error handling
1340 def logLikelihood = {val ans =
1342 object Send
1343 Actor.actor{
1344 receive{
1345 case Send =>
1346 for (t<-tree){
1347 t ! LogLikelihoodCalc(components,self)
1349 var ans:Double=0.0D
1350 var returned = 0
1351 while (returned < tree.length){
1352 receive{
1353 case LogLikelihood(d) =>
1354 returned=returned+1
1355 ans=ans+d
1358 reply{ans}
1360 exit
1361 } !? Send
1362 }.asInstanceOf[Double]
1363 if (ans.isNaN){-1E100}else{ans}
1366 def paramString=paramMap.map{t=> t._2.name + " = " + (t._2 !? WriteSerial).asInstanceOf[Seq[Double]].mkString(",")}.mkString("\n")
1368 override def toString = paramString + "\nlog-likelihood: " + logLikelihood
1370 def optimise(params:ParamName*):Double={
1371 optimise(params.toList)
1373 def optimise(params:List[ParamName],tolfx:Double,tolx:Double):Double={
1374 import ModelOptimiser._
1375 ModelOptimiser.optimise(getConjugateDirection,params,this,tolfx,tolx)
1377 def optimiseQuick(params:List[ParamName]):Double=optimise(params,1E-1,1E-1)
1378 def optimise(params:List[ParamName]):Double={
1379 import ModelOptimiser._
1380 ModelOptimiser.optimise(getConjugateDirection,params,this)
1382 def optimise(params:List[List[ParamName]])(implicit m:Manifest[List[List[ParamName]]]):Double={
1383 var end = logLikelihood
1384 var start = end
1385 do {
1386 start=end
1387 params.foreach{pset=>
1388 optimise(pset)
1390 end = logLikelihood
1391 } while (end - start > 0.001)
1394 def optimiseCustom(params:List[List[ParamName]],tolfx:Double,tolx:Double)(implicit m:Manifest[List[List[ParamName]]]):Double={
1395 var end = logLikelihood
1396 var start = end
1397 do {
1398 start=end
1399 params.foreach{pset=>
1400 optimise(pset,tolfx,tolx)
1402 end = logLikelihood
1403 } while (end - start > 0.001)
1406 def optimiseQuick(params:List[List[ParamName]])(implicit m:Manifest[List[List[ParamName]]]):Double={
1407 var end = logLikelihood
1408 var start = end
1409 do {
1410 start=end
1411 params.foreach{pset=>
1412 optimiseQuick(pset)
1414 end = logLikelihood
1415 } while (end - start > 0.001)
1420 // def switchingRate(nodeID:Int)={
1421 // logLikelihood //make sure parameters are set
1422 // (components !? SwitchingRate(nodeID)).asInstanceOf[Option[Double]].get
1423 // }
1425 def switchingRate(nodeID:Int)={
1426 val myTree=tree(0)
1427 val ans = rawReq(QMatReq(myTree(nodeID),None,None)).asInstanceOf[QMatReq[_]]
1428 val qMat = ans.m.get
1429 val pi = ans.pi.get
1430 Math.max(qMat.rate(pi),1.0)-1.0
1433 def switchingBranchLengths={
1434 val myTree = currentTree
1435 val branchLengths=apply(BranchLengths(0)).toList
1436 myTree.descendentNodes.map{i:Node[_]=>i.id}.map{i=> (i,switchingRate(i) * myTree(i).lengthTo)}.foldLeft(Map[Int,Double]()){_+_}
1438 def switchingTree={
1439 t setBranchLengths switchingBranchLengths
1441 def currentTree={
1442 t setBranchLengths (apply(BranchLengths(0)).toList)
1446 case class MatReq[A <: BioEnum](n:Node[A],m:Option[Matrix],pi:Option[Vector]){
1447 def toQMatReq=QMatReq(n,m,pi)
1449 case class QMatReq[A <: BioEnum](n:Node[A],m:Option[Matrix],pi:Option[Vector]){// extends MatReq(n2,m2,pi2) //used for skipping exponentiation
1450 def toMatReq=MatReq(n,m,pi)
1452 object NewMatReq{
1453 def apply[A <: BioEnum](n:Node[A])=MatReq(n,None,None)