Vector и компания

Семейство классов типов векторного пространства предоставляет базовые векторные операции. Они параметризованы на 2 типа: векторный тип и скалярный тип.

Очень полезное векторное пространство — это пространство функций T => Double. Функции можно добавлять, просто складывая их по точкам, (f + g)(x) = f(x) + g(x) и умножение обрабатывается аналогичным образом. Учитывая это определение, определение функционального пространства довольно просто:

import spire.algebra.{Field, VectorSpace}
import spire.implicits.*

given vspace[T]: VectorSpace[T => Double, Double] with
  def scalar: Field[Double] = summon[Field[Double]]

  def zero: T => Double                                 = _ => 0.0
  def negate(f: T => Double): T => Double               = x => -1 * f(x)
  def plus(f: T => Double, g: T => Double): T => Double = x => f(x) + g(x)
  def timesl(r: Double, f: T => Double): T => Double    = x => r * f(x)

Как только это будет сделано, мы сможем рассматривать функции типа T => Double как векторы:

def f(x: String) = x.length.toDouble
def g(x: String) = x.hashCode.toDouble

val h: String => Double = 4.0 *: f _ + g _
h("test")
// val res0: Double = 3556514.0

Эквивалентно мы могли бы определить h как:

def h(x: String) = 4*x.length.toDouble + x.hashCode.toDouble

LeftModule

Левый модуль — это обобщение векторного пространства над полем, где скаляры — это элементы кольца (не обязательно коммутативного).

Левый модуль определяет левое умножение на скаляры.

trait LeftModule[V, R]:
  def timesl(r: R, v: V): V

Пусть V — абелева группа (с аддитивными обозначениями), а R — скалярное кольцо. Должны соблюдаться следующие законы для x, y в V и r, s в R:

  1. r *: (x + y) = r *: x + r *: y
  2. (r + s) *: x = r *: x + s *: x
  3. (r * s) *: x = r *: (s *: x)
  4. R.one * x = x
import spire.algebra.{Field, VectorSpace}
import spire.implicits.*

4.0 *: Vector(1.0, 5.0, 3.0)
// val res0: Vector[Double] = Vector(4.0, 20.0, 12.0)

RightModule

Правый модуль — это обобщение векторного пространства над полем, где скаляры — это элементы кольца (не обязательно коммутативного).

Правый модуль определяет правое умножение на скаляры.

trait RightModule[V, R]:
  def timesr(v: V, r: R): V

Пусть V — абелева группа (с аддитивными обозначениями), а R — скалярное кольцо. Должны соблюдаться следующие законы для x, y в V и r, s в R:

  1. (x + y) :* r = x :* r + y :* r
  2. x :* (r + s) = x :* r + x :* s
  3. x :* (r * s) = (x :* r) :* s
  4. x :* R.one = x
import spire.algebra.{Field, VectorSpace}
import spire.implicits.*

Vector(1.0, 5.0, 3.0) :* 4.0
// val res0: Vector[Double] = Vector(4.0, 20.0, 12.0)

CModule

Модуль над коммутативным кольцом по определению имеет эквивалентные левый и правый модули.

trait CModule[V, R] extends LeftModule[V, R], RightModule[V, R]:
  override def timesr(v: V, r: R): V = timesl(r, v)

В дополнение к законам левых и правых модулей имеем:

import spire.algebra.{Field, VectorSpace}
import spire.implicits.*

0.25 *: Vector(1.0, 5.0, 3.0) :* 4.0
// val res0: Vector[Double] = Vector(1.0, 5.0, 3.0)

VectorSpace

Векторное пространство — это группа V, которую можно умножить на скаляры из поля F.

Векторное пространство определяет скалярное деление:

trait VectorSpace[V, F] extends CModule[V, F]:
  given def scalar: Field[F]

  def divr(v: V, f: F): V = timesl(scalar.reciprocal(f), v)

Для векторного пространства должны соблюдаться следующие законы:

import spire.algebra.{Field, VectorSpace}
import spire.implicits.*

Vector(1.0, 5.0, 3.0) :/ 0.5
// val res0: Vector[Double] = Vector(2.0, 10.0, 6.0)

MetricSpace[V,R]

MetricSpace[V,R] - типы со связанной метрикой

Этот класс типов моделирует метрическое пространство V. Расстояние между двумя точками в V измеряется в R, которое должно быть действительным (т.е. существует IsReal[R]).

import spire.algebra.*
import spire.implicits.*

MetricSpace.distance(Vector(1.0, 5.0), Vector(5.0, 1.0))
// val res2: Double = 5.656854249492381

NormedVectorSpace

Нормированное векторное пространство — это векторное пространство, снабженное функцией нормирования: V => F. Основное ограничение состоит в том, что норма вектора должна масштабироваться линейно при масштабировании вектора; что означает norm(k *: v) == k.abs * norm(v). Кроме того, нормированное векторное пространство также является MetricSpace, где distance(v, w) = norm(v - w), и поэтому должно подчиняться неравенству треугольника. Примером нормированного векторного пространства является \(R^{n}\), снабженное длиной евклидового вектора в качестве нормы.

trait NormedVectorSpace[V, F] extends VectorSpace[V, F], MetricSpace[V, F]:
  def norm(v: V): F
  
  def normalize(v: V): V = divr(v, norm(v))
  def distance(v: V, w: V): F = norm(minus(v, w))

Операции нормированного векторного пространства:

import spire.algebra.*
import spire.implicits.*

Vector(1.0, 5.0, 3.0).norm
// val res0: Double = 5.916079783099616
Vector(1.0, 5.0, 3.0).normalize
// val res1: Vector[Double] = Vector(0.1690308509457033, 0.8451542547285165, 0.50709255283711)

MetricSpace.distance(Vector(1.0, 5.0), Vector(5.0, 1.0))
// val res2: Double = 5.656854249492381

InnerProductSpace

import spire.algebra.InnerProductSpace
import spire.implicits.*

Vector(1.0, 5.0, 3.0).dot(Vector(1.0, 5.0, 3.0))
// val res0: Double = 35.0

Ссылки: