1 use crate::{RawStorage, SimdComplexField}; 2 use num::{One, Zero}; 3 use simba::scalar::{ClosedAdd, ClosedMul}; 4 5 use crate::base::allocator::Allocator; 6 use crate::base::blas_uninit::{axcpy_uninit, gemm_uninit, gemv_uninit}; 7 use crate::base::constraint::{ 8 AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint, 9 }; 10 use crate::base::dimension::{Const, Dim, Dynamic, U1, U2, U3, U4}; 11 use crate::base::storage::{Storage, StorageMut}; 12 use crate::base::uninit::Init; 13 use crate::base::{ 14 DVectorSlice, DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector, VectorSlice, 15 }; 16 17 /// # Dot/scalar product 18 impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> 19 where 20 T: Scalar + Zero + ClosedAdd + ClosedMul, 21 { 22 #[inline(always)] dotx<R2: Dim, C2: Dim, SB>( &self, rhs: &Matrix<T, R2, C2, SB>, conjugate: impl Fn(T) -> T, ) -> T where SB: RawStorage<T, R2, C2>, ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,23 fn dotx<R2: Dim, C2: Dim, SB>( 24 &self, 25 rhs: &Matrix<T, R2, C2, SB>, 26 conjugate: impl Fn(T) -> T, 27 ) -> T 28 where 29 SB: RawStorage<T, R2, C2>, 30 ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>, 31 { 32 assert!( 33 self.nrows() == rhs.nrows(), 34 "Dot product dimensions mismatch for shapes {:?} and {:?}: left rows != right rows.", 35 self.shape(), 36 rhs.shape(), 37 ); 38 39 assert!( 40 self.ncols() == rhs.ncols(), 41 "Dot product dimensions mismatch for shapes {:?} and {:?}: left cols != right cols.", 42 self.shape(), 43 rhs.shape(), 44 ); 45 46 // So we do some special cases for common fixed-size vectors of dimension lower than 8 47 // because the `for` loop below won't be very efficient on those. 48 if (R::is::<U2>() || R2::is::<U2>()) && (C::is::<U1>() || C2::is::<U1>()) { 49 unsafe { 50 let a = conjugate(self.get_unchecked((0, 0)).clone()) 51 * rhs.get_unchecked((0, 0)).clone(); 52 let b = conjugate(self.get_unchecked((1, 0)).clone()) 53 * rhs.get_unchecked((1, 0)).clone(); 54 55 return a + b; 56 } 57 } 58 if (R::is::<U3>() || R2::is::<U3>()) && (C::is::<U1>() || C2::is::<U1>()) { 59 unsafe { 60 let a = conjugate(self.get_unchecked((0, 0)).clone()) 61 * rhs.get_unchecked((0, 0)).clone(); 62 let b = conjugate(self.get_unchecked((1, 0)).clone()) 63 * rhs.get_unchecked((1, 0)).clone(); 64 let c = conjugate(self.get_unchecked((2, 0)).clone()) 65 * rhs.get_unchecked((2, 0)).clone(); 66 67 return a + b + c; 68 } 69 } 70 if (R::is::<U4>() || R2::is::<U4>()) && (C::is::<U1>() || C2::is::<U1>()) { 71 unsafe { 72 let mut a = conjugate(self.get_unchecked((0, 0)).clone()) 73 * rhs.get_unchecked((0, 0)).clone(); 74 let mut b = conjugate(self.get_unchecked((1, 0)).clone()) 75 * rhs.get_unchecked((1, 0)).clone(); 76 let c = conjugate(self.get_unchecked((2, 0)).clone()) 77 * rhs.get_unchecked((2, 0)).clone(); 78 let d = conjugate(self.get_unchecked((3, 0)).clone()) 79 * rhs.get_unchecked((3, 0)).clone(); 80 81 a += c; 82 b += d; 83 84 return a + b; 85 } 86 } 87 88 // All this is inspired from the "unrolled version" discussed in: 89 // https://blog.theincredibleholk.org/blog/2012/12/10/optimizing-dot-product/ 90 // 91 // And this comment from bluss: 92 // https://users.rust-lang.org/t/how-to-zip-two-slices-efficiently/2048/12 93 let mut res = T::zero(); 94 95 // We have to define them outside of the loop (and not inside at first assignment) 96 // otherwise vectorization won't kick in for some reason. 97 let mut acc0; 98 let mut acc1; 99 let mut acc2; 100 let mut acc3; 101 let mut acc4; 102 let mut acc5; 103 let mut acc6; 104 let mut acc7; 105 106 for j in 0..self.ncols() { 107 let mut i = 0; 108 109 acc0 = T::zero(); 110 acc1 = T::zero(); 111 acc2 = T::zero(); 112 acc3 = T::zero(); 113 acc4 = T::zero(); 114 acc5 = T::zero(); 115 acc6 = T::zero(); 116 acc7 = T::zero(); 117 118 while self.nrows() - i >= 8 { 119 acc0 += unsafe { 120 conjugate(self.get_unchecked((i, j)).clone()) 121 * rhs.get_unchecked((i, j)).clone() 122 }; 123 acc1 += unsafe { 124 conjugate(self.get_unchecked((i + 1, j)).clone()) 125 * rhs.get_unchecked((i + 1, j)).clone() 126 }; 127 acc2 += unsafe { 128 conjugate(self.get_unchecked((i + 2, j)).clone()) 129 * rhs.get_unchecked((i + 2, j)).clone() 130 }; 131 acc3 += unsafe { 132 conjugate(self.get_unchecked((i + 3, j)).clone()) 133 * rhs.get_unchecked((i + 3, j)).clone() 134 }; 135 acc4 += unsafe { 136 conjugate(self.get_unchecked((i + 4, j)).clone()) 137 * rhs.get_unchecked((i + 4, j)).clone() 138 }; 139 acc5 += unsafe { 140 conjugate(self.get_unchecked((i + 5, j)).clone()) 141 * rhs.get_unchecked((i + 5, j)).clone() 142 }; 143 acc6 += unsafe { 144 conjugate(self.get_unchecked((i + 6, j)).clone()) 145 * rhs.get_unchecked((i + 6, j)).clone() 146 }; 147 acc7 += unsafe { 148 conjugate(self.get_unchecked((i + 7, j)).clone()) 149 * rhs.get_unchecked((i + 7, j)).clone() 150 }; 151 i += 8; 152 } 153 154 res += acc0 + acc4; 155 res += acc1 + acc5; 156 res += acc2 + acc6; 157 res += acc3 + acc7; 158 159 for k in i..self.nrows() { 160 res += unsafe { 161 conjugate(self.get_unchecked((k, j)).clone()) 162 * rhs.get_unchecked((k, j)).clone() 163 } 164 } 165 } 166 167 res 168 } 169 170 /// The dot product between two vectors or matrices (seen as vectors). 171 /// 172 /// This is equal to `self.transpose() * rhs`. For the sesquilinear complex dot product, use 173 /// `self.dotc(rhs)`. 174 /// 175 /// Note that this is **not** the matrix multiplication as in, e.g., numpy. For matrix 176 /// multiplication, use one of: `.gemm`, `.mul_to`, `.mul`, the `*` operator. 177 /// 178 /// # Examples: 179 /// 180 /// ``` 181 /// # use nalgebra::{Vector3, Matrix2x3}; 182 /// let vec1 = Vector3::new(1.0, 2.0, 3.0); 183 /// let vec2 = Vector3::new(0.1, 0.2, 0.3); 184 /// assert_eq!(vec1.dot(&vec2), 1.4); 185 /// 186 /// let mat1 = Matrix2x3::new(1.0, 2.0, 3.0, 187 /// 4.0, 5.0, 6.0); 188 /// let mat2 = Matrix2x3::new(0.1, 0.2, 0.3, 189 /// 0.4, 0.5, 0.6); 190 /// assert_eq!(mat1.dot(&mat2), 9.1); 191 /// ``` 192 /// 193 #[inline] 194 #[must_use] dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T where SB: RawStorage<T, R2, C2>, ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,195 pub fn dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T 196 where 197 SB: RawStorage<T, R2, C2>, 198 ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>, 199 { 200 self.dotx(rhs, |e| e) 201 } 202 203 /// The conjugate-linear dot product between two vectors or matrices (seen as vectors). 204 /// 205 /// This is equal to `self.adjoint() * rhs`. 206 /// For real vectors, this is identical to `self.dot(&rhs)`. 207 /// Note that this is **not** the matrix multiplication as in, e.g., numpy. For matrix 208 /// multiplication, use one of: `.gemm`, `.mul_to`, `.mul`, the `*` operator. 209 /// 210 /// # Examples: 211 /// 212 /// ``` 213 /// # use nalgebra::{Vector2, Complex}; 214 /// let vec1 = Vector2::new(Complex::new(1.0, 2.0), Complex::new(3.0, 4.0)); 215 /// let vec2 = Vector2::new(Complex::new(0.4, 0.3), Complex::new(0.2, 0.1)); 216 /// assert_eq!(vec1.dotc(&vec2), Complex::new(2.0, -1.0)); 217 /// 218 /// // Note that for complex vectors, we generally have: 219 /// // vec1.dotc(&vec2) != vec2.dot(&vec2) 220 /// assert_ne!(vec1.dotc(&vec2), vec1.dot(&vec2)); 221 /// ``` 222 #[inline] 223 #[must_use] dotc<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T where T: SimdComplexField, SB: RawStorage<T, R2, C2>, ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,224 pub fn dotc<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T 225 where 226 T: SimdComplexField, 227 SB: RawStorage<T, R2, C2>, 228 ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>, 229 { 230 self.dotx(rhs, T::simd_conjugate) 231 } 232 233 /// The dot product between the transpose of `self` and `rhs`. 234 /// 235 /// # Examples: 236 /// 237 /// ``` 238 /// # use nalgebra::{Vector3, RowVector3, Matrix2x3, Matrix3x2}; 239 /// let vec1 = Vector3::new(1.0, 2.0, 3.0); 240 /// let vec2 = RowVector3::new(0.1, 0.2, 0.3); 241 /// assert_eq!(vec1.tr_dot(&vec2), 1.4); 242 /// 243 /// let mat1 = Matrix2x3::new(1.0, 2.0, 3.0, 244 /// 4.0, 5.0, 6.0); 245 /// let mat2 = Matrix3x2::new(0.1, 0.4, 246 /// 0.2, 0.5, 247 /// 0.3, 0.6); 248 /// assert_eq!(mat1.tr_dot(&mat2), 9.1); 249 /// ``` 250 #[inline] 251 #[must_use] tr_dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T where SB: RawStorage<T, R2, C2>, ShapeConstraint: DimEq<C, R2> + DimEq<R, C2>,252 pub fn tr_dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T 253 where 254 SB: RawStorage<T, R2, C2>, 255 ShapeConstraint: DimEq<C, R2> + DimEq<R, C2>, 256 { 257 let (nrows, ncols) = self.shape(); 258 assert_eq!( 259 (ncols, nrows), 260 rhs.shape(), 261 "Transposed dot product dimension mismatch." 262 ); 263 264 let mut res = T::zero(); 265 266 for j in 0..self.nrows() { 267 for i in 0..self.ncols() { 268 res += unsafe { 269 self.get_unchecked((j, i)).clone() * rhs.get_unchecked((i, j)).clone() 270 } 271 } 272 } 273 274 res 275 } 276 } 277 278 /// # BLAS functions 279 impl<T, D: Dim, S> Vector<T, D, S> 280 where 281 T: Scalar + Zero + ClosedAdd + ClosedMul, 282 S: StorageMut<T, D>, 283 { 284 /// Computes `self = a * x * c + b * self`. 285 /// 286 /// If `b` is zero, `self` is never read from. 287 /// 288 /// # Examples: 289 /// 290 /// ``` 291 /// # use nalgebra::Vector3; 292 /// let mut vec1 = Vector3::new(1.0, 2.0, 3.0); 293 /// let vec2 = Vector3::new(0.1, 0.2, 0.3); 294 /// vec1.axcpy(5.0, &vec2, 2.0, 5.0); 295 /// assert_eq!(vec1, Vector3::new(6.0, 12.0, 18.0)); 296 /// ``` 297 #[inline] 298 #[allow(clippy::many_single_char_names)] axcpy<D2: Dim, SB>(&mut self, a: T, x: &Vector<T, D2, SB>, c: T, b: T) where SB: Storage<T, D2>, ShapeConstraint: DimEq<D, D2>,299 pub fn axcpy<D2: Dim, SB>(&mut self, a: T, x: &Vector<T, D2, SB>, c: T, b: T) 300 where 301 SB: Storage<T, D2>, 302 ShapeConstraint: DimEq<D, D2>, 303 { 304 unsafe { axcpy_uninit(Init, self, a, x, c, b) }; 305 } 306 307 /// Computes `self = a * x + b * self`. 308 /// 309 /// If `b` is zero, `self` is never read from. 310 /// 311 /// # Examples: 312 /// 313 /// ``` 314 /// # use nalgebra::Vector3; 315 /// let mut vec1 = Vector3::new(1.0, 2.0, 3.0); 316 /// let vec2 = Vector3::new(0.1, 0.2, 0.3); 317 /// vec1.axpy(10.0, &vec2, 5.0); 318 /// assert_eq!(vec1, Vector3::new(6.0, 12.0, 18.0)); 319 /// ``` 320 #[inline] axpy<D2: Dim, SB>(&mut self, a: T, x: &Vector<T, D2, SB>, b: T) where T: One, SB: Storage<T, D2>, ShapeConstraint: DimEq<D, D2>,321 pub fn axpy<D2: Dim, SB>(&mut self, a: T, x: &Vector<T, D2, SB>, b: T) 322 where 323 T: One, 324 SB: Storage<T, D2>, 325 ShapeConstraint: DimEq<D, D2>, 326 { 327 assert_eq!(self.nrows(), x.nrows(), "Axpy: mismatched vector shapes."); 328 self.axcpy(a, x, T::one(), b) 329 } 330 331 /// Computes `self = alpha * a * x + beta * self`, where `a` is a matrix, `x` a vector, and 332 /// `alpha, beta` two scalars. 333 /// 334 /// If `beta` is zero, `self` is never read. 335 /// 336 /// # Examples: 337 /// 338 /// ``` 339 /// # use nalgebra::{Matrix2, Vector2}; 340 /// let mut vec1 = Vector2::new(1.0, 2.0); 341 /// let vec2 = Vector2::new(0.1, 0.2); 342 /// let mat = Matrix2::new(1.0, 2.0, 343 /// 3.0, 4.0); 344 /// vec1.gemv(10.0, &mat, &vec2, 5.0); 345 /// assert_eq!(vec1, Vector2::new(10.0, 21.0)); 346 /// ``` 347 #[inline] gemv<R2: Dim, C2: Dim, D3: Dim, SB, SC>( &mut self, alpha: T, a: &Matrix<T, R2, C2, SB>, x: &Vector<T, D3, SC>, beta: T, ) where T: One, SB: Storage<T, R2, C2>, SC: Storage<T, D3>, ShapeConstraint: DimEq<D, R2> + AreMultipliable<R2, C2, D3, U1>,348 pub fn gemv<R2: Dim, C2: Dim, D3: Dim, SB, SC>( 349 &mut self, 350 alpha: T, 351 a: &Matrix<T, R2, C2, SB>, 352 x: &Vector<T, D3, SC>, 353 beta: T, 354 ) where 355 T: One, 356 SB: Storage<T, R2, C2>, 357 SC: Storage<T, D3>, 358 ShapeConstraint: DimEq<D, R2> + AreMultipliable<R2, C2, D3, U1>, 359 { 360 // Safety: this is safe because we are passing Status == Init. 361 unsafe { gemv_uninit(Init, self, alpha, a, x, beta) } 362 } 363 364 #[inline(always)] xxgemv<D2: Dim, D3: Dim, SB, SC>( &mut self, alpha: T, a: &SquareMatrix<T, D2, SB>, x: &Vector<T, D3, SC>, beta: T, dot: impl Fn( &DVectorSlice<'_, T, SB::RStride, SB::CStride>, &DVectorSlice<'_, T, SC::RStride, SC::CStride>, ) -> T, ) where T: One, SB: Storage<T, D2, D2>, SC: Storage<T, D3>, ShapeConstraint: DimEq<D, D2> + AreMultipliable<D2, D2, D3, U1>,365 fn xxgemv<D2: Dim, D3: Dim, SB, SC>( 366 &mut self, 367 alpha: T, 368 a: &SquareMatrix<T, D2, SB>, 369 x: &Vector<T, D3, SC>, 370 beta: T, 371 dot: impl Fn( 372 &DVectorSlice<'_, T, SB::RStride, SB::CStride>, 373 &DVectorSlice<'_, T, SC::RStride, SC::CStride>, 374 ) -> T, 375 ) where 376 T: One, 377 SB: Storage<T, D2, D2>, 378 SC: Storage<T, D3>, 379 ShapeConstraint: DimEq<D, D2> + AreMultipliable<D2, D2, D3, U1>, 380 { 381 let dim1 = self.nrows(); 382 let dim2 = a.nrows(); 383 let dim3 = x.nrows(); 384 385 assert!( 386 a.is_square(), 387 "Symmetric cgemv: the input matrix must be square." 388 ); 389 assert!( 390 dim2 == dim3 && dim1 == dim2, 391 "Symmetric cgemv: dimensions mismatch." 392 ); 393 394 if dim2 == 0 { 395 return; 396 } 397 398 // TODO: avoid bound checks. 399 let col2 = a.column(0); 400 let val = unsafe { x.vget_unchecked(0).clone() }; 401 self.axpy(alpha.clone() * val, &col2, beta); 402 self[0] += alpha.clone() * dot(&a.slice_range(1.., 0), &x.rows_range(1..)); 403 404 for j in 1..dim2 { 405 let col2 = a.column(j); 406 let dot = dot(&col2.rows_range(j..), &x.rows_range(j..)); 407 408 let val; 409 unsafe { 410 val = x.vget_unchecked(j).clone(); 411 *self.vget_unchecked_mut(j) += alpha.clone() * dot; 412 } 413 self.rows_range_mut(j + 1..).axpy( 414 alpha.clone() * val, 415 &col2.rows_range(j + 1..), 416 T::one(), 417 ); 418 } 419 } 420 421 /// Computes `self = alpha * a * x + beta * self`, where `a` is a **symmetric** matrix, `x` a 422 /// vector, and `alpha, beta` two scalars. 423 /// 424 /// For hermitian matrices, use `.hegemv` instead. 425 /// If `beta` is zero, `self` is never read. If `self` is read, only its lower-triangular part 426 /// (including the diagonal) is actually read. 427 /// 428 /// # Examples: 429 /// 430 /// ``` 431 /// # use nalgebra::{Matrix2, Vector2}; 432 /// let mat = Matrix2::new(1.0, 2.0, 433 /// 2.0, 4.0); 434 /// let mut vec1 = Vector2::new(1.0, 2.0); 435 /// let vec2 = Vector2::new(0.1, 0.2); 436 /// vec1.sygemv(10.0, &mat, &vec2, 5.0); 437 /// assert_eq!(vec1, Vector2::new(10.0, 20.0)); 438 /// 439 /// 440 /// // The matrix upper-triangular elements can be garbage because it is never 441 /// // read by this method. Therefore, it is not necessary for the caller to 442 /// // fill the matrix struct upper-triangle. 443 /// let mat = Matrix2::new(1.0, 9999999.9999999, 444 /// 2.0, 4.0); 445 /// let mut vec1 = Vector2::new(1.0, 2.0); 446 /// vec1.sygemv(10.0, &mat, &vec2, 5.0); 447 /// assert_eq!(vec1, Vector2::new(10.0, 20.0)); 448 /// ``` 449 #[inline] sygemv<D2: Dim, D3: Dim, SB, SC>( &mut self, alpha: T, a: &SquareMatrix<T, D2, SB>, x: &Vector<T, D3, SC>, beta: T, ) where T: One, SB: Storage<T, D2, D2>, SC: Storage<T, D3>, ShapeConstraint: DimEq<D, D2> + AreMultipliable<D2, D2, D3, U1>,450 pub fn sygemv<D2: Dim, D3: Dim, SB, SC>( 451 &mut self, 452 alpha: T, 453 a: &SquareMatrix<T, D2, SB>, 454 x: &Vector<T, D3, SC>, 455 beta: T, 456 ) where 457 T: One, 458 SB: Storage<T, D2, D2>, 459 SC: Storage<T, D3>, 460 ShapeConstraint: DimEq<D, D2> + AreMultipliable<D2, D2, D3, U1>, 461 { 462 self.xxgemv(alpha, a, x, beta, |a, b| a.dot(b)) 463 } 464 465 /// Computes `self = alpha * a * x + beta * self`, where `a` is an **hermitian** matrix, `x` a 466 /// vector, and `alpha, beta` two scalars. 467 /// 468 /// If `beta` is zero, `self` is never read. If `self` is read, only its lower-triangular part 469 /// (including the diagonal) is actually read. 470 /// 471 /// # Examples: 472 /// 473 /// ``` 474 /// # use nalgebra::{Matrix2, Vector2, Complex}; 475 /// let mat = Matrix2::new(Complex::new(1.0, 0.0), Complex::new(2.0, -0.1), 476 /// Complex::new(2.0, 1.0), Complex::new(4.0, 0.0)); 477 /// let mut vec1 = Vector2::new(Complex::new(1.0, 2.0), Complex::new(3.0, 4.0)); 478 /// let vec2 = Vector2::new(Complex::new(0.1, 0.2), Complex::new(0.3, 0.4)); 479 /// vec1.sygemv(Complex::new(10.0, 20.0), &mat, &vec2, Complex::new(5.0, 15.0)); 480 /// assert_eq!(vec1, Vector2::new(Complex::new(-48.0, 44.0), Complex::new(-75.0, 110.0))); 481 /// 482 /// 483 /// // The matrix upper-triangular elements can be garbage because it is never 484 /// // read by this method. Therefore, it is not necessary for the caller to 485 /// // fill the matrix struct upper-triangle. 486 /// 487 /// let mat = Matrix2::new(Complex::new(1.0, 0.0), Complex::new(99999999.9, 999999999.9), 488 /// Complex::new(2.0, 1.0), Complex::new(4.0, 0.0)); 489 /// let mut vec1 = Vector2::new(Complex::new(1.0, 2.0), Complex::new(3.0, 4.0)); 490 /// let vec2 = Vector2::new(Complex::new(0.1, 0.2), Complex::new(0.3, 0.4)); 491 /// vec1.sygemv(Complex::new(10.0, 20.0), &mat, &vec2, Complex::new(5.0, 15.0)); 492 /// assert_eq!(vec1, Vector2::new(Complex::new(-48.0, 44.0), Complex::new(-75.0, 110.0))); 493 /// ``` 494 #[inline] hegemv<D2: Dim, D3: Dim, SB, SC>( &mut self, alpha: T, a: &SquareMatrix<T, D2, SB>, x: &Vector<T, D3, SC>, beta: T, ) where T: SimdComplexField, SB: Storage<T, D2, D2>, SC: Storage<T, D3>, ShapeConstraint: DimEq<D, D2> + AreMultipliable<D2, D2, D3, U1>,495 pub fn hegemv<D2: Dim, D3: Dim, SB, SC>( 496 &mut self, 497 alpha: T, 498 a: &SquareMatrix<T, D2, SB>, 499 x: &Vector<T, D3, SC>, 500 beta: T, 501 ) where 502 T: SimdComplexField, 503 SB: Storage<T, D2, D2>, 504 SC: Storage<T, D3>, 505 ShapeConstraint: DimEq<D, D2> + AreMultipliable<D2, D2, D3, U1>, 506 { 507 self.xxgemv(alpha, a, x, beta, |a, b| a.dotc(b)) 508 } 509 510 #[inline(always)] gemv_xx<R2: Dim, C2: Dim, D3: Dim, SB, SC>( &mut self, alpha: T, a: &Matrix<T, R2, C2, SB>, x: &Vector<T, D3, SC>, beta: T, dot: impl Fn(&VectorSlice<'_, T, R2, SB::RStride, SB::CStride>, &Vector<T, D3, SC>) -> T, ) where T: One, SB: Storage<T, R2, C2>, SC: Storage<T, D3>, ShapeConstraint: DimEq<D, C2> + AreMultipliable<C2, R2, D3, U1>,511 fn gemv_xx<R2: Dim, C2: Dim, D3: Dim, SB, SC>( 512 &mut self, 513 alpha: T, 514 a: &Matrix<T, R2, C2, SB>, 515 x: &Vector<T, D3, SC>, 516 beta: T, 517 dot: impl Fn(&VectorSlice<'_, T, R2, SB::RStride, SB::CStride>, &Vector<T, D3, SC>) -> T, 518 ) where 519 T: One, 520 SB: Storage<T, R2, C2>, 521 SC: Storage<T, D3>, 522 ShapeConstraint: DimEq<D, C2> + AreMultipliable<C2, R2, D3, U1>, 523 { 524 let dim1 = self.nrows(); 525 let (nrows2, ncols2) = a.shape(); 526 let dim3 = x.nrows(); 527 528 assert!( 529 nrows2 == dim3 && dim1 == ncols2, 530 "Gemv: dimensions mismatch." 531 ); 532 533 if ncols2 == 0 { 534 return; 535 } 536 537 if beta.is_zero() { 538 for j in 0..ncols2 { 539 let val = unsafe { self.vget_unchecked_mut(j) }; 540 *val = alpha.clone() * dot(&a.column(j), x) 541 } 542 } else { 543 for j in 0..ncols2 { 544 let val = unsafe { self.vget_unchecked_mut(j) }; 545 *val = alpha.clone() * dot(&a.column(j), x) + beta.clone() * val.clone(); 546 } 547 } 548 } 549 550 /// Computes `self = alpha * a.transpose() * x + beta * self`, where `a` is a matrix, `x` a vector, and 551 /// `alpha, beta` two scalars. 552 /// 553 /// If `beta` is zero, `self` is never read. 554 /// 555 /// # Examples: 556 /// 557 /// ``` 558 /// # use nalgebra::{Matrix2, Vector2}; 559 /// let mat = Matrix2::new(1.0, 3.0, 560 /// 2.0, 4.0); 561 /// let mut vec1 = Vector2::new(1.0, 2.0); 562 /// let vec2 = Vector2::new(0.1, 0.2); 563 /// let expected = mat.transpose() * vec2 * 10.0 + vec1 * 5.0; 564 /// 565 /// vec1.gemv_tr(10.0, &mat, &vec2, 5.0); 566 /// assert_eq!(vec1, expected); 567 /// ``` 568 #[inline] gemv_tr<R2: Dim, C2: Dim, D3: Dim, SB, SC>( &mut self, alpha: T, a: &Matrix<T, R2, C2, SB>, x: &Vector<T, D3, SC>, beta: T, ) where T: One, SB: Storage<T, R2, C2>, SC: Storage<T, D3>, ShapeConstraint: DimEq<D, C2> + AreMultipliable<C2, R2, D3, U1>,569 pub fn gemv_tr<R2: Dim, C2: Dim, D3: Dim, SB, SC>( 570 &mut self, 571 alpha: T, 572 a: &Matrix<T, R2, C2, SB>, 573 x: &Vector<T, D3, SC>, 574 beta: T, 575 ) where 576 T: One, 577 SB: Storage<T, R2, C2>, 578 SC: Storage<T, D3>, 579 ShapeConstraint: DimEq<D, C2> + AreMultipliable<C2, R2, D3, U1>, 580 { 581 self.gemv_xx(alpha, a, x, beta, |a, b| a.dot(b)) 582 } 583 584 /// Computes `self = alpha * a.adjoint() * x + beta * self`, where `a` is a matrix, `x` a vector, and 585 /// `alpha, beta` two scalars. 586 /// 587 /// For real matrices, this is the same as `.gemv_tr`. 588 /// If `beta` is zero, `self` is never read. 589 /// 590 /// # Examples: 591 /// 592 /// ``` 593 /// # use nalgebra::{Matrix2, Vector2, Complex}; 594 /// let mat = Matrix2::new(Complex::new(1.0, 2.0), Complex::new(3.0, 4.0), 595 /// Complex::new(5.0, 6.0), Complex::new(7.0, 8.0)); 596 /// let mut vec1 = Vector2::new(Complex::new(1.0, 2.0), Complex::new(3.0, 4.0)); 597 /// let vec2 = Vector2::new(Complex::new(0.1, 0.2), Complex::new(0.3, 0.4)); 598 /// let expected = mat.adjoint() * vec2 * Complex::new(10.0, 20.0) + vec1 * Complex::new(5.0, 15.0); 599 /// 600 /// vec1.gemv_ad(Complex::new(10.0, 20.0), &mat, &vec2, Complex::new(5.0, 15.0)); 601 /// assert_eq!(vec1, expected); 602 /// ``` 603 #[inline] gemv_ad<R2: Dim, C2: Dim, D3: Dim, SB, SC>( &mut self, alpha: T, a: &Matrix<T, R2, C2, SB>, x: &Vector<T, D3, SC>, beta: T, ) where T: SimdComplexField, SB: Storage<T, R2, C2>, SC: Storage<T, D3>, ShapeConstraint: DimEq<D, C2> + AreMultipliable<C2, R2, D3, U1>,604 pub fn gemv_ad<R2: Dim, C2: Dim, D3: Dim, SB, SC>( 605 &mut self, 606 alpha: T, 607 a: &Matrix<T, R2, C2, SB>, 608 x: &Vector<T, D3, SC>, 609 beta: T, 610 ) where 611 T: SimdComplexField, 612 SB: Storage<T, R2, C2>, 613 SC: Storage<T, D3>, 614 ShapeConstraint: DimEq<D, C2> + AreMultipliable<C2, R2, D3, U1>, 615 { 616 self.gemv_xx(alpha, a, x, beta, |a, b| a.dotc(b)) 617 } 618 } 619 620 impl<T, R1: Dim, C1: Dim, S: StorageMut<T, R1, C1>> Matrix<T, R1, C1, S> 621 where 622 T: Scalar + Zero + ClosedAdd + ClosedMul, 623 { 624 #[inline(always)] gerx<D2: Dim, D3: Dim, SB, SC>( &mut self, alpha: T, x: &Vector<T, D2, SB>, y: &Vector<T, D3, SC>, beta: T, conjugate: impl Fn(T) -> T, ) where T: One, SB: Storage<T, D2>, SC: Storage<T, D3>, ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>,625 fn gerx<D2: Dim, D3: Dim, SB, SC>( 626 &mut self, 627 alpha: T, 628 x: &Vector<T, D2, SB>, 629 y: &Vector<T, D3, SC>, 630 beta: T, 631 conjugate: impl Fn(T) -> T, 632 ) where 633 T: One, 634 SB: Storage<T, D2>, 635 SC: Storage<T, D3>, 636 ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>, 637 { 638 let (nrows1, ncols1) = self.shape(); 639 let dim2 = x.nrows(); 640 let dim3 = y.nrows(); 641 642 assert!( 643 nrows1 == dim2 && ncols1 == dim3, 644 "ger: dimensions mismatch." 645 ); 646 647 for j in 0..ncols1 { 648 // TODO: avoid bound checks. 649 let val = unsafe { conjugate(y.vget_unchecked(j).clone()) }; 650 self.column_mut(j) 651 .axpy(alpha.clone() * val, x, beta.clone()); 652 } 653 } 654 655 /// Computes `self = alpha * x * y.transpose() + beta * self`. 656 /// 657 /// If `beta` is zero, `self` is never read. 658 /// 659 /// # Examples: 660 /// 661 /// ``` 662 /// # use nalgebra::{Matrix2x3, Vector2, Vector3}; 663 /// let mut mat = Matrix2x3::repeat(4.0); 664 /// let vec1 = Vector2::new(1.0, 2.0); 665 /// let vec2 = Vector3::new(0.1, 0.2, 0.3); 666 /// let expected = vec1 * vec2.transpose() * 10.0 + mat * 5.0; 667 /// 668 /// mat.ger(10.0, &vec1, &vec2, 5.0); 669 /// assert_eq!(mat, expected); 670 /// ``` 671 #[inline] ger<D2: Dim, D3: Dim, SB, SC>( &mut self, alpha: T, x: &Vector<T, D2, SB>, y: &Vector<T, D3, SC>, beta: T, ) where T: One, SB: Storage<T, D2>, SC: Storage<T, D3>, ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>,672 pub fn ger<D2: Dim, D3: Dim, SB, SC>( 673 &mut self, 674 alpha: T, 675 x: &Vector<T, D2, SB>, 676 y: &Vector<T, D3, SC>, 677 beta: T, 678 ) where 679 T: One, 680 SB: Storage<T, D2>, 681 SC: Storage<T, D3>, 682 ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>, 683 { 684 self.gerx(alpha, x, y, beta, |e| e) 685 } 686 687 /// Computes `self = alpha * x * y.adjoint() + beta * self`. 688 /// 689 /// If `beta` is zero, `self` is never read. 690 /// 691 /// # Examples: 692 /// 693 /// ``` 694 /// # #[macro_use] extern crate approx; 695 /// # use nalgebra::{Matrix2x3, Vector2, Vector3, Complex}; 696 /// let mut mat = Matrix2x3::repeat(Complex::new(4.0, 5.0)); 697 /// let vec1 = Vector2::new(Complex::new(1.0, 2.0), Complex::new(3.0, 4.0)); 698 /// let vec2 = Vector3::new(Complex::new(0.6, 0.5), Complex::new(0.4, 0.5), Complex::new(0.2, 0.1)); 699 /// let expected = vec1 * vec2.adjoint() * Complex::new(10.0, 20.0) + mat * Complex::new(5.0, 15.0); 700 /// 701 /// mat.gerc(Complex::new(10.0, 20.0), &vec1, &vec2, Complex::new(5.0, 15.0)); 702 /// assert_eq!(mat, expected); 703 /// ``` 704 #[inline] gerc<D2: Dim, D3: Dim, SB, SC>( &mut self, alpha: T, x: &Vector<T, D2, SB>, y: &Vector<T, D3, SC>, beta: T, ) where T: SimdComplexField, SB: Storage<T, D2>, SC: Storage<T, D3>, ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>,705 pub fn gerc<D2: Dim, D3: Dim, SB, SC>( 706 &mut self, 707 alpha: T, 708 x: &Vector<T, D2, SB>, 709 y: &Vector<T, D3, SC>, 710 beta: T, 711 ) where 712 T: SimdComplexField, 713 SB: Storage<T, D2>, 714 SC: Storage<T, D3>, 715 ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>, 716 { 717 self.gerx(alpha, x, y, beta, SimdComplexField::simd_conjugate) 718 } 719 720 /// Computes `self = alpha * a * b + beta * self`, where `a, b, self` are matrices. 721 /// `alpha` and `beta` are scalar. 722 /// 723 /// If `beta` is zero, `self` is never read. 724 /// 725 /// # Examples: 726 /// 727 /// ``` 728 /// # #[macro_use] extern crate approx; 729 /// # use nalgebra::{Matrix2x3, Matrix3x4, Matrix2x4}; 730 /// let mut mat1 = Matrix2x4::identity(); 731 /// let mat2 = Matrix2x3::new(1.0, 2.0, 3.0, 732 /// 4.0, 5.0, 6.0); 733 /// let mat3 = Matrix3x4::new(0.1, 0.2, 0.3, 0.4, 734 /// 0.5, 0.6, 0.7, 0.8, 735 /// 0.9, 1.0, 1.1, 1.2); 736 /// let expected = mat2 * mat3 * 10.0 + mat1 * 5.0; 737 /// 738 /// mat1.gemm(10.0, &mat2, &mat3, 5.0); 739 /// assert_relative_eq!(mat1, expected); 740 /// ``` 741 #[inline] gemm<R2: Dim, C2: Dim, R3: Dim, C3: Dim, SB, SC>( &mut self, alpha: T, a: &Matrix<T, R2, C2, SB>, b: &Matrix<T, R3, C3, SC>, beta: T, ) where T: One, SB: Storage<T, R2, C2>, SC: Storage<T, R3, C3>, ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C3> + AreMultipliable<R2, C2, R3, C3>,742 pub fn gemm<R2: Dim, C2: Dim, R3: Dim, C3: Dim, SB, SC>( 743 &mut self, 744 alpha: T, 745 a: &Matrix<T, R2, C2, SB>, 746 b: &Matrix<T, R3, C3, SC>, 747 beta: T, 748 ) where 749 T: One, 750 SB: Storage<T, R2, C2>, 751 SC: Storage<T, R3, C3>, 752 ShapeConstraint: SameNumberOfRows<R1, R2> 753 + SameNumberOfColumns<C1, C3> 754 + AreMultipliable<R2, C2, R3, C3>, 755 { 756 // SAFETY: this is valid because our matrices are initialized and 757 // we are using status = Init. 758 unsafe { gemm_uninit(Init, self, alpha, a, b, beta) } 759 } 760 761 /// Computes `self = alpha * a.transpose() * b + beta * self`, where `a, b, self` are matrices. 762 /// `alpha` and `beta` are scalar. 763 /// 764 /// If `beta` is zero, `self` is never read. 765 /// 766 /// # Examples: 767 /// 768 /// ``` 769 /// # #[macro_use] extern crate approx; 770 /// # use nalgebra::{Matrix3x2, Matrix3x4, Matrix2x4}; 771 /// let mut mat1 = Matrix2x4::identity(); 772 /// let mat2 = Matrix3x2::new(1.0, 4.0, 773 /// 2.0, 5.0, 774 /// 3.0, 6.0); 775 /// let mat3 = Matrix3x4::new(0.1, 0.2, 0.3, 0.4, 776 /// 0.5, 0.6, 0.7, 0.8, 777 /// 0.9, 1.0, 1.1, 1.2); 778 /// let expected = mat2.transpose() * mat3 * 10.0 + mat1 * 5.0; 779 /// 780 /// mat1.gemm_tr(10.0, &mat2, &mat3, 5.0); 781 /// assert_eq!(mat1, expected); 782 /// ``` 783 #[inline] gemm_tr<R2: Dim, C2: Dim, R3: Dim, C3: Dim, SB, SC>( &mut self, alpha: T, a: &Matrix<T, R2, C2, SB>, b: &Matrix<T, R3, C3, SC>, beta: T, ) where T: One, SB: Storage<T, R2, C2>, SC: Storage<T, R3, C3>, ShapeConstraint: SameNumberOfRows<R1, C2> + SameNumberOfColumns<C1, C3> + AreMultipliable<C2, R2, R3, C3>,784 pub fn gemm_tr<R2: Dim, C2: Dim, R3: Dim, C3: Dim, SB, SC>( 785 &mut self, 786 alpha: T, 787 a: &Matrix<T, R2, C2, SB>, 788 b: &Matrix<T, R3, C3, SC>, 789 beta: T, 790 ) where 791 T: One, 792 SB: Storage<T, R2, C2>, 793 SC: Storage<T, R3, C3>, 794 ShapeConstraint: SameNumberOfRows<R1, C2> 795 + SameNumberOfColumns<C1, C3> 796 + AreMultipliable<C2, R2, R3, C3>, 797 { 798 let (nrows1, ncols1) = self.shape(); 799 let (nrows2, ncols2) = a.shape(); 800 let (nrows3, ncols3) = b.shape(); 801 802 assert_eq!( 803 nrows2, nrows3, 804 "gemm: dimensions mismatch for multiplication." 805 ); 806 assert_eq!( 807 (nrows1, ncols1), 808 (ncols2, ncols3), 809 "gemm: dimensions mismatch for addition." 810 ); 811 812 for j1 in 0..ncols1 { 813 // TODO: avoid bound checks. 814 self.column_mut(j1) 815 .gemv_tr(alpha.clone(), a, &b.column(j1), beta.clone()); 816 } 817 } 818 819 /// Computes `self = alpha * a.adjoint() * b + beta * self`, where `a, b, self` are matrices. 820 /// `alpha` and `beta` are scalar. 821 /// 822 /// If `beta` is zero, `self` is never read. 823 /// 824 /// # Examples: 825 /// 826 /// ``` 827 /// # #[macro_use] extern crate approx; 828 /// # use nalgebra::{Matrix3x2, Matrix3x4, Matrix2x4, Complex}; 829 /// let mut mat1 = Matrix2x4::identity(); 830 /// let mat2 = Matrix3x2::new(Complex::new(1.0, 4.0), Complex::new(7.0, 8.0), 831 /// Complex::new(2.0, 5.0), Complex::new(9.0, 10.0), 832 /// Complex::new(3.0, 6.0), Complex::new(11.0, 12.0)); 833 /// let mat3 = Matrix3x4::new(Complex::new(0.1, 1.3), Complex::new(0.2, 1.4), Complex::new(0.3, 1.5), Complex::new(0.4, 1.6), 834 /// Complex::new(0.5, 1.7), Complex::new(0.6, 1.8), Complex::new(0.7, 1.9), Complex::new(0.8, 2.0), 835 /// Complex::new(0.9, 2.1), Complex::new(1.0, 2.2), Complex::new(1.1, 2.3), Complex::new(1.2, 2.4)); 836 /// let expected = mat2.adjoint() * mat3 * Complex::new(10.0, 20.0) + mat1 * Complex::new(5.0, 15.0); 837 /// 838 /// mat1.gemm_ad(Complex::new(10.0, 20.0), &mat2, &mat3, Complex::new(5.0, 15.0)); 839 /// assert_eq!(mat1, expected); 840 /// ``` 841 #[inline] gemm_ad<R2: Dim, C2: Dim, R3: Dim, C3: Dim, SB, SC>( &mut self, alpha: T, a: &Matrix<T, R2, C2, SB>, b: &Matrix<T, R3, C3, SC>, beta: T, ) where T: SimdComplexField, SB: Storage<T, R2, C2>, SC: Storage<T, R3, C3>, ShapeConstraint: SameNumberOfRows<R1, C2> + SameNumberOfColumns<C1, C3> + AreMultipliable<C2, R2, R3, C3>,842 pub fn gemm_ad<R2: Dim, C2: Dim, R3: Dim, C3: Dim, SB, SC>( 843 &mut self, 844 alpha: T, 845 a: &Matrix<T, R2, C2, SB>, 846 b: &Matrix<T, R3, C3, SC>, 847 beta: T, 848 ) where 849 T: SimdComplexField, 850 SB: Storage<T, R2, C2>, 851 SC: Storage<T, R3, C3>, 852 ShapeConstraint: SameNumberOfRows<R1, C2> 853 + SameNumberOfColumns<C1, C3> 854 + AreMultipliable<C2, R2, R3, C3>, 855 { 856 let (nrows1, ncols1) = self.shape(); 857 let (nrows2, ncols2) = a.shape(); 858 let (nrows3, ncols3) = b.shape(); 859 860 assert_eq!( 861 nrows2, nrows3, 862 "gemm: dimensions mismatch for multiplication." 863 ); 864 assert_eq!( 865 (nrows1, ncols1), 866 (ncols2, ncols3), 867 "gemm: dimensions mismatch for addition." 868 ); 869 870 for j1 in 0..ncols1 { 871 // TODO: avoid bound checks. 872 self.column_mut(j1) 873 .gemv_ad(alpha.clone(), a, &b.column(j1), beta.clone()); 874 } 875 } 876 } 877 878 impl<T, R1: Dim, C1: Dim, S: StorageMut<T, R1, C1>> Matrix<T, R1, C1, S> 879 where 880 T: Scalar + Zero + ClosedAdd + ClosedMul, 881 { 882 #[inline(always)] xxgerx<D2: Dim, D3: Dim, SB, SC>( &mut self, alpha: T, x: &Vector<T, D2, SB>, y: &Vector<T, D3, SC>, beta: T, conjugate: impl Fn(T) -> T, ) where T: One, SB: Storage<T, D2>, SC: Storage<T, D3>, ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>,883 fn xxgerx<D2: Dim, D3: Dim, SB, SC>( 884 &mut self, 885 alpha: T, 886 x: &Vector<T, D2, SB>, 887 y: &Vector<T, D3, SC>, 888 beta: T, 889 conjugate: impl Fn(T) -> T, 890 ) where 891 T: One, 892 SB: Storage<T, D2>, 893 SC: Storage<T, D3>, 894 ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>, 895 { 896 let dim1 = self.nrows(); 897 let dim2 = x.nrows(); 898 let dim3 = y.nrows(); 899 900 assert!( 901 self.is_square(), 902 "Symmetric ger: the input matrix must be square." 903 ); 904 assert!(dim1 == dim2 && dim1 == dim3, "ger: dimensions mismatch."); 905 906 for j in 0..dim1 { 907 let val = unsafe { conjugate(y.vget_unchecked(j).clone()) }; 908 let subdim = Dynamic::new(dim1 - j); 909 // TODO: avoid bound checks. 910 self.generic_slice_mut((j, j), (subdim, Const::<1>)).axpy( 911 alpha.clone() * val, 912 &x.rows_range(j..), 913 beta.clone(), 914 ); 915 } 916 } 917 918 /// Computes `self = alpha * x * y.transpose() + beta * self`, where `self` is a **symmetric** 919 /// matrix. 920 /// 921 /// If `beta` is zero, `self` is never read. The result is symmetric. Only the lower-triangular 922 /// (including the diagonal) part of `self` is read/written. 923 /// 924 /// # Examples: 925 /// 926 /// ``` 927 /// # use nalgebra::{Matrix2, Vector2}; 928 /// let mut mat = Matrix2::identity(); 929 /// let vec1 = Vector2::new(1.0, 2.0); 930 /// let vec2 = Vector2::new(0.1, 0.2); 931 /// let expected = vec1 * vec2.transpose() * 10.0 + mat * 5.0; 932 /// mat.m12 = 99999.99999; // This component is on the upper-triangular part and will not be read/written. 933 /// 934 /// mat.ger_symm(10.0, &vec1, &vec2, 5.0); 935 /// assert_eq!(mat.lower_triangle(), expected.lower_triangle()); 936 /// assert_eq!(mat.m12, 99999.99999); // This was untouched. 937 #[inline] 938 #[deprecated(note = "This is renamed `syger` to match the original BLAS terminology.")] ger_symm<D2: Dim, D3: Dim, SB, SC>( &mut self, alpha: T, x: &Vector<T, D2, SB>, y: &Vector<T, D3, SC>, beta: T, ) where T: One, SB: Storage<T, D2>, SC: Storage<T, D3>, ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>,939 pub fn ger_symm<D2: Dim, D3: Dim, SB, SC>( 940 &mut self, 941 alpha: T, 942 x: &Vector<T, D2, SB>, 943 y: &Vector<T, D3, SC>, 944 beta: T, 945 ) where 946 T: One, 947 SB: Storage<T, D2>, 948 SC: Storage<T, D3>, 949 ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>, 950 { 951 self.syger(alpha, x, y, beta) 952 } 953 954 /// Computes `self = alpha * x * y.transpose() + beta * self`, where `self` is a **symmetric** 955 /// matrix. 956 /// 957 /// For hermitian complex matrices, use `.hegerc` instead. 958 /// If `beta` is zero, `self` is never read. The result is symmetric. Only the lower-triangular 959 /// (including the diagonal) part of `self` is read/written. 960 /// 961 /// # Examples: 962 /// 963 /// ``` 964 /// # use nalgebra::{Matrix2, Vector2}; 965 /// let mut mat = Matrix2::identity(); 966 /// let vec1 = Vector2::new(1.0, 2.0); 967 /// let vec2 = Vector2::new(0.1, 0.2); 968 /// let expected = vec1 * vec2.transpose() * 10.0 + mat * 5.0; 969 /// mat.m12 = 99999.99999; // This component is on the upper-triangular part and will not be read/written. 970 /// 971 /// mat.syger(10.0, &vec1, &vec2, 5.0); 972 /// assert_eq!(mat.lower_triangle(), expected.lower_triangle()); 973 /// assert_eq!(mat.m12, 99999.99999); // This was untouched. 974 #[inline] syger<D2: Dim, D3: Dim, SB, SC>( &mut self, alpha: T, x: &Vector<T, D2, SB>, y: &Vector<T, D3, SC>, beta: T, ) where T: One, SB: Storage<T, D2>, SC: Storage<T, D3>, ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>,975 pub fn syger<D2: Dim, D3: Dim, SB, SC>( 976 &mut self, 977 alpha: T, 978 x: &Vector<T, D2, SB>, 979 y: &Vector<T, D3, SC>, 980 beta: T, 981 ) where 982 T: One, 983 SB: Storage<T, D2>, 984 SC: Storage<T, D3>, 985 ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>, 986 { 987 self.xxgerx(alpha, x, y, beta, |e| e) 988 } 989 990 /// Computes `self = alpha * x * y.adjoint() + beta * self`, where `self` is an **hermitian** 991 /// matrix. 992 /// 993 /// If `beta` is zero, `self` is never read. The result is symmetric. Only the lower-triangular 994 /// (including the diagonal) part of `self` is read/written. 995 /// 996 /// # Examples: 997 /// 998 /// ``` 999 /// # use nalgebra::{Matrix2, Vector2, Complex}; 1000 /// let mut mat = Matrix2::identity(); 1001 /// let vec1 = Vector2::new(Complex::new(1.0, 3.0), Complex::new(2.0, 4.0)); 1002 /// let vec2 = Vector2::new(Complex::new(0.2, 0.4), Complex::new(0.1, 0.3)); 1003 /// let expected = vec1 * vec2.adjoint() * Complex::new(10.0, 20.0) + mat * Complex::new(5.0, 15.0); 1004 /// mat.m12 = Complex::new(99999.99999, 88888.88888); // This component is on the upper-triangular part and will not be read/written. 1005 /// 1006 /// mat.hegerc(Complex::new(10.0, 20.0), &vec1, &vec2, Complex::new(5.0, 15.0)); 1007 /// assert_eq!(mat.lower_triangle(), expected.lower_triangle()); 1008 /// assert_eq!(mat.m12, Complex::new(99999.99999, 88888.88888)); // This was untouched. 1009 #[inline] hegerc<D2: Dim, D3: Dim, SB, SC>( &mut self, alpha: T, x: &Vector<T, D2, SB>, y: &Vector<T, D3, SC>, beta: T, ) where T: SimdComplexField, SB: Storage<T, D2>, SC: Storage<T, D3>, ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>,1010 pub fn hegerc<D2: Dim, D3: Dim, SB, SC>( 1011 &mut self, 1012 alpha: T, 1013 x: &Vector<T, D2, SB>, 1014 y: &Vector<T, D3, SC>, 1015 beta: T, 1016 ) where 1017 T: SimdComplexField, 1018 SB: Storage<T, D2>, 1019 SC: Storage<T, D3>, 1020 ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>, 1021 { 1022 self.xxgerx(alpha, x, y, beta, SimdComplexField::simd_conjugate) 1023 } 1024 } 1025 1026 impl<T, D1: Dim, S: StorageMut<T, D1, D1>> SquareMatrix<T, D1, S> 1027 where 1028 T: Scalar + Zero + One + ClosedAdd + ClosedMul, 1029 { 1030 /// Computes the quadratic form `self = alpha * lhs * mid * lhs.transpose() + beta * self`. 1031 /// 1032 /// This uses the provided workspace `work` to avoid allocations for intermediate results. 1033 /// 1034 /// # Examples: 1035 /// 1036 /// ``` 1037 /// # #[macro_use] extern crate approx; 1038 /// # use nalgebra::{DMatrix, DVector}; 1039 /// // Note that all those would also work with statically-sized matrices. 1040 /// // We use DMatrix/DVector since that's the only case where pre-allocating the 1041 /// // workspace is actually useful (assuming the same workspace is re-used for 1042 /// // several computations) because it avoids repeated dynamic allocations. 1043 /// let mut mat = DMatrix::identity(2, 2); 1044 /// let lhs = DMatrix::from_row_slice(2, 3, &[1.0, 2.0, 3.0, 1045 /// 4.0, 5.0, 6.0]); 1046 /// let mid = DMatrix::from_row_slice(3, 3, &[0.1, 0.2, 0.3, 1047 /// 0.5, 0.6, 0.7, 1048 /// 0.9, 1.0, 1.1]); 1049 /// // The random shows that values on the workspace do not 1050 /// // matter as they will be overwritten. 1051 /// let mut workspace = DVector::new_random(2); 1052 /// let expected = &lhs * &mid * lhs.transpose() * 10.0 + &mat * 5.0; 1053 /// 1054 /// mat.quadform_tr_with_workspace(&mut workspace, 10.0, &lhs, &mid, 5.0); 1055 /// assert_relative_eq!(mat, expected); quadform_tr_with_workspace<D2, S2, R3, C3, S3, D4, S4>( &mut self, work: &mut Vector<T, D2, S2>, alpha: T, lhs: &Matrix<T, R3, C3, S3>, mid: &SquareMatrix<T, D4, S4>, beta: T, ) where D2: Dim, R3: Dim, C3: Dim, D4: Dim, S2: StorageMut<T, D2>, S3: Storage<T, R3, C3>, S4: Storage<T, D4, D4>, ShapeConstraint: DimEq<D1, D2> + DimEq<D1, R3> + DimEq<D2, R3> + DimEq<C3, D4>,1056 pub fn quadform_tr_with_workspace<D2, S2, R3, C3, S3, D4, S4>( 1057 &mut self, 1058 work: &mut Vector<T, D2, S2>, 1059 alpha: T, 1060 lhs: &Matrix<T, R3, C3, S3>, 1061 mid: &SquareMatrix<T, D4, S4>, 1062 beta: T, 1063 ) where 1064 D2: Dim, 1065 R3: Dim, 1066 C3: Dim, 1067 D4: Dim, 1068 S2: StorageMut<T, D2>, 1069 S3: Storage<T, R3, C3>, 1070 S4: Storage<T, D4, D4>, 1071 ShapeConstraint: DimEq<D1, D2> + DimEq<D1, R3> + DimEq<D2, R3> + DimEq<C3, D4>, 1072 { 1073 work.gemv(T::one(), lhs, &mid.column(0), T::zero()); 1074 self.ger(alpha.clone(), work, &lhs.column(0), beta); 1075 1076 for j in 1..mid.ncols() { 1077 work.gemv(T::one(), lhs, &mid.column(j), T::zero()); 1078 self.ger(alpha.clone(), work, &lhs.column(j), T::one()); 1079 } 1080 } 1081 1082 /// Computes the quadratic form `self = alpha * lhs * mid * lhs.transpose() + beta * self`. 1083 /// 1084 /// This allocates a workspace vector of dimension D1 for intermediate results. 1085 /// If `D1` is a type-level integer, then the allocation is performed on the stack. 1086 /// Use `.quadform_tr_with_workspace(...)` instead to avoid allocations. 1087 /// 1088 /// # Examples: 1089 /// 1090 /// ``` 1091 /// # #[macro_use] extern crate approx; 1092 /// # use nalgebra::{Matrix2, Matrix3, Matrix2x3, Vector2}; 1093 /// let mut mat = Matrix2::identity(); 1094 /// let lhs = Matrix2x3::new(1.0, 2.0, 3.0, 1095 /// 4.0, 5.0, 6.0); 1096 /// let mid = Matrix3::new(0.1, 0.2, 0.3, 1097 /// 0.5, 0.6, 0.7, 1098 /// 0.9, 1.0, 1.1); 1099 /// let expected = lhs * mid * lhs.transpose() * 10.0 + mat * 5.0; 1100 /// 1101 /// mat.quadform_tr(10.0, &lhs, &mid, 5.0); 1102 /// assert_relative_eq!(mat, expected); quadform_tr<R3, C3, S3, D4, S4>( &mut self, alpha: T, lhs: &Matrix<T, R3, C3, S3>, mid: &SquareMatrix<T, D4, S4>, beta: T, ) where R3: Dim, C3: Dim, D4: Dim, S3: Storage<T, R3, C3>, S4: Storage<T, D4, D4>, ShapeConstraint: DimEq<D1, D1> + DimEq<D1, R3> + DimEq<C3, D4>, DefaultAllocator: Allocator<T, D1>,1103 pub fn quadform_tr<R3, C3, S3, D4, S4>( 1104 &mut self, 1105 alpha: T, 1106 lhs: &Matrix<T, R3, C3, S3>, 1107 mid: &SquareMatrix<T, D4, S4>, 1108 beta: T, 1109 ) where 1110 R3: Dim, 1111 C3: Dim, 1112 D4: Dim, 1113 S3: Storage<T, R3, C3>, 1114 S4: Storage<T, D4, D4>, 1115 ShapeConstraint: DimEq<D1, D1> + DimEq<D1, R3> + DimEq<C3, D4>, 1116 DefaultAllocator: Allocator<T, D1>, 1117 { 1118 // TODO: would it be useful to avoid the zero-initialization of the workspace data? 1119 let mut work = Matrix::zeros_generic(self.shape_generic().0, Const::<1>); 1120 self.quadform_tr_with_workspace(&mut work, alpha, lhs, mid, beta) 1121 } 1122 1123 /// Computes the quadratic form `self = alpha * rhs.transpose() * mid * rhs + beta * self`. 1124 /// 1125 /// This uses the provided workspace `work` to avoid allocations for intermediate results. 1126 /// 1127 /// ``` 1128 /// # #[macro_use] extern crate approx; 1129 /// # use nalgebra::{DMatrix, DVector}; 1130 /// // Note that all those would also work with statically-sized matrices. 1131 /// // We use DMatrix/DVector since that's the only case where pre-allocating the 1132 /// // workspace is actually useful (assuming the same workspace is re-used for 1133 /// // several computations) because it avoids repeated dynamic allocations. 1134 /// let mut mat = DMatrix::identity(2, 2); 1135 /// let rhs = DMatrix::from_row_slice(3, 2, &[1.0, 2.0, 1136 /// 3.0, 4.0, 1137 /// 5.0, 6.0]); 1138 /// let mid = DMatrix::from_row_slice(3, 3, &[0.1, 0.2, 0.3, 1139 /// 0.5, 0.6, 0.7, 1140 /// 0.9, 1.0, 1.1]); 1141 /// // The random shows that values on the workspace do not 1142 /// // matter as they will be overwritten. 1143 /// let mut workspace = DVector::new_random(3); 1144 /// let expected = rhs.transpose() * &mid * &rhs * 10.0 + &mat * 5.0; 1145 /// 1146 /// mat.quadform_with_workspace(&mut workspace, 10.0, &mid, &rhs, 5.0); 1147 /// assert_relative_eq!(mat, expected); quadform_with_workspace<D2, S2, D3, S3, R4, C4, S4>( &mut self, work: &mut Vector<T, D2, S2>, alpha: T, mid: &SquareMatrix<T, D3, S3>, rhs: &Matrix<T, R4, C4, S4>, beta: T, ) where D2: Dim, D3: Dim, R4: Dim, C4: Dim, S2: StorageMut<T, D2>, S3: Storage<T, D3, D3>, S4: Storage<T, R4, C4>, ShapeConstraint: DimEq<D3, R4> + DimEq<D1, C4> + DimEq<D2, D3> + AreMultipliable<C4, R4, D2, U1>,1148 pub fn quadform_with_workspace<D2, S2, D3, S3, R4, C4, S4>( 1149 &mut self, 1150 work: &mut Vector<T, D2, S2>, 1151 alpha: T, 1152 mid: &SquareMatrix<T, D3, S3>, 1153 rhs: &Matrix<T, R4, C4, S4>, 1154 beta: T, 1155 ) where 1156 D2: Dim, 1157 D3: Dim, 1158 R4: Dim, 1159 C4: Dim, 1160 S2: StorageMut<T, D2>, 1161 S3: Storage<T, D3, D3>, 1162 S4: Storage<T, R4, C4>, 1163 ShapeConstraint: 1164 DimEq<D3, R4> + DimEq<D1, C4> + DimEq<D2, D3> + AreMultipliable<C4, R4, D2, U1>, 1165 { 1166 work.gemv(T::one(), mid, &rhs.column(0), T::zero()); 1167 self.column_mut(0) 1168 .gemv_tr(alpha.clone(), rhs, work, beta.clone()); 1169 1170 for j in 1..rhs.ncols() { 1171 work.gemv(T::one(), mid, &rhs.column(j), T::zero()); 1172 self.column_mut(j) 1173 .gemv_tr(alpha.clone(), rhs, work, beta.clone()); 1174 } 1175 } 1176 1177 /// Computes the quadratic form `self = alpha * rhs.transpose() * mid * rhs + beta * self`. 1178 /// 1179 /// This allocates a workspace vector of dimension D2 for intermediate results. 1180 /// If `D2` is a type-level integer, then the allocation is performed on the stack. 1181 /// Use `.quadform_with_workspace(...)` instead to avoid allocations. 1182 /// 1183 /// ``` 1184 /// # #[macro_use] extern crate approx; 1185 /// # use nalgebra::{Matrix2, Matrix3x2, Matrix3}; 1186 /// let mut mat = Matrix2::identity(); 1187 /// let rhs = Matrix3x2::new(1.0, 2.0, 1188 /// 3.0, 4.0, 1189 /// 5.0, 6.0); 1190 /// let mid = Matrix3::new(0.1, 0.2, 0.3, 1191 /// 0.5, 0.6, 0.7, 1192 /// 0.9, 1.0, 1.1); 1193 /// let expected = rhs.transpose() * mid * rhs * 10.0 + mat * 5.0; 1194 /// 1195 /// mat.quadform(10.0, &mid, &rhs, 5.0); 1196 /// assert_relative_eq!(mat, expected); quadform<D2, S2, R3, C3, S3>( &mut self, alpha: T, mid: &SquareMatrix<T, D2, S2>, rhs: &Matrix<T, R3, C3, S3>, beta: T, ) where D2: Dim, R3: Dim, C3: Dim, S2: Storage<T, D2, D2>, S3: Storage<T, R3, C3>, ShapeConstraint: DimEq<D2, R3> + DimEq<D1, C3> + AreMultipliable<C3, R3, D2, U1>, DefaultAllocator: Allocator<T, D2>,1197 pub fn quadform<D2, S2, R3, C3, S3>( 1198 &mut self, 1199 alpha: T, 1200 mid: &SquareMatrix<T, D2, S2>, 1201 rhs: &Matrix<T, R3, C3, S3>, 1202 beta: T, 1203 ) where 1204 D2: Dim, 1205 R3: Dim, 1206 C3: Dim, 1207 S2: Storage<T, D2, D2>, 1208 S3: Storage<T, R3, C3>, 1209 ShapeConstraint: DimEq<D2, R3> + DimEq<D1, C3> + AreMultipliable<C3, R3, D2, U1>, 1210 DefaultAllocator: Allocator<T, D2>, 1211 { 1212 // TODO: would it be useful to avoid the zero-initialization of the workspace data? 1213 let mut work = Vector::zeros_generic(mid.shape_generic().0, Const::<1>); 1214 self.quadform_with_workspace(&mut work, alpha, mid, rhs, beta) 1215 } 1216 } 1217