NumCpp  2.4.0
A Templatized Header Only C++ Implementation of the Python NumPy Library
gradient.hpp
Go to the documentation of this file.
1 #pragma once
29 
34 #include "NumCpp/Core/Shape.hpp"
35 #include "NumCpp/Core/Types.hpp"
36 #include "NumCpp/NdArray.hpp"
37 
38 #include <complex>
39 #include <string>
40 
41 namespace nc
42 {
43  //============================================================================
44  // Method Description:
55  template<typename dtype>
57  {
59 
60  switch (inAxis)
61  {
62  case Axis::ROW:
63  {
64  const auto inShape = inArray.shape();
65  if (inShape.rows < 2)
66  {
67  THROW_INVALID_ARGUMENT_ERROR("input array must have more than 1 row.");
68  }
69 
70  // first do the first and last rows
71  auto returnArray = NdArray<double>(inShape);
72  for (uint32 col = 0; col < inShape.cols; ++col)
73  {
74  returnArray(0, col) = static_cast<double>(inArray(1, col)) - static_cast<double>(inArray(0, col));
75  returnArray(-1, col) = static_cast<double>(inArray(-1, col)) - static_cast<double>(inArray(-2, col));
76  }
77 
78  // then rip through the rest of the array
79  for (uint32 col = 0; col < inShape.cols; ++col)
80  {
81  for (uint32 row = 1; row < inShape.rows - 1; ++row)
82  {
83  returnArray(row, col) = (static_cast<double>(inArray(row + 1, col)) - static_cast<double>(inArray(row - 1, col))) / 2.0;
84  }
85  }
86 
87  return returnArray;
88  }
89  case Axis::COL:
90  {
91  const auto inShape = inArray.shape();
92  if (inShape.cols < 2)
93  {
94  THROW_INVALID_ARGUMENT_ERROR("input array must have more than 1 columns.");
95  }
96 
97  // first do the first and last columns
98  auto returnArray = NdArray<double>(inShape);
99  for (uint32 row = 0; row < inShape.rows; ++row)
100  {
101  returnArray(row, 0) = static_cast<double>(inArray(row, 1)) - static_cast<double>(inArray(row, 0));
102  returnArray(row, -1) = static_cast<double>(inArray(row, -1)) - static_cast<double>(inArray(row, -2));
103  }
104 
105  // then rip through the rest of the array
106  for (uint32 row = 0; row < inShape.rows; ++row)
107  {
108  for (uint32 col = 1; col < inShape.cols - 1; ++col)
109  {
110  returnArray(row, col) = (static_cast<double>(inArray(row, col + 1)) - static_cast<double>(inArray(row, col - 1))) / 2.0;
111  }
112  }
113 
114  return returnArray;
115  }
116  default:
117  {
118  // will return the gradient of the flattened array
119  if (inArray.size() < 2)
120  {
121  THROW_INVALID_ARGUMENT_ERROR("input array must have more than 1 element.");
122  }
123 
124  auto returnArray = NdArray<double>(1, inArray.size());
125  returnArray[0] = static_cast<double>(inArray[1]) - static_cast<double>(inArray[0]);
126  returnArray[-1] = static_cast<double>(inArray[-1]) - static_cast<double>(inArray[-2]);
127 
128  stl_algorithms::transform(inArray.cbegin() + 2, inArray.cend(), inArray.cbegin(), returnArray.begin() + 1,
129  [](dtype value1, dtype value2) -> double
130  {
131  return (static_cast<double>(value1) - static_cast<double>(value2)) / 2.0;
132  });
133 
134  return returnArray;
135  }
136  }
137  }
138 
139  //============================================================================
140  // Method Description:
151  template<typename dtype>
152  NdArray<std::complex<double>> gradient(const NdArray<std::complex<dtype>>& inArray, Axis inAxis = Axis::ROW)
153  {
155 
156  switch (inAxis)
157  {
158  case Axis::ROW:
159  {
160  const auto inShape = inArray.shape();
161  if (inShape.rows < 2)
162  {
163  THROW_INVALID_ARGUMENT_ERROR("input array must have more than 1 row.");
164  }
165 
166  // first do the first and last rows
167  auto returnArray = NdArray<std::complex<double>>(inShape);
168  for (uint32 col = 0; col < inShape.cols; ++col)
169  {
170  returnArray(0, col) = complex_cast<double>(inArray(1, col)) - complex_cast<double>(inArray(0, col));
171  returnArray(-1, col) = complex_cast<double>(inArray(-1, col)) - complex_cast<double>(inArray(-2, col));
172  }
173 
174  // then rip through the rest of the array
175  for (uint32 col = 0; col < inShape.cols; ++col)
176  {
177  for (uint32 row = 1; row < inShape.rows - 1; ++row)
178  {
179  returnArray(row, col) = (complex_cast<double>(inArray(row + 1, col)) -
180  complex_cast<double>(inArray(row - 1, col))) / 2.0;
181  }
182  }
183 
184  return returnArray;
185  }
186  case Axis::COL:
187  {
188  const auto inShape = inArray.shape();
189  if (inShape.cols < 2)
190  {
191  THROW_INVALID_ARGUMENT_ERROR("input array must have more than 1 columns.");
192  }
193 
194  // first do the first and last columns
195  auto returnArray = NdArray<std::complex<double>>(inShape);
196  for (uint32 row = 0; row < inShape.rows; ++row)
197  {
198  returnArray(row, 0) = complex_cast<double>(inArray(row, 1)) - complex_cast<double>(inArray(row, 0));
199  returnArray(row, -1) = complex_cast<double>(inArray(row, -1)) - complex_cast<double>(inArray(row, -2));
200  }
201 
202  // then rip through the rest of the array
203  for (uint32 row = 0; row < inShape.rows; ++row)
204  {
205  for (uint32 col = 1; col < inShape.cols - 1; ++col)
206  {
207  returnArray(row, col) = (complex_cast<double>(inArray(row, col + 1)) -
208  complex_cast<double>(inArray(row, col - 1))) / 2.0;
209  }
210  }
211 
212  return returnArray;
213  }
214  default:
215  {
216  // will return the gradient of the flattened array
217  if (inArray.size() < 2)
218  {
219  THROW_INVALID_ARGUMENT_ERROR("input array must have more than 1 element.");
220  }
221 
222  auto returnArray = NdArray<std::complex<double>>(1, inArray.size());
223  returnArray[0] = complex_cast<double>(inArray[1]) - complex_cast<double>(inArray[0]);
224  returnArray[-1] = complex_cast<double>(inArray[-1]) - complex_cast<double>(inArray[-2]);
225 
226  stl_algorithms::transform(inArray.cbegin() + 2, inArray.cend(), inArray.cbegin(), returnArray.begin() + 1,
227  [](const std::complex<dtype>& value1, const std::complex<dtype>& value2) -> std::complex<double>
228  {
229  return (complex_cast<double>(value1) - complex_cast<double>(value2)) / 2.0;
230  });
231 
232  return returnArray;
233  }
234  }
235  }
236 } // namespace nc
StaticAsserts.hpp
nc::NdArray::shape
Shape shape() const noexcept
Definition: NdArrayCore.hpp:4356
Error.hpp
STATIC_ASSERT_ARITHMETIC
#define STATIC_ASSERT_ARITHMETIC(dtype)
Definition: StaticAsserts.hpp:37
nc::Axis::ROW
@ ROW
StdComplexOperators.hpp
nc::NdArray< double >
nc::stl_algorithms::transform
OutputIt transform(InputIt first, InputIt last, OutputIt destination, UnaryOperation unaryFunction)
Definition: StlAlgorithms.hpp:702
nc::uint32
std::uint32_t uint32
Definition: Types.hpp:40
NdArray.hpp
nc::NdArray::size
size_type size() const noexcept
Definition: NdArrayCore.hpp:4370
nc::NdArray::cend
const_iterator cend() const noexcept
Definition: NdArrayCore.hpp:1487
nc::Axis
Axis
Enum To describe an axis.
Definition: Types.hpp:46
Shape.hpp
nc
Definition: Coordinate.hpp:44
THROW_INVALID_ARGUMENT_ERROR
#define THROW_INVALID_ARGUMENT_ERROR(msg)
Definition: Error.hpp:36
nc::NdArray::cbegin
const_iterator cbegin() const noexcept
Definition: NdArrayCore.hpp:1143
StlAlgorithms.hpp
nc::gradient
NdArray< double > gradient(const NdArray< dtype > &inArray, Axis inAxis=Axis::ROW)
Definition: gradient.hpp:56
Types.hpp
nc::NdArray::begin
iterator begin() noexcept
Definition: NdArrayCore.hpp:1087
nc::Axis::COL
@ COL