Skip to content

Commit

Permalink
Add mutating scale method to Vector and Matrix structs
Browse files Browse the repository at this point in the history
  • Loading branch information
wigging committed Jan 4, 2025
1 parent 0a0c5b5 commit 9a8742f
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 2 deletions.
11 changes: 11 additions & 0 deletions Sources/MatrixModule/Matrix.swift
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,17 @@ extension Matrix where Scalar: MatrixAlgebra {
Scalar.norm(self)
}

/// Multiply each value in the matrix by a constant.
///
/// For integer matrices, this performs element-wise multiplication. For
/// single and double precision matrices this uses BLAS routines `sscal`
/// and `dscal` respectively.
///
/// - Parameter k: The scaling factor.
public mutating func scale(by k: Scalar) {
Scalar.scale(&self, by: k)
}

/// Transpose the matrix and return the result.
/// - Returns: The transposed matrix.
public func transpose() -> Matrix {
Expand Down
13 changes: 13 additions & 0 deletions Sources/MatrixModule/MatrixAlgebra.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Accelerate

public protocol MatrixAlgebra {
static func norm(_ a: Matrix<Self>) -> Self
static func scale(_ a: inout Matrix<Self>, by k: Self)
static func transpose(_ a: Matrix<Self>) -> Matrix<Self>
}

Expand All @@ -22,6 +23,10 @@ extension Int: MatrixAlgebra {
return Int(result)
}

public static func scale(_ a: inout Matrix<Int>, by k: Int) {
a = a .* k
}

public static func transpose(_ a: Matrix<Int>) -> Matrix<Int> {
var transposed = Matrix<Int>(rows: a.columns, columns: a.rows)
for i in 0..<a.rows {
Expand All @@ -39,6 +44,10 @@ extension Float: MatrixAlgebra {
cblas_snrm2(a.buffer.count, a.buffer.baseAddress, 1)
}

public static func scale(_ a: inout Matrix<Float>, by k: Float) {
cblas_sscal(a.rows * a.columns, k, a.buffer.baseAddress, 1)
}

public static func transpose(_ a: Matrix<Float>) -> Matrix<Float> {
let m = vDSP_Length(a.columns)
let n = vDSP_Length(a.rows)
Expand All @@ -54,6 +63,10 @@ extension Double: MatrixAlgebra {
cblas_dnrm2(a.buffer.count, a.buffer.baseAddress, 1)
}

public static func scale(_ a: inout Matrix<Double>, by k: Double) {
cblas_dscal(a.rows * a.columns, k, a.buffer.baseAddress, 1)
}

public static func transpose(_ a: Matrix<Double>) -> Matrix<Double> {
let m = vDSP_Length(a.columns)
let n = vDSP_Length(a.rows)
Expand Down
18 changes: 17 additions & 1 deletion Sources/VectorModule/Vector.swift
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ extension Vector where Scalar: VectorArithmetic {
public static func * (lhs: Vector, rhs: Vector) -> Vector {
Scalar.multiply(lhs, rhs)
}

public static func *= (lhs: inout Vector, rhs: Scalar) {
lhs = lhs * rhs
}
}

extension Vector where Scalar: VectorAlgebra {
Expand All @@ -172,12 +176,24 @@ extension Vector where Scalar: VectorAlgebra {
return Scalar.dot(self, b)
}

/// The Euclidean norm of the vector. Also known as the L² norm, 2-norm, vector magnitude, or Euclidean length.
/// The Euclidean norm of the vector. Also known as the L² norm, 2-norm,
/// vector magnitude, or Euclidean length.
/// - Returns: The vector norm.
public func norm() -> Scalar {
Scalar.norm(self)
}

/// Multiply each value in the vector by a constant.
///
/// For integer vectors, this performs element-wise multiplication. For
/// single and double precision vectors this uses BLAS routines `sscal`
/// and `dscal` respectively.
///
/// - Parameter k: The scaling factor.
public mutating func scale(by k: Scalar) {
Scalar.scale(&self, by: k)
}

/// Sum of the vector values.
///
/// This example calculates the sum of the values in vector `a`.
Expand Down
13 changes: 13 additions & 0 deletions Sources/VectorModule/VectorAlgebra.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Accelerate
public protocol VectorAlgebra {
static func dot(_ a: Vector<Self>, _ b: Vector<Self>) -> Self
static func norm(_ a: Vector<Self>) -> Self
static func scale(_ a: inout Vector<Self>, by k: Self)
static func sum(_ a: Vector<Self>) -> Self
static func absoluteSum(_ a: Vector<Self>) -> Self
static func cumulativeSum(_ a: Vector<Self>) -> Vector<Self>
Expand All @@ -33,6 +34,10 @@ extension Int: VectorAlgebra {
return Int(result)
}

public static func scale(_ a: inout Vector<Int>, by k: Int) {
a *= k
}

public static func sum(_ a: Vector<Int>) -> Int {
var res = Int.zero
for i in 0..<a.size {
Expand Down Expand Up @@ -70,6 +75,10 @@ extension Float: VectorAlgebra {
cblas_snrm2(a.size, a.buffer.baseAddress, 1)
}

public static func scale(_ a: inout Vector<Float>, by k: Float) {
cblas_sscal(a.size, k, a.buffer.baseAddress, 1)
}

public static func sum(_ a: Vector<Float>) -> Float {
vDSP.sum(a.buffer)
}
Expand Down Expand Up @@ -100,6 +109,10 @@ extension Double: VectorAlgebra {
cblas_dnrm2(a.size, a.buffer.baseAddress, 1)
}

public static func scale(_ a: inout Vector<Double>, by k: Double) {
cblas_dscal(a.size, k, a.buffer.baseAddress, 1)
}

public static func sum(_ a: Vector<Double>) -> Double {
vDSP.sum(a.buffer)
}
Expand Down
12 changes: 12 additions & 0 deletions Tests/MatrixTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ struct MatrixTests {
#expect(a.norm() == 16)
#expect(a.transpose() == Matrix([[1, 4, 7], [2, 5, 8], [3, 6, 9]]))
#expect(b.transpose() == Matrix([[2, 6], [3, 7], [4, 8], [5, 9]]))

var c = Matrix([[1, 2, 3], [4, 5, 6]])
c.scale(by: 3)
#expect(c == [[3, 6, 9], [12, 15, 18]])
}

@Test func floatAlgebra() {
Expand All @@ -200,6 +204,10 @@ struct MatrixTests {
#expect(a.norm() == 16.881943)
#expect(a.transpose() == Matrix<Float>([[1, 4, 7], [2, 5, 8], [3, 6, 9]]))
#expect(b.transpose() == Matrix<Float>([[2, 6], [3, 7], [4, 8], [5, 9]]))

var c = Matrix<Float>([[1, 2, 3], [4, 5, 6]])
c.scale(by: 3.0)
#expect(c == [[3, 6, 9], [12, 15, 18.0]])
}

@Test func doubleAlgebra() {
Expand All @@ -209,5 +217,9 @@ struct MatrixTests {
#expect(a.norm() == 16.881943016134134)
#expect(a.transpose() == Matrix([[1, 4, 7], [2, 5, 8], [3, 6, 9.0]]))
#expect(b.transpose() == Matrix([[2, 6], [3, 7], [4, 8], [5, 9.0]]))

var c = Matrix([[1, 2, 3], [4, 5, 6.0]])
c.scale(by: 3.0)
#expect(c == [[3, 6, 9], [12, 15, 18.0]])
}
}
13 changes: 12 additions & 1 deletion Tests/VectorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,15 @@ struct VectorTests {
@Test func integerAlgebra() {
let a = Vector([1, 2, 3, 4, 5])
let b = Vector([4, 5, 6, 7, 8])

#expect(a.dot(b) == 100)
#expect(a.norm() == 7)
#expect(a.sum() == 15)
#expect(a.absoluteSum() == 15)
#expect(a.cumulativeSum() == [1, 3, 6, 10, 15])

var c = Vector([8, 9, 10, 11])
c.scale(by: 3)
#expect(c == [24, 27, 30, 33])
}

@Test func floatAlgebra() {
Expand All @@ -158,6 +161,10 @@ struct VectorTests {
#expect(a.sum() == 15)
#expect(a.absoluteSum() == 15)
#expect(a.cumulativeSum() == [1, 3, 6, 10, 15])

var c = Vector<Float>([8, 9, 10, 11])
c.scale(by: 3)
#expect(c == [24, 27, 30, 33])
}

@Test func doubleAlgebra() {
Expand All @@ -169,5 +176,9 @@ struct VectorTests {
#expect(a.sum() == 15)
#expect(a.absoluteSum() == 15)
#expect(a.cumulativeSum() == [1, 3, 6, 10, 15])

var c = Vector([8, 9, 10, 11.0])
c.scale(by: 3)
#expect(c == [24, 27, 30, 33])
}
}

0 comments on commit 9a8742f

Please sign in to comment.