Actions
|
|
[ Date Prev][ Date Next][ Thread Prev][ Thread Next][ Date Index][ Thread Index]
[patch] Toeplitz system solver
- To: VSIPL++ Developers List <vsipl++@xxxxxxxxxxxxxxxx>
- Subject: [patch] Toeplitz system solver
- From: Jules Bergmann <jules@xxxxxxxxxxxxxxxx>
- Date: Thu, 29 Sep 2005 11:37:04 -0400
This patch implements and tests the toeplitz system solver.
Implementation is based on the TASP C-VSIPL version.
To write a generic version that works for both real and complex, I
needed a conj function that works for both real and complex numbers.
However, the VSIPL++ conj is limited to just complex<T>. To get around
this, I added impl_conj (and impl_real and impl_imag) scalar and
element-wise functions that work for both real and complex (conj(real)
is just the identity function).
It may be worthwhile to make 'conj' have the same behavior as
'impl_conj'. This would let users write generic code that works for
both complex and real values.
-- Jules
Index: ChangeLog
===================================================================
RCS file: /home/cvs/Repository/vpp/ChangeLog,v
retrieving revision 1.282
diff -c -p -r1.282 ChangeLog
*** ChangeLog 29 Sep 2005 06:00:51 -0000 1.282
--- ChangeLog 29 Sep 2005 15:28:11 -0000
***************
*** 1,3 ****
--- 1,13 ----
+ 2005-09-29 Jules Bergmann <jules@xxxxxxxxxxxxxxxx>
+
+ Implement toeplitz linear system solver.
+ * src/vsip/solvers.hpp: Include solver-toepsol.
+ * src/vsip/impl/fns_scalar.hpp: Implement impl_conj, impl_real,
+ and impl_imag functions that work with both scalar and complex.
+ * src/vsip/impl/fns_elementwise.hpp: Likewise.
+ * src/vsip/impl/solver-toepsol.hpp: New file, toeplitz solver.
+ * tests/solver-toepsol.cpp: New file, test for toeplitz solver.
+
2005-09-28 Don McCoy <don@xxxxxxxxxxxxxxxx>
* src/vsip/impl/matvec-prod.hpp: added prod3, prod4,
Index: src/vsip/solvers.hpp
===================================================================
RCS file: /home/cvs/Repository/vpp/src/vsip/solvers.hpp,v
retrieving revision 1.4
diff -c -p -r1.4 solvers.hpp
*** src/vsip/solvers.hpp 27 Sep 2005 21:30:17 -0000 1.4
--- src/vsip/solvers.hpp 29 Sep 2005 15:28:11 -0000
***************
*** 19,23 ****
--- 19,24 ----
#include <vsip/impl/solver-llsqsol.hpp>
#include <vsip/impl/solver-cholesky.hpp>
#include <vsip/impl/solver-svd.hpp>
+ #include <vsip/impl/solver-toepsol.hpp>
#endif // VSIP_SOLVERS_HPP
Index: src/vsip/impl/fns_elementwise.hpp
===================================================================
RCS file: /home/cvs/Repository/vpp/src/vsip/impl/fns_elementwise.hpp,v
retrieving revision 1.12
diff -c -p -r1.12 fns_elementwise.hpp
*** src/vsip/impl/fns_elementwise.hpp 26 Sep 2005 14:09:24 -0000 1.12
--- src/vsip/impl/fns_elementwise.hpp 29 Sep 2005 15:28:11 -0000
*************** VSIP_IMPL_UNARY_FUNC(sqrt)
*** 305,310 ****
--- 305,334 ----
VSIP_IMPL_UNARY_FUNC(tan)
VSIP_IMPL_UNARY_FUNC(tanh)
+ VSIP_IMPL_UNARY_FUNC(impl_conj)
+
+ template <typename T>
+ struct impl_real_functor
+ {
+ typedef typename Scalar_of<T>::type result_type;
+ static result_type apply(T t) { return fn::impl_real(t);}
+ result_type operator()(T t) const { return apply(t);}
+ };
+
+ VSIP_IMPL_UNARY_DISPATCH(impl_real)
+ VSIP_IMPL_UNARY_FUNCTION(impl_real)
+
+ template <typename T>
+ struct impl_imag_functor
+ {
+ typedef typename Scalar_of<T>::type result_type;
+ static result_type apply(T t) { return fn::impl_imag(t);}
+ result_type operator()(T t) const { return apply(t);}
+ };
+
+ VSIP_IMPL_UNARY_DISPATCH(impl_imag)
+ VSIP_IMPL_UNARY_FUNCTION(impl_imag)
+
/***********************************************************************
Binary Functions
***********************************************************************/
Index: src/vsip/impl/fns_scalar.hpp
===================================================================
RCS file: /home/cvs/Repository/vpp/src/vsip/impl/fns_scalar.hpp,v
retrieving revision 1.11
diff -c -p -r1.11 fns_scalar.hpp
*** src/vsip/impl/fns_scalar.hpp 17 Sep 2005 18:26:39 -0000 1.11
--- src/vsip/impl/fns_scalar.hpp 29 Sep 2005 15:28:12 -0000
*************** template <typename T1, typename T2, type
*** 275,280 ****
--- 275,308 ----
inline typename Promotion<typename Promotion<T1, T2>::type, T3>::type
sbm(T1 t1, T2 t2, T3 t3) VSIP_NOTHROW { return (t1 - t2) * t3;}
+ template <typename T>
+ struct Impl_complex_class
+ {
+ static T conj(T val) { return val; }
+ static T real(T val) { return val; }
+ static T imag(T val) { return T(); }
+ };
+
+ template <typename T>
+ struct Impl_complex_class<std::complex<T> >
+ {
+ static std::complex<T> conj(std::complex<T> val) { return std::conj(val); }
+ static T real(std::complex<T> val) { return val.real(); }
+ static T imag(std::complex<T> val) { return val.imag(); }
+ };
+
+ template <typename T>
+ inline T
+ impl_conj(T val) { return Impl_complex_class<T>::conj(val); }
+
+ template <typename T>
+ inline typename Scalar_of<T>::type
+ impl_real(T val) { return Impl_complex_class<T>::real(val); }
+
+ template <typename T>
+ inline typename Scalar_of<T>::type
+ impl_imag(T val) { return Impl_complex_class<T>::imag(val); }
+
} // namespace vsip::impl::fn
} // namespace vsip::impl
} // namespace vsip
Index: src/vsip/impl/solver-toepsol.hpp
===================================================================
RCS file: src/vsip/impl/solver-toepsol.hpp
diff -N src/vsip/impl/solver-toepsol.hpp
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- src/vsip/impl/solver-toepsol.hpp 29 Sep 2005 15:28:12 -0000
***************
*** 0 ****
--- 1,159 ----
+ /* Copyright (c) 2005 by CodeSourcery, LLC. All rights reserved. */
+
+ /** @file vsip/impl/solver-svd.hpp
+ @author Jules Bergmann
+ @date 2005-09-11
+ @brief VSIPL++ Library: Toeplitz linear system solver.
+
+ Algorithm based on TASP C-VSIPL toeplitz solver.
+ */
+
+ #ifndef VSIP_IMPL_SOLVER_TOEPSOL_HPP
+ #define VSIP_IMPL_SOLVER_TOEPSOL_HPP
+
+ /***********************************************************************
+ Included Files
+ ***********************************************************************/
+
+ #include <algorithm>
+
+ #include <vsip/support.hpp>
+ #include <vsip/matrix.hpp>
+ #include <vsip/math.hpp>
+
+
+
+ /***********************************************************************
+ Declarations
+ ***********************************************************************/
+
+ namespace vsip
+ {
+
+ /// Solve a real symmetric or complex Hermetian positive definite Toeplitz
+ /// linear system.
+
+ /// Solves:
+ /// T x = B
+ /// for x, given T and B.
+ ///
+ /// Requires:
+ /// T to be an input vector of length N, first row of the Toeplitz matrix.
+ /// B to be an input vector of length N.
+ /// Y to be a vector of length N used for temporary workspace.
+ /// X to be a vector of length N, for the result to be stored.
+ ///
+ /// Effects:
+ /// On return, X containts solution to system T X = B.
+ ///
+ /// Returns X.
+ ///
+ /// Throws:
+ /// computation_error if T is ill-formed (non postive definite)
+ /// bad_alloc if allocation fails.
+
+ template <typename T,
+ typename Block0,
+ typename Block1,
+ typename Block2,
+ typename Block3>
+ const_Vector<T, Block3>
+ toepsol(
+ const_Vector<T, Block0> t,
+ const_Vector<T, Block1> b,
+ Vector<T, Block2> y,
+ Vector<T, Block3> x)
+ VSIP_THROW((std::bad_alloc, computation_error))
+ {
+ typedef typename impl::Scalar_of<T>::type scalar_type;
+
+ assert(t.size() == b.size());
+ assert(t.size() == y.size());
+ assert(t.size() == x.size());
+
+ length_type n = t.size();
+
+
+ typename const_Vector<T, Block0>::subview_type r = t(Domain<1>(1, 1, n-1));
+ Vector<T> tmpv(n);
+
+ scalar_type beta = 1.0;
+ scalar_type scale = impl::impl_real(t(0));
+ T alpha = impl::impl_conj(-r(0)/scale);
+ T tmps;
+
+ alpha = impl::impl_conj(-r(0)/scale);
+
+ y(0) = alpha;
+ x(0) = b(0) / scale;
+
+ for (index_type k=1; k<n; ++k)
+ {
+ beta *= (1.0 - magsq(alpha));
+ if (beta == 0.0)
+ {
+ VSIP_IMPL_THROW(computation_error("TOEPSOL: not full rank"));
+ }
+
+ tmps = dot(impl_conj(r(Domain<1>(k))), x(Domain<1>(k-1, -1, k)));
+ T mu = (b(k) - tmps) / (scale*beta);
+
+ // x(Domain<1>(k)) += mu * impl_conj(y(Domain<1>(k-1, -1, k)));
+ x(Domain<1>(k)) = mu * impl_conj(y(Domain<1>(k-1, -1, k)))
+ + x(Domain<1>(k));
+ x(k) = mu;
+
+ if (k < (n - 1))
+ {
+ tmps = dot(impl_conj(r(Domain<1>(k))), y(Domain<1>(k-1, -1, k)));
+ alpha = -(tmps + impl::impl_conj(r(k))) / (scale*beta);
+
+ tmpv(Domain<1>(k)) = alpha * impl_conj(y(Domain<1>(k-1, -1, k)))
+ + y(Domain<1>(k));
+ y(Domain<1>(k)) = tmpv(Domain<1>(k));
+ y(k) = alpha;
+ }
+ }
+
+ return x;
+ }
+
+
+
+ /// Solve a real symmetric or complex Hermetian positive definite Toeplitz
+ /// linear system.
+
+ /// Solves:
+ /// T x = B
+ /// for x, given T and B.
+ ///
+ /// Requires:
+ /// T to be an input vector of length N, first row of the Toeplitz matrix.
+ /// B to be an input vector of length N.
+ /// Y to be a vector of length N used for temporary workspace.
+ ///
+ /// Effects:
+ /// Returns vector X of length N, solution to system T X = B.
+ ///
+ /// Throws:
+ /// computation_error if T is ill-formed (non postive definite)
+ /// bad_alloc if allocation fails.
+
+ template <typename T,
+ typename Block0,
+ typename Block1,
+ typename Block2>
+ const_Vector<T>
+ toepsol(
+ const_Vector<T, Block0> t,
+ const_Vector<T, Block1> b,
+ Vector<T, Block2> y)
+ VSIP_THROW((std::bad_alloc, computation_error))
+ {
+ Vector<T> x(t.size());
+ return toepsol(t, b, y, x);
+ }
+
+ } // namespace vsip
+
+ #endif // VSIP_IMPL_SOLVER_TOEPSOL_HPP
Index: tests/solver-toepsol.cpp
===================================================================
RCS file: tests/solver-toepsol.cpp
diff -N tests/solver-toepsol.cpp
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- tests/solver-toepsol.cpp 29 Sep 2005 15:28:12 -0000
***************
*** 0 ****
--- 1,267 ----
+ /* Copyright (c) 2005 by CodeSourcery, LLC. All rights reserved. */
+
+ /** @file tests/solver-toepsol.cpp
+ @author Jules Bergmann
+ @date 2005-09-28
+ @brief VSIPL++ Library: Unit tests for toeplitz solver.
+ */
+
+ /***********************************************************************
+ Included Files
+ ***********************************************************************/
+
+ #include <cassert>
+
+ #include <vsip/initfin.hpp>
+ #include <vsip/support.hpp>
+ #include <vsip/tensor.hpp>
+ #include <vsip/solvers.hpp>
+ #include <vsip/selgen.hpp>
+ #include <vsip/random.hpp>
+
+ #include "test.hpp"
+ #include "test-precision.hpp"
+ #include "test-random.hpp"
+ #include "solver-common.hpp"
+
+ #define VERBOSE 0
+ #define DO_FULL 0
+
+ #if VERBOSE
+ # include <iostream>
+ # include "output.hpp"
+ # include "extdata-output.hpp"
+ #endif
+
+ using namespace std;
+ using namespace vsip;
+
+
+
+ /***********************************************************************
+ function tests
+ ***********************************************************************/
+
+ /// Solve a linear system with the Toeplitz solver.
+
+ template <typename T,
+ typename Block1,
+ typename Block2>
+ void
+ test_toepsol(
+ return_mechanism_type rtm,
+ Vector<T, Block1> a,
+ Vector<T, Block2> b)
+ {
+ typedef typename vsip::impl::Scalar_of<T>::type scalar_type;
+
+ length_type size = a.size();
+
+ Vector<T> y(size);
+ Vector<T> x(size, T(99));
+
+ Matrix<T> aa(size, size);
+
+ aa.diag() = a(0);
+ for (index_type i=1; i<size; ++i)
+ {
+ aa.diag(+i) = a(i);
+ aa.diag(-i) = impl::impl_conj(a(i));
+ }
+
+
+ // Solve toeplize system
+ if (rtm == by_reference)
+ toepsol(a, b, y, x);
+ else
+ x = toepsol(a, b, y);
+
+
+ // Check answer
+ Vector<T> chk(size);
+ Vector<scalar_type> gauge(size);
+
+ chk = prod(aa, x);
+ gauge = prod(mag(aa), mag(x));
+
+ for (index_type i=0; i<gauge.size(0); ++i)
+ if (!(gauge(i) > scalar_type()))
+ gauge(i) = scalar_type(1);
+
+ Index<1> idx;
+ scalar_type err = maxval(((mag(chk - b) / gauge)
+ / Precision_traits<scalar_type>::eps
+ / size),
+ idx);
+
+ #if VERBOSE
+ cout << "aa = " << endl << aa << endl;
+ cout << "a = " << endl << a << endl;
+ cout << "b = " << endl << b << endl;
+ cout << "x = " << endl << x << endl;
+ cout << "chk = " << endl << chk << endl;
+ cout << "err = " << err << endl;
+ #endif
+
+ assert(err < 5.0);
+ }
+
+
+
+ /// Test a simple toeplitz linear system with zeros outside of diagonal.
+
+ template <typename T>
+ void
+ test_toepsol_diag(
+ return_mechanism_type rtm,
+ T value,
+ length_type size)
+ {
+ Vector<T> a(size, T());
+ Vector<T> b(size);
+
+ a = T(); a(0) = value;
+
+ b = ramp(T(1), T(1), size);
+
+ test_toepsol(rtm, a, b);
+ }
+
+
+
+ template <typename T>
+ struct Toepsol_traits
+ {
+ static T value(index_type i)
+ {
+ if (i == 0) return T(5);
+ if (i == 1) return T(0.5);
+ if (i == 2) return T(0.2);
+ if (i == 3) return T(0.1);
+ return T(0);
+ }
+ };
+
+
+
+ template <typename T>
+ struct Toepsol_traits<complex<T> >
+ {
+ static complex<T> value(index_type i)
+ {
+ if (i == 0) return complex<T>(5, 0);
+ if (i == 1) return complex<T>(0.5, .1);
+ if (i == 2) return complex<T>(0.2, .1);
+ if (i == 3) return complex<T>(0.1, .15);
+ return complex<T>(0, 0);
+ }
+ };
+
+
+
+ /// Test a general toeplitz linear system.
+
+ template <typename T>
+ void
+ test_toepsol_rand(
+ return_mechanism_type rtm,
+ length_type size,
+ length_type loop)
+ {
+ typedef typename vsip::impl::Scalar_of<T>::type scalar_type;
+
+ Vector<T> a(size, T());
+ Vector<T> b(size);
+
+ a = T();
+
+ for (index_type i=0; i<size; ++i)
+ a(i) = Toepsol_traits<T>::value(i);
+
+ Rand<T> rand(1);
+
+ for (index_type l=0; l<loop; ++l)
+ {
+ b = rand.randu(size);
+ test_toepsol(rtm, a, b);
+ }
+ }
+
+
+
+ /// Test a non positive-definite toeplitz linear system.
+
+ template <typename T>
+ void
+ test_toepsol_illformed(
+ return_mechanism_type rtm,
+ length_type size)
+ {
+ typedef typename vsip::impl::Scalar_of<T>::type scalar_type;
+
+ Vector<T> a(size, T());
+ Vector<T> b(size);
+
+ // Specify a non positive-definite matrix.
+ a = T();
+ a(0) = T(1);
+ a(1) = T(1);
+
+ Rand<T> rand(1);
+
+ b = rand.randu(size);
+
+ int pass = 0;
+ try
+ {
+ test_toepsol(rtm, a, b);
+ pass = 0;
+ }
+ catch (const std::exception& error)
+ {
+ if (error.what() == std::string("TOEPSOL: not full rank"))
+ pass = 1;
+ }
+
+ assert(pass == 1);
+ }
+
+
+ void
+ toepsol_cases(return_mechanism_type rtm)
+ {
+ test_toepsol_diag<float> (rtm, 1.0, 5);
+ test_toepsol_diag<double> (rtm, 2.0, 5);
+ test_toepsol_diag<complex<float> > (rtm, complex<float>(2.0, 0.0), 5);
+ test_toepsol_diag<complex<double> >(rtm, complex<double>(3.0, 0.0), 5);
+
+ test_toepsol_rand<float> (rtm, 4, 5);
+ test_toepsol_rand<double> (rtm, 5, 5);
+ test_toepsol_rand<complex<float> > (rtm, 6, 5);
+ test_toepsol_rand<complex<double> >(rtm, 7, 5);
+
+ test_toepsol_illformed<float> (rtm, 4);
+ }
+
+
+
+ /***********************************************************************
+ Main
+ ***********************************************************************/
+
+ template <> float Precision_traits<float>::eps = 0.0;
+ template <> double Precision_traits<double>::eps = 0.0;
+
+
+
+ int
+ main(int argc, char** argv)
+ {
+ vsipl init(argc, argv);
+
+ Precision_traits<float>::compute_eps();
+ Precision_traits<double>::compute_eps();
+
+ toepsol_cases(by_reference);
+ toepsol_cases(by_value);
+ }
|