///|
/// An owned dense vector with explicit dimension-safe operations.
///
/// `DenseVector` is useful at API boundaries where callers want a named value
/// rather than a raw array. Model hot paths still accept `Array[Double]` to
/// keep interop with MoonBit data processing code allocation-free.
pub struct DenseVector {
values : Array[Double]
} derive(ToJson, FromJson, Debug)
///|
pub fn DenseVector::new(size : Int, fill? : Double = 0.0) -> DenseVector {
{ values: Array::make(if size < 0 { 0 } else { size }, fill) }
}
///|
pub fn DenseVector::from_array(values : Array[Double]) -> DenseVector {
{ values: copy_vector(values) }
}
///|
pub fn DenseVector::from_view(values : ArrayView[Double]) -> DenseVector {
{ values: Array::makei(values.length(), i => values[i]) }
}
///|
pub fn DenseVector::zeros(size : Int) -> DenseVector {
DenseVector::new(size)
}
///|
pub fn DenseVector::ones(size : Int) -> DenseVector {
DenseVector::new(size, fill=1.0)
}
///|
pub fn DenseVector::values(self : DenseVector) -> Array[Double] {
copy_vector(self.values)
}
///|
pub fn DenseVector::dimension(self : DenseVector) -> Int {
self.values.length()
}
///|
pub fn DenseVector::get(self : DenseVector, index : Int) -> Double? {
self.values.get(index)
}
///|
pub fn DenseVector::set(
self : DenseVector,
index : Int,
value : Double,
) -> Bool {
if index < 0 || index >= self.values.length() {
false
} else {
self.values[index] = value
true
}
}
///|
pub fn DenseVector::fill(self : DenseVector, value : Double) -> Unit {
self.values.fill(value)
}
///|
pub fn DenseVector::add(self : DenseVector, other : DenseVector) -> DenseVector {
DenseVector::from_array(add_values(self.values, other.values))
}
///|
pub fn DenseVector::subtract(
self : DenseVector,
other : DenseVector,
) -> DenseVector {
DenseVector::from_array(subtract_values(self.values, other.values))
}
///|
pub fn DenseVector::scale(self : DenseVector, factor : Double) -> DenseVector {
DenseVector::from_array(scale_values(self.values, factor))
}
///|
pub fn DenseVector::hadamard(
self : DenseVector,
other : DenseVector,
) -> DenseVector {
DenseVector::from_array(hadamard_product(self.values, other.values))
}
///|
pub fn DenseVector::dot(self : DenseVector, other : DenseVector) -> Double {
dot_product(self.values, other.values)
}
///|
pub fn DenseVector::dot_checked(
self : DenseVector,
other : DenseVector,
) -> Double? {
dot_product_checked(self.values, other.values)
}
///|
pub fn DenseVector::l1_norm(self : DenseVector) -> Double {
l1_norm(self.values)
}
///|
pub fn DenseVector::l2_norm(self : DenseVector) -> Double {
squared_norm(self.values).sqrt()
}
///|
pub fn DenseVector::max_abs(self : DenseVector) -> Double {
max_abs(self.values)
}
///|
pub fn DenseVector::normalize(self : DenseVector) -> DenseVector {
DenseVector::from_array(normalize_l2(self.values))
}
///|
pub fn DenseVector::cosine(self : DenseVector, other : DenseVector) -> Double {
cosine_similarity(self.values, other.values)
}
///|
pub fn DenseVector::sum(self : DenseVector) -> Double {
sum_values(self.values)
}
///|
pub fn DenseVector::mean(self : DenseVector) -> Double {
mean_values(self.values)
}
///|
pub fn DenseVector::variance(self : DenseVector) -> Double {
variance_values(self.values)
}
///|
pub fn DenseVector::distance(self : DenseVector, other : DenseVector) -> Double {
let size = if self.values.length() < other.values.length() {
self.values.length()
} else {
other.values.length()
}
let mut total = 0.0
for i in 0.. Double,
) -> DenseVector {
DenseVector::from_array(
Array::makei(self.values.length(), i => transform(self.values[i])),
)
}
///|
pub fn DenseVector::zip_map(
self : DenseVector,
other : DenseVector,
transform : (Double, Double) -> Double,
) -> DenseVector {
let size = if self.values.length() < other.values.length() {
self.values.length()
} else {
other.values.length()
}
DenseVector::from_array(
Array::makei(size, i => transform(self.values[i], other.values[i])),
)
}
///|
pub fn DenseVector::axpy(
self : DenseVector,
factor : Double,
other : DenseVector,
) -> Unit {
add_scaled_in_place(self.values, other.values, factor)
}
///|
pub fn DenseVector::clamp(
self : DenseVector,
lower : Double,
upper : Double,
) -> DenseVector {
self.map(value => clamp(value, lower, upper))
}
///|
pub fn DenseVector::softmax(self : DenseVector) -> DenseVector {
DenseVector::from_array(probabilities_from_logits(self.values))
}
///|
pub fn DenseVector::argmax(self : DenseVector) -> Int? {
argmax(self.values)
}
///|
pub fn DenseVector::top_index(self : DenseVector, rank : Int) -> Int? {
top_index(self.values, rank)
}
///|
pub fn DenseVector::append(self : DenseVector, value : Double) -> Unit {
self.values.push(value)
}
///|
pub fn DenseVector::is_empty(self : DenseVector) -> Bool {
self.values.is_empty()
}
///|
pub fn DenseVector::is_zero(
self : DenseVector,
tolerance? : Double = 1.0e-12,
) -> Bool {
max_abs(self.values) <= tolerance
}
///|
pub fn DenseVector::slice(
self : DenseVector,
start : Int,
end : Int,
) -> DenseVector {
let from = if start < 0 {
0
} else if start > self.values.length() {
self.values.length()
} else {
start
}
let to = if end < from {
from
} else if end > self.values.length() {
self.values.length()
} else {
end
}
DenseVector::from_array(Array::makei(to - from, i => self.values[from + i]))
}
///|
pub fn DenseVector::concat(
self : DenseVector,
other : DenseVector,
) -> DenseVector {
let result = copy_vector(self.values)
result.append(other.values[:])
DenseVector::from_array(result)
}
///|
pub fn DenseVector::distance_squared(
self : DenseVector,
other : DenseVector,
) -> Double {
let size = if self.values.length() < other.values.length() {
self.values.length()
} else {
other.values.length()
}
let mut total = 0.0
for i in 0.. ValidationReport {
validate_vector(self.values, expected)
}
///|
pub struct Matrix {
rows : Int
cols : Int
values : Array[Double]
} derive(ToJson, FromJson, Debug)
///|
pub fn Matrix::new(rows : Int, cols : Int, fill? : Double = 0.0) -> Matrix {
let safe_rows = if rows < 0 { 0 } else { rows }
let safe_cols = if cols < 0 { 0 } else { cols }
{
rows: safe_rows,
cols: safe_cols,
values: Array::make(safe_rows * safe_cols, fill),
}
}
///|
pub fn Matrix::identity(size : Int) -> Matrix {
let matrix = Matrix::new(size, size)
for i in 0.. Matrix {
if rows.is_empty() {
Matrix::new(0, 0)
} else {
let cols = rows[0].length()
let matrix = Matrix::new(rows.length(), cols)
for r in 0.. Int {
self.rows
}
///|
pub fn Matrix::cols(self : Matrix) -> Int {
self.cols
}
///|
pub fn Matrix::get(self : Matrix, row : Int, col : Int) -> Double? {
if row < 0 || row >= self.rows || col < 0 || col >= self.cols {
None
} else {
Some(self.values[row * self.cols + col])
}
}
///|
pub fn Matrix::set(self : Matrix, row : Int, col : Int, value : Double) -> Bool {
if row < 0 || row >= self.rows || col < 0 || col >= self.cols {
false
} else {
self.values[row * self.cols + col] = value
true
}
}
///|
pub fn Matrix::row(self : Matrix, index : Int) -> DenseVector? {
if index < 0 || index >= self.rows {
None
} else {
Some(
DenseVector::from_array(
Array::makei(self.cols, i => self.values[index * self.cols + i]),
),
)
}
}
///|
pub fn Matrix::column(self : Matrix, index : Int) -> DenseVector? {
if index < 0 || index >= self.cols {
None
} else {
Some(
DenseVector::from_array(
Array::makei(self.rows, i => self.values[i * self.cols + index]),
),
)
}
}
///|
pub fn Matrix::to_rows(self : Matrix) -> Array[Array[Double]] {
Array::makei(self.rows, r => {
Array::makei(self.cols, c => self.values[r * self.cols + c])
})
}
///|
pub fn Matrix::transpose(self : Matrix) -> Matrix {
let result = Matrix::new(self.cols, self.rows)
for r in 0.. Array[Double] {
Array::makei(self.rows, r => {
let mut total = 0.0
for c in 0.. Matrix {
let result = Matrix::new(self.rows, other.cols)
let shared = if self.cols < other.rows { self.cols } else { other.rows }
for r in 0.. Matrix {
let result = Matrix::new(self.rows, self.cols)
let size = if self.values.length() < other.values.length() {
self.values.length()
} else {
other.values.length()
}
for i in 0.. Matrix {
{
rows: self.rows,
cols: self.cols,
values: scale_values(self.values, factor),
}
}
///|
pub fn Matrix::trace(self : Matrix) -> Double {
let size = if self.rows < self.cols { self.rows } else { self.cols }
let mut total = 0.0
for i in 0.. Double {
squared_norm(self.values).sqrt()
}
///|
pub fn Matrix::is_symmetric(
self : Matrix,
tolerance? : Double = 1.0e-9,
) -> Bool {
if self.rows != self.cols {
false
} else {
let mut result = true
for r in 0..
tolerance {
result = false
}
}
}
result
}
}