2

I try to use spire, a math framework, but I have an error message:

import spire.algebra._
import spire.implicits._

trait AbGroup[A] extends Group[A]

final class Rationnel_Quadratique(val n1: Int = 2)(val coef: (Int, Int)) {
  override def toString = {
    coef match {
        case (c, i) =>
            s"$c + $i√$n"
    }
  }

  def a() = coef._1

  def b() = coef._2

  def n() = n1


} 

object Rationnel_Quadratique {

  def apply(coef: (Int, Int),n: Int = 2)= {
    new Rationnel_Quadratique(n)(coef)
  }

}

object AbGroup {

  implicit object RQAbGroup extends AbGroup[Rationnel_Quadratique] {

    def +(a: Rationnel_Quadratique, b: Rationnel_Quadratique): Rationnel_Quadratique = Rationnel_Quadratique(coef=(a.a() + b.a(), a.b() + b.b()))

    def inverse(a: Rationnel_Quadratique): Rationnel_Quadratique = Rationnel_Quadratique((-a.a(), -a.b()))

    def id: Rationnel_Quadratique = Rationnel_Quadratique((0, 0))
  }

} 


object euler66_2 extends App {

  val c = Rationnel_Quadratique((1, 2))
  val d = Rationnel_Quadratique((3, 4))
  val e = c + d
  println(e)

}

the program is expected to add 1+2√2 and 3+4√2, but instead I have this error:

could not find implicit value for evidence parameter of type spire.algebra.AdditiveSemigroup[Rationnel_Quadratique] val e = c + d ^

I think there is something essential I have missed (usage of implicits?)

ekad
  • 14,436
  • 26
  • 44
  • 46
lolveley
  • 1,659
  • 2
  • 18
  • 34
  • try `import AbGroup._` in the `object euler66_2` method. – pedrofurla Oct 02 '13 at 21:46
  • hello, it does not change anything – lolveley Oct 02 '13 at 23:33
  • In that case try making RQAbGroup a val with type AbGroup[Rationnel_Quadratique]. – pedrofurla Oct 03 '13 at 11:03
  • I tried this: val groupe=AbGroup.RQAbGroup val c = Rationnel_Quadratique((1, 2)) val d = Rationnel_Quadratique((3, 4)) val e = c + d, I am sure the problem comes from the fact that the Rationnel_Quadratique values aren't linked to a group.But I'm not very good in implicits, I will try to grab some tutorials about this. – lolveley Oct 03 '13 at 15:47

1 Answers1

9

It looks like you are not using Spire correctly.

Spire already has an AbGroup type, so you should be using that instead of redefining your own. Here's an example using a simple type I created called X.

import spire.implicits._
import spire.algebra._

case class X(n: BigInt)

object X {
  implicit object XAbGroup extends AbGroup[X] {
    def id: X = X(BigInt(0))
    def op(lhs: X, rhs: X): X = X(lhs.n + rhs.n)
    def inverse(lhs: X): X = X(-lhs.n)
  }
}

def test(a: X, b: X): X = a |+| b

Note that with groups (as well as semigroups and monoids) you'd use |+| rather than +. To get plus, you'll want to define something with an AdditiveSemigroup (e.g. Semiring, or Ring, or Field or something).

You'll also use .inverse and |-| instead of unary and binary - if that makes sense.

Looking at your code, I am also not sure your actual number type is right. What will happen if I want to add two numbers with different values for n?

Anyway, hope this clears things up for you a bit.

EDIT: Since it seems like you're also getting hung up on Scala syntax, let me try to sketch a few designs that might work. First, there's always a more general solution:

import spire.implicits._
import spire.algebra._
import spire.math._

case class RQ(m: Map[Natural, SafeLong]) {
  override def toString: String = m.map {
    case (k, v) => if (k == 1) s"$v" else s"$v√$k" }.mkString(" + ")
}

object RQ {
  implicit def abgroup[R <: Radical](implicit r: R): AbGroup[RQ] =
    new AbGroup[RQ] {
      def id: RQ = RQ(Map.empty)
      def op(lhs: RQ, rhs: RQ): RQ = RQ(lhs.m + rhs.m)
      def inverse(lhs: RQ): RQ = RQ(-lhs.m)
    }
}

object Test {
  def main(args: Array[String]) {
    implicit val radical = _2
    val x = RQ(Map(Natural(1) -> 1, Natural(2) -> 2))
    val y = RQ(Map(Natural(1) -> 3, Natural(2) -> 4))
    println(x)
    println(y)
    println(x |+| y)
  }
}

This allows you to add different roots together without problem, at the cost of some indirection. You could also stick more closely to your design with something like this:

import spire.implicits._
import spire.algebra._

abstract class Radical(val n: Int) { override def toString: String = n.toString }
case object _2 extends Radical(2)
case object _3 extends Radical(3)

case class RQ[R <: Radical](a: Int, b: Int)(implicit r: R) {
  override def toString: String = s"$a + $b√$r"
}

object RQ {
  implicit def abgroup[R <: Radical](implicit r: R): AbGroup[RQ[R]] =
    new AbGroup[RQ[R]] {
      def id: RQ[R] = RQ[R](0, 0)
      def op(lhs: RQ[R], rhs: RQ[R]): RQ[R] = RQ[R](lhs.a + rhs.a, lhs.b + rhs.b)
      def inverse(lhs: RQ[R]): RQ[R] = RQ[R](-lhs.a, -lhs.b)
    }
}

object Test {
  def main(args: Array[String]) {
    implicit val radical = _2
    val x = RQ[_2.type](1, 2)
    val y = RQ[_2.type](3, 4)
    println(x)
    println(y)
    println(x |+| y)
  }
}

This approach creates a fake type to represent whatever radical you are using (e.g. √2) and parameterizes QR on that type. This way you can be sure that no one will try to do additions that are invalid.

Hopefully one of these approaches will work for you.

d_m
  • 176
  • 1
  • 2
  • thanks ,but I am unable to adapt your answer;the type of group's elements is quadratic integers(QI), like '3+5√2'. They can be added, substracted, but you can not add 'x√2' and 'y√3', the result is 'x√2+y√3' which is not contained in these groups.I want to create a group which elements are QI, which are generics : definition: `final class Rationnel_Quadratique[n1: Int](val coef: (Int, Int))` but when I try `implicit object RQAbGroup[n:Int] extends AbGroup[Rationnel_Quadratique[Int]]` I have an error (definition or declaration expected).Do you know how I can resolve this problem? – lolveley Oct 03 '13 at 18:46
  • (n=3 means QI are of type 'a+b√3') – lolveley Oct 03 '13 at 18:50
  • So that looks like invalid Scala syntax. I don't think `[n1: Int]` will ever work. If I were you, I'd try a slightly different design, where the radical is implicit. For instance, we do something similar in spire.math.FixedPoint (there is an implicit denominator). – d_m Oct 03 '13 at 20:39
  • sure, I saw it later, I also tried `object RQAbGroup extends AbGroup[Rationnel_Quadratique[Int] {` and the compiler accepts it but I need to transmit the Int parameter to the object RQAbGroup. Do you know how to do? – lolveley Oct 03 '13 at 20:42
  • I just read your entire comment, I will have a look tomorrow; thanks anyway, and see you soon! – lolveley Oct 03 '13 at 20:43
  • I edited the answer to show a few approaches that might work. – d_m Oct 03 '13 at 21:17
  • hello, I'm back.I have not tested your codes, but I have some questions:for the class X, the test method calls a.|+|(b), but I see nowhere the definition of this method, so when the compiler has the need of the implicit object XAbGroup?I mean : there is no direct link between an X instance and the XAbGroup...I have other questions but each thing at its own time :-) – lolveley Oct 04 '13 at 16:03
  • The `import spire.implicits._` bring conversions into scope which add these generic operators based on the existence of a type class instance. In this case the exact import would be `import spire.syntax.group._`. – d_m Oct 04 '13 at 16:23
  • ... and the suite is : the .|+| function searches in the X class the right group, which is a class that hinerits from AbGroup[X]?That's not easy to understand, it's a shame that spire does not provides a detailed tutorial explaining all this!(are you working for them??) – lolveley Oct 04 '13 at 16:27
  • I am one of the maintainers, yes. Documentation is definitely something we're trying to improve. You can see most of the implicits providing operators in `core/src/main/scala/spire/syntax/Ops.scala`. – d_m Oct 04 '13 at 18:49
  • thanks! Is my assertion concerning the class inherited from AbGroup[X] true? Guess what : I have not ended with this subject, because my final purpose is to modelize a ring(the ring of the quadratic integers), in order to resolve one of the numerous questions of the euler project (if you don't know it, enter 'project euler' in google!).But now and for this WE I will study groups and scala syntax.Is an other way to contact you(I guess so long talks won't please to stack overflow's moderators), like by mail? – lolveley Oct 04 '13 at 19:44
  • Feel free to email me at d_m@plastic-idolatry.com, or come hang out in the #spire-math IRC channel (on Freenode). There's also a mailing list: https://groups.google.com/forum/#!forum/spire-math. I'm not totally I understand your meaning. When looking for an AbGroup[X] instance, the companion object of X is checked, so that's what I'm using here. I do think you should accept this answer then open new questions. At this point it's not clear what part of your question is unanswered. – d_m Oct 04 '13 at 20:32