Complex numbers

Is there a complex number implementation in the Scala (or Java) standard library? If not, is there a recommended implementation out there somewhere? Thanks.

I suspect that breeze and spire are the most popular scala math libraries that include complex numbers. I don’t have much experience with either.

2 Likes

Thanks. It seems to me that there should be a basic complex number implementation in the standard library.

I have occasion to solve cubic equations, so I implemented some formulas from the web. However, I discovered that I need to use complex numbers even to find a real root in some cases (because the formulas take the square root of a number that can be negative).

I prefer to avoid external library dependencies for a single use case.

Spire (and probably Breeze too) also has a Polynomial type with a function for finding all real roots.

It really isn’t appropriate for the standard library. Stdlib tries very hard to stick to very broadly-applicable data structures, with fairly universal applicability – while complex numbers are useful in a bunch of scientific / simulation situations, that’s still a fairly specific domain in the grand scheme of things.

In general, the trend is to remove things from stdlib, not add them, and to leave these topics to specialist libraries that care about doing them as well as possible. External open-source libraries are what makes the Scala ecosystem run…

2 Likes

If you want something added to the standard library, publish what you want as a library and once many people use it, there may be a case for it to be added.

I’d have to agree with @Justin du coeur, though, that complex numbers are too specific to be in the standard library. Their relevance is limited to certain kinds of math, engineering and science applications. Keep in mind that Scala, like Java, does not have much math support even for plain old Double, not even an error function, so most people will reach for a math library long before they consider something as fancy as complex numbers.

If you need complex numbers, roll your own or use a math library.

I ended up writing my own Complex class. I didn’t realize it initially, but a generic Complex class would not be sufficient for my purposes. I need one that can take Scalar arguments. My Scalar class represents scalars with physical units. For my purposes of solving cubic polynomials, my Complex class needs the real and imaginary parts to be in terms of such Scalars rather than just plain real numbers (i.e., so-called “Doubles”).

I got side-tracked trying to make my Complex class elegant. Not that it’s critical, but it would be nice to be able to write

val x = 3 * Complex(4,2)
val y = 3.0 * Complex(4,2)

But that requires implicit conversions from Int and Double to Complex. Unfortunately, when I tried to add such an implicit conversion it conflicted with implicit conversions that I already had from Int and Double to Scalar, so I had to abandon it.

For example, I want to be able to write

val x = 4 * m/s

which requires an implicit conversion from Int to Scalar. But then apparently I cannot also have an implicit conversion from Int to Complex in the same scope. Or can I? It seems that the compiler should be able to determine which implicit conversion is needed based on the type of the arguments. No?

In a similar situation (probability distributions) I defined methods like *: so one can have statements like

val x = 3 *: Complex(4,2)
val y = 3.0 *: Complex(4,2)

Less elegant than just * but with clean code.

regards,
Siddhartha

You need complex numbers with different units on the real and imaginary axes?! Or you just need the whole thing to have physical units? (So it is Scalar-like, but not a pair of Scalars.)

I’d just define a typeclass:

trait MultipliesOnLeft[A] {
  def leftMult(i: Int, a: A): A
  def leftMult(d: Double, a: A): A
}

Create implicit instances for Complex and Scalar.

Then you enrich Int and Double with

implicit class LeftMultiplyDouble(value: Double) extends AnyVal {
  def *[A: MultipliesOnLeft](a: A) =
    implicitly[MultipliesOnLeft[A]].leftMult(value, a)
}

Then you get the proper type inference. Generally the JVM will manage to optimize the extra code away without performance penalty.

1 Like

You can, at least in this simple implementation of what you described:

scala> object m
object m

scala> case class Meters(d: Int)
class Meters

scala> case class Complex(d: Int, i: Int) { def *(that: Complex): Complex = ??? }
class Complex

scala> class MeterSyntax(d: Int) { def *(x: m.type): Meters = Meters(d) }
class MeterSyntax

scala> object s
object s

scala> case class MeterPerSecond(d: Int)
class MeterPerSecond

scala> class MeterPerSecondSyntax(m: Meters) { def /(x: s.type): MeterPerSecond = MeterPerSecond(m.d)  }
class MeterPerSecondSyntax

scala> object implicits {
     |   implicit def meterSyntax(d: Int) = new MeterSyntax(d)
     |   implicit def int2Complex(d: Int) = Complex(d, 0)
     |   implicit def meterPerSecondSyntax(m: Meters) = new MeterPerSecondSyntax(m)
     | }
warning: 3 feature warnings; for details, enable `:setting -feature' or `:replay -feature'
object implicits

scala> import implicits._
import implicits._

scala> 42 * Complex(1, 2)
scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:288)
  at Complex.$times(<console>:11)
  ... 36 elided

