All Downloads are FREE. Search and download functionalities are using the official Maven repository.

spire.math.poly.Term.scala Maven / Gradle / Ivy

package spire.math.poly

import scala.{specialized => spec}

import spire.algebra.{Eq, Field, Order, Rig, Ring, Rng, Semiring}
import spire.syntax.field._
import spire.syntax.eq._

// Univariate polynomial term
case class Term[@spec(Float, Double) C](coeff: C, exp: Int) { lhs =>

  def unary_-(implicit r: Rng[C]): Term[C] = Term(-coeff, exp)

  def +(rhs: Term[C])(implicit r: Semiring[C]): Term[C] = {
    if (lhs.exp != rhs.exp)
      throw new IllegalArgumentException(s"can't add terms of degree $exp and ${rhs.exp}")
    Term(lhs.coeff + rhs.coeff, lhs.exp)
  }

  def *(rhs: Term[C])(implicit r: Semiring[C]): Term[C] =
    Term(lhs.coeff * rhs.coeff, lhs.exp + rhs.exp)

  def toTuple: (Int, C) = (exp, coeff)

  def eval(x: C)(implicit r: Semiring[C]): C =
    if (exp != 0) coeff * (x pow exp) else coeff

  def isIndexZero: Boolean =
    exp == 0

  def isZero(implicit ring: Semiring[C], eq: Eq[C]): Boolean =
    coeff === ring.zero

  def divideBy(x: C)(implicit f: Field[C]): Term[C] =
    Term(coeff / x, exp)

  def der(implicit r: Ring[C]): Term[C] =
    Term(coeff * r.fromInt(exp), exp - 1)

  def int(implicit f: Field[C]): Term[C] =
    Term(coeff / f.fromInt(exp + 1), exp + 1)

  override def toString: String = {
    import Term._

    def expString = exp match {
      case 0 => ""
      case 1 => "x"
      case _ => "x" + exp.toString.map(superscript)
    }

    def simpleCoeff: Option[String] = coeff match {
      case 0 => Some("")
      case 1 if exp == 0 => Some(s" + $coeff")
      case 1 => Some(s" + $expString")
      case -1 if exp != 0 => Some(s" - $expString")
      case _ => None
    }

    def stringCoeff: Option[String] = coeff.toString match {
      case IsZero() => Some("")
      case IsNegative(posPart) if exp == 0 => Some(s" - $posPart")
      case IsNegative(posPart) => Some(s" - $posPart$expString")
      case _ => None
    }

    simpleCoeff orElse stringCoeff getOrElse s" + $coeff$expString"
  }
}

object Term {
  implicit def ordering[C]: Order[Term[C]] = new Order[Term[C]] {
    def compare(x: Term[C], y: Term[C]): Int = x.exp compare y.exp
  }

  def fromTuple[@spec(Float, Double) C](tpl: (Int, C)): Term[C] =
    Term(tpl._2, tpl._1)
  def zero[@spec(Float, Double) C](implicit r: Semiring[C]): Term[C] =
    Term(r.zero, 0)
  def one[@spec(Float, Double) C](implicit r: Rig[C]): Term[C] =
    Term(r.one, 0)

  private val IsZero = "0".r
  private val IsNegative = "-(.*)".r

  private val digitToSuperscript = Array(
    '0' -> '\u2070',
    '1' -> '\u2071',
    '2' -> '\u2072',
    '3' -> '\u2073',
    '4' -> '\u2074',
    '5' -> '\u2075',
    '6' -> '\u2076',
    '7' -> '\u2077',
    '8' -> '\u2078',
    '9' -> '\u2079',
    '-' -> '\u207B',
    '1' -> '\u00B9',
    '2' -> '\u00B2',
    '3' -> '\u00B3'
  )

  // call Regex constructor directly to get rid of compiler warning
  // replace with "".r once SI-6723 is fixed
  private val superscriptRegex =
    new scala.util.matching.Regex("[\\u2070\\u2071\\u2072\\u2073\\u2074\\u2075\\u2076\\u2077\\u2078\\u2079\\u207B\\u00B9\\u00B2\\u00B3]+")

  private[spire] def removeSuperscript(text: String): String =
    superscriptRegex.replaceAllIn(text, "^" + _.group(0).map(removeSuperscript))

  private val superscript : (Char => Char) = Map(digitToSuperscript:_*)

  private val removeSuperscript : (Char => Char) = Map(digitToSuperscript.map(_.swap):_*)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy