Sequential Quantum Gate Decomposer  v1.9.6
Powerful decomposition of general unitarias into one- and two-qubit gates gates
matrix_base.hpp
Go to the documentation of this file.
1 /*
2 Copyright 2020 Peter Rakyta, Ph.D.
3 
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 
16 */
17 
18 #ifndef matrix_BASE_H
19 #define matrix_BASE_H
20 
21 #include "QGDTypes.h"
22 #include <atomic>
23 #include <cstring>
24 #include <iostream>
25 #include <tbb/scalable_allocator.h>
26 
27 
28 
37 template<typename scalar>
38 class matrix_base {
39 
40 public:
42  int rows;
44  int cols;
46  int stride;
49 
50 protected:
51 
53  bool conjugated;
55  bool transposed;
57  bool owner;
59  std::atomic<int64_t>* references;
60 
61 
62 
63 public:
64 
70 
71  // The number of rows
72  rows = 0;
73  // The number of columns
74  cols = 0;
75  // The column stride of the matrix
76  stride = 0;
77  // pointer to the stored data
78  data = NULL;
79  // logical variable indicating whether the matrix needs to be conjugated in CBLAS operations
80  conjugated = false;
81  // logical variable indicating whether the matrix needs to be transposed in CBLAS operations
82  transposed = false;
83  // logical value indicating whether the class instance is the owner of the stored data or not. (If true, the data array is released in the destructor)
84  owner = false;
85  references = new std::atomic<int64_t>(1);
86 }
87 
88 
96 matrix_base( scalar* data_in, int rows_in, int cols_in) {
97 
98  // The number of rows
99  rows = rows_in;
100  // The number of columns
101  cols = cols_in;
102  // The column stride of the matrix
103  stride = cols_in;
104  // pointer to the stored data
105  data = data_in;
106  // logical variable indicating whether the matrix needs to be conjugated in CBLAS operations
107  conjugated = false;
108  // logical variable indicating whether the matrix needs to be transposed in CBLAS operations
109  transposed = false;
110  // logical value indicating whether the class instance is the owner of the stored data or not. (If true, the data array is released in the destructor)
111  owner = false;
112  references = new std::atomic<int64_t>(1);
113 }
114 
115 
116 
125 matrix_base( scalar* data_in, int rows_in, int cols_in, int stride_in) {
126 
127  // The number of rows
128  rows = rows_in;
129  // The number of columns
130  cols = cols_in;
131  // The column stride of the matrix
132  stride = stride_in;
133  // pointer to the stored data
134  data = data_in;
135  // logical variable indicating whether the matrix needs to be conjugated in CBLAS operations
136  conjugated = false;
137  // logical variable indicating whether the matrix needs to be transposed in CBLAS operations
138  transposed = false;
139  // logical value indicating whether the class instance is the owner of the stored data or not. (If true, the data array is released in the destructor)
140  owner = false;
141  references = new std::atomic<int64_t>(1);
142 }
143 
144 
145 
152 matrix_base( int rows_in, int cols_in) {
153 
154  // The number of rows
155  rows = rows_in;
156  // The number of columns
157  cols = cols_in;
158  // The column stride of the matrix
159  stride = cols_in;
160  // pointer to the stored data
161  data = (scalar*)scalable_aligned_malloc( rows*cols*sizeof(scalar), CACHELINE);
162  assert(data);
163  // logical variable indicating whether the matrix needs to be conjugated in CBLAS operations
164  conjugated = false;
165  // logical variable indicating whether the matrix needs to be transposed in CBLAS operations
166  transposed = false;
167  // logical value indicating whether the class instance is the owner of the stored data or not. (If true, the data array is released in the destructor)
168  owner = true;
169  references = new std::atomic<int64_t>(1);
170 
171 
172 }
173 
174 
182 matrix_base( int rows_in, int cols_in, int stride_in) {
183 
184  // The number of rows
185  rows = rows_in;
186  // The number of columns
187  cols = cols_in;
188  // The column stride of the matrix
189  stride = stride_in;
190  // pointer to the stored data
191  data = (scalar*)scalable_aligned_malloc( rows*stride*sizeof(scalar), CACHELINE);
192 #ifdef DEBUG
193  if (rows > 0 && cols>0) assert(data);
194 #endif
195  // logical variable indicating whether the matrix needs to be conjugated in CBLAS operations
196  conjugated = false;
197  // logical variable indicating whether the matrix needs to be transposed in CBLAS operations
198  transposed = false;
199  // logical value indicating whether the class instance is the owner of the stored data or not. (If true, the data array is released in the destructor)
200  owner = true;
201  references = new std::atomic<int64_t>(1);
202 
203 
204 }
205 
206 
213 
214  data = in.data;
215  rows = in.rows;
216  cols = in.cols;
217  stride = in.stride;
218  transposed = in.transposed;
219  conjugated = in.conjugated;
220  owner = in.owner;
221 
222  references = in.references;
223 
224  if (references != NULL) {
225  references->fetch_add(1, std::memory_order_relaxed);
226  }
227 
228 
229 
230 }
231 
232 
233 
238  release_data();
239 }
240 
245 bool is_conjugated() const {
246  return conjugated;
247 }
248 
252 void conjugate() {
253 
254  conjugated = !conjugated;
255 
256 }
257 
258 
263 bool is_transposed() const {
264 
265  return transposed;
266 
267 }
268 
269 
273 void transpose() {
274 
275  transposed = !transposed;
276 
277 }
278 
279 
280 
281 
285 scalar* get_data() const {
286 
287  return data;
288 
289 }
290 
291 
297 void replace_data( scalar* data_in, bool owner_in) {
298 
299  release_data();
300  data = data_in;
301  owner = owner_in;
302 
303  references = new std::atomic<int64_t>(1);
304 
305 }
306 
307 
311 void release_data() {
312 
313  if (references == NULL) return;
314 
315  std::atomic<int64_t>* references_loc = references;
316  scalar* data_loc = data;
317  const bool owner_loc = owner;
318 
319  data = NULL;
320  references = NULL;
321 
322  if (references_loc->fetch_sub(1, std::memory_order_acq_rel) == 1) {
323  if (owner_loc) {
324  scalable_aligned_free(data_loc);
325  }
326  delete references_loc;
327  }
328 
329 }
330 
331 
332 
337 void set_owner( bool owner_in) {
338 
339  owner=owner_in;
340 
341 }
342 
348 void operator= (const matrix_base& mtx ) {
349 
350  // releasing the containing data
351  release_data();
352 
353  // The number of rows
354  rows = mtx.rows;
355  // The number of columns
356  cols = mtx.cols;
357  // The column stride of the matrix
358  stride = mtx.stride;
359  // pointer to the stored data
360  data = mtx.data;
361  // logical variable indicating whether the matrix needs to be conjugated in CBLAS operations
362  conjugated = mtx.conjugated;
363  // logical variable indicating whether the matrix needs to be transposed in CBLAS operations
364  transposed = mtx.transposed;
365  // logical value indicating whether the class instance is the owner of the stored data or not. (If true, the data array is released in the destructor)
366  owner = mtx.owner;
367 
368  references = mtx.references;
369 
370  if (references != NULL) {
371  references->fetch_add(1, std::memory_order_relaxed);
372  }
373 
374 }
375 
376 
382 scalar& operator[](int idx) const {
383 
384 #ifdef DEBUG
385  if ( idx >= rows*stride || idx < 0) {
386  std::cout << "Accessing element out of bonds. Exiting" << std::endl;
387  exit(-1);
388  }
389 #endif
390 
391  return data[idx];
392 }
393 
394 bool operator<(const matrix_base<scalar>& other) const {
395  if (rows != other.rows) return rows < other.rows;
396  if (cols != other.cols) return cols < other.cols;
397  for (int i = 0; i < rows; ++i) {
398  for (int j = 0; j < cols; ++j) {
399  if (data[i * stride + j] != other.data[i * stride + j])
400  return data[i * stride + j] < other.data[i * stride + j];
401  }
402  }
403  return false; // they are equal
404 }
405 
411 
413 
414  // logical variable indicating whether the matrix needs to be conjugated in CBLAS operations
415  ret.conjugated = conjugated;
416  // logical variable indicating whether the matrix needs to be transposed in CBLAS operations
417  ret.transposed = transposed;
418  // logical value indicating whether the class instance is the owner of the stored data or not. (If true, the data array is released in the destructor)
419  ret.owner = true;
420 
421  memcpy( ret.data, data, rows*stride*sizeof(scalar));
422 
423  return ret;
424 
425 }
426 
433 void copy_to(matrix_base<scalar>& target) const {
434 
435  if (target.rows != rows || target.cols != cols || target.stride != stride) {
436  target = matrix_base<scalar>(rows, cols, stride);
437  }
438 
439  if (data != NULL && target.data != data) {
440  memcpy(target.data, data, rows*stride*sizeof(scalar));
441  }
442 
443  target.conjugated = conjugated;
444  target.transposed = transposed;
445 
446 }
447 
449  if (((uintptr_t)(void*)data & (CACHELINE-1)) == 0) return; //CACHELINE must be power of 2, 16 sufficient, 64 is okay though
450  scalar* newdata = (scalar*)scalable_aligned_malloc( rows*stride*sizeof(scalar), CACHELINE);
451  memcpy( newdata, data, rows*stride*sizeof(scalar));
452  replace_data(newdata, true);
453 }
454 
455 
456 
461 int size() const {
462 
463  return rows*cols;
464 
465 }
466 
467 
471 void print_matrix() const {
472  std::cout << std::endl << "The stored matrix:" << std::endl;
473  for ( int row_idx=0; row_idx < rows; row_idx++ ) {
474  for ( int col_idx=0; col_idx < cols; col_idx++ ) {
475  int element_idx = row_idx*stride + col_idx;
476  std::cout << " " << data[element_idx];
477  }
478  std::cout << std::endl;
479  }
480  std::cout << std::endl << std::endl << std::endl;
481 
482 }
483 
484 
485 
486 
487 
488 
489 
490 }; //matrix_base
491 
492 
493 
494 
495 
496 #endif
bool owner
logical value indicating whether the class instance is the owner of the stored data or not...
Definition: matrix_base.hpp:57
int stride
The column stride of the array. (The array elements in one row are a_0, a_1, ... a_{cols-1}, 0, 0, 0, 0. The number of zeros is stride-cols)
Definition: matrix_base.hpp:46
matrix_base< scalar > copy() const
Call to create a copy of the matrix.
scalar * data
pointer to the stored data
Definition: matrix_base.hpp:48
matrix_base(scalar *data_in, int rows_in, int cols_in)
Constructor of the class.
Definition: matrix_base.hpp:96
void release_data()
Call to release the data stored by the matrix.
void ensure_aligned()
matrix_base(scalar *data_in, int rows_in, int cols_in, int stride_in)
Constructor of the class.
bool transposed
logical variable indicating whether the matrix needs to be transposed in CBLAS operations ...
Definition: matrix_base.hpp:55
bool conjugated
logical variable indicating whether the matrix needs to be conjugated in CBLAS operations ...
Definition: matrix_base.hpp:53
scalar * get_data() const
Call to get the pointer to the stored data.
~matrix_base()
Destructor of the class.
#define CACHELINE
Definition: QGDTypes.h:33
Base Class to store data of arrays and its properties.
Definition: matrix_base.hpp:38
void operator=(const matrix_base &mtx)
Assignment operator.
scalar & operator[](int idx) const
Operator [] to access elements in array style (does not check the boundaries of the stored array) ...
int rows
The number of rows.
Definition: matrix_base.hpp:42
int cols
The number of columns.
Definition: matrix_base.hpp:44
void replace_data(scalar *data_in, bool owner_in)
Call to replace the stored data by an another data array.
matrix_base(int rows_in, int cols_in, int stride_in)
Constructor of the class.
Custom types for the SQUANDER package.
void print_matrix() const
Call to prints the stored matrix on the standard output.
void set_owner(bool owner_in)
Call to set the current class instance to be (or not to be) the owner of the stored data array...
void copy_to(matrix_base< scalar > &target) const
Copy the current matrix storage into a reusable target matrix.
std::atomic< int64_t > * references
the number of the current references of the present object
Definition: matrix_base.hpp:59
int size() const
Call to get the number of the allocated elements.
void transpose()
Call to transpose (or un-transpose) the matrix for CBLAS functions.
matrix_base()
Default constructor of the class.
Definition: matrix_base.hpp:69
bool is_conjugated() const
Call to get whether the matrix should be conjugated in CBLAS functions or not.
matrix_base(int rows_in, int cols_in)
Constructor of the class.
void conjugate()
Call to conjugate (or un-conjugate) the matrix for CBLAS functions.
matrix_base(const matrix_base< scalar > &in)
Copy constructor of the class.
bool is_transposed() const
Call to get whether the matrix should be conjugated in CBLAS functions or not.