scala> 42 * m/s
res3: MeterPerSecond = MeterPerSecond(42)

Add some more complexity and it’s possible that it breaks down. Maybe you have a second conversion of Int to “something that has a *(_: Complex): ? method”.

The units should be the same on the real and imaginary axes. I don’t think it would make sense otherwise, and computing the magnitude and direction would throw an exception.

If I wanted to spend a lot of time just for fun, I suppose I could develop a class that factors out the units from the complex number itself, but for my current purposes it is sufficient to just use my Scalar class for both the real and imaginary components and require that the units be consistent.

Thanks for the other suggestions. I’ll give them a try when I get a chance.

My Scalar class implements the entire SI (metric) system of units and many English and other units also. Unless I am missing something, the approach that you are suggesting is unlikely to be scalable to that level.

The scalar package represents physical scalars and can help to prevent errors involving physical units in engineering and scientific computation. The scalar package includes a complete implementation of the standard SI metric system of units and many common non-metric units. The design also allows users to easily define a specialized or reduced set of physical units for any particular application or domain. The scalar package can be used in two different modes: one mode provides unit compatibility checking but is slower, and the other mode bypasses the compatibility checks but is much faster and still prevents the most common type of unit error. Switching between the two modes requires no changes in the user’s code, making it convenient and usable with no significant performance penalty for even the most computationally intensive applications.

Thanks again for the suggestion, but I haven’t been able to make it work. Your LeftMultiplyDouble conflicts with my implicit ScalarToComplex conversion. And if I eliminate the latter, that causes all kinds of other problems, so that’s not a good option either.

[error] /home/rpaielli/trajspec/src/plot/AltAnglePlots.scala:22:13: type mismatch;
[error] found : Double(3.0)
[error] required: ?{def *(x$1: ? >: scalar_.Complex): Any}
[error] Note that implicit conversions are not applicable because they are ambiguous:
[error] both method ScalarToComplex in object Complex of type (r: scalar_.Scalar)scalar_.Complex
[error] and method LeftMultiplyDouble in object Complex of type (value: Double)scalar_.Complex.LeftMultiplyDouble
[error] are possible conversion functions from Double(3.0) to ?{def *(x$1: ? >: scalar_.Complex): Any}
[error] println(3.0 * Complex(5,-3))

So you already can write 3.0 * c where c is complex, but you don’t want to go through the overhead of creating a complex value along the way?

You could make the implicits be different priority. The answer to this StackOverflow question was the first thing I googled that explains how: https://stackoverflow.com/questions/36996916/enforcing-precedence-in-implicit-instances-in-scala

Just make the LeftMultiplyDouble instance higher precedence and you will probably be fine.

No, I can’t can write 3.0 * c where c is complex, at least not without conflicting with my higher priority implicit conversion from Double to Scalar (I use Scalar far more than Complex). And I don’t care about the overhead of creating a new Complex value along the way.

The StackOverflow post is not doing it for me.

I don’t understand. Why do you even need the LeftMultiply thing if you already have a conversion from Double to Scalar, and you can left-multiply a Scalar by a Complex?

I don’t need it. As you say, I can write

val x = Complex(6,1) * 3.0 // or just 3

but I can’t write

val x = 3.0 * Complex(6,1)

As I said before, it’s not critical by any means, but from an intuituve perspective, the latter should work too. It’s just a matter of aesthetics – and an exercise in the use of implicits.

If I used Complex extensively, then I might worry about it, but since I don’t I won’t. Thanks for your feedback.

I don’t understand why you get a conflict in implicit resolution, then. If the implicit conversion from 3.0 to Scalar doesn’t give a * operation, why would the lookup be ambiguous? If it does give a * operation, why doesn’t it work to do the multiplication? Do you not have a * operation on Scalar that works on Complex?

I have an implicit conversion that converts a “Double” to a Scalar, so if I write

5.3 * J/cube(m) // Joules/cubic meter, energy density

the 5.3 gets comverted to a (dimensionless) Scalar and then multiplies the units (which also evaluate to a Scalar).

I tried a similar implicit conversion from Double to Complex, but it conflicts with the conversion from Double to Scalar. That’s the problem. And your suggested implicit class LeftMultiplyDouble also conflicts, unfortunately.

Perhaps Scala 3 implicits will have a way around this problem.

Scala 2 implicits already get around this problem, as illustrated by the StackOverflow post.

trait LowPriorityDoubleImplicits {
  implicit def doubleToComplex(d: Double): Complex = Complex(d, 0)
}

object AllDoubleImplicits extends LowPriorityDoubleImplicits {
  implicit def doubleToScalar(d: Double): Scalar = Scalar(d)
}

import AllDoubleImplicits._ anywhere you need them. You don’t even need the LeftMultiplies thing because you just convert as needed.