annotate armadillo-3.900.4/include/armadillo_bits/SpMat_meat.hpp @ 84:55a047986812 tip

Update library URI so as not to be document-local
author Chris Cannam
date Wed, 22 Apr 2020 14:21:57 +0100
parents 1ec0e2823891
children
rev   line source
Chris@49 1 // Copyright (C) 2011-2013 Ryan Curtin
Chris@49 2 // Copyright (C) 2012-2013 Conrad Sanderson
Chris@49 3 // Copyright (C) 2011 Matthew Amidon
Chris@49 4 //
Chris@49 5 // This Source Code Form is subject to the terms of the Mozilla Public
Chris@49 6 // License, v. 2.0. If a copy of the MPL was not distributed with this
Chris@49 7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
Chris@49 8
Chris@49 9 //! \addtogroup SpMat
Chris@49 10 //! @{
Chris@49 11
Chris@49 12 /**
Chris@49 13 * Initialize a sparse matrix with size 0x0 (empty).
Chris@49 14 */
Chris@49 15 template<typename eT>
Chris@49 16 inline
Chris@49 17 SpMat<eT>::SpMat()
Chris@49 18 : n_rows(0)
Chris@49 19 , n_cols(0)
Chris@49 20 , n_elem(0)
Chris@49 21 , n_nonzero(0)
Chris@49 22 , vec_state(0)
Chris@49 23 , values(memory::acquire_chunked<eT>(1))
Chris@49 24 , row_indices(memory::acquire_chunked<uword>(1))
Chris@49 25 , col_ptrs(memory::acquire<uword>(2))
Chris@49 26 {
Chris@49 27 arma_extra_debug_sigprint_this(this);
Chris@49 28
Chris@49 29 access::rw(values[0]) = 0;
Chris@49 30 access::rw(row_indices[0]) = 0;
Chris@49 31
Chris@49 32 access::rw(col_ptrs[0]) = 0; // No elements.
Chris@49 33 access::rw(col_ptrs[1]) = std::numeric_limits<uword>::max();
Chris@49 34 }
Chris@49 35
Chris@49 36
Chris@49 37
Chris@49 38 /**
Chris@49 39 * Clean up the memory of a sparse matrix and destruct it.
Chris@49 40 */
Chris@49 41 template<typename eT>
Chris@49 42 inline
Chris@49 43 SpMat<eT>::~SpMat()
Chris@49 44 {
Chris@49 45 arma_extra_debug_sigprint_this(this);
Chris@49 46
Chris@49 47 // If necessary, release the memory.
Chris@49 48 if (values)
Chris@49 49 {
Chris@49 50 // values being non-NULL implies row_indices is non-NULL.
Chris@49 51 memory::release(access::rw(values));
Chris@49 52 memory::release(access::rw(row_indices));
Chris@49 53 }
Chris@49 54
Chris@49 55 // Column pointers always must be deleted.
Chris@49 56 memory::release(access::rw(col_ptrs));
Chris@49 57 }
Chris@49 58
Chris@49 59
Chris@49 60
Chris@49 61 /**
Chris@49 62 * Constructor with size given.
Chris@49 63 */
Chris@49 64 template<typename eT>
Chris@49 65 inline
Chris@49 66 SpMat<eT>::SpMat(const uword in_rows, const uword in_cols)
Chris@49 67 : n_rows(0)
Chris@49 68 , n_cols(0)
Chris@49 69 , n_elem(0)
Chris@49 70 , n_nonzero(0)
Chris@49 71 , vec_state(0)
Chris@49 72 , values(NULL)
Chris@49 73 , row_indices(NULL)
Chris@49 74 , col_ptrs(NULL)
Chris@49 75 {
Chris@49 76 arma_extra_debug_sigprint_this(this);
Chris@49 77
Chris@49 78 init(in_rows, in_cols);
Chris@49 79 }
Chris@49 80
Chris@49 81
Chris@49 82
Chris@49 83 /**
Chris@49 84 * Assemble from text.
Chris@49 85 */
Chris@49 86 template<typename eT>
Chris@49 87 inline
Chris@49 88 SpMat<eT>::SpMat(const char* text)
Chris@49 89 : n_rows(0)
Chris@49 90 , n_cols(0)
Chris@49 91 , n_elem(0)
Chris@49 92 , n_nonzero(0)
Chris@49 93 , vec_state(0)
Chris@49 94 , values(NULL)
Chris@49 95 , row_indices(NULL)
Chris@49 96 , col_ptrs(NULL)
Chris@49 97 {
Chris@49 98 arma_extra_debug_sigprint_this(this);
Chris@49 99
Chris@49 100 init(std::string(text));
Chris@49 101 }
Chris@49 102
Chris@49 103
Chris@49 104
Chris@49 105 template<typename eT>
Chris@49 106 inline
Chris@49 107 const SpMat<eT>&
Chris@49 108 SpMat<eT>::operator=(const char* text)
Chris@49 109 {
Chris@49 110 arma_extra_debug_sigprint();
Chris@49 111
Chris@49 112 init(std::string(text));
Chris@49 113 }
Chris@49 114
Chris@49 115
Chris@49 116
Chris@49 117 template<typename eT>
Chris@49 118 inline
Chris@49 119 SpMat<eT>::SpMat(const std::string& text)
Chris@49 120 : n_rows(0)
Chris@49 121 , n_cols(0)
Chris@49 122 , n_elem(0)
Chris@49 123 , n_nonzero(0)
Chris@49 124 , vec_state(0)
Chris@49 125 , values(NULL)
Chris@49 126 , row_indices(NULL)
Chris@49 127 , col_ptrs(NULL)
Chris@49 128 {
Chris@49 129 arma_extra_debug_sigprint();
Chris@49 130
Chris@49 131 init(text);
Chris@49 132 }
Chris@49 133
Chris@49 134
Chris@49 135
Chris@49 136 template<typename eT>
Chris@49 137 inline
Chris@49 138 const SpMat<eT>&
Chris@49 139 SpMat<eT>::operator=(const std::string& text)
Chris@49 140 {
Chris@49 141 arma_extra_debug_sigprint();
Chris@49 142
Chris@49 143 init(text);
Chris@49 144 }
Chris@49 145
Chris@49 146
Chris@49 147
Chris@49 148 template<typename eT>
Chris@49 149 inline
Chris@49 150 SpMat<eT>::SpMat(const SpMat<eT>& x)
Chris@49 151 : n_rows(0)
Chris@49 152 , n_cols(0)
Chris@49 153 , n_elem(0)
Chris@49 154 , n_nonzero(0)
Chris@49 155 , vec_state(0)
Chris@49 156 , values(NULL)
Chris@49 157 , row_indices(NULL)
Chris@49 158 , col_ptrs(NULL)
Chris@49 159 {
Chris@49 160 arma_extra_debug_sigprint_this(this);
Chris@49 161
Chris@49 162 init(x);
Chris@49 163 }
Chris@49 164
Chris@49 165
Chris@49 166
Chris@49 167 //! Insert a large number of values at once.
Chris@49 168 //! locations.row[0] should be row indices, locations.row[1] should be column indices,
Chris@49 169 //! and values should be the corresponding values.
Chris@49 170 //! If sort_locations is false, then it is assumed that the locations and values
Chris@49 171 //! are already sorted in column-major ordering.
Chris@49 172 template<typename eT>
Chris@49 173 template<typename T1, typename T2>
Chris@49 174 inline
Chris@49 175 SpMat<eT>::SpMat(const Base<uword,T1>& locations_expr, const Base<eT,T2>& vals_expr, const bool sort_locations)
Chris@49 176 : n_rows(0)
Chris@49 177 , n_cols(0)
Chris@49 178 , n_elem(0)
Chris@49 179 , n_nonzero(0)
Chris@49 180 , vec_state(0)
Chris@49 181 , values(NULL)
Chris@49 182 , row_indices(NULL)
Chris@49 183 , col_ptrs(NULL)
Chris@49 184 {
Chris@49 185 arma_extra_debug_sigprint_this(this);
Chris@49 186
Chris@49 187 const unwrap<T1> locs_tmp( locations_expr.get_ref() );
Chris@49 188 const Mat<uword>& locs = locs_tmp.M;
Chris@49 189
Chris@49 190 const unwrap<T2> vals_tmp( vals_expr.get_ref() );
Chris@49 191 const Mat<eT>& vals = vals_tmp.M;
Chris@49 192
Chris@49 193 arma_debug_check( (vals.is_vec() == false), "SpMat::SpMat(): given 'values' object is not a vector" );
Chris@49 194
Chris@49 195 arma_debug_check((locs.n_cols != vals.n_elem), "SpMat::SpMat(): number of locations is different than number of values");
Chris@49 196
Chris@49 197 // If there are no elements in the list, max() will fail.
Chris@49 198 if (locs.n_cols == 0)
Chris@49 199 {
Chris@49 200 init(0, 0);
Chris@49 201 return;
Chris@49 202 }
Chris@49 203
Chris@49 204 arma_debug_check((locs.n_rows != 2), "SpMat::SpMat(): locations matrix must have two rows");
Chris@49 205
Chris@49 206 // Automatically determine size (and check if it's sorted).
Chris@49 207 uvec bounds = arma::max(locs, 1);
Chris@49 208 init(bounds[0] + 1, bounds[1] + 1);
Chris@49 209
Chris@49 210 // Resize to correct number of elements.
Chris@49 211 mem_resize(vals.n_elem);
Chris@49 212
Chris@49 213 // Reset column pointers to zero.
Chris@49 214 arrayops::inplace_set(access::rwp(col_ptrs), uword(0), n_cols + 1);
Chris@49 215
Chris@49 216 bool actually_sorted = true;
Chris@49 217 if(sort_locations == true)
Chris@49 218 {
Chris@49 219 // sort_index() uses std::sort() which may use quicksort... so we better
Chris@49 220 // make sure it's not already sorted before taking an O(N^2) sort penalty.
Chris@49 221 for (uword i = 1; i < locs.n_cols; ++i)
Chris@49 222 {
Chris@49 223 if ((locs.at(1, i) < locs.at(1, i - 1)) || (locs.at(1, i) == locs.at(1, i - 1) && locs.at(0, i) <= locs.at(0, i - 1)))
Chris@49 224 {
Chris@49 225 actually_sorted = false;
Chris@49 226 break;
Chris@49 227 }
Chris@49 228 }
Chris@49 229
Chris@49 230 if(actually_sorted == false)
Chris@49 231 {
Chris@49 232 // This may not be the fastest possible implementation but it maximizes code reuse.
Chris@49 233 Col<uword> abslocs(locs.n_cols);
Chris@49 234
Chris@49 235 for (uword i = 0; i < locs.n_cols; ++i)
Chris@49 236 {
Chris@49 237 abslocs[i] = locs.at(1, i) * n_rows + locs.at(0, i);
Chris@49 238 }
Chris@49 239
Chris@49 240 // Now we will sort with sort_index().
Chris@49 241 uvec sorted_indices = sort_index(abslocs); // Ascending sort.
Chris@49 242
Chris@49 243 // Now we add the elements in this sorted order.
Chris@49 244 for (uword i = 0; i < sorted_indices.n_elem; ++i)
Chris@49 245 {
Chris@49 246 arma_debug_check((locs.at(0, sorted_indices[i]) >= n_rows), "SpMat::SpMat(): invalid row index");
Chris@49 247 arma_debug_check((locs.at(1, sorted_indices[i]) >= n_cols), "SpMat::SpMat(): invalid column index");
Chris@49 248
Chris@49 249 access::rw(values[i]) = vals[sorted_indices[i]];
Chris@49 250 access::rw(row_indices[i]) = locs.at(0, sorted_indices[i]);
Chris@49 251
Chris@49 252 access::rw(col_ptrs[locs.at(1, sorted_indices[i]) + 1])++;
Chris@49 253 }
Chris@49 254 }
Chris@49 255 }
Chris@49 256
Chris@49 257 if( (sort_locations == false) || (actually_sorted == true) )
Chris@49 258 {
Chris@49 259 // Now set the values and row indices correctly.
Chris@49 260 // Increment the column pointers in each column (so they are column "counts").
Chris@49 261 for (uword i = 0; i < vals.n_elem; ++i)
Chris@49 262 {
Chris@49 263 arma_debug_check((locs.at(0, i) >= n_rows), "SpMat::SpMat(): invalid row index");
Chris@49 264 arma_debug_check((locs.at(1, i) >= n_cols), "SpMat::SpMat(): invalid column index");
Chris@49 265
Chris@49 266 // Check ordering in debug mode.
Chris@49 267 if(i > 0)
Chris@49 268 {
Chris@49 269 arma_debug_check
Chris@49 270 (
Chris@49 271 ( (locs.at(1, i) < locs.at(1, i - 1)) || (locs.at(1, i) == locs.at(1, i - 1) && locs.at(0, i) < locs.at(0, i - 1)) ),
Chris@49 272 "SpMat::SpMat(): out of order points; either pass sort_locations = true, or sort points in column-major ordering"
Chris@49 273 );
Chris@49 274 arma_debug_check((locs.at(1, i) == locs.at(1, i - 1) && locs.at(0, i) == locs.at(0, i - 1)), "SpMat::SpMat(): two identical point locations in list");
Chris@49 275 }
Chris@49 276
Chris@49 277 access::rw(values[i]) = vals[i];
Chris@49 278 access::rw(row_indices[i]) = locs.at(0, i);
Chris@49 279
Chris@49 280 access::rw(col_ptrs[locs.at(1, i) + 1])++;
Chris@49 281 }
Chris@49 282 }
Chris@49 283
Chris@49 284 // Now fix the column pointers.
Chris@49 285 for (uword i = 0; i <= n_cols; ++i)
Chris@49 286 {
Chris@49 287 access::rw(col_ptrs[i + 1]) += col_ptrs[i];
Chris@49 288 }
Chris@49 289 }
Chris@49 290
Chris@49 291
Chris@49 292
Chris@49 293 //! Insert a large number of values at once.
Chris@49 294 //! locations.row[0] should be row indices, locations.row[1] should be column indices,
Chris@49 295 //! and values should be the corresponding values.
Chris@49 296 //! If sort_locations is false, then it is assumed that the locations and values
Chris@49 297 //! are already sorted in column-major ordering.
Chris@49 298 //! In this constructor the size is explicitly given.
Chris@49 299 template<typename eT>
Chris@49 300 template<typename T1, typename T2>
Chris@49 301 inline
Chris@49 302 SpMat<eT>::SpMat(const Base<uword,T1>& locations_expr, const Base<eT,T2>& vals_expr, const uword in_n_rows, const uword in_n_cols, const bool sort_locations)
Chris@49 303 : n_rows(0)
Chris@49 304 , n_cols(0)
Chris@49 305 , n_elem(0)
Chris@49 306 , n_nonzero(0)
Chris@49 307 , vec_state(0)
Chris@49 308 , values(NULL)
Chris@49 309 , row_indices(NULL)
Chris@49 310 , col_ptrs(NULL)
Chris@49 311 {
Chris@49 312 arma_extra_debug_sigprint_this(this);
Chris@49 313
Chris@49 314 init(in_n_rows, in_n_cols);
Chris@49 315
Chris@49 316 const unwrap<T1> locs_tmp( locations_expr.get_ref() );
Chris@49 317 const Mat<uword>& locs = locs_tmp.M;
Chris@49 318
Chris@49 319 const unwrap<T2> vals_tmp( vals_expr.get_ref() );
Chris@49 320 const Mat<eT>& vals = vals_tmp.M;
Chris@49 321
Chris@49 322 arma_debug_check( (vals.is_vec() == false), "SpMat::SpMat(): given 'values' object is not a vector" );
Chris@49 323
Chris@49 324 arma_debug_check((locs.n_rows != 2), "SpMat::SpMat(): locations matrix must have two rows");
Chris@49 325
Chris@49 326 arma_debug_check((locs.n_cols != vals.n_elem), "SpMat::SpMat(): number of locations is different than number of values");
Chris@49 327
Chris@49 328 // Resize to correct number of elements.
Chris@49 329 mem_resize(vals.n_elem);
Chris@49 330
Chris@49 331 // Reset column pointers to zero.
Chris@49 332 arrayops::inplace_set(access::rwp(col_ptrs), uword(0), n_cols + 1);
Chris@49 333
Chris@49 334 bool actually_sorted = true;
Chris@49 335 if(sort_locations == true)
Chris@49 336 {
Chris@49 337 // sort_index() uses std::sort() which may use quicksort... so we better
Chris@49 338 // make sure it's not already sorted before taking an O(N^2) sort penalty.
Chris@49 339 for (uword i = 1; i < locs.n_cols; ++i)
Chris@49 340 {
Chris@49 341 if ((locs.at(1, i) < locs.at(1, i - 1)) || (locs.at(1, i) == locs.at(1, i - 1) && locs.at(0, i) <= locs.at(0, i - 1)))
Chris@49 342 {
Chris@49 343 actually_sorted = false;
Chris@49 344 break;
Chris@49 345 }
Chris@49 346 }
Chris@49 347
Chris@49 348 if(actually_sorted == false)
Chris@49 349 {
Chris@49 350 // This may not be the fastest possible implementation but it maximizes code reuse.
Chris@49 351 Col<uword> abslocs(locs.n_cols);
Chris@49 352
Chris@49 353 for (uword i = 0; i < locs.n_cols; ++i)
Chris@49 354 {
Chris@49 355 abslocs[i] = locs.at(1, i) * n_rows + locs.at(0, i);
Chris@49 356 }
Chris@49 357
Chris@49 358 // Now we will sort with sort_index().
Chris@49 359 uvec sorted_indices = sort_index(abslocs); // Ascending sort.
Chris@49 360
Chris@49 361 // Now we add the elements in this sorted order.
Chris@49 362 for (uword i = 0; i < sorted_indices.n_elem; ++i)
Chris@49 363 {
Chris@49 364 arma_debug_check((locs.at(0, sorted_indices[i]) >= n_rows), "SpMat::SpMat(): invalid row index");
Chris@49 365 arma_debug_check((locs.at(1, sorted_indices[i]) >= n_cols), "SpMat::SpMat(): invalid column index");
Chris@49 366
Chris@49 367 access::rw(values[i]) = vals[sorted_indices[i]];
Chris@49 368 access::rw(row_indices[i]) = locs.at(0, sorted_indices[i]);
Chris@49 369
Chris@49 370 access::rw(col_ptrs[locs.at(1, sorted_indices[i]) + 1])++;
Chris@49 371 }
Chris@49 372 }
Chris@49 373 }
Chris@49 374
Chris@49 375 if( (sort_locations == false) || (actually_sorted == true) )
Chris@49 376 {
Chris@49 377 // Now set the values and row indices correctly.
Chris@49 378 // Increment the column pointers in each column (so they are column "counts").
Chris@49 379 for (uword i = 0; i < vals.n_elem; ++i)
Chris@49 380 {
Chris@49 381 arma_debug_check((locs.at(0, i) >= n_rows), "SpMat::SpMat(): invalid row index");
Chris@49 382 arma_debug_check((locs.at(1, i) >= n_cols), "SpMat::SpMat(): invalid column index");
Chris@49 383
Chris@49 384 // Check ordering in debug mode.
Chris@49 385 if(i > 0)
Chris@49 386 {
Chris@49 387 arma_debug_check
Chris@49 388 (
Chris@49 389 ( (locs.at(1, i) < locs.at(1, i - 1)) || (locs.at(1, i) == locs.at(1, i - 1) && locs.at(0, i) < locs.at(0, i - 1)) ),
Chris@49 390 "SpMat::SpMat(): out of order points; either pass sort_locations = true or sort points in column-major ordering"
Chris@49 391 );
Chris@49 392 arma_debug_check((locs.at(1, i) == locs.at(1, i - 1) && locs.at(0, i) == locs.at(0, i - 1)), "SpMat::SpMat(): two identical point locations in list");
Chris@49 393 }
Chris@49 394
Chris@49 395 access::rw(values[i]) = vals[i];
Chris@49 396 access::rw(row_indices[i]) = locs.at(0, i);
Chris@49 397
Chris@49 398 access::rw(col_ptrs[locs.at(1, i) + 1])++;
Chris@49 399 }
Chris@49 400 }
Chris@49 401
Chris@49 402 // Now fix the column pointers.
Chris@49 403 for (uword i = 0; i <= n_cols; ++i)
Chris@49 404 {
Chris@49 405 access::rw(col_ptrs[i + 1]) += col_ptrs[i];
Chris@49 406 }
Chris@49 407 }
Chris@49 408
Chris@49 409
Chris@49 410
Chris@49 411 /**
Chris@49 412 * Simple operators with plain values. These operate on every value in the
Chris@49 413 * matrix, so a sparse matrix += 1 will turn all those zeroes into ones. Be
Chris@49 414 * careful and make sure that's what you really want!
Chris@49 415 */
Chris@49 416 template<typename eT>
Chris@49 417 inline
Chris@49 418 const SpMat<eT>&
Chris@49 419 SpMat<eT>::operator=(const eT val)
Chris@49 420 {
Chris@49 421 arma_extra_debug_sigprint();
Chris@49 422
Chris@49 423 // Resize to 1x1 then set that to the right value.
Chris@49 424 init(1, 1); // Sets col_ptrs to 0.
Chris@49 425 mem_resize(1); // One element.
Chris@49 426
Chris@49 427 // Manually set element.
Chris@49 428 access::rw(values[0]) = val;
Chris@49 429 access::rw(row_indices[0]) = 0;
Chris@49 430 access::rw(col_ptrs[1]) = 1;
Chris@49 431
Chris@49 432 return *this;
Chris@49 433 }
Chris@49 434
Chris@49 435
Chris@49 436
Chris@49 437 template<typename eT>
Chris@49 438 inline
Chris@49 439 const SpMat<eT>&
Chris@49 440 SpMat<eT>::operator*=(const eT val)
Chris@49 441 {
Chris@49 442 arma_extra_debug_sigprint();
Chris@49 443
Chris@49 444 if(val == eT(0))
Chris@49 445 {
Chris@49 446 // Everything will be zero.
Chris@49 447 init(n_rows, n_cols);
Chris@49 448 return *this;
Chris@49 449 }
Chris@49 450
Chris@49 451 arrayops::inplace_mul( access::rwp(values), val, n_nonzero );
Chris@49 452
Chris@49 453 return *this;
Chris@49 454 }
Chris@49 455
Chris@49 456
Chris@49 457
Chris@49 458 template<typename eT>
Chris@49 459 inline
Chris@49 460 const SpMat<eT>&
Chris@49 461 SpMat<eT>::operator/=(const eT val)
Chris@49 462 {
Chris@49 463 arma_extra_debug_sigprint();
Chris@49 464
Chris@49 465 arma_debug_check( (val == eT(0)), "element-wise division: division by zero" );
Chris@49 466
Chris@49 467 arrayops::inplace_div( access::rwp(values), val, n_nonzero );
Chris@49 468
Chris@49 469 return *this;
Chris@49 470 }
Chris@49 471
Chris@49 472
Chris@49 473
Chris@49 474 template<typename eT>
Chris@49 475 inline
Chris@49 476 const SpMat<eT>&
Chris@49 477 SpMat<eT>::operator=(const SpMat<eT>& x)
Chris@49 478 {
Chris@49 479 arma_extra_debug_sigprint();
Chris@49 480
Chris@49 481 init(x);
Chris@49 482
Chris@49 483 return *this;
Chris@49 484 }
Chris@49 485
Chris@49 486
Chris@49 487
Chris@49 488 template<typename eT>
Chris@49 489 inline
Chris@49 490 const SpMat<eT>&
Chris@49 491 SpMat<eT>::operator+=(const SpMat<eT>& x)
Chris@49 492 {
Chris@49 493 arma_extra_debug_sigprint();
Chris@49 494
Chris@49 495 arma_debug_assert_same_size(n_rows, n_cols, x.n_rows, x.n_cols, "addition");
Chris@49 496
Chris@49 497 // Iterate over nonzero values of other matrix.
Chris@49 498 for (const_iterator it = x.begin(); it != x.end(); it++)
Chris@49 499 {
Chris@49 500 get_value(it.row(), it.col()) += *it;
Chris@49 501 }
Chris@49 502
Chris@49 503 return *this;
Chris@49 504 }
Chris@49 505
Chris@49 506
Chris@49 507
Chris@49 508 template<typename eT>
Chris@49 509 inline
Chris@49 510 const SpMat<eT>&
Chris@49 511 SpMat<eT>::operator-=(const SpMat<eT>& x)
Chris@49 512 {
Chris@49 513 arma_extra_debug_sigprint();
Chris@49 514
Chris@49 515 arma_debug_assert_same_size(n_rows, n_cols, x.n_rows, x.n_cols, "subtraction");
Chris@49 516
Chris@49 517 // Iterate over nonzero values of other matrix.
Chris@49 518 for (const_iterator it = x.begin(); it != x.end(); it++)
Chris@49 519 {
Chris@49 520 get_value(it.row(), it.col()) -= *it;
Chris@49 521 }
Chris@49 522
Chris@49 523 return *this;
Chris@49 524 }
Chris@49 525
Chris@49 526
Chris@49 527
Chris@49 528 template<typename eT>
Chris@49 529 inline
Chris@49 530 const SpMat<eT>&
Chris@49 531 SpMat<eT>::operator*=(const SpMat<eT>& y)
Chris@49 532 {
Chris@49 533 arma_extra_debug_sigprint();
Chris@49 534
Chris@49 535 arma_debug_assert_mul_size(n_rows, n_cols, y.n_rows, y.n_cols, "matrix multiplication");
Chris@49 536
Chris@49 537 SpMat<eT> z;
Chris@49 538 z = (*this) * y;
Chris@49 539 steal_mem(z);
Chris@49 540
Chris@49 541 return *this;
Chris@49 542 }
Chris@49 543
Chris@49 544
Chris@49 545
Chris@49 546 // This is in-place element-wise matrix multiplication.
Chris@49 547 template<typename eT>
Chris@49 548 inline
Chris@49 549 const SpMat<eT>&
Chris@49 550 SpMat<eT>::operator%=(const SpMat<eT>& x)
Chris@49 551 {
Chris@49 552 arma_extra_debug_sigprint();
Chris@49 553
Chris@49 554 arma_debug_assert_same_size(n_rows, n_cols, x.n_rows, x.n_cols, "element-wise multiplication");
Chris@49 555
Chris@49 556 // We can do this with two iterators rather simply.
Chris@49 557 iterator it = begin();
Chris@49 558 const_iterator x_it = x.begin();
Chris@49 559
Chris@49 560 while (it != end() && x_it != x.end())
Chris@49 561 {
Chris@49 562 // One of these will be further advanced than the other (or they will be at the same place).
Chris@49 563 if ((it.row() == x_it.row()) && (it.col() == x_it.col()))
Chris@49 564 {
Chris@49 565 // There is an element at this place in both matrices. Multiply.
Chris@49 566 (*it) *= (*x_it);
Chris@49 567
Chris@49 568 // Now move on to the next position.
Chris@49 569 it++;
Chris@49 570 x_it++;
Chris@49 571 }
Chris@49 572
Chris@49 573 else if ((it.col() < x_it.col()) || ((it.col() == x_it.col()) && (it.row() < x_it.row())))
Chris@49 574 {
Chris@49 575 // This case is when our matrix has an element which the other matrix does not.
Chris@49 576 // So we must delete this element.
Chris@49 577 (*it) = 0;
Chris@49 578
Chris@49 579 // Because we have deleted the element, we now have to manually set the position...
Chris@49 580 it.internal_pos--;
Chris@49 581
Chris@49 582 // Now we can increment our iterator.
Chris@49 583 it++;
Chris@49 584 }
Chris@49 585
Chris@49 586 else /* if our iterator is ahead of the other matrix */
Chris@49 587 {
Chris@49 588 // In this case we don't need to set anything to 0; our element is already 0.
Chris@49 589 // We can just increment the iterator of the other matrix.
Chris@49 590 x_it++;
Chris@49 591 }
Chris@49 592
Chris@49 593 }
Chris@49 594
Chris@49 595 // If we are not at the end of our matrix, then we must terminate the remaining elements.
Chris@49 596 while (it != end())
Chris@49 597 {
Chris@49 598 (*it) = 0;
Chris@49 599
Chris@49 600 // Hack to manually set the position right...
Chris@49 601 it.internal_pos--;
Chris@49 602 it++; // ...and then an increment.
Chris@49 603 }
Chris@49 604
Chris@49 605 return *this;
Chris@49 606 }
Chris@49 607
Chris@49 608
Chris@49 609
Chris@49 610 // Construct a complex matrix out of two non-complex matrices
Chris@49 611 template<typename eT>
Chris@49 612 template<typename T1, typename T2>
Chris@49 613 inline
Chris@49 614 SpMat<eT>::SpMat
Chris@49 615 (
Chris@49 616 const SpBase<typename SpMat<eT>::pod_type, T1>& A,
Chris@49 617 const SpBase<typename SpMat<eT>::pod_type, T2>& B
Chris@49 618 )
Chris@49 619 : n_rows(0)
Chris@49 620 , n_cols(0)
Chris@49 621 , n_elem(0)
Chris@49 622 , n_nonzero(0)
Chris@49 623 , vec_state(0)
Chris@49 624 , values(NULL) // extra element is set when mem_resize is called
Chris@49 625 , row_indices(NULL)
Chris@49 626 , col_ptrs(NULL)
Chris@49 627 {
Chris@49 628 arma_extra_debug_sigprint();
Chris@49 629
Chris@49 630 typedef typename T1::elem_type T;
Chris@49 631
Chris@49 632 // Make sure eT is complex and T is not (compile-time check).
Chris@49 633 arma_type_check(( is_complex<eT>::value == false ));
Chris@49 634 arma_type_check(( is_complex< T>::value == true ));
Chris@49 635
Chris@49 636 // Compile-time abort if types are not compatible.
Chris@49 637 arma_type_check(( is_same_type< std::complex<T>, eT >::value == false ));
Chris@49 638
Chris@49 639 const unwrap_spmat<T1> tmp1(A.get_ref());
Chris@49 640 const unwrap_spmat<T2> tmp2(B.get_ref());
Chris@49 641
Chris@49 642 const SpMat<T>& X = tmp1.M;
Chris@49 643 const SpMat<T>& Y = tmp2.M;
Chris@49 644
Chris@49 645 arma_debug_assert_same_size(X.n_rows, X.n_cols, Y.n_rows, Y.n_cols, "SpMat()");
Chris@49 646
Chris@49 647 const uword l_n_rows = X.n_rows;
Chris@49 648 const uword l_n_cols = X.n_cols;
Chris@49 649
Chris@49 650 // Set size of matrix correctly.
Chris@49 651 init(l_n_rows, l_n_cols);
Chris@49 652 mem_resize(n_unique(X, Y, op_n_unique_count()));
Chris@49 653
Chris@49 654 // Now on a second iteration, fill it.
Chris@49 655 typename SpMat<T>::const_iterator x_it = X.begin();
Chris@49 656 typename SpMat<T>::const_iterator x_end = X.end();
Chris@49 657
Chris@49 658 typename SpMat<T>::const_iterator y_it = Y.begin();
Chris@49 659 typename SpMat<T>::const_iterator y_end = Y.end();
Chris@49 660
Chris@49 661 uword cur_pos = 0;
Chris@49 662
Chris@49 663 while ((x_it != x_end) || (y_it != y_end))
Chris@49 664 {
Chris@49 665 if(x_it == y_it) // if we are at the same place
Chris@49 666 {
Chris@49 667 access::rw(values[cur_pos]) = std::complex<T>((T) *x_it, (T) *y_it);
Chris@49 668 access::rw(row_indices[cur_pos]) = x_it.row();
Chris@49 669 ++access::rw(col_ptrs[x_it.col() + 1]);
Chris@49 670
Chris@49 671 ++x_it;
Chris@49 672 ++y_it;
Chris@49 673 }
Chris@49 674 else
Chris@49 675 {
Chris@49 676 if((x_it.col() < y_it.col()) || ((x_it.col() == y_it.col()) && (x_it.row() < y_it.row()))) // if y is closer to the end
Chris@49 677 {
Chris@49 678 access::rw(values[cur_pos]) = std::complex<T>((T) *x_it, T(0));
Chris@49 679 access::rw(row_indices[cur_pos]) = x_it.row();
Chris@49 680 ++access::rw(col_ptrs[x_it.col() + 1]);
Chris@49 681
Chris@49 682 ++x_it;
Chris@49 683 }
Chris@49 684 else // x is closer to the end
Chris@49 685 {
Chris@49 686 access::rw(values[cur_pos]) = std::complex<T>(T(0), (T) *y_it);
Chris@49 687 access::rw(row_indices[cur_pos]) = y_it.row();
Chris@49 688 ++access::rw(col_ptrs[y_it.col() + 1]);
Chris@49 689
Chris@49 690 ++y_it;
Chris@49 691 }
Chris@49 692 }
Chris@49 693
Chris@49 694 ++cur_pos;
Chris@49 695 }
Chris@49 696
Chris@49 697 // Now fix the column pointers; they are supposed to be a sum.
Chris@49 698 for (uword c = 1; c <= n_cols; ++c)
Chris@49 699 {
Chris@49 700 access::rw(col_ptrs[c]) += col_ptrs[c - 1];
Chris@49 701 }
Chris@49 702
Chris@49 703 }
Chris@49 704
Chris@49 705
Chris@49 706
Chris@49 707 template<typename eT>
Chris@49 708 inline
Chris@49 709 const SpMat<eT>&
Chris@49 710 SpMat<eT>::operator/=(const SpMat<eT>& x)
Chris@49 711 {
Chris@49 712 arma_extra_debug_sigprint();
Chris@49 713
Chris@49 714 arma_debug_assert_same_size(n_rows, n_cols, x.n_rows, x.n_cols, "element-wise division");
Chris@49 715
Chris@49 716 // If you use this method, you are probably stupid or misguided, but for compatibility with Mat, we have implemented it anyway.
Chris@49 717 // We have to loop over every element, which is not good. In fact, it makes me physically sad to write this.
Chris@49 718 for(uword c = 0; c < n_cols; ++c)
Chris@49 719 {
Chris@49 720 for(uword r = 0; r < n_rows; ++r)
Chris@49 721 {
Chris@49 722 at(r, c) /= x.at(r, c);
Chris@49 723 }
Chris@49 724 }
Chris@49 725
Chris@49 726 return *this;
Chris@49 727 }
Chris@49 728
Chris@49 729
Chris@49 730
Chris@49 731 template<typename eT>
Chris@49 732 template<typename T1>
Chris@49 733 inline
Chris@49 734 SpMat<eT>::SpMat(const Base<eT, T1>& x)
Chris@49 735 : n_rows(0)
Chris@49 736 , n_cols(0)
Chris@49 737 , n_elem(0)
Chris@49 738 , n_nonzero(0)
Chris@49 739 , vec_state(0)
Chris@49 740 , values(NULL) // extra element is set when mem_resize is called in operator=()
Chris@49 741 , row_indices(NULL)
Chris@49 742 , col_ptrs(NULL)
Chris@49 743 {
Chris@49 744 arma_extra_debug_sigprint_this(this);
Chris@49 745
Chris@49 746 (*this).operator=(x);
Chris@49 747 }
Chris@49 748
Chris@49 749
Chris@49 750
Chris@49 751 template<typename eT>
Chris@49 752 template<typename T1>
Chris@49 753 inline
Chris@49 754 const SpMat<eT>&
Chris@49 755 SpMat<eT>::operator=(const Base<eT, T1>& x)
Chris@49 756 {
Chris@49 757 arma_extra_debug_sigprint();
Chris@49 758
Chris@49 759 const Proxy<T1> p(x.get_ref());
Chris@49 760
Chris@49 761 const uword x_n_rows = p.get_n_rows();
Chris@49 762 const uword x_n_cols = p.get_n_cols();
Chris@49 763 const uword x_n_elem = p.get_n_elem();
Chris@49 764
Chris@49 765 init(x_n_rows, x_n_cols);
Chris@49 766
Chris@49 767 // Count number of nonzero elements in base object.
Chris@49 768 uword n = 0;
Chris@49 769 if(Proxy<T1>::prefer_at_accessor == true)
Chris@49 770 {
Chris@49 771 for(uword j = 0; j < x_n_cols; ++j)
Chris@49 772 for(uword i = 0; i < x_n_rows; ++i)
Chris@49 773 {
Chris@49 774 if(p.at(i, j) != eT(0)) { ++n; }
Chris@49 775 }
Chris@49 776 }
Chris@49 777 else
Chris@49 778 {
Chris@49 779 for(uword i = 0; i < x_n_elem; ++i)
Chris@49 780 {
Chris@49 781 if(p[i] != eT(0)) { ++n; }
Chris@49 782 }
Chris@49 783 }
Chris@49 784
Chris@49 785 mem_resize(n);
Chris@49 786
Chris@49 787 // Now the memory is resized correctly; add nonzero elements.
Chris@49 788 n = 0;
Chris@49 789 for(uword j = 0; j < x_n_cols; ++j)
Chris@49 790 for(uword i = 0; i < x_n_rows; ++i)
Chris@49 791 {
Chris@49 792 const eT val = p.at(i, j);
Chris@49 793
Chris@49 794 if(val != eT(0))
Chris@49 795 {
Chris@49 796 access::rw(values[n]) = val;
Chris@49 797 access::rw(row_indices[n]) = i;
Chris@49 798 access::rw(col_ptrs[j + 1])++;
Chris@49 799 ++n;
Chris@49 800 }
Chris@49 801 }
Chris@49 802
Chris@49 803 // Sum column counts to be column pointers.
Chris@49 804 for(uword c = 1; c <= n_cols; ++c)
Chris@49 805 {
Chris@49 806 access::rw(col_ptrs[c]) += col_ptrs[c - 1];
Chris@49 807 }
Chris@49 808
Chris@49 809 return *this;
Chris@49 810 }
Chris@49 811
Chris@49 812
Chris@49 813
Chris@49 814 template<typename eT>
Chris@49 815 template<typename T1>
Chris@49 816 inline
Chris@49 817 const SpMat<eT>&
Chris@49 818 SpMat<eT>::operator*=(const Base<eT, T1>& y)
Chris@49 819 {
Chris@49 820 arma_extra_debug_sigprint();
Chris@49 821
Chris@49 822 const Proxy<T1> p(y.get_ref());
Chris@49 823
Chris@49 824 arma_debug_assert_mul_size(n_rows, n_cols, p.get_n_rows(), p.get_n_cols(), "matrix multiplication");
Chris@49 825
Chris@49 826 // We assume the matrix structure is such that we will end up with a sparse
Chris@49 827 // matrix. Assuming that every entry in the dense matrix is nonzero (which is
Chris@49 828 // a fairly valid assumption), each row with any nonzero elements in it (in this
Chris@49 829 // matrix) implies an entire nonzero column. Therefore, we iterate over all
Chris@49 830 // the row_indices and count the number of rows with any elements in them
Chris@49 831 // (using the quasi-linked-list idea from SYMBMM -- see operator_times.hpp).
Chris@49 832 podarray<uword> index(n_rows);
Chris@49 833 index.fill(n_rows); // Fill with invalid links.
Chris@49 834
Chris@49 835 uword last_index = n_rows + 1;
Chris@49 836 for(uword i = 0; i < n_nonzero; ++i)
Chris@49 837 {
Chris@49 838 if(index[row_indices[i]] == n_rows)
Chris@49 839 {
Chris@49 840 index[row_indices[i]] = last_index;
Chris@49 841 last_index = row_indices[i];
Chris@49 842 }
Chris@49 843 }
Chris@49 844
Chris@49 845 // Now count the number of rows which have nonzero elements.
Chris@49 846 uword nonzero_rows = 0;
Chris@49 847 while(last_index != n_rows + 1)
Chris@49 848 {
Chris@49 849 ++nonzero_rows;
Chris@49 850 last_index = index[last_index];
Chris@49 851 }
Chris@49 852
Chris@49 853 SpMat<eT> z(n_rows, p.get_n_cols());
Chris@49 854
Chris@49 855 z.mem_resize(nonzero_rows * p.get_n_cols()); // upper bound on size
Chris@49 856
Chris@49 857 // Now we have to fill all the elements using a modification of the NUMBMM algorithm.
Chris@49 858 uword cur_pos = 0;
Chris@49 859
Chris@49 860 podarray<eT> partial_sums(n_rows);
Chris@49 861 partial_sums.zeros();
Chris@49 862
Chris@49 863 for(uword lcol = 0; lcol < n_cols; ++lcol)
Chris@49 864 {
Chris@49 865 const_iterator it = begin();
Chris@49 866
Chris@49 867 while(it != end())
Chris@49 868 {
Chris@49 869 const eT value = (*it);
Chris@49 870
Chris@49 871 partial_sums[it.row()] += (value * p.at(it.col(), lcol));
Chris@49 872
Chris@49 873 ++it;
Chris@49 874 }
Chris@49 875
Chris@49 876 // Now add all partial sums to the matrix.
Chris@49 877 for(uword i = 0; i < n_rows; ++i)
Chris@49 878 {
Chris@49 879 if(partial_sums[i] != eT(0))
Chris@49 880 {
Chris@49 881 access::rw(z.values[cur_pos]) = partial_sums[i];
Chris@49 882 access::rw(z.row_indices[cur_pos]) = i;
Chris@49 883 ++access::rw(z.col_ptrs[lcol + 1]);
Chris@49 884 //printf("colptr %d now %d\n", lcol + 1, z.col_ptrs[lcol + 1]);
Chris@49 885 ++cur_pos;
Chris@49 886 partial_sums[i] = 0; // Would it be faster to do this in batch later?
Chris@49 887 }
Chris@49 888 }
Chris@49 889 }
Chris@49 890
Chris@49 891 // Now fix the column pointers.
Chris@49 892 for(uword c = 1; c <= z.n_cols; ++c)
Chris@49 893 {
Chris@49 894 access::rw(z.col_ptrs[c]) += z.col_ptrs[c - 1];
Chris@49 895 }
Chris@49 896
Chris@49 897 // Resize to final correct size.
Chris@49 898 z.mem_resize(z.col_ptrs[z.n_cols]);
Chris@49 899
Chris@49 900 // Now take the memory of the temporary matrix.
Chris@49 901 steal_mem(z);
Chris@49 902
Chris@49 903 return *this;
Chris@49 904 }
Chris@49 905
Chris@49 906
Chris@49 907
Chris@49 908 /**
Chris@49 909 * Don't use this function. It's not mathematically well-defined and wastes
Chris@49 910 * cycles to trash all your data. This is dumb.
Chris@49 911 */
Chris@49 912 template<typename eT>
Chris@49 913 template<typename T1>
Chris@49 914 inline
Chris@49 915 const SpMat<eT>&
Chris@49 916 SpMat<eT>::operator/=(const Base<eT, T1>& x)
Chris@49 917 {
Chris@49 918 arma_extra_debug_sigprint();
Chris@49 919
Chris@49 920 SpMat<eT> tmp = (*this) / x.get_ref();
Chris@49 921
Chris@49 922 steal_mem(tmp);
Chris@49 923
Chris@49 924 return *this;
Chris@49 925 }
Chris@49 926
Chris@49 927
Chris@49 928
Chris@49 929 template<typename eT>
Chris@49 930 template<typename T1>
Chris@49 931 inline
Chris@49 932 const SpMat<eT>&
Chris@49 933 SpMat<eT>::operator%=(const Base<eT, T1>& x)
Chris@49 934 {
Chris@49 935 arma_extra_debug_sigprint();
Chris@49 936
Chris@49 937 const Proxy<T1> p(x.get_ref());
Chris@49 938
Chris@49 939 arma_debug_assert_same_size(n_rows, n_cols, p.get_n_rows(), p.get_n_cols(), "element-wise multiplication");
Chris@49 940
Chris@49 941 // Count the number of elements we will need.
Chris@49 942 SpMat<eT> tmp(n_rows, n_cols);
Chris@49 943 const_iterator it = begin();
Chris@49 944 uword new_n_nonzero = 0;
Chris@49 945
Chris@49 946 while(it != end())
Chris@49 947 {
Chris@49 948 // prefer_at_accessor == false can't save us any work here
Chris@49 949 if(((*it) * p.at(it.row(), it.col())) != eT(0))
Chris@49 950 {
Chris@49 951 ++new_n_nonzero;
Chris@49 952 }
Chris@49 953 ++it;
Chris@49 954 }
Chris@49 955
Chris@49 956 // Resize.
Chris@49 957 tmp.mem_resize(new_n_nonzero);
Chris@49 958
Chris@49 959 const_iterator c_it = begin();
Chris@49 960 uword cur_pos = 0;
Chris@49 961 while(c_it != end())
Chris@49 962 {
Chris@49 963 // prefer_at_accessor == false can't save us any work here
Chris@49 964 const eT val = (*c_it) * p.at(c_it.row(), c_it.col());
Chris@49 965 if(val != eT(0))
Chris@49 966 {
Chris@49 967 access::rw(tmp.values[cur_pos]) = val;
Chris@49 968 access::rw(tmp.row_indices[cur_pos]) = c_it.row();
Chris@49 969 ++access::rw(tmp.col_ptrs[c_it.col() + 1]);
Chris@49 970 ++cur_pos;
Chris@49 971 }
Chris@49 972
Chris@49 973 ++c_it;
Chris@49 974 }
Chris@49 975
Chris@49 976 // Fix column pointers.
Chris@49 977 for(uword c = 1; c <= n_cols; ++c)
Chris@49 978 {
Chris@49 979 access::rw(tmp.col_ptrs[c]) += tmp.col_ptrs[c - 1];
Chris@49 980 }
Chris@49 981
Chris@49 982 steal_mem(tmp);
Chris@49 983
Chris@49 984 return *this;
Chris@49 985 }
Chris@49 986
Chris@49 987
Chris@49 988
Chris@49 989 /**
Chris@49 990 * Functions on subviews.
Chris@49 991 */
Chris@49 992 template<typename eT>
Chris@49 993 inline
Chris@49 994 SpMat<eT>::SpMat(const SpSubview<eT>& X)
Chris@49 995 : n_rows(0)
Chris@49 996 , n_cols(0)
Chris@49 997 , n_elem(0)
Chris@49 998 , n_nonzero(0)
Chris@49 999 , vec_state(0)
Chris@49 1000 , values(NULL) // extra element added when mem_resize is called
Chris@49 1001 , row_indices(NULL)
Chris@49 1002 , col_ptrs(NULL)
Chris@49 1003 {
Chris@49 1004 arma_extra_debug_sigprint_this(this);
Chris@49 1005
Chris@49 1006 (*this).operator=(X);
Chris@49 1007 }
Chris@49 1008
Chris@49 1009
Chris@49 1010
Chris@49 1011 template<typename eT>
Chris@49 1012 inline
Chris@49 1013 const SpMat<eT>&
Chris@49 1014 SpMat<eT>::operator=(const SpSubview<eT>& X)
Chris@49 1015 {
Chris@49 1016 arma_extra_debug_sigprint();
Chris@49 1017
Chris@49 1018 const uword in_n_cols = X.n_cols;
Chris@49 1019 const uword in_n_rows = X.n_rows;
Chris@49 1020
Chris@49 1021 const bool alias = (this == &(X.m));
Chris@49 1022
Chris@49 1023 if(alias == false)
Chris@49 1024 {
Chris@49 1025 init(in_n_rows, in_n_cols);
Chris@49 1026
Chris@49 1027 const uword x_n_nonzero = X.n_nonzero;
Chris@49 1028
Chris@49 1029 mem_resize(x_n_nonzero);
Chris@49 1030
Chris@49 1031 typename SpSubview<eT>::const_iterator it = X.begin();
Chris@49 1032
Chris@49 1033 while(it != X.end())
Chris@49 1034 {
Chris@49 1035 access::rw(row_indices[it.pos()]) = it.row();
Chris@49 1036 access::rw(values[it.pos()]) = (*it);
Chris@49 1037 ++access::rw(col_ptrs[it.col() + 1]);
Chris@49 1038 ++it;
Chris@49 1039 }
Chris@49 1040
Chris@49 1041 // Now sum column pointers.
Chris@49 1042 for(uword c = 1; c <= n_cols; ++c)
Chris@49 1043 {
Chris@49 1044 access::rw(col_ptrs[c]) += col_ptrs[c - 1];
Chris@49 1045 }
Chris@49 1046 }
Chris@49 1047 else
Chris@49 1048 {
Chris@49 1049 // Create it in a temporary.
Chris@49 1050 SpMat<eT> tmp(X);
Chris@49 1051
Chris@49 1052 steal_mem(tmp);
Chris@49 1053 }
Chris@49 1054
Chris@49 1055 return *this;
Chris@49 1056 }
Chris@49 1057
Chris@49 1058
Chris@49 1059
Chris@49 1060 template<typename eT>
Chris@49 1061 inline
Chris@49 1062 const SpMat<eT>&
Chris@49 1063 SpMat<eT>::operator+=(const SpSubview<eT>& X)
Chris@49 1064 {
Chris@49 1065 arma_extra_debug_sigprint();
Chris@49 1066
Chris@49 1067 arma_debug_assert_same_size(n_rows, n_cols, X.n_rows, X.n_cols, "addition");
Chris@49 1068
Chris@49 1069 typename SpSubview<eT>::const_iterator it = X.begin();
Chris@49 1070
Chris@49 1071 while(it != X.end())
Chris@49 1072 {
Chris@49 1073 at(it.row(), it.col()) += (*it);
Chris@49 1074 ++it;
Chris@49 1075 }
Chris@49 1076
Chris@49 1077 return *this;
Chris@49 1078 }
Chris@49 1079
Chris@49 1080
Chris@49 1081
Chris@49 1082 template<typename eT>
Chris@49 1083 inline
Chris@49 1084 const SpMat<eT>&
Chris@49 1085 SpMat<eT>::operator-=(const SpSubview<eT>& X)
Chris@49 1086 {
Chris@49 1087 arma_extra_debug_sigprint();
Chris@49 1088
Chris@49 1089 arma_debug_assert_same_size(n_rows, n_cols, X.n_rows, X.n_cols, "subtraction");
Chris@49 1090
Chris@49 1091 typename SpSubview<eT>::const_iterator it = X.begin();
Chris@49 1092
Chris@49 1093 while(it != X.end())
Chris@49 1094 {
Chris@49 1095 at(it.row(), it.col()) -= (*it);
Chris@49 1096 ++it;
Chris@49 1097 }
Chris@49 1098
Chris@49 1099 return *this;
Chris@49 1100 }
Chris@49 1101
Chris@49 1102
Chris@49 1103
Chris@49 1104 template<typename eT>
Chris@49 1105 inline
Chris@49 1106 const SpMat<eT>&
Chris@49 1107 SpMat<eT>::operator*=(const SpSubview<eT>& y)
Chris@49 1108 {
Chris@49 1109 arma_extra_debug_sigprint();
Chris@49 1110
Chris@49 1111 arma_debug_assert_mul_size(n_rows, n_cols, y.n_rows, y.n_cols, "matrix multiplication");
Chris@49 1112
Chris@49 1113 // Cannot be done in-place (easily).
Chris@49 1114 SpMat<eT> z = (*this) * y;
Chris@49 1115 steal_mem(z);
Chris@49 1116
Chris@49 1117 return *this;
Chris@49 1118 }
Chris@49 1119
Chris@49 1120
Chris@49 1121
Chris@49 1122 template<typename eT>
Chris@49 1123 inline
Chris@49 1124 const SpMat<eT>&
Chris@49 1125 SpMat<eT>::operator%=(const SpSubview<eT>& x)
Chris@49 1126 {
Chris@49 1127 arma_extra_debug_sigprint();
Chris@49 1128
Chris@49 1129 arma_debug_assert_same_size(n_rows, n_cols, x.n_rows, x.n_cols, "element-wise multiplication");
Chris@49 1130
Chris@49 1131 iterator it = begin();
Chris@49 1132 typename SpSubview<eT>::const_iterator xit = x.begin();
Chris@49 1133
Chris@49 1134 while((it != end()) || (xit != x.end()))
Chris@49 1135 {
Chris@49 1136 if((xit.row() == it.row()) && (xit.col() == it.col()))
Chris@49 1137 {
Chris@49 1138 (*it) *= (*xit);
Chris@49 1139 ++it;
Chris@49 1140 ++xit;
Chris@49 1141 }
Chris@49 1142 else
Chris@49 1143 {
Chris@49 1144 if((xit.col() > it.col()) || ((xit.col() == it.col()) && (xit.row() > it.row())))
Chris@49 1145 {
Chris@49 1146 // xit is "ahead"
Chris@49 1147 (*it) = eT(0); // erase element; x has a zero here
Chris@49 1148 it.internal_pos--; // update iterator so it still works
Chris@49 1149 ++it;
Chris@49 1150 }
Chris@49 1151 else
Chris@49 1152 {
Chris@49 1153 // it is "ahead"
Chris@49 1154 ++xit;
Chris@49 1155 }
Chris@49 1156 }
Chris@49 1157 }
Chris@49 1158
Chris@49 1159 return *this;
Chris@49 1160 }
Chris@49 1161
Chris@49 1162
Chris@49 1163 template<typename eT>
Chris@49 1164 inline
Chris@49 1165 const SpMat<eT>&
Chris@49 1166 SpMat<eT>::operator/=(const SpSubview<eT>& x)
Chris@49 1167 {
Chris@49 1168 arma_extra_debug_sigprint();
Chris@49 1169
Chris@49 1170 arma_debug_assert_same_size(n_rows, n_cols, x.n_rows, x.n_cols, "element-wise division");
Chris@49 1171
Chris@49 1172 // There is no pretty way to do this.
Chris@49 1173 for(uword elem = 0; elem < n_elem; elem++)
Chris@49 1174 {
Chris@49 1175 at(elem) /= x(elem);
Chris@49 1176 }
Chris@49 1177
Chris@49 1178 return *this;
Chris@49 1179 }
Chris@49 1180
Chris@49 1181
Chris@49 1182
Chris@49 1183 /**
Chris@49 1184 * Operators on regular subviews.
Chris@49 1185 */
Chris@49 1186 template<typename eT>
Chris@49 1187 inline
Chris@49 1188 SpMat<eT>::SpMat(const subview<eT>& x)
Chris@49 1189 : n_rows(0)
Chris@49 1190 , n_cols(0)
Chris@49 1191 , n_elem(0)
Chris@49 1192 , n_nonzero(0)
Chris@49 1193 , vec_state(0)
Chris@49 1194 , values(NULL) // extra value set in operator=()
Chris@49 1195 , row_indices(NULL)
Chris@49 1196 , col_ptrs(NULL)
Chris@49 1197 {
Chris@49 1198 arma_extra_debug_sigprint_this(this);
Chris@49 1199
Chris@49 1200 (*this).operator=(x);
Chris@49 1201 }
Chris@49 1202
Chris@49 1203
Chris@49 1204
Chris@49 1205 template<typename eT>
Chris@49 1206 inline
Chris@49 1207 const SpMat<eT>&
Chris@49 1208 SpMat<eT>::operator=(const subview<eT>& x)
Chris@49 1209 {
Chris@49 1210 arma_extra_debug_sigprint();
Chris@49 1211
Chris@49 1212 const uword x_n_rows = x.n_rows;
Chris@49 1213 const uword x_n_cols = x.n_cols;
Chris@49 1214
Chris@49 1215 // Set the size correctly.
Chris@49 1216 init(x_n_rows, x_n_cols);
Chris@49 1217
Chris@49 1218 // Count number of nonzero elements.
Chris@49 1219 uword n = 0;
Chris@49 1220 for(uword c = 0; c < x_n_cols; ++c)
Chris@49 1221 {
Chris@49 1222 for(uword r = 0; r < x_n_rows; ++r)
Chris@49 1223 {
Chris@49 1224 if(x.at(r, c) != eT(0))
Chris@49 1225 {
Chris@49 1226 ++n;
Chris@49 1227 }
Chris@49 1228 }
Chris@49 1229 }
Chris@49 1230
Chris@49 1231 // Resize memory appropriately.
Chris@49 1232 mem_resize(n);
Chris@49 1233
Chris@49 1234 n = 0;
Chris@49 1235 for(uword c = 0; c < x_n_cols; ++c)
Chris@49 1236 {
Chris@49 1237 for(uword r = 0; r < x_n_rows; ++r)
Chris@49 1238 {
Chris@49 1239 const eT val = x.at(r, c);
Chris@49 1240
Chris@49 1241 if(val != eT(0))
Chris@49 1242 {
Chris@49 1243 access::rw(values[n]) = val;
Chris@49 1244 access::rw(row_indices[n]) = r;
Chris@49 1245 ++access::rw(col_ptrs[c + 1]);
Chris@49 1246 ++n;
Chris@49 1247 }
Chris@49 1248 }
Chris@49 1249 }
Chris@49 1250
Chris@49 1251 // Fix column counts into column pointers.
Chris@49 1252 for(uword c = 1; c <= n_cols; ++c)
Chris@49 1253 {
Chris@49 1254 access::rw(col_ptrs[c]) += col_ptrs[c - 1];
Chris@49 1255 }
Chris@49 1256
Chris@49 1257 return *this;
Chris@49 1258 }
Chris@49 1259
Chris@49 1260
Chris@49 1261
Chris@49 1262 template<typename eT>
Chris@49 1263 inline
Chris@49 1264 const SpMat<eT>&
Chris@49 1265 SpMat<eT>::operator+=(const subview<eT>& x)
Chris@49 1266 {
Chris@49 1267 arma_extra_debug_sigprint();
Chris@49 1268
Chris@49 1269 arma_debug_assert_same_size(n_rows, n_cols, x.n_rows, x.n_cols, "addition");
Chris@49 1270
Chris@49 1271 // Loop over every element. This could probably be written in a more
Chris@49 1272 // efficient way, by calculating the number of nonzero elements the output
Chris@49 1273 // matrix will have, allocating the memory correctly, and then filling the
Chris@49 1274 // matrix correctly. However... for now, this works okay.
Chris@49 1275 for(uword lcol = 0; lcol < n_cols; ++lcol)
Chris@49 1276 for(uword lrow = 0; lrow < n_rows; ++lrow)
Chris@49 1277 {
Chris@49 1278 at(lrow, lcol) += x.at(lrow, lcol);
Chris@49 1279 }
Chris@49 1280
Chris@49 1281 return *this;
Chris@49 1282 }
Chris@49 1283
Chris@49 1284
Chris@49 1285
Chris@49 1286 template<typename eT>
Chris@49 1287 inline
Chris@49 1288 const SpMat<eT>&
Chris@49 1289 SpMat<eT>::operator-=(const subview<eT>& x)
Chris@49 1290 {
Chris@49 1291 arma_extra_debug_sigprint();
Chris@49 1292
Chris@49 1293 arma_debug_assert_same_size(n_rows, n_cols, x.n_rows, x.n_cols, "subtraction");
Chris@49 1294
Chris@49 1295 // Loop over every element.
Chris@49 1296 for(uword lcol = 0; lcol < n_cols; ++lcol)
Chris@49 1297 for(uword lrow = 0; lrow < n_rows; ++lrow)
Chris@49 1298 {
Chris@49 1299 at(lrow, lcol) -= x.at(lrow, lcol);
Chris@49 1300 }
Chris@49 1301
Chris@49 1302 return *this;
Chris@49 1303 }
Chris@49 1304
Chris@49 1305
Chris@49 1306
Chris@49 1307 template<typename eT>
Chris@49 1308 inline
Chris@49 1309 const SpMat<eT>&
Chris@49 1310 SpMat<eT>::operator*=(const subview<eT>& y)
Chris@49 1311 {
Chris@49 1312 arma_extra_debug_sigprint();
Chris@49 1313
Chris@49 1314 arma_debug_assert_mul_size(n_rows, n_cols, y.n_rows, y.n_cols, "matrix multiplication");
Chris@49 1315
Chris@49 1316 SpMat<eT> z(n_rows, y.n_cols);
Chris@49 1317
Chris@49 1318 // Performed in the same fashion as operator*=(SpMat).
Chris@49 1319 for (const_row_iterator x_row_it = begin_row(); x_row_it.pos() < n_nonzero; ++x_row_it)
Chris@49 1320 {
Chris@49 1321 for (uword lcol = 0; lcol < y.n_cols; ++lcol)
Chris@49 1322 {
Chris@49 1323 // At this moment in the loop, we are calculating anything that is contributed to by *x_row_it and *y_col_it.
Chris@49 1324 // Given that our position is x_ab and y_bc, there will only be a contribution if x.col == y.row, and that
Chris@49 1325 // contribution will be in location z_ac.
Chris@49 1326 z.at(x_row_it.row, lcol) += (*x_row_it) * y.at(x_row_it.col, lcol);
Chris@49 1327 }
Chris@49 1328 }
Chris@49 1329
Chris@49 1330 steal_mem(z);
Chris@49 1331
Chris@49 1332 return *this;
Chris@49 1333 }
Chris@49 1334
Chris@49 1335
Chris@49 1336
Chris@49 1337 template<typename eT>
Chris@49 1338 inline
Chris@49 1339 const SpMat<eT>&
Chris@49 1340 SpMat<eT>::operator%=(const subview<eT>& x)
Chris@49 1341 {
Chris@49 1342 arma_extra_debug_sigprint();
Chris@49 1343
Chris@49 1344 arma_debug_assert_same_size(n_rows, n_cols, x.n_rows, x.n_cols, "element-wise multiplication");
Chris@49 1345
Chris@49 1346 // Loop over every element.
Chris@49 1347 for(uword lcol = 0; lcol < n_cols; ++lcol)
Chris@49 1348 for(uword lrow = 0; lrow < n_rows; ++lrow)
Chris@49 1349 {
Chris@49 1350 at(lrow, lcol) *= x.at(lrow, lcol);
Chris@49 1351 }
Chris@49 1352
Chris@49 1353 return *this;
Chris@49 1354 }
Chris@49 1355
Chris@49 1356
Chris@49 1357
Chris@49 1358 template<typename eT>
Chris@49 1359 inline
Chris@49 1360 const SpMat<eT>&
Chris@49 1361 SpMat<eT>::operator/=(const subview<eT>& x)
Chris@49 1362 {
Chris@49 1363 arma_extra_debug_sigprint();
Chris@49 1364
Chris@49 1365 arma_debug_assert_same_size(n_rows, n_cols, x.n_rows, x.n_cols, "element-wise division");
Chris@49 1366
Chris@49 1367 // Loop over every element.
Chris@49 1368 for(uword lcol = 0; lcol < n_cols; ++lcol)
Chris@49 1369 for(uword lrow = 0; lrow < n_rows; ++lrow)
Chris@49 1370 {
Chris@49 1371 at(lrow, lcol) /= x.at(lrow, lcol);
Chris@49 1372 }
Chris@49 1373
Chris@49 1374 return *this;
Chris@49 1375 }
Chris@49 1376
Chris@49 1377
Chris@49 1378
Chris@49 1379 template<typename eT>
Chris@49 1380 template<typename T1, typename spop_type>
Chris@49 1381 inline
Chris@49 1382 SpMat<eT>::SpMat(const SpOp<T1, spop_type>& X)
Chris@49 1383 : n_rows(0)
Chris@49 1384 , n_cols(0)
Chris@49 1385 , n_elem(0)
Chris@49 1386 , n_nonzero(0)
Chris@49 1387 , vec_state(0)
Chris@49 1388 , values(NULL) // set in application of sparse operation
Chris@49 1389 , row_indices(NULL)
Chris@49 1390 , col_ptrs(NULL)
Chris@49 1391 {
Chris@49 1392 arma_extra_debug_sigprint_this(this);
Chris@49 1393
Chris@49 1394 arma_type_check(( is_same_type< eT, typename T1::elem_type >::value == false ));
Chris@49 1395
Chris@49 1396 spop_type::apply(*this, X);
Chris@49 1397 }
Chris@49 1398
Chris@49 1399
Chris@49 1400
Chris@49 1401 template<typename eT>
Chris@49 1402 template<typename T1, typename spop_type>
Chris@49 1403 inline
Chris@49 1404 const SpMat<eT>&
Chris@49 1405 SpMat<eT>::operator=(const SpOp<T1, spop_type>& X)
Chris@49 1406 {
Chris@49 1407 arma_extra_debug_sigprint();
Chris@49 1408
Chris@49 1409 arma_type_check(( is_same_type< eT, typename T1::elem_type >::value == false ));
Chris@49 1410
Chris@49 1411 spop_type::apply(*this, X);
Chris@49 1412
Chris@49 1413 return *this;
Chris@49 1414 }
Chris@49 1415
Chris@49 1416
Chris@49 1417
Chris@49 1418 template<typename eT>
Chris@49 1419 template<typename T1, typename spop_type>
Chris@49 1420 inline
Chris@49 1421 const SpMat<eT>&
Chris@49 1422 SpMat<eT>::operator+=(const SpOp<T1, spop_type>& X)
Chris@49 1423 {
Chris@49 1424 arma_extra_debug_sigprint();
Chris@49 1425
Chris@49 1426 arma_type_check(( is_same_type< eT, typename T1::elem_type >::value == false ));
Chris@49 1427
Chris@49 1428 const SpMat<eT> m(X);
Chris@49 1429
Chris@49 1430 return (*this).operator+=(m);
Chris@49 1431 }
Chris@49 1432
Chris@49 1433
Chris@49 1434
Chris@49 1435 template<typename eT>
Chris@49 1436 template<typename T1, typename spop_type>
Chris@49 1437 inline
Chris@49 1438 const SpMat<eT>&
Chris@49 1439 SpMat<eT>::operator-=(const SpOp<T1, spop_type>& X)
Chris@49 1440 {
Chris@49 1441 arma_extra_debug_sigprint();
Chris@49 1442
Chris@49 1443 arma_type_check(( is_same_type< eT, typename T1::elem_type >::value == false ));
Chris@49 1444
Chris@49 1445 const SpMat<eT> m(X);
Chris@49 1446
Chris@49 1447 return (*this).operator-=(m);
Chris@49 1448 }
Chris@49 1449
Chris@49 1450
Chris@49 1451
Chris@49 1452 template<typename eT>
Chris@49 1453 template<typename T1, typename spop_type>
Chris@49 1454 inline
Chris@49 1455 const SpMat<eT>&
Chris@49 1456 SpMat<eT>::operator*=(const SpOp<T1, spop_type>& X)
Chris@49 1457 {
Chris@49 1458 arma_extra_debug_sigprint();
Chris@49 1459
Chris@49 1460 arma_type_check(( is_same_type< eT, typename T1::elem_type >::value == false ));
Chris@49 1461
Chris@49 1462 const SpMat<eT> m(X);
Chris@49 1463
Chris@49 1464 return (*this).operator*=(m);
Chris@49 1465 }
Chris@49 1466
Chris@49 1467
Chris@49 1468
Chris@49 1469 template<typename eT>
Chris@49 1470 template<typename T1, typename spop_type>
Chris@49 1471 inline
Chris@49 1472 const SpMat<eT>&
Chris@49 1473 SpMat<eT>::operator%=(const SpOp<T1, spop_type>& X)
Chris@49 1474 {
Chris@49 1475 arma_extra_debug_sigprint();
Chris@49 1476
Chris@49 1477 arma_type_check(( is_same_type< eT, typename T1::elem_type >::value == false ));
Chris@49 1478
Chris@49 1479 const SpMat<eT> m(X);
Chris@49 1480
Chris@49 1481 return (*this).operator%=(m);
Chris@49 1482 }
Chris@49 1483
Chris@49 1484
Chris@49 1485
Chris@49 1486 template<typename eT>
Chris@49 1487 template<typename T1, typename spop_type>
Chris@49 1488 inline
Chris@49 1489 const SpMat<eT>&
Chris@49 1490 SpMat<eT>::operator/=(const SpOp<T1, spop_type>& X)
Chris@49 1491 {
Chris@49 1492 arma_extra_debug_sigprint();
Chris@49 1493
Chris@49 1494 arma_type_check(( is_same_type< eT, typename T1::elem_type >::value == false ));
Chris@49 1495
Chris@49 1496 const SpMat<eT> m(X);
Chris@49 1497
Chris@49 1498 return (*this).operator/=(m);
Chris@49 1499 }
Chris@49 1500
Chris@49 1501
Chris@49 1502
Chris@49 1503 template<typename eT>
Chris@49 1504 template<typename T1, typename T2, typename spglue_type>
Chris@49 1505 inline
Chris@49 1506 SpMat<eT>::SpMat(const SpGlue<T1, T2, spglue_type>& X)
Chris@49 1507 : n_rows(0)
Chris@49 1508 , n_cols(0)
Chris@49 1509 , n_elem(0)
Chris@49 1510 , n_nonzero(0)
Chris@49 1511 , vec_state(0)
Chris@49 1512 , values(NULL) // extra element set in application of sparse glue
Chris@49 1513 , row_indices(NULL)
Chris@49 1514 , col_ptrs(NULL)
Chris@49 1515 {
Chris@49 1516 arma_extra_debug_sigprint_this(this);
Chris@49 1517
Chris@49 1518 arma_type_check(( is_same_type< eT, typename T1::elem_type >::value == false ));
Chris@49 1519
Chris@49 1520 spglue_type::apply(*this, X);
Chris@49 1521 }
Chris@49 1522
Chris@49 1523
Chris@49 1524
Chris@49 1525 template<typename eT>
Chris@49 1526 template<typename T1, typename spop_type>
Chris@49 1527 inline
Chris@49 1528 SpMat<eT>::SpMat(const mtSpOp<eT, T1, spop_type>& X)
Chris@49 1529 : n_rows(0)
Chris@49 1530 , n_cols(0)
Chris@49 1531 , n_elem(0)
Chris@49 1532 , n_nonzero(0)
Chris@49 1533 , vec_state(0)
Chris@49 1534 , values(NULL) // extra element set in application of sparse glue
Chris@49 1535 , row_indices(NULL)
Chris@49 1536 , col_ptrs(NULL)
Chris@49 1537 {
Chris@49 1538 arma_extra_debug_sigprint_this(this);
Chris@49 1539
Chris@49 1540 spop_type::apply(*this, X);
Chris@49 1541 }
Chris@49 1542
Chris@49 1543
Chris@49 1544
Chris@49 1545 template<typename eT>
Chris@49 1546 template<typename T1, typename spop_type>
Chris@49 1547 inline
Chris@49 1548 const SpMat<eT>&
Chris@49 1549 SpMat<eT>::operator=(const mtSpOp<eT, T1, spop_type>& X)
Chris@49 1550 {
Chris@49 1551 arma_extra_debug_sigprint();
Chris@49 1552
Chris@49 1553 spop_type::apply(*this, X);
Chris@49 1554
Chris@49 1555 return *this;
Chris@49 1556 }
Chris@49 1557
Chris@49 1558
Chris@49 1559
Chris@49 1560 template<typename eT>
Chris@49 1561 template<typename T1, typename spop_type>
Chris@49 1562 inline
Chris@49 1563 const SpMat<eT>&
Chris@49 1564 SpMat<eT>::operator+=(const mtSpOp<eT, T1, spop_type>& X)
Chris@49 1565 {
Chris@49 1566 arma_extra_debug_sigprint();
Chris@49 1567
Chris@49 1568 const SpMat<eT> m(X);
Chris@49 1569
Chris@49 1570 return (*this).operator+=(m);
Chris@49 1571 }
Chris@49 1572
Chris@49 1573
Chris@49 1574
Chris@49 1575 template<typename eT>
Chris@49 1576 template<typename T1, typename spop_type>
Chris@49 1577 inline
Chris@49 1578 const SpMat<eT>&
Chris@49 1579 SpMat<eT>::operator-=(const mtSpOp<eT, T1, spop_type>& X)
Chris@49 1580 {
Chris@49 1581 arma_extra_debug_sigprint();
Chris@49 1582
Chris@49 1583 const SpMat<eT> m(X);
Chris@49 1584
Chris@49 1585 return (*this).operator-=(m);
Chris@49 1586 }
Chris@49 1587
Chris@49 1588
Chris@49 1589
Chris@49 1590 template<typename eT>
Chris@49 1591 template<typename T1, typename spop_type>
Chris@49 1592 inline
Chris@49 1593 const SpMat<eT>&
Chris@49 1594 SpMat<eT>::operator*=(const mtSpOp<eT, T1, spop_type>& X)
Chris@49 1595 {
Chris@49 1596 arma_extra_debug_sigprint();
Chris@49 1597
Chris@49 1598 const SpMat<eT> m(X);
Chris@49 1599
Chris@49 1600 return (*this).operator*=(m);
Chris@49 1601 }
Chris@49 1602
Chris@49 1603
Chris@49 1604
Chris@49 1605 template<typename eT>
Chris@49 1606 template<typename T1, typename spop_type>
Chris@49 1607 inline
Chris@49 1608 const SpMat<eT>&
Chris@49 1609 SpMat<eT>::operator%=(const mtSpOp<eT, T1, spop_type>& X)
Chris@49 1610 {
Chris@49 1611 arma_extra_debug_sigprint();
Chris@49 1612
Chris@49 1613 const SpMat<eT> m(X);
Chris@49 1614
Chris@49 1615 return (*this).operator%=(m);
Chris@49 1616 }
Chris@49 1617
Chris@49 1618
Chris@49 1619
Chris@49 1620 template<typename eT>
Chris@49 1621 template<typename T1, typename spop_type>
Chris@49 1622 inline
Chris@49 1623 const SpMat<eT>&
Chris@49 1624 SpMat<eT>::operator/=(const mtSpOp<eT, T1, spop_type>& X)
Chris@49 1625 {
Chris@49 1626 arma_extra_debug_sigprint();
Chris@49 1627
Chris@49 1628 const SpMat<eT> m(X);
Chris@49 1629
Chris@49 1630 return (*this).operator/=(m);
Chris@49 1631 }
Chris@49 1632
Chris@49 1633
Chris@49 1634
Chris@49 1635 template<typename eT>
Chris@49 1636 template<typename T1, typename T2, typename spglue_type>
Chris@49 1637 inline
Chris@49 1638 const SpMat<eT>&
Chris@49 1639 SpMat<eT>::operator=(const SpGlue<T1, T2, spglue_type>& X)
Chris@49 1640 {
Chris@49 1641 arma_extra_debug_sigprint();
Chris@49 1642
Chris@49 1643 arma_type_check(( is_same_type< eT, typename T1::elem_type >::value == false ));
Chris@49 1644
Chris@49 1645 spglue_type::apply(*this, X);
Chris@49 1646
Chris@49 1647 return *this;
Chris@49 1648 }
Chris@49 1649
Chris@49 1650
Chris@49 1651
Chris@49 1652 template<typename eT>
Chris@49 1653 template<typename T1, typename T2, typename spglue_type>
Chris@49 1654 inline
Chris@49 1655 const SpMat<eT>&
Chris@49 1656 SpMat<eT>::operator+=(const SpGlue<T1, T2, spglue_type>& X)
Chris@49 1657 {
Chris@49 1658 arma_extra_debug_sigprint();
Chris@49 1659
Chris@49 1660 arma_type_check(( is_same_type< eT, typename T1::elem_type >::value == false ));
Chris@49 1661
Chris@49 1662 const SpMat<eT> m(X);
Chris@49 1663
Chris@49 1664 return (*this).operator+=(m);
Chris@49 1665 }
Chris@49 1666
Chris@49 1667
Chris@49 1668
Chris@49 1669 template<typename eT>
Chris@49 1670 template<typename T1, typename T2, typename spglue_type>
Chris@49 1671 inline
Chris@49 1672 const SpMat<eT>&
Chris@49 1673 SpMat<eT>::operator-=(const SpGlue<T1, T2, spglue_type>& X)
Chris@49 1674 {
Chris@49 1675 arma_extra_debug_sigprint();
Chris@49 1676
Chris@49 1677 arma_type_check(( is_same_type< eT, typename T1::elem_type >::value == false ));
Chris@49 1678
Chris@49 1679 const SpMat<eT> m(X);
Chris@49 1680
Chris@49 1681 return (*this).operator-=(m);
Chris@49 1682 }
Chris@49 1683
Chris@49 1684
Chris@49 1685
Chris@49 1686 template<typename eT>
Chris@49 1687 template<typename T1, typename T2, typename spglue_type>
Chris@49 1688 inline
Chris@49 1689 const SpMat<eT>&
Chris@49 1690 SpMat<eT>::operator*=(const SpGlue<T1, T2, spglue_type>& X)
Chris@49 1691 {
Chris@49 1692 arma_extra_debug_sigprint();
Chris@49 1693
Chris@49 1694 arma_type_check(( is_same_type< eT, typename T1::elem_type >::value == false ));
Chris@49 1695
Chris@49 1696 const SpMat<eT> m(X);
Chris@49 1697
Chris@49 1698 return (*this).operator*=(m);
Chris@49 1699 }
Chris@49 1700
Chris@49 1701
Chris@49 1702
Chris@49 1703 template<typename eT>
Chris@49 1704 template<typename T1, typename T2, typename spglue_type>
Chris@49 1705 inline
Chris@49 1706 const SpMat<eT>&
Chris@49 1707 SpMat<eT>::operator%=(const SpGlue<T1, T2, spglue_type>& X)
Chris@49 1708 {
Chris@49 1709 arma_extra_debug_sigprint();
Chris@49 1710
Chris@49 1711 arma_type_check(( is_same_type< eT, typename T1::elem_type >::value == false ));
Chris@49 1712
Chris@49 1713 const SpMat<eT> m(X);
Chris@49 1714
Chris@49 1715 return (*this).operator%=(m);
Chris@49 1716 }
Chris@49 1717
Chris@49 1718
Chris@49 1719
Chris@49 1720 template<typename eT>
Chris@49 1721 template<typename T1, typename T2, typename spglue_type>
Chris@49 1722 inline
Chris@49 1723 const SpMat<eT>&
Chris@49 1724 SpMat<eT>::operator/=(const SpGlue<T1, T2, spglue_type>& X)
Chris@49 1725 {
Chris@49 1726 arma_extra_debug_sigprint();
Chris@49 1727
Chris@49 1728 arma_type_check(( is_same_type< eT, typename T1::elem_type >::value == false ));
Chris@49 1729
Chris@49 1730 const SpMat<eT> m(X);
Chris@49 1731
Chris@49 1732 return (*this).operator/=(m);
Chris@49 1733 }
Chris@49 1734
Chris@49 1735
Chris@49 1736
Chris@49 1737 template<typename eT>
Chris@49 1738 arma_inline
Chris@49 1739 SpSubview<eT>
Chris@49 1740 SpMat<eT>::row(const uword row_num)
Chris@49 1741 {
Chris@49 1742 arma_extra_debug_sigprint();
Chris@49 1743
Chris@49 1744 arma_debug_check(row_num >= n_rows, "SpMat::row(): out of bounds");
Chris@49 1745
Chris@49 1746 return SpSubview<eT>(*this, row_num, 0, 1, n_cols);
Chris@49 1747 }
Chris@49 1748
Chris@49 1749
Chris@49 1750
Chris@49 1751 template<typename eT>
Chris@49 1752 arma_inline
Chris@49 1753 const SpSubview<eT>
Chris@49 1754 SpMat<eT>::row(const uword row_num) const
Chris@49 1755 {
Chris@49 1756 arma_extra_debug_sigprint();
Chris@49 1757
Chris@49 1758 arma_debug_check(row_num >= n_rows, "SpMat::row(): out of bounds");
Chris@49 1759
Chris@49 1760 return SpSubview<eT>(*this, row_num, 0, 1, n_cols);
Chris@49 1761 }
Chris@49 1762
Chris@49 1763
Chris@49 1764
Chris@49 1765 template<typename eT>
Chris@49 1766 inline
Chris@49 1767 SpSubview<eT>
Chris@49 1768 SpMat<eT>::operator()(const uword row_num, const span& col_span)
Chris@49 1769 {
Chris@49 1770 arma_extra_debug_sigprint();
Chris@49 1771
Chris@49 1772 const bool col_all = col_span.whole;
Chris@49 1773
Chris@49 1774 const uword local_n_cols = n_cols;
Chris@49 1775
Chris@49 1776 const uword in_col1 = col_all ? 0 : col_span.a;
Chris@49 1777 const uword in_col2 = col_span.b;
Chris@49 1778 const uword submat_n_cols = col_all ? local_n_cols : in_col2 - in_col1 + 1;
Chris@49 1779
Chris@49 1780 arma_debug_check
Chris@49 1781 (
Chris@49 1782 (row_num >= n_rows)
Chris@49 1783 ||
Chris@49 1784 ( col_all ? false : ((in_col1 > in_col2) || (in_col2 >= local_n_cols)) )
Chris@49 1785 ,
Chris@49 1786 "SpMat::operator(): indices out of bounds or incorrectly used"
Chris@49 1787 );
Chris@49 1788
Chris@49 1789 return SpSubview<eT>(*this, row_num, in_col1, 1, submat_n_cols);
Chris@49 1790 }
Chris@49 1791
Chris@49 1792
Chris@49 1793
Chris@49 1794 template<typename eT>
Chris@49 1795 inline
Chris@49 1796 const SpSubview<eT>
Chris@49 1797 SpMat<eT>::operator()(const uword row_num, const span& col_span) const
Chris@49 1798 {
Chris@49 1799 arma_extra_debug_sigprint();
Chris@49 1800
Chris@49 1801 const bool col_all = col_span.whole;
Chris@49 1802
Chris@49 1803 const uword local_n_cols = n_cols;
Chris@49 1804
Chris@49 1805 const uword in_col1 = col_all ? 0 : col_span.a;
Chris@49 1806 const uword in_col2 = col_span.b;
Chris@49 1807 const uword submat_n_cols = col_all ? local_n_cols : in_col2 - in_col1 + 1;
Chris@49 1808
Chris@49 1809 arma_debug_check
Chris@49 1810 (
Chris@49 1811 (row_num >= n_rows)
Chris@49 1812 ||
Chris@49 1813 ( col_all ? false : ((in_col1 > in_col2) || (in_col2 >= local_n_cols)) )
Chris@49 1814 ,
Chris@49 1815 "SpMat::operator(): indices out of bounds or incorrectly used"
Chris@49 1816 );
Chris@49 1817
Chris@49 1818 return SpSubview<eT>(*this, row_num, in_col1, 1, submat_n_cols);
Chris@49 1819 }
Chris@49 1820
Chris@49 1821
Chris@49 1822
Chris@49 1823 template<typename eT>
Chris@49 1824 arma_inline
Chris@49 1825 SpSubview<eT>
Chris@49 1826 SpMat<eT>::col(const uword col_num)
Chris@49 1827 {
Chris@49 1828 arma_extra_debug_sigprint();
Chris@49 1829
Chris@49 1830 arma_debug_check(col_num >= n_cols, "SpMat::col(): out of bounds");
Chris@49 1831
Chris@49 1832 return SpSubview<eT>(*this, 0, col_num, n_rows, 1);
Chris@49 1833 }
Chris@49 1834
Chris@49 1835
Chris@49 1836
Chris@49 1837 template<typename eT>
Chris@49 1838 arma_inline
Chris@49 1839 const SpSubview<eT>
Chris@49 1840 SpMat<eT>::col(const uword col_num) const
Chris@49 1841 {
Chris@49 1842 arma_extra_debug_sigprint();
Chris@49 1843
Chris@49 1844 arma_debug_check(col_num >= n_cols, "SpMat::col(): out of bounds");
Chris@49 1845
Chris@49 1846 return SpSubview<eT>(*this, 0, col_num, n_rows, 1);
Chris@49 1847 }
Chris@49 1848
Chris@49 1849
Chris@49 1850
Chris@49 1851 template<typename eT>
Chris@49 1852 inline
Chris@49 1853 SpSubview<eT>
Chris@49 1854 SpMat<eT>::operator()(const span& row_span, const uword col_num)
Chris@49 1855 {
Chris@49 1856 arma_extra_debug_sigprint();
Chris@49 1857
Chris@49 1858 const bool row_all = row_span.whole;
Chris@49 1859
Chris@49 1860 const uword local_n_rows = n_rows;
Chris@49 1861
Chris@49 1862 const uword in_row1 = row_all ? 0 : row_span.a;
Chris@49 1863 const uword in_row2 = row_span.b;
Chris@49 1864 const uword submat_n_rows = row_all ? local_n_rows : in_row2 - in_row1 + 1;
Chris@49 1865
Chris@49 1866 arma_debug_check
Chris@49 1867 (
Chris@49 1868 (col_num >= n_cols)
Chris@49 1869 ||
Chris@49 1870 ( row_all ? false : ((in_row1 > in_row2) || (in_row2 >= local_n_rows)) )
Chris@49 1871 ,
Chris@49 1872 "SpMat::operator(): indices out of bounds or incorrectly used"
Chris@49 1873 );
Chris@49 1874
Chris@49 1875 return SpSubview<eT>(*this, in_row1, col_num, submat_n_rows, 1);
Chris@49 1876 }
Chris@49 1877
Chris@49 1878
Chris@49 1879
Chris@49 1880 template<typename eT>
Chris@49 1881 inline
Chris@49 1882 const SpSubview<eT>
Chris@49 1883 SpMat<eT>::operator()(const span& row_span, const uword col_num) const
Chris@49 1884 {
Chris@49 1885 arma_extra_debug_sigprint();
Chris@49 1886
Chris@49 1887 const bool row_all = row_span.whole;
Chris@49 1888
Chris@49 1889 const uword local_n_rows = n_rows;
Chris@49 1890
Chris@49 1891 const uword in_row1 = row_all ? 0 : row_span.a;
Chris@49 1892 const uword in_row2 = row_span.b;
Chris@49 1893 const uword submat_n_rows = row_all ? local_n_rows : in_row2 - in_row1 + 1;
Chris@49 1894
Chris@49 1895 arma_debug_check
Chris@49 1896 (
Chris@49 1897 (col_num >= n_cols)
Chris@49 1898 ||
Chris@49 1899 ( row_all ? false : ((in_row1 > in_row2) || (in_row2 >= local_n_rows)) )
Chris@49 1900 ,
Chris@49 1901 "SpMat::operator(): indices out of bounds or incorrectly used"
Chris@49 1902 );
Chris@49 1903
Chris@49 1904 return SpSubview<eT>(*this, in_row1, col_num, submat_n_rows, 1);
Chris@49 1905 }
Chris@49 1906
Chris@49 1907
Chris@49 1908
Chris@49 1909 /**
Chris@49 1910 * Swap in_row1 with in_row2.
Chris@49 1911 */
Chris@49 1912 template<typename eT>
Chris@49 1913 inline
Chris@49 1914 void
Chris@49 1915 SpMat<eT>::swap_rows(const uword in_row1, const uword in_row2)
Chris@49 1916 {
Chris@49 1917 arma_extra_debug_sigprint();
Chris@49 1918
Chris@49 1919 arma_debug_check
Chris@49 1920 (
Chris@49 1921 (in_row1 >= n_rows) || (in_row2 >= n_rows),
Chris@49 1922 "SpMat::swap_rows(): out of bounds"
Chris@49 1923 );
Chris@49 1924
Chris@49 1925 // Sanity check.
Chris@49 1926 if (in_row1 == in_row2)
Chris@49 1927 {
Chris@49 1928 return;
Chris@49 1929 }
Chris@49 1930
Chris@49 1931 // The easier way to do this, instead of collecting all the elements in one row and then swapping with the other, will be
Chris@49 1932 // to iterate over each column of the matrix (since we store in column-major format) and then swap the two elements in the two rows at that time.
Chris@49 1933 // We will try to avoid using the at() call since it is expensive, instead preferring to use an iterator to track our position.
Chris@49 1934 uword col1 = (in_row1 < in_row2) ? in_row1 : in_row2;
Chris@49 1935 uword col2 = (in_row1 < in_row2) ? in_row2 : in_row1;
Chris@49 1936
Chris@49 1937 for (uword lcol = 0; lcol < n_cols; lcol++)
Chris@49 1938 {
Chris@49 1939 // If there is nothing in this column we can ignore it.
Chris@49 1940 if (col_ptrs[lcol] == col_ptrs[lcol + 1])
Chris@49 1941 {
Chris@49 1942 continue;
Chris@49 1943 }
Chris@49 1944
Chris@49 1945 // These will represent the positions of the items themselves.
Chris@49 1946 uword loc1 = n_nonzero + 1;
Chris@49 1947 uword loc2 = n_nonzero + 1;
Chris@49 1948
Chris@49 1949 for (uword search_pos = col_ptrs[lcol]; search_pos < col_ptrs[lcol + 1]; search_pos++)
Chris@49 1950 {
Chris@49 1951 if (row_indices[search_pos] == col1)
Chris@49 1952 {
Chris@49 1953 loc1 = search_pos;
Chris@49 1954 }
Chris@49 1955
Chris@49 1956 if (row_indices[search_pos] == col2)
Chris@49 1957 {
Chris@49 1958 loc2 = search_pos;
Chris@49 1959 break; // No need to look any further.
Chris@49 1960 }
Chris@49 1961 }
Chris@49 1962
Chris@49 1963 // There are four cases: we found both elements; we found one element (loc1); we found one element (loc2); we found zero elements.
Chris@49 1964 // If we found zero elements no work needs to be done and we can continue to the next column.
Chris@49 1965 if ((loc1 != (n_nonzero + 1)) && (loc2 != (n_nonzero + 1)))
Chris@49 1966 {
Chris@49 1967 // This is an easy case: just swap the values. No index modifying necessary.
Chris@49 1968 eT tmp = values[loc1];
Chris@49 1969 access::rw(values[loc1]) = values[loc2];
Chris@49 1970 access::rw(values[loc2]) = tmp;
Chris@49 1971 }
Chris@49 1972 else if (loc1 != (n_nonzero + 1)) // We only found loc1 and not loc2.
Chris@49 1973 {
Chris@49 1974 // We need to find the correct place to move our value to. It will be forward (not backwards) because in_row2 > in_row1.
Chris@49 1975 // Each iteration of the loop swaps the current value (loc1) with (loc1 + 1); in this manner we move our value down to where it should be.
Chris@49 1976 while (((loc1 + 1) < col_ptrs[lcol + 1]) && (row_indices[loc1 + 1] < in_row2))
Chris@49 1977 {
Chris@49 1978 // Swap both the values and the indices. The column should not change.
Chris@49 1979 eT tmp = values[loc1];
Chris@49 1980 access::rw(values[loc1]) = values[loc1 + 1];
Chris@49 1981 access::rw(values[loc1 + 1]) = tmp;
Chris@49 1982
Chris@49 1983 uword tmp_index = row_indices[loc1];
Chris@49 1984 access::rw(row_indices[loc1]) = row_indices[loc1 + 1];
Chris@49 1985 access::rw(row_indices[loc1 + 1]) = tmp_index;
Chris@49 1986
Chris@49 1987 loc1++; // And increment the counter.
Chris@49 1988 }
Chris@49 1989
Chris@49 1990 // Now set the row index correctly.
Chris@49 1991 access::rw(row_indices[loc1]) = in_row2;
Chris@49 1992
Chris@49 1993 }
Chris@49 1994 else if (loc2 != (n_nonzero + 1))
Chris@49 1995 {
Chris@49 1996 // We need to find the correct place to move our value to. It will be backwards (not forwards) because in_row1 < in_row2.
Chris@49 1997 // Each iteration of the loop swaps the current value (loc2) with (loc2 - 1); in this manner we move our value up to where it should be.
Chris@49 1998 while (((loc2 - 1) >= col_ptrs[lcol]) && (row_indices[loc2 - 1] > in_row1))
Chris@49 1999 {
Chris@49 2000 // Swap both the values and the indices. The column should not change.
Chris@49 2001 eT tmp = values[loc2];
Chris@49 2002 access::rw(values[loc2]) = values[loc2 - 1];
Chris@49 2003 access::rw(values[loc2 - 1]) = tmp;
Chris@49 2004
Chris@49 2005 uword tmp_index = row_indices[loc2];
Chris@49 2006 access::rw(row_indices[loc2]) = row_indices[loc2 - 1];
Chris@49 2007 access::rw(row_indices[loc2 - 1]) = tmp_index;
Chris@49 2008
Chris@49 2009 loc2--; // And decrement the counter.
Chris@49 2010 }
Chris@49 2011
Chris@49 2012 // Now set the row index correctly.
Chris@49 2013 access::rw(row_indices[loc2]) = in_row1;
Chris@49 2014
Chris@49 2015 }
Chris@49 2016 /* else: no need to swap anything; both values are zero */
Chris@49 2017 }
Chris@49 2018 }
Chris@49 2019
Chris@49 2020 /**
Chris@49 2021 * Swap in_col1 with in_col2.
Chris@49 2022 */
Chris@49 2023 template<typename eT>
Chris@49 2024 inline
Chris@49 2025 void
Chris@49 2026 SpMat<eT>::swap_cols(const uword in_col1, const uword in_col2)
Chris@49 2027 {
Chris@49 2028 arma_extra_debug_sigprint();
Chris@49 2029
Chris@49 2030 // slow but works
Chris@49 2031 for(uword lrow = 0; lrow < n_rows; ++lrow)
Chris@49 2032 {
Chris@49 2033 eT tmp = at(lrow, in_col1);
Chris@49 2034 at(lrow, in_col1) = at(lrow, in_col2);
Chris@49 2035 at(lrow, in_col2) = tmp;
Chris@49 2036 }
Chris@49 2037 }
Chris@49 2038
Chris@49 2039 /**
Chris@49 2040 * Remove the row row_num.
Chris@49 2041 */
Chris@49 2042 template<typename eT>
Chris@49 2043 inline
Chris@49 2044 void
Chris@49 2045 SpMat<eT>::shed_row(const uword row_num)
Chris@49 2046 {
Chris@49 2047 arma_extra_debug_sigprint();
Chris@49 2048 arma_debug_check (row_num >= n_rows, "SpMat::shed_row(): out of bounds");
Chris@49 2049
Chris@49 2050 shed_rows (row_num, row_num);
Chris@49 2051 }
Chris@49 2052
Chris@49 2053 /**
Chris@49 2054 * Remove the column col_num.
Chris@49 2055 */
Chris@49 2056 template<typename eT>
Chris@49 2057 inline
Chris@49 2058 void
Chris@49 2059 SpMat<eT>::shed_col(const uword col_num)
Chris@49 2060 {
Chris@49 2061 arma_extra_debug_sigprint();
Chris@49 2062 arma_debug_check (col_num >= n_cols, "SpMat::shed_col(): out of bounds");
Chris@49 2063
Chris@49 2064 shed_cols(col_num, col_num);
Chris@49 2065 }
Chris@49 2066
Chris@49 2067 /**
Chris@49 2068 * Remove all rows between (and including) in_row1 and in_row2.
Chris@49 2069 */
Chris@49 2070 template<typename eT>
Chris@49 2071 inline
Chris@49 2072 void
Chris@49 2073 SpMat<eT>::shed_rows(const uword in_row1, const uword in_row2)
Chris@49 2074 {
Chris@49 2075 arma_extra_debug_sigprint();
Chris@49 2076
Chris@49 2077 arma_debug_check
Chris@49 2078 (
Chris@49 2079 (in_row1 > in_row2) || (in_row2 >= n_rows),
Chris@49 2080 "SpMat::shed_rows(): indices out of bounds or incorectly used"
Chris@49 2081 );
Chris@49 2082
Chris@49 2083 uword i, j;
Chris@49 2084 // Store the length of values
Chris@49 2085 uword vlength = n_nonzero;
Chris@49 2086 // Store the length of col_ptrs
Chris@49 2087 uword clength = n_cols + 1;
Chris@49 2088
Chris@49 2089 // This is O(n * n_cols) and inplace, there may be a faster way, though.
Chris@49 2090 for (i = 0, j = 0; i < vlength; ++i)
Chris@49 2091 {
Chris@49 2092 // Store the row of the ith element.
Chris@49 2093 const uword lrow = row_indices[i];
Chris@49 2094 // Is the ith element in the range of rows we want to remove?
Chris@49 2095 if (lrow >= in_row1 && lrow <= in_row2)
Chris@49 2096 {
Chris@49 2097 // Increment our "removed elements" counter.
Chris@49 2098 ++j;
Chris@49 2099
Chris@49 2100 // Adjust the values of col_ptrs each time we remove an element.
Chris@49 2101 // Basically, the length of one column reduces by one, and everything to
Chris@49 2102 // its right gets reduced by one to represent all the elements being
Chris@49 2103 // shifted to the left by one.
Chris@49 2104 for(uword k = 0; k < clength; ++k)
Chris@49 2105 {
Chris@49 2106 if (col_ptrs[k] > (i - j + 1))
Chris@49 2107 {
Chris@49 2108 --access::rw(col_ptrs[k]);
Chris@49 2109 }
Chris@49 2110 }
Chris@49 2111 }
Chris@49 2112 else
Chris@49 2113 {
Chris@49 2114 // We shift the element we checked to the left by how many elements
Chris@49 2115 // we have removed.
Chris@49 2116 // j = 0 until we remove the first element.
Chris@49 2117 if (j != 0)
Chris@49 2118 {
Chris@49 2119 access::rw(row_indices[i - j]) = (lrow > in_row2) ? (lrow - (in_row2 - in_row1 + 1)) : lrow;
Chris@49 2120 access::rw(values[i - j]) = values[i];
Chris@49 2121 }
Chris@49 2122 }
Chris@49 2123 }
Chris@49 2124
Chris@49 2125 // j is the number of elements removed.
Chris@49 2126
Chris@49 2127 // Shrink the vectors. This will copy the memory.
Chris@49 2128 mem_resize(n_nonzero - j);
Chris@49 2129
Chris@49 2130 // Adjust row and element counts.
Chris@49 2131 access::rw(n_rows) = n_rows - (in_row2 - in_row1) - 1;
Chris@49 2132 access::rw(n_elem) = n_rows * n_cols;
Chris@49 2133 }
Chris@49 2134
Chris@49 2135 /**
Chris@49 2136 * Remove all columns between (and including) in_col1 and in_col2.
Chris@49 2137 */
Chris@49 2138 template<typename eT>
Chris@49 2139 inline
Chris@49 2140 void
Chris@49 2141 SpMat<eT>::shed_cols(const uword in_col1, const uword in_col2)
Chris@49 2142 {
Chris@49 2143 arma_extra_debug_sigprint();
Chris@49 2144
Chris@49 2145 arma_debug_check
Chris@49 2146 (
Chris@49 2147 (in_col1 > in_col2) || (in_col2 >= n_cols),
Chris@49 2148 "SpMat::shed_cols(): indices out of bounds or incorrectly used"
Chris@49 2149 );
Chris@49 2150
Chris@49 2151 // First we find the locations in values and row_indices for the column entries.
Chris@49 2152 uword col_beg = col_ptrs[in_col1];
Chris@49 2153 uword col_end = col_ptrs[in_col2 + 1];
Chris@49 2154
Chris@49 2155 // Then we find the number of entries in the column.
Chris@49 2156 uword diff = col_end - col_beg;
Chris@49 2157
Chris@49 2158 if (diff > 0)
Chris@49 2159 {
Chris@49 2160 eT* new_values = memory::acquire_chunked<eT> (n_nonzero - diff);
Chris@49 2161 uword* new_row_indices = memory::acquire_chunked<uword>(n_nonzero - diff);
Chris@49 2162
Chris@49 2163 // Copy first part.
Chris@49 2164 if (col_beg != 0)
Chris@49 2165 {
Chris@49 2166 arrayops::copy(new_values, values, col_beg);
Chris@49 2167 arrayops::copy(new_row_indices, row_indices, col_beg);
Chris@49 2168 }
Chris@49 2169
Chris@49 2170 // Copy second part.
Chris@49 2171 if (col_end != n_nonzero)
Chris@49 2172 {
Chris@49 2173 arrayops::copy(new_values + col_beg, values + col_end, n_nonzero - col_end);
Chris@49 2174 arrayops::copy(new_row_indices + col_beg, row_indices + col_end, n_nonzero - col_end);
Chris@49 2175 }
Chris@49 2176
Chris@49 2177 memory::release(values);
Chris@49 2178 memory::release(row_indices);
Chris@49 2179
Chris@49 2180 access::rw(values) = new_values;
Chris@49 2181 access::rw(row_indices) = new_row_indices;
Chris@49 2182
Chris@49 2183 // Update counts and such.
Chris@49 2184 access::rw(n_nonzero) -= diff;
Chris@49 2185 }
Chris@49 2186
Chris@49 2187 // Update column pointers.
Chris@49 2188 const uword new_n_cols = n_cols - ((in_col2 - in_col1) + 1);
Chris@49 2189
Chris@49 2190 uword* new_col_ptrs = memory::acquire<uword>(new_n_cols + 2);
Chris@49 2191 new_col_ptrs[new_n_cols + 1] = std::numeric_limits<uword>::max();
Chris@49 2192
Chris@49 2193 // Copy first set of columns (no manipulation required).
Chris@49 2194 if (in_col1 != 0)
Chris@49 2195 {
Chris@49 2196 arrayops::copy(new_col_ptrs, col_ptrs, in_col1);
Chris@49 2197 }
Chris@49 2198
Chris@49 2199 // Copy second set of columns (manipulation required).
Chris@49 2200 uword cur_col = in_col1;
Chris@49 2201 for (uword i = in_col2 + 1; i <= n_cols; ++i, ++cur_col)
Chris@49 2202 {
Chris@49 2203 new_col_ptrs[cur_col] = col_ptrs[i] - diff;
Chris@49 2204 }
Chris@49 2205
Chris@49 2206 memory::release(col_ptrs);
Chris@49 2207 access::rw(col_ptrs) = new_col_ptrs;
Chris@49 2208
Chris@49 2209 // We update the element and column counts, and we're done.
Chris@49 2210 access::rw(n_cols) = new_n_cols;
Chris@49 2211 access::rw(n_elem) = n_cols * n_rows;
Chris@49 2212 }
Chris@49 2213
Chris@49 2214
Chris@49 2215
Chris@49 2216 template<typename eT>
Chris@49 2217 arma_inline
Chris@49 2218 SpSubview<eT>
Chris@49 2219 SpMat<eT>::rows(const uword in_row1, const uword in_row2)
Chris@49 2220 {
Chris@49 2221 arma_extra_debug_sigprint();
Chris@49 2222
Chris@49 2223 arma_debug_check
Chris@49 2224 (
Chris@49 2225 (in_row1 > in_row2) || (in_row2 >= n_rows),
Chris@49 2226 "SpMat::rows(): indices out of bounds or incorrectly used"
Chris@49 2227 );
Chris@49 2228
Chris@49 2229 const uword subview_n_rows = in_row2 - in_row1 + 1;
Chris@49 2230
Chris@49 2231 return SpSubview<eT>(*this, in_row1, 0, subview_n_rows, n_cols);
Chris@49 2232 }
Chris@49 2233
Chris@49 2234
Chris@49 2235
Chris@49 2236 template<typename eT>
Chris@49 2237 arma_inline
Chris@49 2238 const SpSubview<eT>
Chris@49 2239 SpMat<eT>::rows(const uword in_row1, const uword in_row2) const
Chris@49 2240 {
Chris@49 2241 arma_extra_debug_sigprint();
Chris@49 2242
Chris@49 2243 arma_debug_check
Chris@49 2244 (
Chris@49 2245 (in_row1 > in_row2) || (in_row2 >= n_rows),
Chris@49 2246 "SpMat::rows(): indices out of bounds or incorrectly used"
Chris@49 2247 );
Chris@49 2248
Chris@49 2249 const uword subview_n_rows = in_row2 - in_row1 + 1;
Chris@49 2250
Chris@49 2251 return SpSubview<eT>(*this, in_row1, 0, subview_n_rows, n_cols);
Chris@49 2252 }
Chris@49 2253
Chris@49 2254
Chris@49 2255
Chris@49 2256 template<typename eT>
Chris@49 2257 arma_inline
Chris@49 2258 SpSubview<eT>
Chris@49 2259 SpMat<eT>::cols(const uword in_col1, const uword in_col2)
Chris@49 2260 {
Chris@49 2261 arma_extra_debug_sigprint();
Chris@49 2262
Chris@49 2263 arma_debug_check
Chris@49 2264 (
Chris@49 2265 (in_col1 > in_col2) || (in_col2 >= n_cols),
Chris@49 2266 "SpMat::cols(): indices out of bounds or incorrectly used"
Chris@49 2267 );
Chris@49 2268
Chris@49 2269 const uword subview_n_cols = in_col2 - in_col1 + 1;
Chris@49 2270
Chris@49 2271 return SpSubview<eT>(*this, 0, in_col1, n_rows, subview_n_cols);
Chris@49 2272 }
Chris@49 2273
Chris@49 2274
Chris@49 2275
Chris@49 2276 template<typename eT>
Chris@49 2277 arma_inline
Chris@49 2278 const SpSubview<eT>
Chris@49 2279 SpMat<eT>::cols(const uword in_col1, const uword in_col2) const
Chris@49 2280 {
Chris@49 2281 arma_extra_debug_sigprint();
Chris@49 2282
Chris@49 2283 arma_debug_check
Chris@49 2284 (
Chris@49 2285 (in_col1 > in_col2) || (in_col2 >= n_cols),
Chris@49 2286 "SpMat::cols(): indices out of bounds or incorrectly used"
Chris@49 2287 );
Chris@49 2288
Chris@49 2289 const uword subview_n_cols = in_col2 - in_col1 + 1;
Chris@49 2290
Chris@49 2291 return SpSubview<eT>(*this, 0, in_col1, n_rows, subview_n_cols);
Chris@49 2292 }
Chris@49 2293
Chris@49 2294
Chris@49 2295
Chris@49 2296 template<typename eT>
Chris@49 2297 arma_inline
Chris@49 2298 SpSubview<eT>
Chris@49 2299 SpMat<eT>::submat(const uword in_row1, const uword in_col1, const uword in_row2, const uword in_col2)
Chris@49 2300 {
Chris@49 2301 arma_extra_debug_sigprint();
Chris@49 2302
Chris@49 2303 arma_debug_check
Chris@49 2304 (
Chris@49 2305 (in_row1 > in_row2) || (in_col1 > in_col2) || (in_row2 >= n_rows) || (in_col2 >= n_cols),
Chris@49 2306 "SpMat::submat(): indices out of bounds or incorrectly used"
Chris@49 2307 );
Chris@49 2308
Chris@49 2309 const uword subview_n_rows = in_row2 - in_row1 + 1;
Chris@49 2310 const uword subview_n_cols = in_col2 - in_col1 + 1;
Chris@49 2311
Chris@49 2312 return SpSubview<eT>(*this, in_row1, in_col1, subview_n_rows, subview_n_cols);
Chris@49 2313 }
Chris@49 2314
Chris@49 2315
Chris@49 2316
Chris@49 2317 template<typename eT>
Chris@49 2318 arma_inline
Chris@49 2319 const SpSubview<eT>
Chris@49 2320 SpMat<eT>::submat(const uword in_row1, const uword in_col1, const uword in_row2, const uword in_col2) const
Chris@49 2321 {
Chris@49 2322 arma_extra_debug_sigprint();
Chris@49 2323
Chris@49 2324 arma_debug_check
Chris@49 2325 (
Chris@49 2326 (in_row1 > in_row2) || (in_col1 > in_col2) || (in_row2 >= n_rows) || (in_col2 >= n_cols),
Chris@49 2327 "SpMat::submat(): indices out of bounds or incorrectly used"
Chris@49 2328 );
Chris@49 2329
Chris@49 2330 const uword subview_n_rows = in_row2 - in_row1 + 1;
Chris@49 2331 const uword subview_n_cols = in_col2 - in_col1 + 1;
Chris@49 2332
Chris@49 2333 return SpSubview<eT>(*this, in_row1, in_col1, subview_n_rows, subview_n_cols);
Chris@49 2334 }
Chris@49 2335
Chris@49 2336
Chris@49 2337
Chris@49 2338 template<typename eT>
Chris@49 2339 inline
Chris@49 2340 SpSubview<eT>
Chris@49 2341 SpMat<eT>::submat (const span& row_span, const span& col_span)
Chris@49 2342 {
Chris@49 2343 arma_extra_debug_sigprint();
Chris@49 2344
Chris@49 2345 const bool row_all = row_span.whole;
Chris@49 2346 const bool col_all = col_span.whole;
Chris@49 2347
Chris@49 2348 const uword local_n_rows = n_rows;
Chris@49 2349 const uword local_n_cols = n_cols;
Chris@49 2350
Chris@49 2351 const uword in_row1 = row_all ? 0 : row_span.a;
Chris@49 2352 const uword in_row2 = row_span.b;
Chris@49 2353 const uword submat_n_rows = row_all ? local_n_rows : in_row2 - in_row1 + 1;
Chris@49 2354
Chris@49 2355 const uword in_col1 = col_all ? 0 : col_span.a;
Chris@49 2356 const uword in_col2 = col_span.b;
Chris@49 2357 const uword submat_n_cols = col_all ? local_n_cols : in_col2 - in_col1 + 1;
Chris@49 2358
Chris@49 2359 arma_debug_check
Chris@49 2360 (
Chris@49 2361 ( row_all ? false : ((in_row1 > in_row2) || (in_row2 >= local_n_rows)) )
Chris@49 2362 ||
Chris@49 2363 ( col_all ? false : ((in_col1 > in_col2) || (in_col2 >= local_n_cols)) )
Chris@49 2364 ,
Chris@49 2365 "SpMat::submat(): indices out of bounds or incorrectly used"
Chris@49 2366 );
Chris@49 2367
Chris@49 2368 return SpSubview<eT>(*this, in_row1, in_col1, submat_n_rows, submat_n_cols);
Chris@49 2369 }
Chris@49 2370
Chris@49 2371
Chris@49 2372
Chris@49 2373 template<typename eT>
Chris@49 2374 inline
Chris@49 2375 const SpSubview<eT>
Chris@49 2376 SpMat<eT>::submat (const span& row_span, const span& col_span) const
Chris@49 2377 {
Chris@49 2378 arma_extra_debug_sigprint();
Chris@49 2379
Chris@49 2380 const bool row_all = row_span.whole;
Chris@49 2381 const bool col_all = col_span.whole;
Chris@49 2382
Chris@49 2383 const uword local_n_rows = n_rows;
Chris@49 2384 const uword local_n_cols = n_cols;
Chris@49 2385
Chris@49 2386 const uword in_row1 = row_all ? 0 : row_span.a;
Chris@49 2387 const uword in_row2 = row_span.b;
Chris@49 2388 const uword submat_n_rows = row_all ? local_n_rows : in_row2 - in_row1 + 1;
Chris@49 2389
Chris@49 2390 const uword in_col1 = col_all ? 0 : col_span.a;
Chris@49 2391 const uword in_col2 = col_span.b;
Chris@49 2392 const uword submat_n_cols = col_all ? local_n_cols : in_col2 - in_col1 + 1;
Chris@49 2393
Chris@49 2394 arma_debug_check
Chris@49 2395 (
Chris@49 2396 ( row_all ? false : ((in_row1 > in_row2) || (in_row2 >= local_n_rows)) )
Chris@49 2397 ||
Chris@49 2398 ( col_all ? false : ((in_col1 > in_col2) || (in_col2 >= local_n_cols)) )
Chris@49 2399 ,
Chris@49 2400 "SpMat::submat(): indices out of bounds or incorrectly used"
Chris@49 2401 );
Chris@49 2402
Chris@49 2403 return SpSubview<eT>(*this, in_row1, in_col1, submat_n_rows, submat_n_cols);
Chris@49 2404 }
Chris@49 2405
Chris@49 2406
Chris@49 2407
Chris@49 2408 template<typename eT>
Chris@49 2409 inline
Chris@49 2410 SpSubview<eT>
Chris@49 2411 SpMat<eT>::operator()(const span& row_span, const span& col_span)
Chris@49 2412 {
Chris@49 2413 arma_extra_debug_sigprint();
Chris@49 2414
Chris@49 2415 return submat(row_span, col_span);
Chris@49 2416 }
Chris@49 2417
Chris@49 2418
Chris@49 2419
Chris@49 2420 template<typename eT>
Chris@49 2421 inline
Chris@49 2422 const SpSubview<eT>
Chris@49 2423 SpMat<eT>::operator()(const span& row_span, const span& col_span) const
Chris@49 2424 {
Chris@49 2425 arma_extra_debug_sigprint();
Chris@49 2426
Chris@49 2427 return submat(row_span, col_span);
Chris@49 2428 }
Chris@49 2429
Chris@49 2430
Chris@49 2431
Chris@49 2432 /**
Chris@49 2433 * Element access; acces the i'th element (works identically to the Mat accessors).
Chris@49 2434 * If there is nothing at element i, 0 is returned.
Chris@49 2435 *
Chris@49 2436 * @param i Element to access.
Chris@49 2437 */
Chris@49 2438
Chris@49 2439 template<typename eT>
Chris@49 2440 arma_inline
Chris@49 2441 arma_warn_unused
Chris@49 2442 SpValProxy<SpMat<eT> >
Chris@49 2443 SpMat<eT>::operator[](const uword i)
Chris@49 2444 {
Chris@49 2445 return get_value(i);
Chris@49 2446 }
Chris@49 2447
Chris@49 2448
Chris@49 2449
Chris@49 2450 template<typename eT>
Chris@49 2451 arma_inline
Chris@49 2452 arma_warn_unused
Chris@49 2453 eT
Chris@49 2454 SpMat<eT>::operator[](const uword i) const
Chris@49 2455 {
Chris@49 2456 return get_value(i);
Chris@49 2457 }
Chris@49 2458
Chris@49 2459
Chris@49 2460
Chris@49 2461 template<typename eT>
Chris@49 2462 arma_inline
Chris@49 2463 arma_warn_unused
Chris@49 2464 SpValProxy<SpMat<eT> >
Chris@49 2465 SpMat<eT>::at(const uword i)
Chris@49 2466 {
Chris@49 2467 return get_value(i);
Chris@49 2468 }
Chris@49 2469
Chris@49 2470
Chris@49 2471
Chris@49 2472 template<typename eT>
Chris@49 2473 arma_inline
Chris@49 2474 arma_warn_unused
Chris@49 2475 eT
Chris@49 2476 SpMat<eT>::at(const uword i) const
Chris@49 2477 {
Chris@49 2478 return get_value(i);
Chris@49 2479 }
Chris@49 2480
Chris@49 2481
Chris@49 2482
Chris@49 2483 template<typename eT>
Chris@49 2484 arma_inline
Chris@49 2485 arma_warn_unused
Chris@49 2486 SpValProxy<SpMat<eT> >
Chris@49 2487 SpMat<eT>::operator()(const uword i)
Chris@49 2488 {
Chris@49 2489 arma_debug_check( (i >= n_elem), "SpMat::operator(): out of bounds");
Chris@49 2490 return get_value(i);
Chris@49 2491 }
Chris@49 2492
Chris@49 2493
Chris@49 2494
Chris@49 2495 template<typename eT>
Chris@49 2496 arma_inline
Chris@49 2497 arma_warn_unused
Chris@49 2498 eT
Chris@49 2499 SpMat<eT>::operator()(const uword i) const
Chris@49 2500 {
Chris@49 2501 arma_debug_check( (i >= n_elem), "SpMat::operator(): out of bounds");
Chris@49 2502 return get_value(i);
Chris@49 2503 }
Chris@49 2504
Chris@49 2505
Chris@49 2506
Chris@49 2507 /**
Chris@49 2508 * Element access; access the element at row in_rows and column in_col.
Chris@49 2509 * If there is nothing at that position, 0 is returned.
Chris@49 2510 */
Chris@49 2511
Chris@49 2512 template<typename eT>
Chris@49 2513 arma_inline
Chris@49 2514 arma_warn_unused
Chris@49 2515 SpValProxy<SpMat<eT> >
Chris@49 2516 SpMat<eT>::at(const uword in_row, const uword in_col)
Chris@49 2517 {
Chris@49 2518 return get_value(in_row, in_col);
Chris@49 2519 }
Chris@49 2520
Chris@49 2521
Chris@49 2522
Chris@49 2523 template<typename eT>
Chris@49 2524 arma_inline
Chris@49 2525 arma_warn_unused
Chris@49 2526 eT
Chris@49 2527 SpMat<eT>::at(const uword in_row, const uword in_col) const
Chris@49 2528 {
Chris@49 2529 return get_value(in_row, in_col);
Chris@49 2530 }
Chris@49 2531
Chris@49 2532
Chris@49 2533
Chris@49 2534 template<typename eT>
Chris@49 2535 arma_inline
Chris@49 2536 arma_warn_unused
Chris@49 2537 SpValProxy<SpMat<eT> >
Chris@49 2538 SpMat<eT>::operator()(const uword in_row, const uword in_col)
Chris@49 2539 {
Chris@49 2540 arma_debug_check( ((in_row >= n_rows) || (in_col >= n_cols)), "SpMat::operator(): out of bounds");
Chris@49 2541 return get_value(in_row, in_col);
Chris@49 2542 }
Chris@49 2543
Chris@49 2544
Chris@49 2545
Chris@49 2546 template<typename eT>
Chris@49 2547 arma_inline
Chris@49 2548 arma_warn_unused
Chris@49 2549 eT
Chris@49 2550 SpMat<eT>::operator()(const uword in_row, const uword in_col) const
Chris@49 2551 {
Chris@49 2552 arma_debug_check( ((in_row >= n_rows) || (in_col >= n_cols)), "SpMat::operator(): out of bounds");
Chris@49 2553 return get_value(in_row, in_col);
Chris@49 2554 }
Chris@49 2555
Chris@49 2556
Chris@49 2557
Chris@49 2558 /**
Chris@49 2559 * Check if matrix is empty (no size, no values).
Chris@49 2560 */
Chris@49 2561 template<typename eT>
Chris@49 2562 arma_inline
Chris@49 2563 arma_warn_unused
Chris@49 2564 bool
Chris@49 2565 SpMat<eT>::is_empty() const
Chris@49 2566 {
Chris@49 2567 return(n_elem == 0);
Chris@49 2568 }
Chris@49 2569
Chris@49 2570
Chris@49 2571
Chris@49 2572 //! returns true if the object can be interpreted as a column or row vector
Chris@49 2573 template<typename eT>
Chris@49 2574 arma_inline
Chris@49 2575 arma_warn_unused
Chris@49 2576 bool
Chris@49 2577 SpMat<eT>::is_vec() const
Chris@49 2578 {
Chris@49 2579 return ( (n_rows == 1) || (n_cols == 1) );
Chris@49 2580 }
Chris@49 2581
Chris@49 2582
Chris@49 2583
Chris@49 2584 //! returns true if the object can be interpreted as a row vector
Chris@49 2585 template<typename eT>
Chris@49 2586 arma_inline
Chris@49 2587 arma_warn_unused
Chris@49 2588 bool
Chris@49 2589 SpMat<eT>::is_rowvec() const
Chris@49 2590 {
Chris@49 2591 return (n_rows == 1);
Chris@49 2592 }
Chris@49 2593
Chris@49 2594
Chris@49 2595
Chris@49 2596 //! returns true if the object can be interpreted as a column vector
Chris@49 2597 template<typename eT>
Chris@49 2598 arma_inline
Chris@49 2599 arma_warn_unused
Chris@49 2600 bool
Chris@49 2601 SpMat<eT>::is_colvec() const
Chris@49 2602 {
Chris@49 2603 return (n_cols == 1);
Chris@49 2604 }
Chris@49 2605
Chris@49 2606
Chris@49 2607
Chris@49 2608 //! returns true if the object has the same number of non-zero rows and columnns
Chris@49 2609 template<typename eT>
Chris@49 2610 arma_inline
Chris@49 2611 arma_warn_unused
Chris@49 2612 bool
Chris@49 2613 SpMat<eT>::is_square() const
Chris@49 2614 {
Chris@49 2615 return (n_rows == n_cols);
Chris@49 2616 }
Chris@49 2617
Chris@49 2618
Chris@49 2619
Chris@49 2620 //! returns true if all of the elements are finite
Chris@49 2621 template<typename eT>
Chris@49 2622 inline
Chris@49 2623 arma_warn_unused
Chris@49 2624 bool
Chris@49 2625 SpMat<eT>::is_finite() const
Chris@49 2626 {
Chris@49 2627 for(uword i = 0; i < n_nonzero; i++)
Chris@49 2628 {
Chris@49 2629 if(arma_isfinite(values[i]) == false)
Chris@49 2630 {
Chris@49 2631 return false;
Chris@49 2632 }
Chris@49 2633 }
Chris@49 2634
Chris@49 2635 return true; // No infinite values.
Chris@49 2636 }
Chris@49 2637
Chris@49 2638
Chris@49 2639
Chris@49 2640 //! returns true if the given index is currently in range
Chris@49 2641 template<typename eT>
Chris@49 2642 arma_inline
Chris@49 2643 arma_warn_unused
Chris@49 2644 bool
Chris@49 2645 SpMat<eT>::in_range(const uword i) const
Chris@49 2646 {
Chris@49 2647 return (i < n_elem);
Chris@49 2648 }
Chris@49 2649
Chris@49 2650
Chris@49 2651 //! returns true if the given start and end indices are currently in range
Chris@49 2652 template<typename eT>
Chris@49 2653 arma_inline
Chris@49 2654 arma_warn_unused
Chris@49 2655 bool
Chris@49 2656 SpMat<eT>::in_range(const span& x) const
Chris@49 2657 {
Chris@49 2658 arma_extra_debug_sigprint();
Chris@49 2659
Chris@49 2660 if(x.whole == true)
Chris@49 2661 {
Chris@49 2662 return true;
Chris@49 2663 }
Chris@49 2664 else
Chris@49 2665 {
Chris@49 2666 const uword a = x.a;
Chris@49 2667 const uword b = x.b;
Chris@49 2668
Chris@49 2669 return ( (a <= b) && (b < n_elem) );
Chris@49 2670 }
Chris@49 2671 }
Chris@49 2672
Chris@49 2673
Chris@49 2674
Chris@49 2675 //! returns true if the given location is currently in range
Chris@49 2676 template<typename eT>
Chris@49 2677 arma_inline
Chris@49 2678 arma_warn_unused
Chris@49 2679 bool
Chris@49 2680 SpMat<eT>::in_range(const uword in_row, const uword in_col) const
Chris@49 2681 {
Chris@49 2682 return ( (in_row < n_rows) && (in_col < n_cols) );
Chris@49 2683 }
Chris@49 2684
Chris@49 2685
Chris@49 2686
Chris@49 2687 template<typename eT>
Chris@49 2688 arma_inline
Chris@49 2689 arma_warn_unused
Chris@49 2690 bool
Chris@49 2691 SpMat<eT>::in_range(const span& row_span, const uword in_col) const
Chris@49 2692 {
Chris@49 2693 arma_extra_debug_sigprint();
Chris@49 2694
Chris@49 2695 if(row_span.whole == true)
Chris@49 2696 {
Chris@49 2697 return (in_col < n_cols);
Chris@49 2698 }
Chris@49 2699 else
Chris@49 2700 {
Chris@49 2701 const uword in_row1 = row_span.a;
Chris@49 2702 const uword in_row2 = row_span.b;
Chris@49 2703
Chris@49 2704 return ( (in_row1 <= in_row2) && (in_row2 < n_rows) && (in_col < n_cols) );
Chris@49 2705 }
Chris@49 2706 }
Chris@49 2707
Chris@49 2708
Chris@49 2709
Chris@49 2710 template<typename eT>
Chris@49 2711 arma_inline
Chris@49 2712 arma_warn_unused
Chris@49 2713 bool
Chris@49 2714 SpMat<eT>::in_range(const uword in_row, const span& col_span) const
Chris@49 2715 {
Chris@49 2716 arma_extra_debug_sigprint();
Chris@49 2717
Chris@49 2718 if(col_span.whole == true)
Chris@49 2719 {
Chris@49 2720 return (in_row < n_rows);
Chris@49 2721 }
Chris@49 2722 else
Chris@49 2723 {
Chris@49 2724 const uword in_col1 = col_span.a;
Chris@49 2725 const uword in_col2 = col_span.b;
Chris@49 2726
Chris@49 2727 return ( (in_row < n_rows) && (in_col1 <= in_col2) && (in_col2 < n_cols) );
Chris@49 2728 }
Chris@49 2729 }
Chris@49 2730
Chris@49 2731
Chris@49 2732
Chris@49 2733 template<typename eT>
Chris@49 2734 arma_inline
Chris@49 2735 arma_warn_unused
Chris@49 2736 bool
Chris@49 2737 SpMat<eT>::in_range(const span& row_span, const span& col_span) const
Chris@49 2738 {
Chris@49 2739 arma_extra_debug_sigprint();
Chris@49 2740
Chris@49 2741 const uword in_row1 = row_span.a;
Chris@49 2742 const uword in_row2 = row_span.b;
Chris@49 2743
Chris@49 2744 const uword in_col1 = col_span.a;
Chris@49 2745 const uword in_col2 = col_span.b;
Chris@49 2746
Chris@49 2747 const bool rows_ok = row_span.whole ? true : ( (in_row1 <= in_row2) && (in_row2 < n_rows) );
Chris@49 2748 const bool cols_ok = col_span.whole ? true : ( (in_col1 <= in_col2) && (in_col2 < n_cols) );
Chris@49 2749
Chris@49 2750 return ( (rows_ok == true) && (cols_ok == true) );
Chris@49 2751 }
Chris@49 2752
Chris@49 2753
Chris@49 2754
Chris@49 2755 template<typename eT>
Chris@49 2756 inline
Chris@49 2757 void
Chris@49 2758 SpMat<eT>::impl_print(const std::string& extra_text) const
Chris@49 2759 {
Chris@49 2760 arma_extra_debug_sigprint();
Chris@49 2761
Chris@49 2762 if(extra_text.length() != 0)
Chris@49 2763 {
Chris@49 2764 const std::streamsize orig_width = ARMA_DEFAULT_OSTREAM.width();
Chris@49 2765
Chris@49 2766 ARMA_DEFAULT_OSTREAM << extra_text << '\n';
Chris@49 2767
Chris@49 2768 ARMA_DEFAULT_OSTREAM.width(orig_width);
Chris@49 2769 }
Chris@49 2770
Chris@49 2771 arma_ostream::print(ARMA_DEFAULT_OSTREAM, *this, true);
Chris@49 2772 }
Chris@49 2773
Chris@49 2774
Chris@49 2775
Chris@49 2776 template<typename eT>
Chris@49 2777 inline
Chris@49 2778 void
Chris@49 2779 SpMat<eT>::impl_print(std::ostream& user_stream, const std::string& extra_text) const
Chris@49 2780 {
Chris@49 2781 arma_extra_debug_sigprint();
Chris@49 2782
Chris@49 2783 if(extra_text.length() != 0)
Chris@49 2784 {
Chris@49 2785 const std::streamsize orig_width = user_stream.width();
Chris@49 2786
Chris@49 2787 user_stream << extra_text << '\n';
Chris@49 2788
Chris@49 2789 user_stream.width(orig_width);
Chris@49 2790 }
Chris@49 2791
Chris@49 2792 arma_ostream::print(user_stream, *this, true);
Chris@49 2793 }
Chris@49 2794
Chris@49 2795
Chris@49 2796
Chris@49 2797 template<typename eT>
Chris@49 2798 inline
Chris@49 2799 void
Chris@49 2800 SpMat<eT>::impl_raw_print(const std::string& extra_text) const
Chris@49 2801 {
Chris@49 2802 arma_extra_debug_sigprint();
Chris@49 2803
Chris@49 2804 if(extra_text.length() != 0)
Chris@49 2805 {
Chris@49 2806 const std::streamsize orig_width = ARMA_DEFAULT_OSTREAM.width();
Chris@49 2807
Chris@49 2808 ARMA_DEFAULT_OSTREAM << extra_text << '\n';
Chris@49 2809
Chris@49 2810 ARMA_DEFAULT_OSTREAM.width(orig_width);
Chris@49 2811 }
Chris@49 2812
Chris@49 2813 arma_ostream::print(ARMA_DEFAULT_OSTREAM, *this, false);
Chris@49 2814 }
Chris@49 2815
Chris@49 2816
Chris@49 2817 template<typename eT>
Chris@49 2818 inline
Chris@49 2819 void
Chris@49 2820 SpMat<eT>::impl_raw_print(std::ostream& user_stream, const std::string& extra_text) const
Chris@49 2821 {
Chris@49 2822 arma_extra_debug_sigprint();
Chris@49 2823
Chris@49 2824 if(extra_text.length() != 0)
Chris@49 2825 {
Chris@49 2826 const std::streamsize orig_width = user_stream.width();
Chris@49 2827
Chris@49 2828 user_stream << extra_text << '\n';
Chris@49 2829
Chris@49 2830 user_stream.width(orig_width);
Chris@49 2831 }
Chris@49 2832
Chris@49 2833 arma_ostream::print(user_stream, *this, false);
Chris@49 2834 }
Chris@49 2835
Chris@49 2836
Chris@49 2837
Chris@49 2838 /**
Chris@49 2839 * Matrix printing, prepends supplied text.
Chris@49 2840 * Prints 0 wherever no element exists.
Chris@49 2841 */
Chris@49 2842 template<typename eT>
Chris@49 2843 inline
Chris@49 2844 void
Chris@49 2845 SpMat<eT>::impl_print_dense(const std::string& extra_text) const
Chris@49 2846 {
Chris@49 2847 arma_extra_debug_sigprint();
Chris@49 2848
Chris@49 2849 if(extra_text.length() != 0)
Chris@49 2850 {
Chris@49 2851 const std::streamsize orig_width = ARMA_DEFAULT_OSTREAM.width();
Chris@49 2852
Chris@49 2853 ARMA_DEFAULT_OSTREAM << extra_text << '\n';
Chris@49 2854
Chris@49 2855 ARMA_DEFAULT_OSTREAM.width(orig_width);
Chris@49 2856 }
Chris@49 2857
Chris@49 2858 arma_ostream::print_dense(ARMA_DEFAULT_OSTREAM, *this, true);
Chris@49 2859 }
Chris@49 2860
Chris@49 2861
Chris@49 2862
Chris@49 2863 template<typename eT>
Chris@49 2864 inline
Chris@49 2865 void
Chris@49 2866 SpMat<eT>::impl_print_dense(std::ostream& user_stream, const std::string& extra_text) const
Chris@49 2867 {
Chris@49 2868 arma_extra_debug_sigprint();
Chris@49 2869
Chris@49 2870 if(extra_text.length() != 0)
Chris@49 2871 {
Chris@49 2872 const std::streamsize orig_width = user_stream.width();
Chris@49 2873
Chris@49 2874 user_stream << extra_text << '\n';
Chris@49 2875
Chris@49 2876 user_stream.width(orig_width);
Chris@49 2877 }
Chris@49 2878
Chris@49 2879 arma_ostream::print_dense(user_stream, *this, true);
Chris@49 2880 }
Chris@49 2881
Chris@49 2882
Chris@49 2883
Chris@49 2884 template<typename eT>
Chris@49 2885 inline
Chris@49 2886 void
Chris@49 2887 SpMat<eT>::impl_raw_print_dense(const std::string& extra_text) const
Chris@49 2888 {
Chris@49 2889 arma_extra_debug_sigprint();
Chris@49 2890
Chris@49 2891 if(extra_text.length() != 0)
Chris@49 2892 {
Chris@49 2893 const std::streamsize orig_width = ARMA_DEFAULT_OSTREAM.width();
Chris@49 2894
Chris@49 2895 ARMA_DEFAULT_OSTREAM << extra_text << '\n';
Chris@49 2896
Chris@49 2897 ARMA_DEFAULT_OSTREAM.width(orig_width);
Chris@49 2898 }
Chris@49 2899
Chris@49 2900 arma_ostream::print_dense(ARMA_DEFAULT_OSTREAM, *this, false);
Chris@49 2901 }
Chris@49 2902
Chris@49 2903
Chris@49 2904
Chris@49 2905 template<typename eT>
Chris@49 2906 inline
Chris@49 2907 void
Chris@49 2908 SpMat<eT>::impl_raw_print_dense(std::ostream& user_stream, const std::string& extra_text) const
Chris@49 2909 {
Chris@49 2910 arma_extra_debug_sigprint();
Chris@49 2911
Chris@49 2912 if(extra_text.length() != 0)
Chris@49 2913 {
Chris@49 2914 const std::streamsize orig_width = user_stream.width();
Chris@49 2915
Chris@49 2916 user_stream << extra_text << '\n';
Chris@49 2917
Chris@49 2918 user_stream.width(orig_width);
Chris@49 2919 }
Chris@49 2920
Chris@49 2921 arma_ostream::print_dense(user_stream, *this, false);
Chris@49 2922 }
Chris@49 2923
Chris@49 2924
Chris@49 2925
Chris@49 2926 //! Set the size to the size of another matrix.
Chris@49 2927 template<typename eT>
Chris@49 2928 template<typename eT2>
Chris@49 2929 inline
Chris@49 2930 void
Chris@49 2931 SpMat<eT>::copy_size(const SpMat<eT2>& m)
Chris@49 2932 {
Chris@49 2933 arma_extra_debug_sigprint();
Chris@49 2934
Chris@49 2935 init(m.n_rows, m.n_cols);
Chris@49 2936 }
Chris@49 2937
Chris@49 2938
Chris@49 2939
Chris@49 2940 template<typename eT>
Chris@49 2941 template<typename eT2>
Chris@49 2942 inline
Chris@49 2943 void
Chris@49 2944 SpMat<eT>::copy_size(const Mat<eT2>& m)
Chris@49 2945 {
Chris@49 2946 arma_extra_debug_sigprint();
Chris@49 2947
Chris@49 2948 init(m.n_rows, m.n_cols);
Chris@49 2949 }
Chris@49 2950
Chris@49 2951
Chris@49 2952
Chris@49 2953 /**
Chris@49 2954 * Resize the matrix to a given size. The matrix will be resized to be a column vector (i.e. in_elem columns, 1 row).
Chris@49 2955 *
Chris@49 2956 * @param in_elem Number of elements to allow.
Chris@49 2957 */
Chris@49 2958 template<typename eT>
Chris@49 2959 inline
Chris@49 2960 void
Chris@49 2961 SpMat<eT>::set_size(const uword in_elem)
Chris@49 2962 {
Chris@49 2963 arma_extra_debug_sigprint();
Chris@49 2964
Chris@49 2965 // If this is a row vector, we resize to a row vector.
Chris@49 2966 if(vec_state == 2)
Chris@49 2967 {
Chris@49 2968 init(1, in_elem);
Chris@49 2969 }
Chris@49 2970 else
Chris@49 2971 {
Chris@49 2972 init(in_elem, 1);
Chris@49 2973 }
Chris@49 2974 }
Chris@49 2975
Chris@49 2976
Chris@49 2977
Chris@49 2978 /**
Chris@49 2979 * Resize the matrix to a given size.
Chris@49 2980 *
Chris@49 2981 * @param in_rows Number of rows to allow.
Chris@49 2982 * @param in_cols Number of columns to allow.
Chris@49 2983 */
Chris@49 2984 template<typename eT>
Chris@49 2985 inline
Chris@49 2986 void
Chris@49 2987 SpMat<eT>::set_size(const uword in_rows, const uword in_cols)
Chris@49 2988 {
Chris@49 2989 arma_extra_debug_sigprint();
Chris@49 2990
Chris@49 2991 init(in_rows, in_cols);
Chris@49 2992 }
Chris@49 2993
Chris@49 2994
Chris@49 2995
Chris@49 2996 template<typename eT>
Chris@49 2997 inline
Chris@49 2998 void
Chris@49 2999 SpMat<eT>::reshape(const uword in_rows, const uword in_cols, const uword dim)
Chris@49 3000 {
Chris@49 3001 arma_extra_debug_sigprint();
Chris@49 3002
Chris@49 3003 if (dim == 0)
Chris@49 3004 {
Chris@49 3005 // We have to modify all of the relevant row indices and the relevant column pointers.
Chris@49 3006 // Iterate over all the points to do this. We won't be deleting any points, but we will be modifying
Chris@49 3007 // columns and rows. We'll have to store a new set of column vectors.
Chris@49 3008 uword* new_col_ptrs = memory::acquire<uword>(in_cols + 2);
Chris@49 3009 new_col_ptrs[in_cols + 1] = std::numeric_limits<uword>::max();
Chris@49 3010
Chris@49 3011 uword* new_row_indices = memory::acquire_chunked<uword>(n_nonzero + 1);
Chris@49 3012 access::rw(new_row_indices[n_nonzero]) = 0;
Chris@49 3013
Chris@49 3014 arrayops::inplace_set(new_col_ptrs, uword(0), in_cols + 1);
Chris@49 3015
Chris@49 3016 for(const_iterator it = begin(); it != end(); it++)
Chris@49 3017 {
Chris@49 3018 uword vector_position = (it.col() * n_rows) + it.row();
Chris@49 3019 new_row_indices[it.pos()] = vector_position % in_rows;
Chris@49 3020 ++new_col_ptrs[vector_position / in_rows + 1];
Chris@49 3021 }
Chris@49 3022
Chris@49 3023 // Now sum the column counts to get the new column pointers.
Chris@49 3024 for(uword i = 1; i <= in_cols; i++)
Chris@49 3025 {
Chris@49 3026 access::rw(new_col_ptrs[i]) += new_col_ptrs[i - 1];
Chris@49 3027 }
Chris@49 3028
Chris@49 3029 // Copy the new row indices.
Chris@49 3030 memory::release(row_indices);
Chris@49 3031 access::rw(row_indices) = new_row_indices;
Chris@49 3032
Chris@49 3033 memory::release(col_ptrs);
Chris@49 3034 access::rw(col_ptrs) = new_col_ptrs;
Chris@49 3035
Chris@49 3036 // Now set the size.
Chris@49 3037 access::rw(n_rows) = in_rows;
Chris@49 3038 access::rw(n_cols) = in_cols;
Chris@49 3039 }
Chris@49 3040 else
Chris@49 3041 {
Chris@49 3042 // Row-wise reshaping. This is more tedious and we will use a separate sparse matrix to do it.
Chris@49 3043 SpMat<eT> tmp(in_rows, in_cols);
Chris@49 3044
Chris@49 3045 for(const_row_iterator it = begin_row(); it.pos() < n_nonzero; it++)
Chris@49 3046 {
Chris@49 3047 uword vector_position = (it.row() * n_cols) + it.col();
Chris@49 3048
Chris@49 3049 tmp((vector_position / in_cols), (vector_position % in_cols)) = (*it);
Chris@49 3050 }
Chris@49 3051
Chris@49 3052 (*this).operator=(tmp);
Chris@49 3053 }
Chris@49 3054 }
Chris@49 3055
Chris@49 3056
Chris@49 3057
Chris@49 3058 template<typename eT>
Chris@49 3059 inline
Chris@49 3060 const SpMat<eT>&
Chris@49 3061 SpMat<eT>::zeros()
Chris@49 3062 {
Chris@49 3063 arma_extra_debug_sigprint();
Chris@49 3064
Chris@49 3065 if (n_nonzero > 0)
Chris@49 3066 {
Chris@49 3067 memory::release(values);
Chris@49 3068 memory::release(row_indices);
Chris@49 3069
Chris@49 3070 access::rw(values) = memory::acquire_chunked<eT>(1);
Chris@49 3071 access::rw(row_indices) = memory::acquire_chunked<uword>(1);
Chris@49 3072
Chris@49 3073 access::rw(values[0]) = 0;
Chris@49 3074 access::rw(row_indices[0]) = 0;
Chris@49 3075 }
Chris@49 3076
Chris@49 3077 access::rw(n_nonzero) = 0;
Chris@49 3078 arrayops::inplace_set(access::rwp(col_ptrs), uword(0), n_cols + 1);
Chris@49 3079
Chris@49 3080 return *this;
Chris@49 3081 }
Chris@49 3082
Chris@49 3083
Chris@49 3084
Chris@49 3085 template<typename eT>
Chris@49 3086 inline
Chris@49 3087 const SpMat<eT>&
Chris@49 3088 SpMat<eT>::zeros(const uword in_elem)
Chris@49 3089 {
Chris@49 3090 arma_extra_debug_sigprint();
Chris@49 3091
Chris@49 3092 if(vec_state == 2)
Chris@49 3093 {
Chris@49 3094 init(1, in_elem); // Row vector
Chris@49 3095 }
Chris@49 3096 else
Chris@49 3097 {
Chris@49 3098 init(in_elem, 1);
Chris@49 3099 }
Chris@49 3100
Chris@49 3101 return *this;
Chris@49 3102 }
Chris@49 3103
Chris@49 3104
Chris@49 3105
Chris@49 3106 template<typename eT>
Chris@49 3107 inline
Chris@49 3108 const SpMat<eT>&
Chris@49 3109 SpMat<eT>::zeros(const uword in_rows, const uword in_cols)
Chris@49 3110 {
Chris@49 3111 arma_extra_debug_sigprint();
Chris@49 3112
Chris@49 3113 init(in_rows, in_cols);
Chris@49 3114
Chris@49 3115 return *this;
Chris@49 3116 }
Chris@49 3117
Chris@49 3118
Chris@49 3119
Chris@49 3120 template<typename eT>
Chris@49 3121 inline
Chris@49 3122 const SpMat<eT>&
Chris@49 3123 SpMat<eT>::eye()
Chris@49 3124 {
Chris@49 3125 arma_extra_debug_sigprint();
Chris@49 3126
Chris@49 3127 return (*this).eye(n_rows, n_cols);
Chris@49 3128 }
Chris@49 3129
Chris@49 3130
Chris@49 3131
Chris@49 3132 template<typename eT>
Chris@49 3133 inline
Chris@49 3134 const SpMat<eT>&
Chris@49 3135 SpMat<eT>::eye(const uword in_rows, const uword in_cols)
Chris@49 3136 {
Chris@49 3137 arma_extra_debug_sigprint();
Chris@49 3138
Chris@49 3139 const uword N = (std::min)(in_rows, in_cols);
Chris@49 3140
Chris@49 3141 init(in_rows, in_cols);
Chris@49 3142
Chris@49 3143 mem_resize(N);
Chris@49 3144
Chris@49 3145 arrayops::inplace_set(access::rwp(values), eT(1), N);
Chris@49 3146
Chris@49 3147 for(uword i = 0; i < N; ++i) { access::rw(row_indices[i]) = i; }
Chris@49 3148
Chris@49 3149 for(uword i = 0; i <= N; ++i) { access::rw(col_ptrs[i]) = i; }
Chris@49 3150
Chris@49 3151 access::rw(n_nonzero) = N;
Chris@49 3152
Chris@49 3153 return *this;
Chris@49 3154 }
Chris@49 3155
Chris@49 3156
Chris@49 3157
Chris@49 3158 template<typename eT>
Chris@49 3159 inline
Chris@49 3160 const SpMat<eT>&
Chris@49 3161 SpMat<eT>::speye()
Chris@49 3162 {
Chris@49 3163 arma_extra_debug_sigprint();
Chris@49 3164
Chris@49 3165 return (*this).eye(n_rows, n_cols);
Chris@49 3166 }
Chris@49 3167
Chris@49 3168
Chris@49 3169
Chris@49 3170 template<typename eT>
Chris@49 3171 inline
Chris@49 3172 const SpMat<eT>&
Chris@49 3173 SpMat<eT>::speye(const uword in_n_rows, const uword in_n_cols)
Chris@49 3174 {
Chris@49 3175 arma_extra_debug_sigprint();
Chris@49 3176
Chris@49 3177 return (*this).eye(in_n_rows, in_n_cols);
Chris@49 3178 }
Chris@49 3179
Chris@49 3180
Chris@49 3181
Chris@49 3182 template<typename eT>
Chris@49 3183 inline
Chris@49 3184 const SpMat<eT>&
Chris@49 3185 SpMat<eT>::sprandu(const uword in_rows, const uword in_cols, const double density)
Chris@49 3186 {
Chris@49 3187 arma_extra_debug_sigprint();
Chris@49 3188
Chris@49 3189 arma_debug_check( ( (density < double(0)) || (density > double(1)) ), "sprandu(): density must be in the [0,1] interval" );
Chris@49 3190
Chris@49 3191 zeros(in_rows, in_cols);
Chris@49 3192
Chris@49 3193 mem_resize( uword(density * double(in_rows) * double(in_cols) + 0.5) );
Chris@49 3194
Chris@49 3195 if(n_nonzero == 0)
Chris@49 3196 {
Chris@49 3197 return *this;
Chris@49 3198 }
Chris@49 3199
Chris@49 3200 eop_aux_randu<eT>::fill( access::rwp(values), n_nonzero );
Chris@49 3201
Chris@49 3202 uvec indices = linspace<uvec>( 0u, in_rows*in_cols-1, n_nonzero );
Chris@49 3203
Chris@49 3204 // perturb the indices
Chris@49 3205 for(uword i=1; i < n_nonzero-1; ++i)
Chris@49 3206 {
Chris@49 3207 const uword index_left = indices[i-1];
Chris@49 3208 const uword index_right = indices[i+1];
Chris@49 3209
Chris@49 3210 const uword center = (index_left + index_right) / 2;
Chris@49 3211
Chris@49 3212 const uword delta1 = center - index_left - 1;
Chris@49 3213 const uword delta2 = index_right - center - 1;
Chris@49 3214
Chris@49 3215 const uword min_delta = (std::min)(delta1, delta2);
Chris@49 3216
Chris@49 3217 uword index_new = uword( double(center) + double(min_delta) * (2.0*randu()-1.0) );
Chris@49 3218
Chris@49 3219 // paranoia, but better be safe than sorry
Chris@49 3220 if( (index_left < index_new) && (index_new < index_right) )
Chris@49 3221 {
Chris@49 3222 indices[i] = index_new;
Chris@49 3223 }
Chris@49 3224 }
Chris@49 3225
Chris@49 3226 uword cur_index = 0;
Chris@49 3227 uword count = 0;
Chris@49 3228
Chris@49 3229 for(uword lcol = 0; lcol < in_cols; ++lcol)
Chris@49 3230 for(uword lrow = 0; lrow < in_rows; ++lrow)
Chris@49 3231 {
Chris@49 3232 if(count == indices[cur_index])
Chris@49 3233 {
Chris@49 3234 access::rw(row_indices[cur_index]) = lrow;
Chris@49 3235 access::rw(col_ptrs[lcol + 1])++;
Chris@49 3236 ++cur_index;
Chris@49 3237 }
Chris@49 3238
Chris@49 3239 ++count;
Chris@49 3240 }
Chris@49 3241
Chris@49 3242 if(cur_index != n_nonzero)
Chris@49 3243 {
Chris@49 3244 // Fix size to correct size.
Chris@49 3245 mem_resize(cur_index);
Chris@49 3246 }
Chris@49 3247
Chris@49 3248 // Sum column pointers.
Chris@49 3249 for(uword lcol = 1; lcol <= in_cols; ++lcol)
Chris@49 3250 {
Chris@49 3251 access::rw(col_ptrs[lcol]) += col_ptrs[lcol - 1];
Chris@49 3252 }
Chris@49 3253
Chris@49 3254 return *this;
Chris@49 3255 }
Chris@49 3256
Chris@49 3257
Chris@49 3258
Chris@49 3259 template<typename eT>
Chris@49 3260 inline
Chris@49 3261 const SpMat<eT>&
Chris@49 3262 SpMat<eT>::sprandn(const uword in_rows, const uword in_cols, const double density)
Chris@49 3263 {
Chris@49 3264 arma_extra_debug_sigprint();
Chris@49 3265
Chris@49 3266 arma_debug_check( ( (density < double(0)) || (density > double(1)) ), "sprandn(): density must be in the [0,1] interval" );
Chris@49 3267
Chris@49 3268 zeros(in_rows, in_cols);
Chris@49 3269
Chris@49 3270 mem_resize( uword(density * double(in_rows) * double(in_cols) + 0.5) );
Chris@49 3271
Chris@49 3272 if(n_nonzero == 0)
Chris@49 3273 {
Chris@49 3274 return *this;
Chris@49 3275 }
Chris@49 3276
Chris@49 3277 eop_aux_randn<eT>::fill( access::rwp(values), n_nonzero );
Chris@49 3278
Chris@49 3279 uvec indices = linspace<uvec>( 0u, in_rows*in_cols-1, n_nonzero );
Chris@49 3280
Chris@49 3281 // perturb the indices
Chris@49 3282 for(uword i=1; i < n_nonzero-1; ++i)
Chris@49 3283 {
Chris@49 3284 const uword index_left = indices[i-1];
Chris@49 3285 const uword index_right = indices[i+1];
Chris@49 3286
Chris@49 3287 const uword center = (index_left + index_right) / 2;
Chris@49 3288
Chris@49 3289 const uword delta1 = center - index_left - 1;
Chris@49 3290 const uword delta2 = index_right - center - 1;
Chris@49 3291
Chris@49 3292 const uword min_delta = (std::min)(delta1, delta2);
Chris@49 3293
Chris@49 3294 uword index_new = uword( double(center) + double(min_delta) * (2.0*randu()-1.0) );
Chris@49 3295
Chris@49 3296 // paranoia, but better be safe than sorry
Chris@49 3297 if( (index_left < index_new) && (index_new < index_right) )
Chris@49 3298 {
Chris@49 3299 indices[i] = index_new;
Chris@49 3300 }
Chris@49 3301 }
Chris@49 3302
Chris@49 3303 uword cur_index = 0;
Chris@49 3304 uword count = 0;
Chris@49 3305
Chris@49 3306 for(uword lcol = 0; lcol < in_cols; ++lcol)
Chris@49 3307 for(uword lrow = 0; lrow < in_rows; ++lrow)
Chris@49 3308 {
Chris@49 3309 if(count == indices[cur_index])
Chris@49 3310 {
Chris@49 3311 access::rw(row_indices[cur_index]) = lrow;
Chris@49 3312 access::rw(col_ptrs[lcol + 1])++;
Chris@49 3313 ++cur_index;
Chris@49 3314 }
Chris@49 3315
Chris@49 3316 ++count;
Chris@49 3317 }
Chris@49 3318
Chris@49 3319 if(cur_index != n_nonzero)
Chris@49 3320 {
Chris@49 3321 // Fix size to correct size.
Chris@49 3322 mem_resize(cur_index);
Chris@49 3323 }
Chris@49 3324
Chris@49 3325 // Sum column pointers.
Chris@49 3326 for(uword lcol = 1; lcol <= in_cols; ++lcol)
Chris@49 3327 {
Chris@49 3328 access::rw(col_ptrs[lcol]) += col_ptrs[lcol - 1];
Chris@49 3329 }
Chris@49 3330
Chris@49 3331 return *this;
Chris@49 3332 }
Chris@49 3333
Chris@49 3334
Chris@49 3335
Chris@49 3336 template<typename eT>
Chris@49 3337 inline
Chris@49 3338 void
Chris@49 3339 SpMat<eT>::reset()
Chris@49 3340 {
Chris@49 3341 arma_extra_debug_sigprint();
Chris@49 3342
Chris@49 3343 set_size(0, 0);
Chris@49 3344 }
Chris@49 3345
Chris@49 3346
Chris@49 3347
Chris@49 3348 /**
Chris@49 3349 * Get the minimum or the maximum of the matrix.
Chris@49 3350 */
Chris@49 3351 template<typename eT>
Chris@49 3352 inline
Chris@49 3353 arma_warn_unused
Chris@49 3354 eT
Chris@49 3355 SpMat<eT>::min() const
Chris@49 3356 {
Chris@49 3357 arma_extra_debug_sigprint();
Chris@49 3358
Chris@49 3359 arma_debug_check((n_elem == 0), "min(): object has no elements");
Chris@49 3360
Chris@49 3361 if (n_nonzero == 0)
Chris@49 3362 {
Chris@49 3363 return 0;
Chris@49 3364 }
Chris@49 3365
Chris@49 3366 eT val = op_min::direct_min(values, n_nonzero);
Chris@49 3367
Chris@49 3368 if ((val > 0) && (n_nonzero < n_elem)) // A sparse 0 is less.
Chris@49 3369 {
Chris@49 3370 val = 0;
Chris@49 3371 }
Chris@49 3372
Chris@49 3373 return val;
Chris@49 3374 }
Chris@49 3375
Chris@49 3376
Chris@49 3377
Chris@49 3378 template<typename eT>
Chris@49 3379 inline
Chris@49 3380 eT
Chris@49 3381 SpMat<eT>::min(uword& index_of_min_val) const
Chris@49 3382 {
Chris@49 3383 arma_extra_debug_sigprint();
Chris@49 3384
Chris@49 3385 arma_debug_check((n_elem == 0), "min(): object has no elements");
Chris@49 3386
Chris@49 3387 eT val = 0;
Chris@49 3388
Chris@49 3389 if (n_nonzero == 0) // There are no other elements. It must be 0.
Chris@49 3390 {
Chris@49 3391 index_of_min_val = 0;
Chris@49 3392 }
Chris@49 3393 else
Chris@49 3394 {
Chris@49 3395 uword location;
Chris@49 3396 val = op_min::direct_min(values, n_nonzero, location);
Chris@49 3397
Chris@49 3398 if ((val > 0) && (n_nonzero < n_elem)) // A sparse 0 is less.
Chris@49 3399 {
Chris@49 3400 val = 0;
Chris@49 3401
Chris@49 3402 // Give back the index to the first zero position.
Chris@49 3403 index_of_min_val = 0;
Chris@49 3404 while (get_position(index_of_min_val) == index_of_min_val) // An element exists at that position.
Chris@49 3405 {
Chris@49 3406 index_of_min_val++;
Chris@49 3407 }
Chris@49 3408
Chris@49 3409 }
Chris@49 3410 else
Chris@49 3411 {
Chris@49 3412 index_of_min_val = get_position(location);
Chris@49 3413 }
Chris@49 3414 }
Chris@49 3415
Chris@49 3416 return val;
Chris@49 3417
Chris@49 3418 }
Chris@49 3419
Chris@49 3420
Chris@49 3421
Chris@49 3422 template<typename eT>
Chris@49 3423 inline
Chris@49 3424 eT
Chris@49 3425 SpMat<eT>::min(uword& row_of_min_val, uword& col_of_min_val) const
Chris@49 3426 {
Chris@49 3427 arma_extra_debug_sigprint();
Chris@49 3428
Chris@49 3429 arma_debug_check((n_elem == 0), "min(): object has no elements");
Chris@49 3430
Chris@49 3431 eT val = 0;
Chris@49 3432
Chris@49 3433 if (n_nonzero == 0) // There are no other elements. It must be 0.
Chris@49 3434 {
Chris@49 3435 row_of_min_val = 0;
Chris@49 3436 col_of_min_val = 0;
Chris@49 3437 }
Chris@49 3438 else
Chris@49 3439 {
Chris@49 3440 uword location;
Chris@49 3441 val = op_min::direct_min(values, n_nonzero, location);
Chris@49 3442
Chris@49 3443 if ((val > 0) && (n_nonzero < n_elem)) // A sparse 0 is less.
Chris@49 3444 {
Chris@49 3445 val = 0;
Chris@49 3446
Chris@49 3447 location = 0;
Chris@49 3448 while (get_position(location) == location) // An element exists at that position.
Chris@49 3449 {
Chris@49 3450 location++;
Chris@49 3451 }
Chris@49 3452
Chris@49 3453 row_of_min_val = location % n_rows;
Chris@49 3454 col_of_min_val = location / n_rows;
Chris@49 3455 }
Chris@49 3456 else
Chris@49 3457 {
Chris@49 3458 get_position(location, row_of_min_val, col_of_min_val);
Chris@49 3459 }
Chris@49 3460 }
Chris@49 3461
Chris@49 3462 return val;
Chris@49 3463
Chris@49 3464 }
Chris@49 3465
Chris@49 3466
Chris@49 3467
Chris@49 3468 template<typename eT>
Chris@49 3469 inline
Chris@49 3470 arma_warn_unused
Chris@49 3471 eT
Chris@49 3472 SpMat<eT>::max() const
Chris@49 3473 {
Chris@49 3474 arma_extra_debug_sigprint();
Chris@49 3475
Chris@49 3476 arma_debug_check((n_elem == 0), "max(): object has no elements");
Chris@49 3477
Chris@49 3478 if (n_nonzero == 0)
Chris@49 3479 {
Chris@49 3480 return 0;
Chris@49 3481 }
Chris@49 3482
Chris@49 3483 eT val = op_max::direct_max(values, n_nonzero);
Chris@49 3484
Chris@49 3485 if ((val < 0) && (n_nonzero < n_elem)) // A sparse 0 is more.
Chris@49 3486 {
Chris@49 3487 return 0;
Chris@49 3488 }
Chris@49 3489
Chris@49 3490 return val;
Chris@49 3491
Chris@49 3492 }
Chris@49 3493
Chris@49 3494
Chris@49 3495
Chris@49 3496 template<typename eT>
Chris@49 3497 inline
Chris@49 3498 eT
Chris@49 3499 SpMat<eT>::max(uword& index_of_max_val) const
Chris@49 3500 {
Chris@49 3501 arma_extra_debug_sigprint();
Chris@49 3502
Chris@49 3503 arma_debug_check((n_elem == 0), "max(): object has no elements");
Chris@49 3504
Chris@49 3505 eT val = 0;
Chris@49 3506
Chris@49 3507 if (n_nonzero == 0)
Chris@49 3508 {
Chris@49 3509 index_of_max_val = 0;
Chris@49 3510 }
Chris@49 3511 else
Chris@49 3512 {
Chris@49 3513 uword location;
Chris@49 3514 val = op_max::direct_max(values, n_nonzero, location);
Chris@49 3515
Chris@49 3516 if ((val < 0) && (n_nonzero < n_elem)) // A sparse 0 is more.
Chris@49 3517 {
Chris@49 3518 val = 0;
Chris@49 3519
Chris@49 3520 location = 0;
Chris@49 3521 while (get_position(location) == location) // An element exists at that position.
Chris@49 3522 {
Chris@49 3523 location++;
Chris@49 3524 }
Chris@49 3525
Chris@49 3526 }
Chris@49 3527 else
Chris@49 3528 {
Chris@49 3529 index_of_max_val = get_position(location);
Chris@49 3530 }
Chris@49 3531
Chris@49 3532 }
Chris@49 3533
Chris@49 3534 return val;
Chris@49 3535
Chris@49 3536 }
Chris@49 3537
Chris@49 3538
Chris@49 3539
Chris@49 3540 template<typename eT>
Chris@49 3541 inline
Chris@49 3542 eT
Chris@49 3543 SpMat<eT>::max(uword& row_of_max_val, uword& col_of_max_val) const
Chris@49 3544 {
Chris@49 3545 arma_extra_debug_sigprint();
Chris@49 3546
Chris@49 3547 arma_debug_check((n_elem == 0), "max(): object has no elements");
Chris@49 3548
Chris@49 3549 eT val = 0;
Chris@49 3550
Chris@49 3551 if (n_nonzero == 0)
Chris@49 3552 {
Chris@49 3553 row_of_max_val = 0;
Chris@49 3554 col_of_max_val = 0;
Chris@49 3555 }
Chris@49 3556 else
Chris@49 3557 {
Chris@49 3558 uword location;
Chris@49 3559 val = op_max::direct_max(values, n_nonzero, location);
Chris@49 3560
Chris@49 3561 if ((val < 0) && (n_nonzero < n_elem)) // A sparse 0 is more.
Chris@49 3562 {
Chris@49 3563 val = 0;
Chris@49 3564
Chris@49 3565 location = 0;
Chris@49 3566 while (get_position(location) == location) // An element exists at that position.
Chris@49 3567 {
Chris@49 3568 location++;
Chris@49 3569 }
Chris@49 3570
Chris@49 3571 row_of_max_val = location % n_rows;
Chris@49 3572 col_of_max_val = location / n_rows;
Chris@49 3573
Chris@49 3574 }
Chris@49 3575 else
Chris@49 3576 {
Chris@49 3577 get_position(location, row_of_max_val, col_of_max_val);
Chris@49 3578 }
Chris@49 3579
Chris@49 3580 }
Chris@49 3581
Chris@49 3582 return val;
Chris@49 3583
Chris@49 3584 }
Chris@49 3585
Chris@49 3586
Chris@49 3587
Chris@49 3588 //! save the matrix to a file
Chris@49 3589 template<typename eT>
Chris@49 3590 inline
Chris@49 3591 bool
Chris@49 3592 SpMat<eT>::save(const std::string name, const file_type type, const bool print_status) const
Chris@49 3593 {
Chris@49 3594 arma_extra_debug_sigprint();
Chris@49 3595
Chris@49 3596 bool save_okay;
Chris@49 3597
Chris@49 3598 switch(type)
Chris@49 3599 {
Chris@49 3600 // case raw_ascii:
Chris@49 3601 // save_okay = diskio::save_raw_ascii(*this, name);
Chris@49 3602 // break;
Chris@49 3603
Chris@49 3604 // case csv_ascii:
Chris@49 3605 // save_okay = diskio::save_csv_ascii(*this, name);
Chris@49 3606 // break;
Chris@49 3607
Chris@49 3608 case arma_binary:
Chris@49 3609 save_okay = diskio::save_arma_binary(*this, name);
Chris@49 3610 break;
Chris@49 3611
Chris@49 3612 case coord_ascii:
Chris@49 3613 save_okay = diskio::save_coord_ascii(*this, name);
Chris@49 3614 break;
Chris@49 3615
Chris@49 3616 default:
Chris@49 3617 arma_warn(true, "SpMat::save(): unsupported file type");
Chris@49 3618 save_okay = false;
Chris@49 3619 }
Chris@49 3620
Chris@49 3621 arma_warn( (save_okay == false), "SpMat::save(): couldn't write to ", name);
Chris@49 3622
Chris@49 3623 return save_okay;
Chris@49 3624 }
Chris@49 3625
Chris@49 3626
Chris@49 3627
Chris@49 3628 //! save the matrix to a stream
Chris@49 3629 template<typename eT>
Chris@49 3630 inline
Chris@49 3631 bool
Chris@49 3632 SpMat<eT>::save(std::ostream& os, const file_type type, const bool print_status) const
Chris@49 3633 {
Chris@49 3634 arma_extra_debug_sigprint();
Chris@49 3635
Chris@49 3636 bool save_okay;
Chris@49 3637
Chris@49 3638 switch(type)
Chris@49 3639 {
Chris@49 3640 // case raw_ascii:
Chris@49 3641 // save_okay = diskio::save_raw_ascii(*this, os);
Chris@49 3642 // break;
Chris@49 3643
Chris@49 3644 // case csv_ascii:
Chris@49 3645 // save_okay = diskio::save_csv_ascii(*this, os);
Chris@49 3646 // break;
Chris@49 3647
Chris@49 3648 case arma_binary:
Chris@49 3649 save_okay = diskio::save_arma_binary(*this, os);
Chris@49 3650 break;
Chris@49 3651
Chris@49 3652 case coord_ascii:
Chris@49 3653 save_okay = diskio::save_coord_ascii(*this, os);
Chris@49 3654 break;
Chris@49 3655
Chris@49 3656 default:
Chris@49 3657 arma_warn(true, "SpMat::save(): unsupported file type");
Chris@49 3658 save_okay = false;
Chris@49 3659 }
Chris@49 3660
Chris@49 3661 arma_warn( (save_okay == false), "SpMat::save(): couldn't write to the given stream");
Chris@49 3662
Chris@49 3663 return save_okay;
Chris@49 3664 }
Chris@49 3665
Chris@49 3666
Chris@49 3667
Chris@49 3668 //! load a matrix from a file
Chris@49 3669 template<typename eT>
Chris@49 3670 inline
Chris@49 3671 bool
Chris@49 3672 SpMat<eT>::load(const std::string name, const file_type type, const bool print_status)
Chris@49 3673 {
Chris@49 3674 arma_extra_debug_sigprint();
Chris@49 3675
Chris@49 3676 bool load_okay;
Chris@49 3677 std::string err_msg;
Chris@49 3678
Chris@49 3679 switch(type)
Chris@49 3680 {
Chris@49 3681 // case auto_detect:
Chris@49 3682 // load_okay = diskio::load_auto_detect(*this, name, err_msg);
Chris@49 3683 // break;
Chris@49 3684
Chris@49 3685 // case raw_ascii:
Chris@49 3686 // load_okay = diskio::load_raw_ascii(*this, name, err_msg);
Chris@49 3687 // break;
Chris@49 3688
Chris@49 3689 // case csv_ascii:
Chris@49 3690 // load_okay = diskio::load_csv_ascii(*this, name, err_msg);
Chris@49 3691 // break;
Chris@49 3692
Chris@49 3693 case arma_binary:
Chris@49 3694 load_okay = diskio::load_arma_binary(*this, name, err_msg);
Chris@49 3695 break;
Chris@49 3696
Chris@49 3697 case coord_ascii:
Chris@49 3698 load_okay = diskio::load_coord_ascii(*this, name, err_msg);
Chris@49 3699 break;
Chris@49 3700
Chris@49 3701 default:
Chris@49 3702 arma_warn(true, "SpMat::load(): unsupported file type");
Chris@49 3703 load_okay = false;
Chris@49 3704 }
Chris@49 3705
Chris@49 3706 if(load_okay == false)
Chris@49 3707 {
Chris@49 3708 if(err_msg.length() > 0)
Chris@49 3709 {
Chris@49 3710 arma_warn(true, "SpMat::load(): ", err_msg, name);
Chris@49 3711 }
Chris@49 3712 else
Chris@49 3713 {
Chris@49 3714 arma_warn(true, "SpMat::load(): couldn't read ", name);
Chris@49 3715 }
Chris@49 3716 }
Chris@49 3717
Chris@49 3718 if(load_okay == false)
Chris@49 3719 {
Chris@49 3720 (*this).reset();
Chris@49 3721 }
Chris@49 3722
Chris@49 3723 return load_okay;
Chris@49 3724 }
Chris@49 3725
Chris@49 3726
Chris@49 3727
Chris@49 3728 //! load a matrix from a stream
Chris@49 3729 template<typename eT>
Chris@49 3730 inline
Chris@49 3731 bool
Chris@49 3732 SpMat<eT>::load(std::istream& is, const file_type type, const bool print_status)
Chris@49 3733 {
Chris@49 3734 arma_extra_debug_sigprint();
Chris@49 3735
Chris@49 3736 bool load_okay;
Chris@49 3737 std::string err_msg;
Chris@49 3738
Chris@49 3739 switch(type)
Chris@49 3740 {
Chris@49 3741 // case auto_detect:
Chris@49 3742 // load_okay = diskio::load_auto_detect(*this, is, err_msg);
Chris@49 3743 // break;
Chris@49 3744
Chris@49 3745 // case raw_ascii:
Chris@49 3746 // load_okay = diskio::load_raw_ascii(*this, is, err_msg);
Chris@49 3747 // break;
Chris@49 3748
Chris@49 3749 // case csv_ascii:
Chris@49 3750 // load_okay = diskio::load_csv_ascii(*this, is, err_msg);
Chris@49 3751 // break;
Chris@49 3752
Chris@49 3753 case arma_binary:
Chris@49 3754 load_okay = diskio::load_arma_binary(*this, is, err_msg);
Chris@49 3755 break;
Chris@49 3756
Chris@49 3757 case coord_ascii:
Chris@49 3758 load_okay = diskio::load_coord_ascii(*this, is, err_msg);
Chris@49 3759 break;
Chris@49 3760
Chris@49 3761 default:
Chris@49 3762 arma_warn(true, "SpMat::load(): unsupported file type");
Chris@49 3763 load_okay = false;
Chris@49 3764 }
Chris@49 3765
Chris@49 3766
Chris@49 3767 if(load_okay == false)
Chris@49 3768 {
Chris@49 3769 if(err_msg.length() > 0)
Chris@49 3770 {
Chris@49 3771 arma_warn(true, "SpMat::load(): ", err_msg, "the given stream");
Chris@49 3772 }
Chris@49 3773 else
Chris@49 3774 {
Chris@49 3775 arma_warn(true, "SpMat::load(): couldn't load from the given stream");
Chris@49 3776 }
Chris@49 3777 }
Chris@49 3778
Chris@49 3779 if(load_okay == false)
Chris@49 3780 {
Chris@49 3781 (*this).reset();
Chris@49 3782 }
Chris@49 3783
Chris@49 3784 return load_okay;
Chris@49 3785 }
Chris@49 3786
Chris@49 3787
Chris@49 3788
Chris@49 3789 //! save the matrix to a file, without printing any error messages
Chris@49 3790 template<typename eT>
Chris@49 3791 inline
Chris@49 3792 bool
Chris@49 3793 SpMat<eT>::quiet_save(const std::string name, const file_type type) const
Chris@49 3794 {
Chris@49 3795 arma_extra_debug_sigprint();
Chris@49 3796
Chris@49 3797 return (*this).save(name, type, false);
Chris@49 3798 }
Chris@49 3799
Chris@49 3800
Chris@49 3801
Chris@49 3802 //! save the matrix to a stream, without printing any error messages
Chris@49 3803 template<typename eT>
Chris@49 3804 inline
Chris@49 3805 bool
Chris@49 3806 SpMat<eT>::quiet_save(std::ostream& os, const file_type type) const
Chris@49 3807 {
Chris@49 3808 arma_extra_debug_sigprint();
Chris@49 3809
Chris@49 3810 return (*this).save(os, type, false);
Chris@49 3811 }
Chris@49 3812
Chris@49 3813
Chris@49 3814
Chris@49 3815 //! load a matrix from a file, without printing any error messages
Chris@49 3816 template<typename eT>
Chris@49 3817 inline
Chris@49 3818 bool
Chris@49 3819 SpMat<eT>::quiet_load(const std::string name, const file_type type)
Chris@49 3820 {
Chris@49 3821 arma_extra_debug_sigprint();
Chris@49 3822
Chris@49 3823 return (*this).load(name, type, false);
Chris@49 3824 }
Chris@49 3825
Chris@49 3826
Chris@49 3827
Chris@49 3828 //! load a matrix from a stream, without printing any error messages
Chris@49 3829 template<typename eT>
Chris@49 3830 inline
Chris@49 3831 bool
Chris@49 3832 SpMat<eT>::quiet_load(std::istream& is, const file_type type)
Chris@49 3833 {
Chris@49 3834 arma_extra_debug_sigprint();
Chris@49 3835
Chris@49 3836 return (*this).load(is, type, false);
Chris@49 3837 }
Chris@49 3838
Chris@49 3839
Chris@49 3840
Chris@49 3841 /**
Chris@49 3842 * Initialize the matrix to the specified size. Data is not preserved, so the matrix is assumed to be entirely sparse (empty).
Chris@49 3843 */
Chris@49 3844 template<typename eT>
Chris@49 3845 inline
Chris@49 3846 void
Chris@49 3847 SpMat<eT>::init(uword in_rows, uword in_cols)
Chris@49 3848 {
Chris@49 3849 arma_extra_debug_sigprint();
Chris@49 3850
Chris@49 3851 // Verify that we are allowed to do this.
Chris@49 3852 if(vec_state > 0)
Chris@49 3853 {
Chris@49 3854 if((in_rows == 0) && (in_cols == 0))
Chris@49 3855 {
Chris@49 3856 if(vec_state == 1)
Chris@49 3857 {
Chris@49 3858 in_cols = 1;
Chris@49 3859 }
Chris@49 3860 else
Chris@49 3861 if(vec_state == 2)
Chris@49 3862 {
Chris@49 3863 in_rows = 1;
Chris@49 3864 }
Chris@49 3865 }
Chris@49 3866 else
Chris@49 3867 {
Chris@49 3868 arma_debug_check
Chris@49 3869 (
Chris@49 3870 ( ((vec_state == 1) && (in_cols != 1)) || ((vec_state == 2) && (in_rows != 1)) ),
Chris@49 3871 "SpMat::init(): object is a row or column vector; requested size is not compatible"
Chris@49 3872 );
Chris@49 3873 }
Chris@49 3874 }
Chris@49 3875
Chris@49 3876 // Ensure that n_elem can hold the result of (n_rows * n_cols)
Chris@49 3877 arma_debug_check
Chris@49 3878 (
Chris@49 3879 (
Chris@49 3880 ( (in_rows > ARMA_MAX_UHWORD) || (in_cols > ARMA_MAX_UHWORD) )
Chris@49 3881 ? ( (float(in_rows) * float(in_cols)) > float(ARMA_MAX_UWORD) )
Chris@49 3882 : false
Chris@49 3883 ),
Chris@49 3884 "SpMat::init(): requested size is too large"
Chris@49 3885 );
Chris@49 3886
Chris@49 3887 // Clean out the existing memory.
Chris@49 3888 if (values)
Chris@49 3889 {
Chris@49 3890 memory::release(values);
Chris@49 3891 memory::release(row_indices);
Chris@49 3892 }
Chris@49 3893
Chris@49 3894 access::rw(values) = memory::acquire_chunked<eT> (1);
Chris@49 3895 access::rw(row_indices) = memory::acquire_chunked<uword>(1);
Chris@49 3896
Chris@49 3897 access::rw(values[0]) = 0;
Chris@49 3898 access::rw(row_indices[0]) = 0;
Chris@49 3899
Chris@49 3900 memory::release(col_ptrs);
Chris@49 3901
Chris@49 3902 // Set the new size accordingly.
Chris@49 3903 access::rw(n_rows) = in_rows;
Chris@49 3904 access::rw(n_cols) = in_cols;
Chris@49 3905 access::rw(n_elem) = (in_rows * in_cols);
Chris@49 3906 access::rw(n_nonzero) = 0;
Chris@49 3907
Chris@49 3908 // Try to allocate the column pointers, filling them with 0, except for the
Chris@49 3909 // last element which contains the maximum possible element (so iterators
Chris@49 3910 // terminate correctly).
Chris@49 3911 access::rw(col_ptrs) = memory::acquire<uword>(in_cols + 2);
Chris@49 3912 access::rw(col_ptrs[in_cols + 1]) = std::numeric_limits<uword>::max();
Chris@49 3913
Chris@49 3914 arrayops::inplace_set(access::rwp(col_ptrs), uword(0), in_cols + 1);
Chris@49 3915 }
Chris@49 3916
Chris@49 3917
Chris@49 3918
Chris@49 3919 /**
Chris@49 3920 * Initialize the matrix from a string.
Chris@49 3921 */
Chris@49 3922 template<typename eT>
Chris@49 3923 inline
Chris@49 3924 void
Chris@49 3925 SpMat<eT>::init(const std::string& text)
Chris@49 3926 {
Chris@49 3927 arma_extra_debug_sigprint();
Chris@49 3928
Chris@49 3929 // Figure out the size first.
Chris@49 3930 uword t_n_rows = 0;
Chris@49 3931 uword t_n_cols = 0;
Chris@49 3932
Chris@49 3933 bool t_n_cols_found = false;
Chris@49 3934
Chris@49 3935 std::string token;
Chris@49 3936
Chris@49 3937 std::string::size_type line_start = 0;
Chris@49 3938 std::string::size_type line_end = 0;
Chris@49 3939
Chris@49 3940 while (line_start < text.length())
Chris@49 3941 {
Chris@49 3942
Chris@49 3943 line_end = text.find(';', line_start);
Chris@49 3944
Chris@49 3945 if (line_end == std::string::npos)
Chris@49 3946 line_end = text.length() - 1;
Chris@49 3947
Chris@49 3948 std::string::size_type line_len = line_end - line_start + 1;
Chris@49 3949 std::stringstream line_stream(text.substr(line_start, line_len));
Chris@49 3950
Chris@49 3951 // Step through each column.
Chris@49 3952 uword line_n_cols = 0;
Chris@49 3953
Chris@49 3954 while (line_stream >> token)
Chris@49 3955 {
Chris@49 3956 ++line_n_cols;
Chris@49 3957 }
Chris@49 3958
Chris@49 3959 if (line_n_cols > 0)
Chris@49 3960 {
Chris@49 3961 if (t_n_cols_found == false)
Chris@49 3962 {
Chris@49 3963 t_n_cols = line_n_cols;
Chris@49 3964 t_n_cols_found = true;
Chris@49 3965 }
Chris@49 3966 else // Check it each time through, just to make sure.
Chris@49 3967 arma_check((line_n_cols != t_n_cols), "SpMat::init(): inconsistent number of columns in given string");
Chris@49 3968
Chris@49 3969 ++t_n_rows;
Chris@49 3970 }
Chris@49 3971
Chris@49 3972 line_start = line_end + 1;
Chris@49 3973
Chris@49 3974 }
Chris@49 3975
Chris@49 3976 set_size(t_n_rows, t_n_cols);
Chris@49 3977
Chris@49 3978 // Second time through will pick up all the values.
Chris@49 3979 line_start = 0;
Chris@49 3980 line_end = 0;
Chris@49 3981
Chris@49 3982 uword lrow = 0;
Chris@49 3983
Chris@49 3984 while (line_start < text.length())
Chris@49 3985 {
Chris@49 3986
Chris@49 3987 line_end = text.find(';', line_start);
Chris@49 3988
Chris@49 3989 if (line_end == std::string::npos)
Chris@49 3990 line_end = text.length() - 1;
Chris@49 3991
Chris@49 3992 std::string::size_type line_len = line_end - line_start + 1;
Chris@49 3993 std::stringstream line_stream(text.substr(line_start, line_len));
Chris@49 3994
Chris@49 3995 uword lcol = 0;
Chris@49 3996 eT val;
Chris@49 3997
Chris@49 3998 while (line_stream >> val)
Chris@49 3999 {
Chris@49 4000 // Only add nonzero elements.
Chris@49 4001 if (val != eT(0))
Chris@49 4002 {
Chris@49 4003 get_value(lrow, lcol) = val;
Chris@49 4004 }
Chris@49 4005
Chris@49 4006 ++lcol;
Chris@49 4007 }
Chris@49 4008
Chris@49 4009 ++lrow;
Chris@49 4010 line_start = line_end + 1;
Chris@49 4011
Chris@49 4012 }
Chris@49 4013
Chris@49 4014 }
Chris@49 4015
Chris@49 4016 /**
Chris@49 4017 * Copy from another matrix.
Chris@49 4018 */
Chris@49 4019 template<typename eT>
Chris@49 4020 inline
Chris@49 4021 void
Chris@49 4022 SpMat<eT>::init(const SpMat<eT>& x)
Chris@49 4023 {
Chris@49 4024 arma_extra_debug_sigprint();
Chris@49 4025
Chris@49 4026 // Ensure we are not initializing to ourselves.
Chris@49 4027 if (this != &x)
Chris@49 4028 {
Chris@49 4029 init(x.n_rows, x.n_cols);
Chris@49 4030
Chris@49 4031 // values and row_indices may not be null.
Chris@49 4032 if (values != NULL)
Chris@49 4033 {
Chris@49 4034 memory::release(values);
Chris@49 4035 memory::release(row_indices);
Chris@49 4036 }
Chris@49 4037
Chris@49 4038 access::rw(values) = memory::acquire_chunked<eT> (x.n_nonzero + 1);
Chris@49 4039 access::rw(row_indices) = memory::acquire_chunked<uword>(x.n_nonzero + 1);
Chris@49 4040
Chris@49 4041 // Now copy over the elements.
Chris@49 4042 arrayops::copy(access::rwp(values), x.values, x.n_nonzero + 1);
Chris@49 4043 arrayops::copy(access::rwp(row_indices), x.row_indices, x.n_nonzero + 1);
Chris@49 4044 arrayops::copy(access::rwp(col_ptrs), x.col_ptrs, x.n_cols + 1);
Chris@49 4045
Chris@49 4046 access::rw(n_nonzero) = x.n_nonzero;
Chris@49 4047 }
Chris@49 4048 }
Chris@49 4049
Chris@49 4050
Chris@49 4051
Chris@49 4052 template<typename eT>
Chris@49 4053 inline
Chris@49 4054 void
Chris@49 4055 SpMat<eT>::mem_resize(const uword new_n_nonzero)
Chris@49 4056 {
Chris@49 4057 arma_extra_debug_sigprint();
Chris@49 4058
Chris@49 4059 if(n_nonzero != new_n_nonzero)
Chris@49 4060 {
Chris@49 4061 if(new_n_nonzero == 0)
Chris@49 4062 {
Chris@49 4063 memory::release(values);
Chris@49 4064 memory::release(row_indices);
Chris@49 4065
Chris@49 4066 access::rw(values) = memory::acquire_chunked<eT> (1);
Chris@49 4067 access::rw(row_indices) = memory::acquire_chunked<uword>(1);
Chris@49 4068
Chris@49 4069 access::rw(values[0]) = 0;
Chris@49 4070 access::rw(row_indices[0]) = 0;
Chris@49 4071 }
Chris@49 4072 else
Chris@49 4073 {
Chris@49 4074 // Figure out the actual amount of memory currently allocated
Chris@49 4075 // NOTE: this relies on memory::acquire_chunked() being used for the 'values' and 'row_indices' arrays
Chris@49 4076 const uword n_alloc = memory::enlarge_to_mult_of_chunksize(n_nonzero);
Chris@49 4077
Chris@49 4078 if(n_alloc < new_n_nonzero)
Chris@49 4079 {
Chris@49 4080 eT* new_values = memory::acquire_chunked<eT> (new_n_nonzero + 1);
Chris@49 4081 uword* new_row_indices = memory::acquire_chunked<uword>(new_n_nonzero + 1);
Chris@49 4082
Chris@49 4083 if(n_nonzero > 0)
Chris@49 4084 {
Chris@49 4085 // Copy old elements.
Chris@49 4086 uword copy_len = std::min(n_nonzero, new_n_nonzero);
Chris@49 4087
Chris@49 4088 arrayops::copy(new_values, values, copy_len);
Chris@49 4089 arrayops::copy(new_row_indices, row_indices, copy_len);
Chris@49 4090 }
Chris@49 4091
Chris@49 4092 memory::release(values);
Chris@49 4093 memory::release(row_indices);
Chris@49 4094
Chris@49 4095 access::rw(values) = new_values;
Chris@49 4096 access::rw(row_indices) = new_row_indices;
Chris@49 4097 }
Chris@49 4098
Chris@49 4099 // Set the "fake end" of the matrix by setting the last value and row
Chris@49 4100 // index to 0. This helps the iterators work correctly.
Chris@49 4101 access::rw(values[new_n_nonzero]) = 0;
Chris@49 4102 access::rw(row_indices[new_n_nonzero]) = 0;
Chris@49 4103 }
Chris@49 4104
Chris@49 4105 access::rw(n_nonzero) = new_n_nonzero;
Chris@49 4106 }
Chris@49 4107 }
Chris@49 4108
Chris@49 4109
Chris@49 4110
Chris@49 4111 // Steal memory from another matrix.
Chris@49 4112 template<typename eT>
Chris@49 4113 inline
Chris@49 4114 void
Chris@49 4115 SpMat<eT>::steal_mem(SpMat<eT>& x)
Chris@49 4116 {
Chris@49 4117 arma_extra_debug_sigprint();
Chris@49 4118
Chris@49 4119 if(this != &x)
Chris@49 4120 {
Chris@49 4121 // Release all the memory.
Chris@49 4122 memory::release(values);
Chris@49 4123 memory::release(row_indices);
Chris@49 4124 memory::release(col_ptrs);
Chris@49 4125
Chris@49 4126 // We'll have to copy everything about the other matrix.
Chris@49 4127 const uword x_n_rows = x.n_rows;
Chris@49 4128 const uword x_n_cols = x.n_cols;
Chris@49 4129 const uword x_n_elem = x.n_elem;
Chris@49 4130 const uword x_n_nonzero = x.n_nonzero;
Chris@49 4131
Chris@49 4132 access::rw(n_rows) = x_n_rows;
Chris@49 4133 access::rw(n_cols) = x_n_cols;
Chris@49 4134 access::rw(n_elem) = x_n_elem;
Chris@49 4135 access::rw(n_nonzero) = x_n_nonzero;
Chris@49 4136
Chris@49 4137 access::rw(values) = x.values;
Chris@49 4138 access::rw(row_indices) = x.row_indices;
Chris@49 4139 access::rw(col_ptrs) = x.col_ptrs;
Chris@49 4140
Chris@49 4141 // Set other matrix to empty.
Chris@49 4142 access::rw(x.n_rows) = 0;
Chris@49 4143 access::rw(x.n_cols) = 0;
Chris@49 4144 access::rw(x.n_elem) = 0;
Chris@49 4145 access::rw(x.n_nonzero) = 0;
Chris@49 4146
Chris@49 4147 access::rw(x.values) = NULL;
Chris@49 4148 access::rw(x.row_indices) = NULL;
Chris@49 4149 access::rw(x.col_ptrs) = NULL;
Chris@49 4150 }
Chris@49 4151 }
Chris@49 4152
Chris@49 4153
Chris@49 4154
Chris@49 4155 template<typename eT>
Chris@49 4156 template<typename T1, typename Functor>
Chris@49 4157 arma_hot
Chris@49 4158 inline
Chris@49 4159 void
Chris@49 4160 SpMat<eT>::init_xform(const SpBase<eT,T1>& A, const Functor& func)
Chris@49 4161 {
Chris@49 4162 arma_extra_debug_sigprint();
Chris@49 4163
Chris@49 4164 // if possible, avoid doing a copy and instead apply func to the generated elements
Chris@49 4165 if(SpProxy<T1>::Q_created_by_proxy == true)
Chris@49 4166 {
Chris@49 4167 (*this) = A.get_ref();
Chris@49 4168
Chris@49 4169 const uword nnz = n_nonzero;
Chris@49 4170
Chris@49 4171 eT* t_values = access::rwp(values);
Chris@49 4172
Chris@49 4173 for(uword i=0; i < nnz; ++i)
Chris@49 4174 {
Chris@49 4175 t_values[i] = func(t_values[i]);
Chris@49 4176 }
Chris@49 4177 }
Chris@49 4178 else
Chris@49 4179 {
Chris@49 4180 init_xform_mt(A.get_ref(), func);
Chris@49 4181 }
Chris@49 4182 }
Chris@49 4183
Chris@49 4184
Chris@49 4185
Chris@49 4186 template<typename eT>
Chris@49 4187 template<typename eT2, typename T1, typename Functor>
Chris@49 4188 arma_hot
Chris@49 4189 inline
Chris@49 4190 void
Chris@49 4191 SpMat<eT>::init_xform_mt(const SpBase<eT2,T1>& A, const Functor& func)
Chris@49 4192 {
Chris@49 4193 arma_extra_debug_sigprint();
Chris@49 4194
Chris@49 4195 const SpProxy<T1> P(A.get_ref());
Chris@49 4196
Chris@49 4197 if( (P.is_alias(*this) == true) || (is_SpMat<typename SpProxy<T1>::stored_type>::value == true) )
Chris@49 4198 {
Chris@49 4199 // NOTE: unwrap_spmat will convert a submatrix to a matrix, which in effect takes care of aliasing with submatrices;
Chris@49 4200 // NOTE: however, when more delayed ops are implemented, more elaborate handling of aliasing will be necessary
Chris@49 4201 const unwrap_spmat<typename SpProxy<T1>::stored_type> tmp(P.Q);
Chris@49 4202
Chris@49 4203 const SpMat<eT2>& x = tmp.M;
Chris@49 4204
Chris@49 4205 if(void_ptr(this) != void_ptr(&x))
Chris@49 4206 {
Chris@49 4207 init(x.n_rows, x.n_cols);
Chris@49 4208
Chris@49 4209 // values and row_indices may not be null.
Chris@49 4210 if(values != NULL)
Chris@49 4211 {
Chris@49 4212 memory::release(values);
Chris@49 4213 memory::release(row_indices);
Chris@49 4214 }
Chris@49 4215
Chris@49 4216 access::rw(values) = memory::acquire_chunked<eT> (x.n_nonzero + 1);
Chris@49 4217 access::rw(row_indices) = memory::acquire_chunked<uword>(x.n_nonzero + 1);
Chris@49 4218
Chris@49 4219 arrayops::copy(access::rwp(row_indices), x.row_indices, x.n_nonzero + 1);
Chris@49 4220 arrayops::copy(access::rwp(col_ptrs), x.col_ptrs, x.n_cols + 1);
Chris@49 4221
Chris@49 4222 access::rw(n_nonzero) = x.n_nonzero;
Chris@49 4223 }
Chris@49 4224
Chris@49 4225
Chris@49 4226 // initialise the elements array with a transformed version of the elements from x
Chris@49 4227
Chris@49 4228 const uword nnz = n_nonzero;
Chris@49 4229
Chris@49 4230 const eT2* x_values = x.values;
Chris@49 4231 eT* t_values = access::rwp(values);
Chris@49 4232
Chris@49 4233 for(uword i=0; i < nnz; ++i)
Chris@49 4234 {
Chris@49 4235 t_values[i] = func(x_values[i]); // NOTE: func() must produce a value of type eT (ie. act as a convertor between eT2 and eT)
Chris@49 4236 }
Chris@49 4237 }
Chris@49 4238 else
Chris@49 4239 {
Chris@49 4240 init(P.get_n_rows(), P.get_n_cols());
Chris@49 4241
Chris@49 4242 mem_resize(P.get_n_nonzero());
Chris@49 4243
Chris@49 4244 typename SpProxy<T1>::const_iterator_type it = P.begin();
Chris@49 4245
Chris@49 4246 while(it != P.end())
Chris@49 4247 {
Chris@49 4248 access::rw(row_indices[it.pos()]) = it.row();
Chris@49 4249 access::rw(values[it.pos()]) = func(*it); // NOTE: func() must produce a value of type eT (ie. act as a convertor between eT2 and eT)
Chris@49 4250 ++access::rw(col_ptrs[it.col() + 1]);
Chris@49 4251 ++it;
Chris@49 4252 }
Chris@49 4253
Chris@49 4254 // Now sum column pointers.
Chris@49 4255 for(uword c = 1; c <= n_cols; ++c)
Chris@49 4256 {
Chris@49 4257 access::rw(col_ptrs[c]) += col_ptrs[c - 1];
Chris@49 4258 }
Chris@49 4259 }
Chris@49 4260 }
Chris@49 4261
Chris@49 4262
Chris@49 4263
Chris@49 4264 template<typename eT>
Chris@49 4265 inline
Chris@49 4266 typename SpMat<eT>::iterator
Chris@49 4267 SpMat<eT>::begin()
Chris@49 4268 {
Chris@49 4269 return iterator(*this);
Chris@49 4270 }
Chris@49 4271
Chris@49 4272
Chris@49 4273
Chris@49 4274 template<typename eT>
Chris@49 4275 inline
Chris@49 4276 typename SpMat<eT>::const_iterator
Chris@49 4277 SpMat<eT>::begin() const
Chris@49 4278 {
Chris@49 4279 return const_iterator(*this);
Chris@49 4280 }
Chris@49 4281
Chris@49 4282
Chris@49 4283
Chris@49 4284 template<typename eT>
Chris@49 4285 inline
Chris@49 4286 typename SpMat<eT>::iterator
Chris@49 4287 SpMat<eT>::end()
Chris@49 4288 {
Chris@49 4289 return iterator(*this, 0, n_cols, n_nonzero);
Chris@49 4290 }
Chris@49 4291
Chris@49 4292
Chris@49 4293
Chris@49 4294 template<typename eT>
Chris@49 4295 inline
Chris@49 4296 typename SpMat<eT>::const_iterator
Chris@49 4297 SpMat<eT>::end() const
Chris@49 4298 {
Chris@49 4299 return const_iterator(*this, 0, n_cols, n_nonzero);
Chris@49 4300 }
Chris@49 4301
Chris@49 4302
Chris@49 4303
Chris@49 4304 template<typename eT>
Chris@49 4305 inline
Chris@49 4306 typename SpMat<eT>::iterator
Chris@49 4307 SpMat<eT>::begin_col(const uword col_num)
Chris@49 4308 {
Chris@49 4309 return iterator(*this, 0, col_num);
Chris@49 4310 }
Chris@49 4311
Chris@49 4312
Chris@49 4313
Chris@49 4314 template<typename eT>
Chris@49 4315 inline
Chris@49 4316 typename SpMat<eT>::const_iterator
Chris@49 4317 SpMat<eT>::begin_col(const uword col_num) const
Chris@49 4318 {
Chris@49 4319 return const_iterator(*this, 0, col_num);
Chris@49 4320 }
Chris@49 4321
Chris@49 4322
Chris@49 4323
Chris@49 4324 template<typename eT>
Chris@49 4325 inline
Chris@49 4326 typename SpMat<eT>::iterator
Chris@49 4327 SpMat<eT>::end_col(const uword col_num)
Chris@49 4328 {
Chris@49 4329 return iterator(*this, 0, col_num + 1);
Chris@49 4330 }
Chris@49 4331
Chris@49 4332
Chris@49 4333
Chris@49 4334 template<typename eT>
Chris@49 4335 inline
Chris@49 4336 typename SpMat<eT>::const_iterator
Chris@49 4337 SpMat<eT>::end_col(const uword col_num) const
Chris@49 4338 {
Chris@49 4339 return const_iterator(*this, 0, col_num + 1);
Chris@49 4340 }
Chris@49 4341
Chris@49 4342
Chris@49 4343
Chris@49 4344 template<typename eT>
Chris@49 4345 inline
Chris@49 4346 typename SpMat<eT>::row_iterator
Chris@49 4347 SpMat<eT>::begin_row(const uword row_num)
Chris@49 4348 {
Chris@49 4349 return row_iterator(*this, row_num, 0);
Chris@49 4350 }
Chris@49 4351
Chris@49 4352
Chris@49 4353
Chris@49 4354 template<typename eT>
Chris@49 4355 inline
Chris@49 4356 typename SpMat<eT>::const_row_iterator
Chris@49 4357 SpMat<eT>::begin_row(const uword row_num) const
Chris@49 4358 {
Chris@49 4359 return const_row_iterator(*this, row_num, 0);
Chris@49 4360 }
Chris@49 4361
Chris@49 4362
Chris@49 4363
Chris@49 4364 template<typename eT>
Chris@49 4365 inline
Chris@49 4366 typename SpMat<eT>::row_iterator
Chris@49 4367 SpMat<eT>::end_row()
Chris@49 4368 {
Chris@49 4369 return row_iterator(*this, n_nonzero);
Chris@49 4370 }
Chris@49 4371
Chris@49 4372
Chris@49 4373
Chris@49 4374 template<typename eT>
Chris@49 4375 inline
Chris@49 4376 typename SpMat<eT>::const_row_iterator
Chris@49 4377 SpMat<eT>::end_row() const
Chris@49 4378 {
Chris@49 4379 return const_row_iterator(*this, n_nonzero);
Chris@49 4380 }
Chris@49 4381
Chris@49 4382
Chris@49 4383
Chris@49 4384 template<typename eT>
Chris@49 4385 inline
Chris@49 4386 typename SpMat<eT>::row_iterator
Chris@49 4387 SpMat<eT>::end_row(const uword row_num)
Chris@49 4388 {
Chris@49 4389 return row_iterator(*this, row_num + 1, 0);
Chris@49 4390 }
Chris@49 4391
Chris@49 4392
Chris@49 4393
Chris@49 4394 template<typename eT>
Chris@49 4395 inline
Chris@49 4396 typename SpMat<eT>::const_row_iterator
Chris@49 4397 SpMat<eT>::end_row(const uword row_num) const
Chris@49 4398 {
Chris@49 4399 return const_row_iterator(*this, row_num + 1, 0);
Chris@49 4400 }
Chris@49 4401
Chris@49 4402
Chris@49 4403
Chris@49 4404 template<typename eT>
Chris@49 4405 inline
Chris@49 4406 void
Chris@49 4407 SpMat<eT>::clear()
Chris@49 4408 {
Chris@49 4409 if (values)
Chris@49 4410 {
Chris@49 4411 memory::release(values);
Chris@49 4412 memory::release(row_indices);
Chris@49 4413
Chris@49 4414 access::rw(values) = memory::acquire_chunked<eT> (1);
Chris@49 4415 access::rw(row_indices) = memory::acquire_chunked<uword>(1);
Chris@49 4416
Chris@49 4417 access::rw(values[0]) = 0;
Chris@49 4418 access::rw(row_indices[0]) = 0;
Chris@49 4419 }
Chris@49 4420
Chris@49 4421 memory::release(col_ptrs);
Chris@49 4422
Chris@49 4423 access::rw(col_ptrs) = memory::acquire<uword>(n_cols + 2);
Chris@49 4424 access::rw(col_ptrs[n_cols + 1]) = std::numeric_limits<uword>::max();
Chris@49 4425
Chris@49 4426 arrayops::inplace_set(col_ptrs, eT(0), n_cols + 1);
Chris@49 4427
Chris@49 4428 access::rw(n_nonzero) = 0;
Chris@49 4429 }
Chris@49 4430
Chris@49 4431
Chris@49 4432
Chris@49 4433 template<typename eT>
Chris@49 4434 inline
Chris@49 4435 bool
Chris@49 4436 SpMat<eT>::empty() const
Chris@49 4437 {
Chris@49 4438 return (n_elem == 0);
Chris@49 4439 }
Chris@49 4440
Chris@49 4441
Chris@49 4442
Chris@49 4443 template<typename eT>
Chris@49 4444 inline
Chris@49 4445 uword
Chris@49 4446 SpMat<eT>::size() const
Chris@49 4447 {
Chris@49 4448 return n_elem;
Chris@49 4449 }
Chris@49 4450
Chris@49 4451
Chris@49 4452
Chris@49 4453 template<typename eT>
Chris@49 4454 inline
Chris@49 4455 arma_hot
Chris@49 4456 arma_warn_unused
Chris@49 4457 SpValProxy<SpMat<eT> >
Chris@49 4458 SpMat<eT>::get_value(const uword i)
Chris@49 4459 {
Chris@49 4460 // First convert to the actual location.
Chris@49 4461 uword lcol = i / n_rows; // Integer division.
Chris@49 4462 uword lrow = i % n_rows;
Chris@49 4463
Chris@49 4464 return get_value(lrow, lcol);
Chris@49 4465 }
Chris@49 4466
Chris@49 4467
Chris@49 4468
Chris@49 4469 template<typename eT>
Chris@49 4470 inline
Chris@49 4471 arma_hot
Chris@49 4472 arma_warn_unused
Chris@49 4473 eT
Chris@49 4474 SpMat<eT>::get_value(const uword i) const
Chris@49 4475 {
Chris@49 4476 // First convert to the actual location.
Chris@49 4477 uword lcol = i / n_rows; // Integer division.
Chris@49 4478 uword lrow = i % n_rows;
Chris@49 4479
Chris@49 4480 return get_value(lrow, lcol);
Chris@49 4481 }
Chris@49 4482
Chris@49 4483
Chris@49 4484
Chris@49 4485 template<typename eT>
Chris@49 4486 inline
Chris@49 4487 arma_hot
Chris@49 4488 arma_warn_unused
Chris@49 4489 SpValProxy<SpMat<eT> >
Chris@49 4490 SpMat<eT>::get_value(const uword in_row, const uword in_col)
Chris@49 4491 {
Chris@49 4492 const uword colptr = col_ptrs[in_col];
Chris@49 4493 const uword next_colptr = col_ptrs[in_col + 1];
Chris@49 4494
Chris@49 4495 // Step through the row indices to see if our element exists.
Chris@49 4496 for (uword i = colptr; i < next_colptr; ++i)
Chris@49 4497 {
Chris@49 4498 const uword row_index = row_indices[i];
Chris@49 4499
Chris@49 4500 // First check that we have not stepped past it.
Chris@49 4501 if (in_row < row_index) // If we have, then it doesn't exist: return 0.
Chris@49 4502 {
Chris@49 4503 return SpValProxy<SpMat<eT> >(in_row, in_col, *this); // Proxy for a zero value.
Chris@49 4504 }
Chris@49 4505
Chris@49 4506 // Now check if we are at the correct place.
Chris@49 4507 if (in_row == row_index) // If we are, return a reference to the value.
Chris@49 4508 {
Chris@49 4509 return SpValProxy<SpMat<eT> >(in_row, in_col, *this, &access::rw(values[i]));
Chris@49 4510 }
Chris@49 4511
Chris@49 4512 }
Chris@49 4513
Chris@49 4514 // We did not find it, so it does not exist: return 0.
Chris@49 4515 return SpValProxy<SpMat<eT> >(in_row, in_col, *this);
Chris@49 4516 }
Chris@49 4517
Chris@49 4518
Chris@49 4519
Chris@49 4520 template<typename eT>
Chris@49 4521 inline
Chris@49 4522 arma_hot
Chris@49 4523 arma_warn_unused
Chris@49 4524 eT
Chris@49 4525 SpMat<eT>::get_value(const uword in_row, const uword in_col) const
Chris@49 4526 {
Chris@49 4527 const uword colptr = col_ptrs[in_col];
Chris@49 4528 const uword next_colptr = col_ptrs[in_col + 1];
Chris@49 4529
Chris@49 4530 // Step through the row indices to see if our element exists.
Chris@49 4531 for (uword i = colptr; i < next_colptr; ++i)
Chris@49 4532 {
Chris@49 4533 const uword row_index = row_indices[i];
Chris@49 4534
Chris@49 4535 // First check that we have not stepped past it.
Chris@49 4536 if (in_row < row_index) // If we have, then it doesn't exist: return 0.
Chris@49 4537 {
Chris@49 4538 return eT(0);
Chris@49 4539 }
Chris@49 4540
Chris@49 4541 // Now check if we are at the correct place.
Chris@49 4542 if (in_row == row_index) // If we are, return the value.
Chris@49 4543 {
Chris@49 4544 return values[i];
Chris@49 4545 }
Chris@49 4546 }
Chris@49 4547
Chris@49 4548 // We did not find it, so it does not exist: return 0.
Chris@49 4549 return eT(0);
Chris@49 4550 }
Chris@49 4551
Chris@49 4552
Chris@49 4553
Chris@49 4554 /**
Chris@49 4555 * Given the index representing which of the nonzero values this is, return its
Chris@49 4556 * actual location, either in row/col or just the index.
Chris@49 4557 */
Chris@49 4558 template<typename eT>
Chris@49 4559 arma_hot
Chris@49 4560 arma_inline
Chris@49 4561 arma_warn_unused
Chris@49 4562 uword
Chris@49 4563 SpMat<eT>::get_position(const uword i) const
Chris@49 4564 {
Chris@49 4565 uword lrow, lcol;
Chris@49 4566
Chris@49 4567 get_position(i, lrow, lcol);
Chris@49 4568
Chris@49 4569 // Assemble the row/col into the element's location in the matrix.
Chris@49 4570 return (lrow + n_rows * lcol);
Chris@49 4571 }
Chris@49 4572
Chris@49 4573
Chris@49 4574
Chris@49 4575 template<typename eT>
Chris@49 4576 arma_hot
Chris@49 4577 arma_inline
Chris@49 4578 void
Chris@49 4579 SpMat<eT>::get_position(const uword i, uword& row_of_i, uword& col_of_i) const
Chris@49 4580 {
Chris@49 4581 arma_debug_check((i >= n_nonzero), "SpMat::get_position(): index out of bounds");
Chris@49 4582
Chris@49 4583 col_of_i = 0;
Chris@49 4584 while (col_ptrs[col_of_i + 1] <= i)
Chris@49 4585 {
Chris@49 4586 col_of_i++;
Chris@49 4587 }
Chris@49 4588
Chris@49 4589 row_of_i = row_indices[i];
Chris@49 4590
Chris@49 4591 return;
Chris@49 4592 }
Chris@49 4593
Chris@49 4594
Chris@49 4595
Chris@49 4596 /**
Chris@49 4597 * Add an element at the given position, and return a reference to it. The
Chris@49 4598 * element will be set to 0 (unless otherwise specified). If the element
Chris@49 4599 * already exists, its value will be overwritten.
Chris@49 4600 *
Chris@49 4601 * @param in_row Row of new element.
Chris@49 4602 * @param in_col Column of new element.
Chris@49 4603 * @param in_val Value to set new element to (default 0.0).
Chris@49 4604 */
Chris@49 4605 template<typename eT>
Chris@49 4606 inline
Chris@49 4607 arma_hot
Chris@49 4608 arma_warn_unused
Chris@49 4609 eT&
Chris@49 4610 SpMat<eT>::add_element(const uword in_row, const uword in_col, const eT val)
Chris@49 4611 {
Chris@49 4612 arma_extra_debug_sigprint();
Chris@49 4613
Chris@49 4614 // We will assume the new element does not exist and begin the search for
Chris@49 4615 // where to insert it. If we find that it already exists, we will then
Chris@49 4616 // overwrite it.
Chris@49 4617 uword colptr = col_ptrs[in_col ];
Chris@49 4618 uword next_colptr = col_ptrs[in_col + 1];
Chris@49 4619
Chris@49 4620 uword pos = colptr; // The position in the matrix of this value.
Chris@49 4621
Chris@49 4622 if (colptr != next_colptr)
Chris@49 4623 {
Chris@49 4624 // There are other elements in this column, so we must find where this
Chris@49 4625 // element will fit as compared to those.
Chris@49 4626 while (pos < next_colptr && in_row > row_indices[pos])
Chris@49 4627 {
Chris@49 4628 pos++;
Chris@49 4629 }
Chris@49 4630
Chris@49 4631 // We aren't inserting into the last position, so it is still possible
Chris@49 4632 // that the element may exist.
Chris@49 4633 if (pos != next_colptr && row_indices[pos] == in_row)
Chris@49 4634 {
Chris@49 4635 // It already exists. Then, just overwrite it.
Chris@49 4636 access::rw(values[pos]) = val;
Chris@49 4637
Chris@49 4638 return access::rw(values[pos]);
Chris@49 4639 }
Chris@49 4640 }
Chris@49 4641
Chris@49 4642
Chris@49 4643 //
Chris@49 4644 // Element doesn't exist, so we have to insert it
Chris@49 4645 //
Chris@49 4646
Chris@49 4647 // We have to update the rest of the column pointers.
Chris@49 4648 for (uword i = in_col + 1; i < n_cols + 1; i++)
Chris@49 4649 {
Chris@49 4650 access::rw(col_ptrs[i])++; // We are only inserting one new element.
Chris@49 4651 }
Chris@49 4652
Chris@49 4653
Chris@49 4654 // Figure out the actual amount of memory currently allocated
Chris@49 4655 // NOTE: this relies on memory::acquire_chunked() being used for the 'values' and 'row_indices' arrays
Chris@49 4656 const uword n_alloc = memory::enlarge_to_mult_of_chunksize(n_nonzero + 1);
Chris@49 4657
Chris@49 4658 // If possible, avoid time-consuming memory allocation
Chris@49 4659 if(n_alloc > (n_nonzero + 1))
Chris@49 4660 {
Chris@49 4661 arrayops::copy_backwards(access::rwp(values) + pos + 1, values + pos, (n_nonzero - pos) + 1);
Chris@49 4662 arrayops::copy_backwards(access::rwp(row_indices) + pos + 1, row_indices + pos, (n_nonzero - pos) + 1);
Chris@49 4663
Chris@49 4664 // Insert the new element.
Chris@49 4665 access::rw(values[pos]) = val;
Chris@49 4666 access::rw(row_indices[pos]) = in_row;
Chris@49 4667
Chris@49 4668 access::rw(n_nonzero)++;
Chris@49 4669 }
Chris@49 4670 else
Chris@49 4671 {
Chris@49 4672 const uword old_n_nonzero = n_nonzero;
Chris@49 4673
Chris@49 4674 access::rw(n_nonzero)++; // Add to count of nonzero elements.
Chris@49 4675
Chris@49 4676 // Allocate larger memory.
Chris@49 4677 eT* new_values = memory::acquire_chunked<eT> (n_nonzero + 1);
Chris@49 4678 uword* new_row_indices = memory::acquire_chunked<uword>(n_nonzero + 1);
Chris@49 4679
Chris@49 4680 // Copy things over, before the new element.
Chris@49 4681 if (pos > 0)
Chris@49 4682 {
Chris@49 4683 arrayops::copy(new_values, values, pos);
Chris@49 4684 arrayops::copy(new_row_indices, row_indices, pos);
Chris@49 4685 }
Chris@49 4686
Chris@49 4687 // Insert the new element.
Chris@49 4688 new_values[pos] = val;
Chris@49 4689 new_row_indices[pos] = in_row;
Chris@49 4690
Chris@49 4691 // Copy the rest of things over (including the extra element at the end).
Chris@49 4692 arrayops::copy(new_values + pos + 1, values + pos, (old_n_nonzero - pos) + 1);
Chris@49 4693 arrayops::copy(new_row_indices + pos + 1, row_indices + pos, (old_n_nonzero - pos) + 1);
Chris@49 4694
Chris@49 4695 // Assign new pointers.
Chris@49 4696 memory::release(values);
Chris@49 4697 memory::release(row_indices);
Chris@49 4698
Chris@49 4699 access::rw(values) = new_values;
Chris@49 4700 access::rw(row_indices) = new_row_indices;
Chris@49 4701 }
Chris@49 4702
Chris@49 4703 return access::rw(values[pos]);
Chris@49 4704 }
Chris@49 4705
Chris@49 4706
Chris@49 4707
Chris@49 4708 /**
Chris@49 4709 * Delete an element at the given position.
Chris@49 4710 *
Chris@49 4711 * @param in_row Row of element to be deleted.
Chris@49 4712 * @param in_col Column of element to be deleted.
Chris@49 4713 */
Chris@49 4714 template<typename eT>
Chris@49 4715 inline
Chris@49 4716 arma_hot
Chris@49 4717 void
Chris@49 4718 SpMat<eT>::delete_element(const uword in_row, const uword in_col)
Chris@49 4719 {
Chris@49 4720 arma_extra_debug_sigprint();
Chris@49 4721
Chris@49 4722 // We assume the element exists (although... it may not) and look for its
Chris@49 4723 // exact position. If it doesn't exist... well, we don't need to do anything.
Chris@49 4724 uword colptr = col_ptrs[in_col];
Chris@49 4725 uword next_colptr = col_ptrs[in_col + 1];
Chris@49 4726
Chris@49 4727 if (colptr != next_colptr)
Chris@49 4728 {
Chris@49 4729 // There's at least one element in this column.
Chris@49 4730 // Let's see if we are one of them.
Chris@49 4731 for (uword pos = colptr; pos < next_colptr; pos++)
Chris@49 4732 {
Chris@49 4733 if (in_row == row_indices[pos])
Chris@49 4734 {
Chris@49 4735 const uword old_n_nonzero = n_nonzero;
Chris@49 4736
Chris@49 4737 --access::rw(n_nonzero); // Remove one from the count of nonzero elements.
Chris@49 4738
Chris@49 4739 // Found it. Now remove it.
Chris@49 4740
Chris@49 4741 // Figure out the actual amount of memory currently allocated and the actual amount that will be required
Chris@49 4742 // NOTE: this relies on memory::acquire_chunked() being used for the 'values' and 'row_indices' arrays
Chris@49 4743
Chris@49 4744 const uword n_alloc = memory::enlarge_to_mult_of_chunksize(old_n_nonzero + 1);
Chris@49 4745 const uword n_alloc_mod = memory::enlarge_to_mult_of_chunksize(n_nonzero + 1);
Chris@49 4746
Chris@49 4747 // If possible, avoid time-consuming memory allocation
Chris@49 4748 if(n_alloc_mod == n_alloc)
Chris@49 4749 {
Chris@49 4750 if (pos < n_nonzero) // remember, we decremented n_nonzero
Chris@49 4751 {
Chris@49 4752 arrayops::copy_forwards(access::rwp(values) + pos, values + pos + 1, (n_nonzero - pos) + 1);
Chris@49 4753 arrayops::copy_forwards(access::rwp(row_indices) + pos, row_indices + pos + 1, (n_nonzero - pos) + 1);
Chris@49 4754 }
Chris@49 4755 }
Chris@49 4756 else
Chris@49 4757 {
Chris@49 4758 // Make new arrays.
Chris@49 4759 eT* new_values = memory::acquire_chunked<eT> (n_nonzero + 1);
Chris@49 4760 uword* new_row_indices = memory::acquire_chunked<uword>(n_nonzero + 1);
Chris@49 4761
Chris@49 4762 if (pos > 0)
Chris@49 4763 {
Chris@49 4764 arrayops::copy(new_values, values, pos);
Chris@49 4765 arrayops::copy(new_row_indices, row_indices, pos);
Chris@49 4766 }
Chris@49 4767
Chris@49 4768 arrayops::copy(new_values + pos, values + pos + 1, (n_nonzero - pos) + 1);
Chris@49 4769 arrayops::copy(new_row_indices + pos, row_indices + pos + 1, (n_nonzero - pos) + 1);
Chris@49 4770
Chris@49 4771 memory::release(values);
Chris@49 4772 memory::release(row_indices);
Chris@49 4773
Chris@49 4774 access::rw(values) = new_values;
Chris@49 4775 access::rw(row_indices) = new_row_indices;
Chris@49 4776 }
Chris@49 4777
Chris@49 4778 // And lastly, update all the column pointers (decrement by one).
Chris@49 4779 for (uword i = in_col + 1; i < n_cols + 1; i++)
Chris@49 4780 {
Chris@49 4781 --access::rw(col_ptrs[i]); // We only removed one element.
Chris@49 4782 }
Chris@49 4783
Chris@49 4784 return; // There is nothing left to do.
Chris@49 4785 }
Chris@49 4786 }
Chris@49 4787 }
Chris@49 4788
Chris@49 4789 return; // The element does not exist, so there's nothing for us to do.
Chris@49 4790 }
Chris@49 4791
Chris@49 4792
Chris@49 4793
Chris@49 4794 #ifdef ARMA_EXTRA_SPMAT_MEAT
Chris@49 4795 #include ARMA_INCFILE_WRAP(ARMA_EXTRA_SPMAT_MEAT)
Chris@49 4796 #endif
Chris@49 4797
Chris@49 4798
Chris@49 4799
Chris@49 4800 //! @}