GammaLib 2.1.0.dev
Loading...
Searching...
No Matches
GVectorSparse.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GVectorSparse.cpp - Sparse vector class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2024 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- *
6 * *
7 * This program is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 * *
20 ***************************************************************************/
21/**
22 * @file GVectorSparse.cpp
23 * @brief Sparse vector class implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include "GVector.hpp"
32#include "GVectorSparse.hpp"
33#include "GTools.hpp"
34
35
36/* __ Method name definitions ____________________________________________ */
37#define G_CONSTRUCTOR "GVectorSparse::GVectorSparse(int&)"
38#define G_OPERATOR "GVectorSparse::operator[](int&)"
39
40
41/*==========================================================================
42 = =
43 = Constructors/destructors =
44 = =
45 ==========================================================================*/
46
47/***********************************************************************//**
48 * @brief Void sparse vector constructor
49 ***************************************************************************/
51{
52 // Initialise class members
54
55 // Return
56 return;
57}
58
59
60/***********************************************************************//**
61 * @brief Sparse vector constructor
62 *
63 * @param[in] num Vector size.
64 * @param[in] alloc Number of elements for allocation.
65 *
66 * Constructs a sparse vector, specifying the size of the expanded vector
67 * @p num and the number of elements @p alloc for which memory should be
68 * allocated. Using pre-allocated memory reduces the dynamic reallocation
69 * of memory.
70 ***************************************************************************/
71GVectorSparse::GVectorSparse(const int& num, const int& alloc)
72{
73 // Initialise class members
75
76 // Store vector size
77 m_num = num;
78
79 // Allocate memory
80 alloc_members(alloc);
81
82 // Return
83 return;
84}
85
86
87/***********************************************************************//**
88 * @brief Vector conversion constructor
89 *
90 * @param[in] vector Vector.
91 *
92 * Converts a regular vector into a sparse vector by stripping all zero
93 * elements.
94 ***************************************************************************/
96{
97 // Initialise class members
99
100 // Set attributes
101 m_num = vector.size();
102 m_elements = vector.non_zeros();
103
104 // Allocate memory
106
107 // Copy non-zero elements
108 for (int i = 0, idst = 0; i < vector.size(); ++i) {
109 if (vector[i] != 0.0) {
110 m_inx[idst] = i;
111 m_data[idst] = vector[i];
112 idst++;
113 }
114 }
115
116 // Return
117 return;
118}
119
120
121/***********************************************************************//**
122 * @brief Copy constructor
123 *
124 * @param[in] vector Sparse vector.
125 ***************************************************************************/
127{
128 // Initialise class members
129 init_members();
130
131 // Copy members
132 copy_members(vector);
133
134 // Return
135 return;
136}
137
138
139/***********************************************************************//**
140 * @brief Destructor
141 ***************************************************************************/
143{
144 // Free members
145 free_members();
146
147 // Return
148 return;
149}
150
151
152/*==========================================================================
153 = =
154 = Operators =
155 = =
156 ==========================================================================*/
157
158/***********************************************************************//**
159 * @brief Assignment operator
160 *
161 * @param[in] vector Sparse vector.
162 * @return Sparse vector.
163 ***************************************************************************/
165{
166 // Execute only if object is not identical
167 if (this != &vector) {
168
169 // Free members
170 free_members();
171
172 // Initialise private members
173 init_members();
174
175 // Copy members
176 copy_members(vector);
177
178 } // endif: object was not identical
179
180 // Return this object
181 return *this;
182}
183
184
185/***********************************************************************//**
186 * @brief Equality operator
187 *
188 * @param[in] vector Sparse vector.
189 * @return True if sparse vectors are identical.
190 *
191 * Returns true if both sparse vectors are identical. Sparse vectors are
192 * considered identical if they have the same size and if all their elements
193 * are identical.
194 ***************************************************************************/
196{
197 // Initalise result depending on sparse vector size and number of
198 // elements. If the test succeeds we can simply check all elements.
199 bool result = ((m_num == vector.m_num) &&
200 (m_elements == vector.m_elements));
201
202 // Test for difference. Break at first difference
203 if (result) {
204 for (int i = 0; i < m_elements; ++i) {
205 if ((m_inx[i] != vector.m_inx[i]) ||
206 (m_data[i] != vector.m_data[i])) {
207 result = false;
208 break;
209 }
210 }
211 }
212
213 // Return result
214 return result;
215}
216
217
218/***********************************************************************//**
219 * @brief Non-equality operator
220 *
221 * @param[in] vector Sparse vector.
222 * @return True if both sparse vectors are different.
223 ***************************************************************************/
225{
226 // Get negated result of equality operation
227 bool result = !(this->operator==(vector));
228
229 // Return result
230 return result;
231}
232
233
234/*==========================================================================
235 = =
236 = Public methods =
237 = =
238 ==========================================================================*/
239
240/***********************************************************************//**
241 * @brief Clear sparse vector
242 ***************************************************************************/
244{
245 // Free members
246 free_members();
247
248 // Initialise private members
249 init_members();
250
251 // Return
252 return;
253}
254
255
256/***********************************************************************//**
257 * @brief Clone sparse vector
258 *
259 * @return Pointer to deep copy of sparse vector.
260 ***************************************************************************/
262{
263 // Clone sparse vector
264 return new GVectorSparse(*this);
265}
266
267
268/***********************************************************************//**
269 * @brief Sparse vector element access with range checking
270 *
271 * @param[in] index Element index [0,...,size()[.
272 * @return Reference to vector element.
273 *
274 * @exception GException::out_of_range
275 * Element index is out of range.
276 *
277 * Returns the sparse vector element on the basis of the @p index of the
278 * full vector. If no element exists yet for this @p index, a element with
279 * value of zero will be added to the vector. Note that using the method
280 * will be very slow, and if no values are set, the sparse vector will be
281 * populated with zero values.
282 ***************************************************************************/
283double& GVectorSparse::operator[](const int& index)
284{
285 // Throw an exception if index is out of range
286 #if defined(G_RANGE_CHECK)
287 if (index < 0 || index >= size()) {
288 throw GException::out_of_range(G_OPERATOR, "Vector element index",
289 index, size());
290 }
291 #endif
292
293 // Allocate pointer to result
294 double* result = NULL;
295
296 // Find first position after the index
297 for (int i = 0; i < m_elements; ++i) {
298
299 // If element with requested index is already in vector
300 // then return pointer to this element.
301 if (m_inx[i] == index) {
302 result = &(m_data[i]);
303 break;
304 }
305
306 // ... otherwise search first inx after requested index
307 else if (m_inx[i] > index) {
308
309 // Insert index and value of zero
310 insert(i, index, 0.0);
311
312 // Set pointer to inserted element
313 result = &(m_data[i]);
314
315 // Exit loop
316 break;
317
318 } // endelse: searched first inx after requested index
319
320 } // endfor: looped over inx array
321
322 // If we have no valid pointer then append element to sparse
323 // vector
324 if (result == NULL) {
325
326 // Save
327 int num = m_elements;
328
329 // Append index and value of zero
330 insert(m_elements, index, 0.0);
331
332 // Set pointer to appended element
333 result = &(m_data[num]);
334
335 }
336
337 // Return reference
338 return (*result);
339}
340
341
342/***********************************************************************//**
343 * @brief Sparse vector element access with range checking
344 *
345 * @param[in] index Element index [0,...,size()[.
346 * @return Reference to vector element.
347 *
348 * @exception GException::out_of_range
349 * Element index is out of range.
350 *
351 * Returns the sparse vector element on the basis of the @p index of the
352 * full vector. If no element exists for this @p index, a static zero value
353 * is returned.
354 ***************************************************************************/
355const double& GVectorSparse::operator[](const int& index) const
356{
357 // Set static zero value
358 static double zero = 0.0;
359
360 // Throw an exception if index is out of range
361 #if defined(G_RANGE_CHECK)
362 if (index < 0 || index >= size()) {
363 throw GException::out_of_range(G_OPERATOR, "Vector element index",
364 index, size());
365 }
366 #endif
367
368 // Get sparse index
369 int inx = index2inx(index);
370
371 // Set result pointer
372 const double* result = (inx != -1) ? &(m_data[inx]) : &zero;
373
374 // Return reference
375 return (*result);
376}
377
378
379/***********************************************************************//**
380 * @brief Print sparse vector information
381 *
382 * @param[in] chatter Chattiness.
383 * @return String containing vector information.
384 ***************************************************************************/
385std::string GVectorSparse::print(const GChatter& chatter) const
386{
387 // Initialise result string
388 std::string result;
389
390 // Continue only if chatter is not silent
391 if (chatter != SILENT) {
392
393 // Append header
394 result.append("=== GVectorSparse ===");
395
396 // Append information
397 result.append("\n"+gammalib::parformat("Size of vector"));
398 result.append(gammalib::str(m_num));
399 result.append("\n"+gammalib::parformat("Number of elements"));
400 result.append(gammalib::str(m_elements));
401 result.append("\n"+gammalib::parformat("Allocated elements"));
402 result.append(gammalib::str(m_alloc));
403 if (m_colinx != -1) {
404 result.append("\n"+gammalib::parformat("Column index"));
405 result.append(gammalib::str(m_colinx));
406 }
407
408 } // endif: chatter was not silent
409
410 // Return result
411 return result;
412}
413
414
415/*==========================================================================
416 = =
417 = Private methods =
418 = =
419 ==========================================================================*/
420
421/***********************************************************************//**
422 * @brief Initialise class members
423 ***************************************************************************/
425{
426 // Initialise members
427 m_num = 0;
428 m_elements = 0;
429 m_alloc = 0;
430 m_colinx = -1;
431 m_inx = NULL;
432 m_data = NULL;
433
434 // Return
435 return;
436}
437
438
439/***********************************************************************//**
440 * @brief Copy class members
441 *
442 * @param[in] vector Sparse vector.
443 ***************************************************************************/
445{
446 // Copy attributes
447 m_num = vector.m_num;
448 m_elements = vector.m_elements;
449 m_alloc = vector.m_alloc;
450 m_colinx = vector.m_colinx;
451
452 // Copy index array
453 if (vector.m_inx != NULL) {
454 m_inx = new int[m_alloc];
455 for (int i = 0; i < m_elements; ++i) {
456 m_inx[i] = vector.m_inx[i];
457 }
458 }
459
460 // Copy data array
461 if (vector.m_data != NULL) {
462 m_data = new double[m_alloc];
463 for (int i = 0; i < m_elements; ++i) {
464 m_data[i] = vector.m_data[i];
465 }
466 }
467
468 // Return
469 return;
470}
471
472
473/***********************************************************************//**
474 * @brief Delete class members
475 ***************************************************************************/
477{
478 // Delete arrays
479 if (m_inx != NULL) delete [] m_inx;
480 if (m_data != NULL) delete [] m_data;
481
482 // Initialise pointers
483 m_inx = NULL;
484 m_data = NULL;
485
486 // Set allocated memory to zero
487 m_alloc = 0;
488
489 // Return
490 return;
491}
492
493
494/***********************************************************************//**
495 * @brief Allocate memory for elements
496 *
497 * @param[in] alloc Number of elements for allocation.
498 *
499 * Allocates memory for @p alloc elements. Memory for existing elements will
500 * be deleted.
501 ***************************************************************************/
502void GVectorSparse::alloc_members(const int& alloc)
503{
504 // Delete existing elements
505 if (m_inx != NULL) delete [] m_inx;
506 if (m_data != NULL) delete [] m_data;
507
508 // If number of elements is positive then allocate memory
509 if (alloc > 0) {
510 m_inx = new int[alloc];
511 m_data = new double[alloc];
512 }
513
514 // Set allocated memory
515 m_alloc = alloc;
516
517 // Return
518 return;
519}
520
521
522/***********************************************************************//**
523 * @brief Return inx for element index
524 *
525 * @param[in] index Element index [0,...,size()[.
526 * @return Sparse index (-1 if not found).
527 *
528 * Returns sparse index for a given element index. If no sparse index is
529 * found the method returns -1.
530 ***************************************************************************/
531int GVectorSparse::index2inx(const int& index) const
532{
533 // Initialise inx to "not found"
534 int inx = -1;
535
536 // Search for index
537 for (int i = 0; i < m_elements; ++i) {
538 if (m_inx[i] == index) {
539 inx = i;
540 break;
541 }
542 }
543
544 // Return sparse index
545 return inx;
546}
547
548
549/***********************************************************************//**
550 * @brief Insert one element into sparse vector
551 *
552 * @param[in] index Element index [0,...,elements()+1[.
553 * @param[in] inx Vector index [0,...,size()[.
554 * @param[in] data Vector data.
555 *
556 * Insert one element into the sparse vector. An element consists of an
557 * index @p inx and a value @p data. The element is inserted before the
558 * element with @p index. If @p index is equal to elements() the element is
559 * appended.
560 *
561 * The method does only allocate fresh memory in case that the existing
562 * memory is exhausted. Fresh memory is allocated in blocks of 512 elements
563 * until the total vector size is filled.
564 ***************************************************************************/
565void GVectorSparse::insert(const int& index, const int& inx, const double& data)
566{
567 // Initialise pointers to elements
568 int* new_inx = m_inx;
569 double* new_data = m_data;
570
571 // Determine if new memory allocation is needed
572 bool allocate = (m_elements + 1 > m_alloc);
573
574 // If there is not enough memory allocated then allocate new memory
575 if (allocate) {
577 if (m_alloc > m_num) {
578 m_alloc = m_num;
579 }
580 new_inx = new int[m_alloc];
581 new_data = new double[m_alloc];
582 }
583
584 // Copy information before inserted element. This is only needed in
585 // case that new memory has been allocated.
586 if (allocate) {
587 for (int i = 0; i < index; ++i) {
588 new_inx[i] = m_inx[i];
589 new_data[i] = m_data[i];
590 }
591 }
592
593 // Copy information after inserted element. This needs to be done in
594 // inverse order to preserve content in case that no new memory was
595 // allocated.
596 for (int i = m_elements; i > index; --i) {
597 new_inx[i] = m_inx[i-1];
598 new_data[i] = m_data[i-1];
599 }
600
601 // Insert element
602 new_inx[index] = inx;
603 new_data[index] = data;
604
605 // If new memory was allocated then replace old memory
606 if (allocate) {
607
608 // Delete old memory
609 delete [] m_inx;
610 delete [] m_data;
611
612 // Store pointers to new memory
613 m_inx = new_inx;
614 m_data = new_data;
615
616 } // endif: replaced old memory
617
618 // Increment number of elements
619 m_elements++;
620
621 // Return
622 return;
623}
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
#define G_OPERATOR
Sparce vector class interface definition.
#define G_SPARSE_VECTOR_DEFAULT_MEM_BLOCK
Vector class interface definition.
Sparse vector class.
int m_elements
Number of elements in vector.
int * m_inx
Index array.
void alloc_members(const int &alloc)
Allocate memory for elements.
void copy_members(const GVectorSparse &vector)
Copy class members.
GVectorSparse & operator=(const GVectorSparse &vector)
Assignment operator.
int m_alloc
Number of allocated elements.
void free_members(void)
Delete class members.
int index2inx(const int &index) const
Return inx for element index.
GVectorSparse(void)
Void sparse vector constructor.
double & operator[](const int &index)
Sparse vector element access with range checking.
void clear(void)
Clear sparse vector.
bool operator==(const GVectorSparse &vector) const
Equality operator.
const int & size(void) const
Return full size of sparse vector.
const int & inx(const int &index) const
Return inx for sparse vector element.
GVectorSparse * clone(void) const
Clone sparse vector.
const double & data(const int &index) const
Return value for sparse vector element.
int m_num
Vector size.
bool operator!=(const GVectorSparse &vector) const
Non-equality operator.
virtual ~GVectorSparse(void)
Destructor.
void insert(const int &index, const int &inx, const double &data)
Insert one element into sparse vector.
void init_members(void)
Initialise class members.
double * m_data
Data array.
int m_colinx
Column index.
std::string print(const GChatter &chatter=NORMAL) const
Print sparse vector information.
Vector class.
Definition GVector.hpp:46
const int & size(void) const
Return size of vector.
Definition GVector.hpp:180
int non_zeros(void) const
Returns number of non-zero elements in vector.
Definition GVector.cpp:627
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition GTools.cpp:1162
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:508