|
2 | 2 | // numpycpp — pycpp/init_py.h [PUBLIC HEADER] |
3 | 3 | // Pybind11 wrappers: array creation / initialisation. |
4 | 4 | // numpy.zeros_like numpy.ones_like numpy.full_like numpy.empty_like |
5 | | -// numpy.zeros numpy.ones numpy.full |
| 5 | +// numpy.zeros numpy.ones numpy.full numpy.empty |
| 6 | +// numpy.arange numpy.linspace numpy.logspace numpy.geomspace |
| 7 | +// numpy.eye numpy.identity numpy.diag |
6 | 8 | // ════════════════════════════════════════════════════════════════════════════ |
7 | 9 | #pragma once |
8 | 10 |
|
@@ -112,4 +114,166 @@ inline py::array ones_like(const py::array& arr, const std::string& dtype) { |
112 | 114 | throw std::runtime_error("ones_like: unsupported dtype: " + dtype); |
113 | 115 | } |
114 | 116 |
|
| 117 | +// ── numpy.empty ────────────────────────────────────────────────────────────── |
| 118 | + |
| 119 | +/// numpy.empty(shape, dtype=float64) |
| 120 | +inline py::array_t<double> empty(const std::vector<py::ssize_t>& shape) { |
| 121 | + return py::array_t<double>(shape); |
| 122 | +} |
| 123 | + |
| 124 | +// ── numpy.arange ───────────────────────────────────────────────────────────── |
| 125 | + |
| 126 | +/// arange<T> — internal typed helper |
| 127 | +template<typename T> |
| 128 | +py::array_t<T> arange(T start, T stop, T step) { |
| 129 | + size_t n = numpy::arange_size(start, stop, step); |
| 130 | + py::array_t<T> result(static_cast<py::ssize_t>(n)); |
| 131 | + numpy::arange(static_cast<T*>(result.request().ptr), start, stop, step); |
| 132 | + return result; |
| 133 | +} |
| 134 | + |
| 135 | +/// numpy.arange([start,] stop[, step]) |
| 136 | +/// Returns float64 array (numpy default). Integer stop/step are cast to double. |
| 137 | +inline py::array arange(py::object a, py::object b = py::none(), |
| 138 | + py::object c = py::none()) { |
| 139 | + double start, stop, step; |
| 140 | + if (b.is_none()) { |
| 141 | + start = 0.0; stop = a.cast<double>(); step = 1.0; |
| 142 | + } else if (c.is_none()) { |
| 143 | + start = a.cast<double>(); stop = b.cast<double>(); step = 1.0; |
| 144 | + } else { |
| 145 | + start = a.cast<double>(); stop = b.cast<double>(); step = c.cast<double>(); |
| 146 | + } |
| 147 | + return arange<double>(start, stop, step); |
| 148 | +} |
| 149 | + |
| 150 | +// ── numpy.linspace ─────────────────────────────────────────────────────────── |
| 151 | + |
| 152 | +/// linspace<T> — internal typed helper |
| 153 | +template<typename T> |
| 154 | +py::array_t<T> linspace(T start, T stop, py::ssize_t num, |
| 155 | + bool endpoint = true) { |
| 156 | + if (num < 0) throw std::invalid_argument("linspace: num must be >= 0"); |
| 157 | + py::array_t<T> result(num); |
| 158 | + numpy::linspace(static_cast<T*>(result.request().ptr), |
| 159 | + start, stop, static_cast<size_t>(num), endpoint); |
| 160 | + return result; |
| 161 | +} |
| 162 | + |
| 163 | +/// numpy.linspace(start, stop, num=50, endpoint=True) |
| 164 | +/// Returns float64 array (numpy default for scalar inputs). |
| 165 | +inline py::array linspace(py::object start_o, py::object stop_o, |
| 166 | + py::ssize_t num = 50, bool endpoint = true) { |
| 167 | + double start = start_o.cast<double>(), stop = stop_o.cast<double>(); |
| 168 | + return linspace<double>(start, stop, num, endpoint); |
| 169 | +} |
| 170 | + |
| 171 | +// ── numpy.logspace ─────────────────────────────────────────────────────────── |
| 172 | + |
| 173 | +/// logspace<T> — internal typed helper |
| 174 | +template<typename T> |
| 175 | +py::array_t<T> logspace(T start, T stop, py::ssize_t num, |
| 176 | + bool endpoint = true, T base = T(10)) { |
| 177 | + if (num < 0) throw std::invalid_argument("logspace: num must be >= 0"); |
| 178 | + py::array_t<T> result(num); |
| 179 | + numpy::logspace(static_cast<T*>(result.request().ptr), |
| 180 | + start, stop, static_cast<size_t>(num), endpoint, base); |
| 181 | + return result; |
| 182 | +} |
| 183 | + |
| 184 | +/// numpy.logspace(start, stop, num=50, endpoint=True, base=10.0) |
| 185 | +/// Returns float64 array (numpy default for scalar inputs). |
| 186 | +inline py::array logspace(py::object start_o, py::object stop_o, |
| 187 | + py::ssize_t num = 50, bool endpoint = true, |
| 188 | + double base = 10.0) { |
| 189 | + double start = start_o.cast<double>(), stop = stop_o.cast<double>(); |
| 190 | + return logspace<double>(start, stop, num, endpoint, base); |
| 191 | +} |
| 192 | + |
| 193 | +// ── numpy.geomspace ────────────────────────────────────────────────────────── |
| 194 | + |
| 195 | +/// geomspace<T> — internal typed helper |
| 196 | +template<typename T> |
| 197 | +py::array_t<T> geomspace(T start, T stop, py::ssize_t num, |
| 198 | + bool endpoint = true) { |
| 199 | + if (num < 0) throw std::invalid_argument("geomspace: num must be >= 0"); |
| 200 | + if (start == T(0) || stop == T(0)) |
| 201 | + throw std::invalid_argument("geomspace: start and stop must be non-zero"); |
| 202 | + py::array_t<T> result(num); |
| 203 | + numpy::geomspace(static_cast<T*>(result.request().ptr), |
| 204 | + start, stop, static_cast<size_t>(num), endpoint); |
| 205 | + return result; |
| 206 | +} |
| 207 | + |
| 208 | +/// numpy.geomspace(start, stop, num=50, endpoint=True) |
| 209 | +/// Returns float64 array (numpy default for scalar inputs). |
| 210 | +inline py::array geomspace(py::object start_o, py::object stop_o, |
| 211 | + py::ssize_t num = 50, bool endpoint = true) { |
| 212 | + double start = start_o.cast<double>(), stop = stop_o.cast<double>(); |
| 213 | + return geomspace<double>(start, stop, num, endpoint); |
| 214 | +} |
| 215 | + |
| 216 | +// ── numpy.eye ──────────────────────────────────────────────────────────────── |
| 217 | + |
| 218 | +/// numpy.eye(N, M=N, k=0, dtype=float64) |
| 219 | +template<typename T> |
| 220 | +py::array_t<T> eye(py::ssize_t N, py::ssize_t M = -1, int k = 0) { |
| 221 | + if (N < 0) throw std::invalid_argument("eye: N must be >= 0"); |
| 222 | + size_t Ns = static_cast<size_t>(N); |
| 223 | + size_t Ms = (M < 0) ? Ns : static_cast<size_t>(M); |
| 224 | + py::array_t<T> result({N, (M < 0 ? N : M)}); |
| 225 | + numpy::eye(static_cast<T*>(result.request().ptr), Ns, Ms, k); |
| 226 | + return result; |
| 227 | +} |
| 228 | + |
| 229 | +inline py::array_t<double> eye(py::ssize_t N, py::ssize_t M = -1, |
| 230 | + int k = 0) { |
| 231 | + return eye<double>(N, M, k); |
| 232 | +} |
| 233 | + |
| 234 | +// ── numpy.identity ─────────────────────────────────────────────────────────── |
| 235 | + |
| 236 | +/// numpy.identity(n, dtype=float64) |
| 237 | +template<typename T> |
| 238 | +py::array_t<T> identity(py::ssize_t n) { |
| 239 | + if (n < 0) throw std::invalid_argument("identity: n must be >= 0"); |
| 240 | + size_t ns = static_cast<size_t>(n); |
| 241 | + py::array_t<T> result({n, n}); |
| 242 | + numpy::identity(static_cast<T*>(result.request().ptr), ns); |
| 243 | + return result; |
| 244 | +} |
| 245 | + |
| 246 | +inline py::array_t<double> identity(py::ssize_t n) { |
| 247 | + return identity<double>(n); |
| 248 | +} |
| 249 | + |
| 250 | +// ── numpy.diag ─────────────────────────────────────────────────────────────── |
| 251 | + |
| 252 | +/// numpy.diag(v, k=0) |
| 253 | +/// 1-D input → 2-D diagonal matrix |
| 254 | +/// 2-D input → 1-D diagonal extraction |
| 255 | +template<typename T> |
| 256 | +py::array_t<T> diag(const py::array_t<T>& v, int k = 0) { |
| 257 | + auto buf = v.request(); |
| 258 | + if (buf.ndim == 1) { |
| 259 | + size_t n = static_cast<size_t>(buf.shape[0]); |
| 260 | + size_t N = n + static_cast<size_t>(std::abs(k)); |
| 261 | + py::array_t<T> result({static_cast<py::ssize_t>(N), |
| 262 | + static_cast<py::ssize_t>(N)}); |
| 263 | + numpy::diag_from_vec(static_cast<T*>(result.request().ptr), |
| 264 | + static_cast<const T*>(buf.ptr), n, k); |
| 265 | + return result; |
| 266 | + } |
| 267 | + if (buf.ndim == 2) { |
| 268 | + size_t rows = static_cast<size_t>(buf.shape[0]); |
| 269 | + size_t cols = static_cast<size_t>(buf.shape[1]); |
| 270 | + size_t len = numpy::diag_size(rows, cols, k); |
| 271 | + py::array_t<T> result(static_cast<py::ssize_t>(len)); |
| 272 | + numpy::diag_from_mat(static_cast<T*>(result.request().ptr), |
| 273 | + static_cast<const T*>(buf.ptr), rows, cols, k); |
| 274 | + return result; |
| 275 | + } |
| 276 | + throw std::invalid_argument("diag: input must be 1-D or 2-D"); |
| 277 | +} |
| 278 | + |
115 | 279 | } // namespace numpy |
0 commit comments