From 442f10535890219fd524b0552be1243e3db64155 Mon Sep 17 00:00:00 2001 From: c Date: Mon, 21 Aug 2023 15:09:41 -0600 Subject: [PATCH] Added: - demonstration of vectors with dimensions defined at runtime. - example to the FAQ in README.md that demonstrates ways to handle vector dimensions defined at runtime. --- README.md | 41 +++++++++++++++++++ .../ai/dragonfly/math/vector/VecNDemo.scala | 29 +++++++++++++ 2 files changed, 70 insertions(+) diff --git a/README.md b/README.md index 084baa6..b3f0df8 100644 --- a/README.md +++ b/README.md @@ -191,6 +191,47 @@ libraryDependencies += "ai.dragonfly" %%% "vector" % "" In Scala.js, the runtime type of `Float` doesn't fully exist, while Scala.js, Scala JVM, and Scala Native all share the same implementation of `Double`. +
  • What if a vector's dimension depends on a variable? Can this library support vectors with defined at runtime? + +Yes, but with some limitations. Please consider the following examples: + +```scala +// Vectors with lengths defined at runtime. + +// method 1: +val l0:Int = r.nextInt (100) +type N0 = l0.type +val rtv0: Vec[N0] = r.nextVec[N0]() +println(rtv0.render()) + +// method 2: +val l1: Int = r.nextInt(100) +val rtv1: Vec[l1.type] = r.nextVec[l1.type]() +println(rtv1.render()) + +// For better or worse, this throws a compiler error even though l1 == l2 is true: +val l1: Int = r.nextInt(100) +val l2: Int = 0 + l1 +val rtv1: Vec[l1.type] = r.nextVec[l1.type]() +val rtv2: Vec[l2.type] = r.nextVec[l2.type]() +println((rtv1 + rtv2).render()) + +// [error] 57 | println((rtv1 + rtv2).render()) +// [error] | ^^^^ +// [error] | Found: (rtv2 : ai.dragonfly.math.vector.Vec[(l2 : Int)]) +// [error] | Required: ai.dragonfly.math.vector.Vec[(l1 : Int)] + + +// However, you can do this: +val l1: Int = r.nextInt(100) +val l2: Int = 0 + l1 +val rtv1: Vec[l1.type] = r.nextVec[l1.type]() +val rtv2: Vec[l2.type] = r.nextVec[l2.type]() +println((rtv1 + rtv2.asInstanceOf[Vec[l1.type]]).render()) +``` + +We recommend writing a representation of a vector space that contains a reference to a dimension type, then sharing that type across all of the vectors in that space. Unfortunately, this means having to think about a concept that no other math library has had, but it can also head off all kinds of run time errors caused by mismatched dimension exceptions. +

  • diff --git a/demo/shared/src/main/scala/ai/dragonfly/math/vector/VecNDemo.scala b/demo/shared/src/main/scala/ai/dragonfly/math/vector/VecNDemo.scala index f5000b9..f7cdc23 100644 --- a/demo/shared/src/main/scala/ai/dragonfly/math/vector/VecNDemo.scala +++ b/demo/shared/src/main/scala/ai/dragonfly/math/vector/VecNDemo.scala @@ -35,6 +35,35 @@ object VecNDemo extends Demonstration { 35, 36, 37, 38, 39, 40, 41 ) println(v42c.render()) + + + // Vectors with lengths defined at runtime. + // method 1: + val l0:Int = r.nextInt (100) + type N0 = l0.type + val rtv0: Vec[N0] = r.nextVec[N0]() + println(rtv0.render()) + + // method 2: + val l1: Int = r.nextInt(100) + val rtv1: Vec[l1.type] = r.nextVec[l1.type]() + println(rtv1.render()) + +/* + // Unfortunately this doesn't work and throws a compiler error even though l1 == l2 is true: + val l1: Int = r.nextInt(100) + val l2: Int = 0 + l1 + val rtv1: Vec[l1.type] = r.nextVec[l1.type]() + val rtv2: Vec[l2.type] = r.nextVec[l2.type]() + println((rtv1 + rtv2).render()) + + // [error] 57 | println((rtv1 + rtv2).render()) + // [error] | ^^^^ + // [error] | Found: (rtv2 : ai.dragonfly.math.vector.Vec[(l2 : Int)]) + // [error] | Required: ai.dragonfly.math.vector.Vec[(l1 : Int)] + // However you can do this: + println((rtv1 + rtv2.asInstanceOf[Vec[l1.type]]).render()) +*/ } override def name: String = "Vec[N]"