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