|
1 | 1 | /*
|
2 |
| - * Copyright (c) 2020-2021 Christoph Conrads |
| 2 | + * Copyright (c) 2020-2021, 2023 Christoph Conrads |
3 | 3 | * All rights reserved.
|
4 | 4 | *
|
5 | 5 | * Redistribution and use in source and binary forms, with or without
|
|
32 | 32 | #include <cstddef>
|
33 | 33 | #include <boost/assert.hpp>
|
34 | 34 | #include <boost/numeric/ublas/matrix.hpp>
|
| 35 | +#include <boost/numeric/ublas/matrix_proxy.hpp> |
35 | 36 | #include <boost/numeric/ublas/vector.hpp>
|
36 | 37 | #include <boost/test/unit_test.hpp>
|
37 | 38 |
|
@@ -267,3 +268,69 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(
|
267 | 268 | {
|
268 | 269 | xUNCSD2BY1_regression_20211024_impl(Number{});
|
269 | 270 | }
|
| 271 | + |
| 272 | + |
| 273 | +BOOST_AUTO_TEST_CASE(xUNCSD2BY1_regression_20231026) |
| 274 | +{ |
| 275 | + using Number = float; |
| 276 | + using Real = typename tools::real_from<Number>::type; |
| 277 | + using Matrix = ublas::matrix<Number, ublas::column_major>; |
| 278 | + |
| 279 | + auto m = std::size_t{2}; |
| 280 | + auto n = std::size_t{2}; |
| 281 | + auto p = std::size_t{1}; |
| 282 | + auto ldq = m + p; |
| 283 | + auto Q = Matrix(ldq, n); |
| 284 | + Q(0, 0) = -2.0392263e-01; Q(0, 1) = -9.7898704e-01; |
| 285 | + Q(1, 0) = 1.1427624e-08; Q(1, 1) = 9.2925374e-09; |
| 286 | + Q(2, 0) = 9.7898704e-01; Q(2, 1) = -2.0392257e-01; |
| 287 | + |
| 288 | + BOOST_VERIFY( tools::is_almost_isometric(Q) ); |
| 289 | + |
| 290 | + auto nan = tools::not_a_number<Number>::value; |
| 291 | + auto real_nan = tools::not_a_number<Real>::value; |
| 292 | + auto theta = ublas::vector<Real>(n, real_nan); |
| 293 | + auto Q_copy = Matrix(Q); |
| 294 | + auto U1 = Matrix(m, m, nan); |
| 295 | + auto U2 = Matrix(p, p, nan); |
| 296 | + auto V = Matrix(n, n, nan); |
| 297 | + auto lwork = 32 * ldq; |
| 298 | + auto work = ublas::vector<Number>(lwork, nan); |
| 299 | + auto iwork = ublas::vector<Integer>(m + p, -1); |
| 300 | + auto ret = lapack::xUNCSD2BY1( |
| 301 | + 'Y', 'Y', 'Y', |
| 302 | + m + p, m, n, |
| 303 | + &Q_copy(0, 0), ldq, &Q_copy(m, 0), ldq, |
| 304 | + &theta(0), |
| 305 | + &U1(0, 0), m, &U2(0, 0), p, &V(0, 0), n, |
| 306 | + &work(0), lwork, &iwork(0) |
| 307 | + ); |
| 308 | + |
| 309 | + BOOST_REQUIRE_EQUAL( ret, 0 ); |
| 310 | + BOOST_CHECK( tools::is_almost_isometric(U1) ); |
| 311 | + BOOST_CHECK( tools::is_almost_isometric(U2) ); |
| 312 | + BOOST_CHECK( tools::is_almost_isometric(V) ); |
| 313 | + |
| 314 | + auto sigma_1 = Matrix(m, n); |
| 315 | + auto sigma_2 = Matrix(p, n); |
| 316 | + |
| 317 | + std::fill(sigma_1.data().begin(), sigma_1.data().end(), 0.0); |
| 318 | + sigma_1(0, 0) = 1.0; |
| 319 | + sigma_1(1, 1) = std::cos(theta(0)); |
| 320 | + sigma_2(0, 0) = 0.0; |
| 321 | + sigma_2(0, 1) = std::sin(theta(0)); |
| 322 | + |
| 323 | + auto almost_Q = Matrix(m + p, n); |
| 324 | + |
| 325 | + std::fill(almost_Q.data().begin(), almost_Q.data().end(), nan); |
| 326 | + ublas::subrange(almost_Q, 0, m, 0, n) = prod(U1, Matrix(prod(sigma_1, V))); |
| 327 | + ublas::subrange(almost_Q, m, m + p, 0, n) = prod(U2, Matrix(prod(sigma_2, V))); |
| 328 | + |
| 329 | + BOOST_CHECK( tools::is_almost_isometric(almost_Q) ); |
| 330 | + |
| 331 | + auto eps = std::numeric_limits<Real>::epsilon(); |
| 332 | + |
| 333 | + BOOST_CHECK_LE( |
| 334 | + ublas::norm_frobenius(Q - almost_Q), 2 * eps * ublas::norm_frobenius(Q) |
| 335 | + ); |
| 336 | +} |
0 commit comments