package pl.edu.pw.mini.sg.mixed.adjuster.inhibitor

import pl.edu.pw.mini.sg.mixed.tree.OptimizerStateType


final class InhibitorState(
  val inhibitor: Vector[Double]
) {
  assert(inhibitor.forall(_ >= 0))
  val normalizer={
    val s = inhibitor.sum /inhibitor.size
    //val s = if(inhibitor.nonEmpty)inhibitor.max-inhibitor.min else 1
    if(s > 0) s else 1.0
  }

  def inhibitingCoefficient(idx: Int) : Double = {
    Math.min(1,((inhibitor(idx))/normalizer))
  }

  def updated(ch: List[(Int, Double)]) : InhibitorState = new InhibitorState(ch.foldLeft(inhibitor){case (i, (idx, c)) => i.updated(idx, Math.max(0, i(idx)+c))})

  def reduce(coeff: Double) : InhibitorState = new InhibitorState(inhibitor.map(_*coeff))
  def extend(requestedLength: Int) : InhibitorState = {
    require(inhibitor.length <= requestedLength)
    if(inhibitor.length == requestedLength)
      this
    else 
      new InhibitorState(inhibitor ++ Seq.fill(requestedLength - inhibitor.length)(0.0))
  }

  def increaseInhibitorsNP(leftUnchanged: Seq[Int], rate: Double) : InhibitorState =
    new InhibitorState(inhibitor.zipWithIndex.map{case (value, idx) => if(leftUnchanged.contains(idx)) value else value+rate})


  def increaseInhibitors(incIdx: Seq[Int], rate: Double) : InhibitorState =
    new InhibitorState(incIdx.foldLeft(inhibitor)((a, i) => a.updated(i, inhibitor(i)+rate)))
}


object InhibitorStateTypeclass extends OptimizerStateType[InhibitorState] {
  def zero: InhibitorState = new InhibitorState(Vector())
  def afterIteration(prev: InhibitorState) : InhibitorState = prev.reduce(0.2)
  def pruneMoves(st: InhibitorState, toDelete: Set[Int]) : InhibitorState =
    new InhibitorState(OptimizerStateType.pruneVector(st.inhibitor, toDelete))
}

