MFEM v4.7.0
Finite element discretization library
Loading...
Searching...
No Matches
tadvector.hpp
Go to the documentation of this file.
1// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12#ifndef MFEM_TADVECTOR
13#define MFEM_TADVECTOR
14
15#include "mfem.hpp"
16
17#include <cmath>
18#include <iostream>
19#include <limits>
20#if defined(_MSC_VER) && (_MSC_VER < 1800)
21#include <float.h>
22#define isfinite _finite
23#endif
24
25namespace mfem
26{
27/// Templated vector data type.
28/** The main goal of the TAutoDiffVector class is to serve as a data container
29 for representing vectors in classes, methods, and functions utilized with
30 automatic differentiation (AD). The functionality/interface is copied from
31 the standard MFEM dense vector mfem::Vector. The basic idea is to utilize
32 the templated vector class in combination with AD during the development
33 phase. The AD parts can be replaced with optimized code once the initial
34 development of the application is complete. The common interface between
35 TAutoDiffVector and Vector will ease the transition from AD to
36 hand-optimized code as it does not require a change in the interface or the
37 code structure. TAutoDiffVector is intended to be utilized for dense serial
38 vectors. */
39template<typename dtype>
41{
42protected:
43 dtype *data;
44 int size;
46
47public:
48 /// Default constructor for Vector. Sets size = 0 and data = NULL.
50 {
51 data = nullptr;
52 size = 0;
53 capacity = 0;
54 }
55
56 /// Copy constructor. Allocates a new data array and copies the data.
58 {
59 const int s = v.Size();
60 if (s > 0)
61 {
62 size = s;
63 data = new dtype[s];
64 capacity = s;
65 for (int i = 0; i < s; i++)
66 {
67 data[i] = v[i];
68 }
69 }
70 else
71 {
72 size = 0;
73 capacity = 0;
74 data = nullptr;
75 }
76 }
77
79 {
80 const int s = v.Size();
81 if (s > 0)
82 {
83 size = s;
84 capacity = s;
85 data = new dtype[s];
86 for (int i = 0; i < s; i++)
87 {
88 data[i] = v[i];
89 }
90 }
91 else
92 {
93 size = 0;
94 capacity = 0;
95 data = nullptr;
96 }
97 }
98
99 /// @brief Creates vector of size s.
100 /// @warning Entries are not initialized to zero!
101 explicit TAutoDiffVector(int s)
102 {
103 if (s > 0)
104 {
105 size = s;
106 capacity = s;
107 data = new dtype[size];
108 }
109 else
110 {
111 size = 0;
112 capacity = 0;
113 data = nullptr;
114 }
115 }
116
117 /// Creates a vector referencing an array of doubles, owned by someone else.
118 /** The pointer @a _data can be NULL. The data array can be replaced later
119 with SetData(). */
120 TAutoDiffVector(dtype *_data, int _size)
121 {
122 if (capacity > 0)
123 {
124 delete[] data;
125 capacity = 0;
126 }
127 size = _size;
128 data = _data;
129 }
130
131 /// Reads a vector from multiple files
132 void Load(std::istream **in, int np, int *dim)
133 {
134 int i, j, s;
135
136 s = 0;
137 for (i = 0; i < np; i++)
138 {
139 s += dim[i];
140 }
141 SetSize(s);
142
143 int p = 0;
144 real_t tmpd;
145 for (i = 0; i < np; i++)
146 {
147 for (j = 0; j < dim[i]; j++)
148 {
149 *in[i] >> tmpd;
150 data[p++] = dtype(tmpd);
151 }
152 }
153 }
154
155 /// Load a vector from an input stream.
156 void Load(std::istream &in, int Size)
157 {
158 SetSize(Size);
159 real_t tmpd;
160 for (int i = 0; i < size; i++)
161 {
162 in >> tmpd;
163 data[i] = dtype(tmpd);
164 }
165 }
166
167 /// Load a vector from an input stream, reading the size from the stream.
168 void Load(std::istream &in)
169 {
170 int s;
171 in >> s;
172 Load(in, s);
173 }
174
175 /// @brief Resize the vector to size @a s.
176 /** If the new size is less than or equal to Capacity() then the internal
177 data array remains the same. Otherwise, the old array is deleted, if
178 owned, and a new array of size @a s is allocated without copying the
179 previous content of the Vector.
180 @warning In the second case above (new size greater than current one),
181 the vector will allocate new data array, even if it did not own the
182 original data! Also, new entries are not initialized! */
183 void SetSize(int s)
184 {
185 if (s == size)
186 {
187 return;
188 }
189
190 if (s <= capacity)
191 {
192 size = s;
193 return;
194 }
195
196 delete[] data;
197 data = new dtype[s];
198 size = s;
199 capacity = s;
200 }
201
202 /// Set the Vector data and size.
203 /** The Vector does not assume ownership of the new data. The new size is
204 @warning This method should be called only when OwnsData() is false.
205 @sa NewDataAndSize(). */
206 void SetDataAndSize(dtype *d, int s)
207 {
208 if (OwnsData())
209 {
210 delete[] data;
211 capacity = 0;
212 }
213 data = d;
214 size = s;
215 }
216
217 /// Set the Vector data and size, deleting the old data, if owned.
218 /** The Vector does not assume ownership of the new data. The new size is
219 also used as the new Capacity().
220 @sa SetDataAndSize(). */
221 void NewDataAndSize(dtype *d, int s) { SetDataAndSize(d, s); }
222
223 /// Reset the Vector to be a reference to a sub-vector of @a base.
224 inline void MakeRef(TAutoDiffVector<dtype> &base, int offset, int size_)
225 {
226 NewDataAndSize(base.GetData() + offset, size_);
227 }
228
229 /** @brief Reset the Vector to be a reference to a sub-vector of @a base
230 without changing its current size. */
231 inline void MakeRef(TAutoDiffVector<dtype> &base, int offset)
232 {
233 int tsiz = size;
234 NewDataAndSize(base.GetData() + offset, tsiz);
235 }
236
237 /// Destroy a vector
238 void Destroy()
239 {
240 size = 0;
241 capacity = 0;
242 delete[] data;
243 }
244
245 /// Returns the size of the vector.
246 inline int Size() const { return size; }
247
248 /// Return the size of the currently allocated data array.
249 /** It is always true that Capacity() >= Size(). */
250 inline int Capacity() const { return capacity; }
251
252 /// Return a pointer to the beginning of the Vector data.
253 /** @warning This method should be used with caution as it gives write access
254 to the data of const-qualified Vector%s. */
255 inline dtype *GetData() const
256 {
257 return const_cast<dtype *>((const dtype *) data);
258 }
259
260 /// Conversion to `double *`.
261 /** @note This conversion function makes it possible to use [] for indexing
262 in addition to the overloaded operator()(int). */
263 inline operator dtype *() { return data; }
264
265 /// Conversion to `const double *`.
266 /** @note This conversion function makes it possible to use [] for indexing
267 in addition to the overloaded operator()(int). */
268 inline operator const dtype *() const { return data; }
269
270 /// Read the Vector data (host pointer) ownership flag.
271 inline bool OwnsData() const { return (capacity > 0); }
272
273 /// Changes the ownership of the data; after the call the Vector is empty
274 inline void StealData(dtype **p)
275 {
276 *p = data;
277 delete[] data;
278 size = 0;
279 capacity = 0;
280 }
281
282 /// Changes the ownership of the data; after the call the Vector is empty
283 inline dtype *StealData()
284 {
285 dtype *p;
286 StealData(&p);
287 return p;
288 }
289
290 /// Access Vector entries. Index i = 0 .. size-1.
291 dtype &Elem(int i) { return operator()(i); }
292 /// Read only access to Vector entries. Index i = 0 .. size-1.
293 const dtype &Elem(int i) const { return operator()(i); }
294
295 /// Access Vector entries using () for 0-based indexing.
296 /** @note If MFEM_DEBUG is enabled, bounds checking is performed. */
297 inline dtype &operator()(int i)
298 {
299 MFEM_ASSERT(data && i >= 0 && i < size,
300 "index [" << i << "] is out of range [0," << size << ")");
301
302 return data[i];
303 }
304
305 /// Read only access to Vector entries using () for 0-based indexing.
306 /** @note If MFEM_DEBUG is enabled, bounds checking is performed. */
307 inline const dtype &operator()(int i) const
308 {
309 MFEM_ASSERT(data && i >= 0 && i < size,
310 "index [" << i << "] is out of range [0," << size << ")");
311
312 return data[i];
313 }
314
315 /// Dot product with a `dtype *` array.
316 dtype operator*(const dtype *v) const
317 {
318 dtype dot = 0.0;
319 for (int i = 0; i < size; i++)
320 {
321 dot += data[i] * v[i];
322 }
323 return dot;
324 }
325
326 /// Return the inner-product.
327 dtype operator*(const TAutoDiffVector<dtype> &v) const
328 {
329 MFEM_ASSERT(size == v.Size(), "incompatible Vectors!");
330 dtype dot = 0.0;
331 for (int i = 0; i < size; i++)
332 {
333 dot += data[i] * v[i];
334 }
335 return dot;
336 }
337
338 dtype operator*(const Vector &v) const
339 {
340 MFEM_ASSERT(size == v.Size(), "incompatible Vectors!");
341 dtype dot = 0.0;
342 for (int i = 0; i < size; i++)
343 {
344 dot += data[i] * v[i];
345 }
346 return dot;
347 }
348
349 /// Copy Size() entries from @a v.
351 {
352 for (int i = 0; i < size; i++)
353 {
354 data[i] = v[i];
355 }
356 return *this;
357 }
358
359 /// Copy assignment.
360 /** @note Defining this method overwrites the implicitly defined copy
361 assignment operator. */
363 {
364 SetSize(v.Size());
365 for (int i = 0; i < size; i++)
366 {
367 data[i] = v[i];
368 }
369 return *this;
370 }
371
373 {
374 SetSize(v.Size());
375 for (int i = 0; i < size; i++)
376 {
377 data[i] = v[i];
378 }
379 return *this;
380 }
381
382 /// Redefine '=' for vector = constant.
383 template<typename ivtype>
385 {
386 for (int i = 0; i < size; i++)
387 {
388 data[i] = (dtype) value;
389 }
390 return *this;
391 }
392
393 template<typename ivtype>
395 {
396 for (int i = 0; i < size; i++)
397 {
398 data[i] = data[i] * c;
399 }
400 return *this;
401 }
402
403 template<typename ivtype>
405 {
406 for (int i = 0; i < size; i++)
407 {
408 data[i] = data[i] / c;
409 }
410 return *this;
411 }
412
414 {
415 MFEM_ASSERT(size == v.Size(), "incompatible Vectors!");
416 for (int i = 0; i < size; i++)
417 {
418 data[i] = data[i] - v[i];
419 }
420 return *this;
421 }
422
423 template<typename ivtype>
425 {
426 for (int i = 0; i < size; i++)
427 {
428 data[i] = data[i] - v;
429 }
430 return *this;
431 }
432
434 {
435 MFEM_ASSERT(size == v.Size(), "incompatible Vectors!");
436 for (int i = 0; i < size; i++)
437 {
438 data[i] = data[i] + v[i];
439 }
440 return *this;
441 }
442
443 template<typename ivtype>
445 {
446 for (int i = 0; i < size; i++)
447 {
448 data[i] = data[i] + v;
449 }
450 return *this;
451 }
452
453 /// (*this) += a * Va
454 template<typename ivtype, typename vtype>
455 TAutoDiffVector &Add(const ivtype a, const vtype &v)
456 {
457 MFEM_ASSERT(size == v.Size(), "incompatible Vectors!");
458 for (int i = 0; i < size; i++)
459 {
460 data[i] = data[i] + a * v[i];
461 }
462 return *this;
463 }
464
465 /// (*this) = a * x
466 template<typename ivtype, typename vtype>
467 TAutoDiffVector &Set(const ivtype a, const vtype &v)
468 {
469 MFEM_ASSERT(size == v.Size(), "incompatible Vectors!");
470 for (int i = 0; i < size; i++)
471 {
472 data[i] = a * v[i];
473 }
474 return *this;
475 }
476
477 template<typename vtype>
478 void SetVector(const vtype &v, int offset)
479 {
480 MFEM_ASSERT(v.Size() + offset <= size, "invalid sub-vector");
481 for (int i = 0; i < size; i++)
482 {
483 data[i + offset] = v[i];
484 }
485 }
486
487 /// (*this) = -(*this)
488 void Neg()
489 {
490 for (int i = 0; i < size; i++)
491 {
492 data[i] = -data[i];
493 }
494 }
495
496 /// Swap the contents of two Vectors
497 inline void Swap(TAutoDiffVector<dtype> &other)
498 {
499 Swap(data, other.data);
500 Swap(size, other.size);
501 Swap(capacity, other.capacity);
502 }
503
504 /// Set v = v1 + v2.
505 template<typename vtype1, typename vtype2>
506 friend void add(const vtype1 &v1, const vtype2 &v2, TAutoDiffVector<dtype> &v)
507 {
508 MFEM_ASSERT(v1.Size() == v.Size(), "incompatible Vectors!");
509 MFEM_ASSERT(v2.Size() == v.Size(), "incompatible Vectors!");
510 for (int i = 0; i < v.Size(); i++)
511 {
512 v[i] = v1[i] + v2[i];
513 }
514 }
515
516 /// Set v = v1 + alpha * v2.
517 template<typename vtype1, typename vtype2>
518 friend void add(const vtype1 &v1,
519 dtype alpha,
520 const vtype2 &v2,
522 {
523 MFEM_ASSERT(v1.Size() == v.Size(), "incompatible Vectors!");
524 MFEM_ASSERT(v2.Size() == v.Size(), "incompatible Vectors!");
525 for (int i = 0; i < v.Size(); i++)
526 {
527 v[i] = v1[i] + alpha * v2[i];
528 }
529 }
530
531 template<typename vtype1, typename vtype2>
532 friend void add(const dtype a,
533 const vtype1 &x,
534 const dtype b,
535 const vtype2 &y,
537 {
538 MFEM_ASSERT(x.Size() == y.Size() && x.Size() == z.Size(),
539 "incompatible Vectors!");
540
541 for (int i = 0; i < z.Size(); i++)
542 {
543 z[i] = a * x[i] + b * y[i];
544 }
545 }
546
547 template<typename vtype1, typename vtype2>
548 friend void add(const dtype a,
549 const vtype1 &x,
550 const vtype2 &y,
552 {
553 MFEM_ASSERT(x.Size() == y.Size() && x.Size() == z.Size(),
554 "incompatible Vectors!");
555
556 for (int i = 0; i < z.Size(); i++)
557 {
558 z[i] = a * x[i] + y[i];
559 }
560 }
561
562 template<typename vtype1, typename vtype2>
563 friend void subtract(const vtype1 &x, const vtype2 &y,
565 {
566 MFEM_ASSERT(x.Size() == y.Size() && x.Size() == z.Size(),
567 "incompatible Vectors!");
568 for (int i = 0; i < z.Size(); i++)
569 {
570 z[i] = x[i] - y[i];
571 }
572 }
573
574 template<typename ivtype, typename vtype1, typename vtype2>
575 friend void subtract(const ivtype a,
576 const vtype1 &x,
577 const vtype2 &y,
579 {
580 MFEM_ASSERT(x.Size() == y.Size() && x.Size() == z.Size(),
581 "incompatible Vectors!");
582 for (int i = 0; i < z.Size(); i++)
583 {
584 z[i] = a * (x[i] - y[i]);
585 }
586 }
587
588 /// Destroys vector.
589 ~TAutoDiffVector() { delete[] data; }
590
591 /// Prints vector to stream @a os with @a width entries per line.
592 void Print(std::ostream &os = mfem::out, int width = 8) const
593 {
594 if (!size)
595 {
596 return;
597 }
598 for (int i = 0; 1;)
599 {
600 os << data[i];
601 i++;
602 if (i == size)
603 {
604 break;
605 }
606 if (i % width == 0)
607 {
608 os << '\n';
609 }
610 else
611 {
612 os << ' ';
613 }
614 }
615 os << '\n';
616 }
617
618 /// Set random values in the vector.
619 void Randomize(int seed = 0)
620 {
621 // static unsigned int seed = time(0);
622
623 if (seed == 0)
624 {
625 seed = (int) time(0);
626 }
627
628 // srand(seed++);
629 srand((unsigned) seed);
630
631 for (int i = 0; i < size; i++)
632 {
633 data[i] = rand_real();
634 }
635 }
636 /// Returns the l2 norm of the vector.
637 dtype Norml2() const
638 {
639 // Scale entries of Vector on the fly, using algorithms from std::hypot()
640 // and LAPACK's drm2. This scaling ensures that the argument of each call
641 // to std::pow is <= 1 to avoid overflow.
642 if (0 == size)
643 {
644 return 0.0;
645 } // end if 0 == size
646
647 if (1 == size)
648 {
649 return abs(data[0]);
650 } // end if 1 == size
651
652 dtype scale = 0.0;
653 dtype sum = 0.0;
654
655 for (int i = 0; i < size; i++)
656 {
657 if (data[i] != 0.0)
658 {
659 const dtype absdata = abs(data[i]);
660 if (scale <= absdata)
661 {
662 const dtype sqr_arg = scale / absdata;
663 sum = 1.0 + sum * (sqr_arg * sqr_arg);
664 scale = absdata;
665 continue;
666 } // end if scale <= absdata
667 const dtype sqr_arg = absdata / scale;
668 sum += (sqr_arg * sqr_arg); // else scale > absdata
669 } // end if data[i] != 0
670 }
671 return scale * sqrt(sum);
672 }
673
674 /// Returns the l_infinity norm of the vector.
675 dtype Normlinf() const
676 {
677 dtype max = 0.0;
678 for (int i = 0; i < size; i++)
679 {
680 max = max(abs(data[i]), max);
681 }
682 return max;
683 }
684 /// Returns the l_1 norm of the vector.
685 dtype Norml1() const
686 {
687 dtype sum = 0.0;
688 for (int i = 0; i < size; i++)
689 {
690 sum += abs(data[i]);
691 }
692 return sum;
693 }
694};
695
696} // namespace mfem
697
698#endif
Templated vector data type.
Definition tadvector.hpp:41
TAutoDiffVector & operator/=(ivtype c)
dtype Normlinf() const
Returns the l_infinity norm of the vector.
bool OwnsData() const
Read the Vector data (host pointer) ownership flag.
dtype * GetData() const
Return a pointer to the beginning of the Vector data.
void NewDataAndSize(dtype *d, int s)
Set the Vector data and size, deleting the old data, if owned.
void Destroy()
Destroy a vector.
void Swap(TAutoDiffVector< dtype > &other)
Swap the contents of two Vectors.
TAutoDiffVector(int s)
Creates vector of size s.
int Capacity() const
Return the size of the currently allocated data array.
TAutoDiffVector< dtype > & operator=(const dtype *v)
Copy Size() entries from v.
dtype operator*(const Vector &v) const
void StealData(dtype **p)
Changes the ownership of the data; after the call the Vector is empty.
TAutoDiffVector & Add(const ivtype a, const vtype &v)
(*this) += a * Va
void MakeRef(TAutoDiffVector< dtype > &base, int offset)
Reset the Vector to be a reference to a sub-vector of base without changing its current size.
const dtype & Elem(int i) const
Read only access to Vector entries. Index i = 0 .. size-1.
TAutoDiffVector & operator=(ivtype value)
Redefine '=' for vector = constant.
TAutoDiffVector & operator+=(const TAutoDiffVector< dtype > &v)
TAutoDiffVector & Set(const ivtype a, const vtype &v)
(*this) = a * x
dtype operator*(const TAutoDiffVector< dtype > &v) const
Return the inner-product.
friend void subtract(const ivtype a, const vtype1 &x, const vtype2 &y, TAutoDiffVector< dtype > &z)
dtype & operator()(int i)
Access Vector entries using () for 0-based indexing.
void Print(std::ostream &os=mfem::out, int width=8) const
Prints vector to stream os with width entries per line.
TAutoDiffVector(const TAutoDiffVector< dtype > &v)
Copy constructor. Allocates a new data array and copies the data.
Definition tadvector.hpp:57
void Load(std::istream &in, int Size)
Load a vector from an input stream.
void MakeRef(TAutoDiffVector< dtype > &base, int offset, int size_)
Reset the Vector to be a reference to a sub-vector of base.
TAutoDiffVector & operator+=(ivtype v)
TAutoDiffVector & operator*=(ivtype c)
void Randomize(int seed=0)
Set random values in the vector.
TAutoDiffVector< dtype > & operator=(const TAutoDiffVector< dtype > &v)
Copy assignment.
dtype Norml2() const
Returns the l2 norm of the vector.
TAutoDiffVector(const Vector &v)
Definition tadvector.hpp:78
friend void subtract(const vtype1 &x, const vtype2 &y, TAutoDiffVector< dtype > &z)
void Load(std::istream &in)
Load a vector from an input stream, reading the size from the stream.
~TAutoDiffVector()
Destroys vector.
friend void add(const vtype1 &v1, const vtype2 &v2, TAutoDiffVector< dtype > &v)
Set v = v1 + v2.
void Neg()
(*this) = -(*this)
void SetVector(const vtype &v, int offset)
dtype & Elem(int i)
Access Vector entries. Index i = 0 .. size-1.
TAutoDiffVector & operator-=(ivtype v)
dtype Norml1() const
Returns the l_1 norm of the vector.
TAutoDiffVector()
Default constructor for Vector. Sets size = 0 and data = NULL.
Definition tadvector.hpp:49
const dtype & operator()(int i) const
Read only access to Vector entries using () for 0-based indexing.
friend void add(const dtype a, const vtype1 &x, const dtype b, const vtype2 &y, TAutoDiffVector< dtype > &z)
friend void add(const dtype a, const vtype1 &x, const vtype2 &y, TAutoDiffVector< dtype > &z)
int Size() const
Returns the size of the vector.
void SetSize(int s)
Resize the vector to size s.
void SetDataAndSize(dtype *d, int s)
Set the Vector data and size.
TAutoDiffVector & operator-=(const TAutoDiffVector< dtype > &v)
dtype * StealData()
Changes the ownership of the data; after the call the Vector is empty.
TAutoDiffVector(dtype *_data, int _size)
Creates a vector referencing an array of doubles, owned by someone else.
void Load(std::istream **in, int np, int *dim)
Reads a vector from multiple files.
dtype operator*(const dtype *v) const
Dot product with a dtype * array.
TAutoDiffVector< dtype > & operator=(const Vector &v)
friend void add(const vtype1 &v1, dtype alpha, const vtype2 &v2, TAutoDiffVector< dtype > &v)
Set v = v1 + alpha * v2.
Vector data type.
Definition vector.hpp:80
int Size() const
Returns the size of the vector.
Definition vector.hpp:218
const real_t alpha
Definition ex15.cpp:369
int dim
Definition ex24.cpp:53
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition globals.hpp:66
real_t rand_real()
Generate a random real_t number in the interval [0,1) using rand().
Definition vector.hpp:59
float real_t
Definition config.hpp:43
real_t p(const Vector &x, real_t t)
RefCoord s[3]