Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r52382 - in sandbox/numeric_bindings: boost/numeric/bindings/lapack/computational boost/numeric/bindings/lapack/detail libs/numeric/bindings/tools libs/numeric/bindings/tools/templates/computational
From: rutger_at_[hidden]
Date: 2009-04-14 05:10:20


Author: rutger
Date: 2009-04-14 05:10:19 EDT (Tue, 14 Apr 2009)
New Revision: 52382
URL: http://svn.boost.org/trac/boost/changeset/52382

Log:
Added support for lapack/stemr

Added:
   sandbox/numeric_bindings/boost/numeric/bindings/lapack/computational/stemr.hpp (contents, props changed)
   sandbox/numeric_bindings/libs/numeric/bindings/tools/templates/computational/stemr.hpp (contents, props changed)
Text files modified:
   sandbox/numeric_bindings/boost/numeric/bindings/lapack/detail/lapack.h | 30 ++++++++++++++++++++++++++++++
   sandbox/numeric_bindings/boost/numeric/bindings/lapack/detail/lapack_names.h | 6 ++++++
   sandbox/numeric_bindings/libs/numeric/bindings/tools/lapack_generator.py | 2 +-
   3 files changed, 37 insertions(+), 1 deletions(-)

Added: sandbox/numeric_bindings/boost/numeric/bindings/lapack/computational/stemr.hpp
==============================================================================
--- (empty file)
+++ sandbox/numeric_bindings/boost/numeric/bindings/lapack/computational/stemr.hpp 2009-04-14 05:10:19 EDT (Tue, 14 Apr 2009)
@@ -0,0 +1,333 @@
+//
+// Copyright (c) 2003--2009
+// Toon Knapen, Karl Meerbergen, Kresimir Fresl,
+// Thomas Klimpel and Rutger ter Borg
+//
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+//
+// THIS FILE IS AUTOMATICALLY GENERATED
+// PLEASE DO NOT EDIT!
+//
+
+#ifndef BOOST_NUMERIC_BINDINGS_LAPACK_COMPUTATIONAL_STEMR_HPP
+#define BOOST_NUMERIC_BINDINGS_LAPACK_COMPUTATIONAL_STEMR_HPP
+
+#include <boost/assert.hpp>
+#include <boost/mpl/bool.hpp>
+#include <boost/numeric/bindings/lapack/detail/lapack.h>
+#include <boost/numeric/bindings/lapack/workspace.hpp>
+#include <boost/numeric/bindings/traits/detail/array.hpp>
+#include <boost/numeric/bindings/traits/detail/utils.hpp>
+#include <boost/numeric/bindings/traits/is_complex.hpp>
+#include <boost/numeric/bindings/traits/is_real.hpp>
+#include <boost/numeric/bindings/traits/traits.hpp>
+#include <boost/numeric/bindings/traits/type_traits.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/utility/enable_if.hpp>
+
+namespace boost {
+namespace numeric {
+namespace bindings {
+namespace lapack {
+
+//$DESCRIPTION
+
+// overloaded functions to call lapack
+namespace detail {
+ inline void stemr( char const jobz, char const range, integer_t const n,
+ float* d, float* e, float const vl, float const vu,
+ integer_t const il, integer_t const iu, integer_t& m, float* w,
+ float* z, integer_t const ldz, integer_t const nzc,
+ integer_t* isuppz, logical_t& tryrac, float* work,
+ integer_t const lwork, integer_t* iwork, integer_t const liwork,
+ integer_t& info ) {
+ LAPACK_SSTEMR( &jobz, &range, &n, d, e, &vl, &vu, &il, &iu, &m, w, z,
+ &ldz, &nzc, isuppz, &tryrac, work, &lwork, iwork, &liwork,
+ &info );
+ }
+ inline void stemr( char const jobz, char const range, integer_t const n,
+ double* d, double* e, double const vl, double const vu,
+ integer_t const il, integer_t const iu, integer_t& m, double* w,
+ double* z, integer_t const ldz, integer_t const nzc,
+ integer_t* isuppz, logical_t& tryrac, double* work,
+ integer_t const lwork, integer_t* iwork, integer_t const liwork,
+ integer_t& info ) {
+ LAPACK_DSTEMR( &jobz, &range, &n, d, e, &vl, &vu, &il, &iu, &m, w, z,
+ &ldz, &nzc, isuppz, &tryrac, work, &lwork, iwork, &liwork,
+ &info );
+ }
+ inline void stemr( char const jobz, char const range, integer_t const n,
+ float* d, float* e, float const vl, float const vu,
+ integer_t const il, integer_t const iu, integer_t& m, float* w,
+ traits::complex_f* z, integer_t const ldz, integer_t const nzc,
+ integer_t* isuppz, logical_t& tryrac, float* work,
+ integer_t const lwork, integer_t* iwork, integer_t const liwork,
+ integer_t& info ) {
+ LAPACK_CSTEMR( &jobz, &range, &n, d, e, &vl, &vu, &il, &iu, &m, w,
+ traits::complex_ptr(z), &ldz, &nzc, isuppz, &tryrac, work,
+ &lwork, iwork, &liwork, &info );
+ }
+ inline void stemr( char const jobz, char const range, integer_t const n,
+ double* d, double* e, double const vl, double const vu,
+ integer_t const il, integer_t const iu, integer_t& m, double* w,
+ traits::complex_d* z, integer_t const ldz, integer_t const nzc,
+ integer_t* isuppz, logical_t& tryrac, double* work,
+ integer_t const lwork, integer_t* iwork, integer_t const liwork,
+ integer_t& info ) {
+ LAPACK_ZSTEMR( &jobz, &range, &n, d, e, &vl, &vu, &il, &iu, &m, w,
+ traits::complex_ptr(z), &ldz, &nzc, isuppz, &tryrac, work,
+ &lwork, iwork, &liwork, &info );
+ }
+}
+
+// value-type based template
+template< typename ValueType, typename Enable = void >
+struct stemr_impl{};
+
+// real specialization
+template< typename ValueType >
+struct stemr_impl< ValueType, typename boost::enable_if< traits::is_real<ValueType> >::type > {
+
+ typedef ValueType value_type;
+ typedef typename traits::type_traits<ValueType>::real_type real_type;
+
+ // user-defined workspace specialization
+ template< typename VectorD, typename VectorE, typename VectorW,
+ typename MatrixZ, typename VectorISUPPZ, typename WORK,
+ typename IWORK >
+ static void invoke( char const jobz, char const range, integer_t const n,
+ VectorD& d, VectorE& e, real_type const vl, real_type const vu,
+ integer_t const il, integer_t const iu, integer_t& m, VectorW& w,
+ MatrixZ& z, integer_t const nzc, VectorISUPPZ& isuppz,
+ logical_t& tryrac, integer_t& info, detail::workspace2< WORK,
+ IWORK > work ) {
+ BOOST_STATIC_ASSERT( (boost::is_same< typename traits::vector_traits<
+ VectorD >::value_type, typename traits::vector_traits<
+ VectorE >::value_type >::value) );
+ BOOST_STATIC_ASSERT( (boost::is_same< typename traits::vector_traits<
+ VectorD >::value_type, typename traits::vector_traits<
+ VectorW >::value_type >::value) );
+ BOOST_STATIC_ASSERT( (boost::is_same< typename traits::vector_traits<
+ VectorD >::value_type, typename traits::matrix_traits<
+ MatrixZ >::value_type >::value) );
+ BOOST_ASSERT( jobz == 'N' || jobz == 'V' );
+ BOOST_ASSERT( range == 'A' || range == 'V' || range == 'I' );
+ BOOST_ASSERT( n >= 0 );
+ BOOST_ASSERT( traits::vector_size(d) >= n );
+ BOOST_ASSERT( traits::vector_size(e) >= n );
+ BOOST_ASSERT( traits::vector_size(w) >= n );
+ BOOST_ASSERT( traits::vector_size(work.select(real_type())) >=
+ min_size_work( n, jobz ));
+ BOOST_ASSERT( traits::vector_size(work.select(integer_t())) >=
+ min_size_iwork( n, jobz ));
+ detail::stemr( jobz, range, n, traits::vector_storage(d),
+ traits::vector_storage(e), vl, vu, il, iu, m,
+ traits::vector_storage(w), traits::matrix_storage(z),
+ traits::leading_dimension(z), nzc,
+ traits::vector_storage(isuppz), tryrac,
+ traits::vector_storage(work.select(real_type())),
+ traits::vector_size(work.select(real_type())),
+ traits::vector_storage(work.select(integer_t())),
+ traits::vector_size(work.select(integer_t())), info );
+ }
+
+ // minimal workspace specialization
+ template< typename VectorD, typename VectorE, typename VectorW,
+ typename MatrixZ, typename VectorISUPPZ >
+ static void invoke( char const jobz, char const range, integer_t const n,
+ VectorD& d, VectorE& e, real_type const vl, real_type const vu,
+ integer_t const il, integer_t const iu, integer_t& m, VectorW& w,
+ MatrixZ& z, integer_t const nzc, VectorISUPPZ& isuppz,
+ logical_t& tryrac, integer_t& info, minimal_workspace work ) {
+ traits::detail::array< real_type > tmp_work( min_size_work( n,
+ jobz ) );
+ traits::detail::array< integer_t > tmp_iwork( min_size_iwork( n,
+ jobz ) );
+ invoke( jobz, range, n, d, e, vl, vu, il, iu, m, w, z, nzc, isuppz,
+ tryrac, info, workspace( tmp_work, tmp_iwork ) );
+ }
+
+ // optimal workspace specialization
+ template< typename VectorD, typename VectorE, typename VectorW,
+ typename MatrixZ, typename VectorISUPPZ >
+ static void invoke( char const jobz, char const range, integer_t const n,
+ VectorD& d, VectorE& e, real_type const vl, real_type const vu,
+ integer_t const il, integer_t const iu, integer_t& m, VectorW& w,
+ MatrixZ& z, integer_t const nzc, VectorISUPPZ& isuppz,
+ logical_t& tryrac, integer_t& info, optimal_workspace work ) {
+ real_type opt_size_work;
+ integer_t opt_size_iwork;
+ detail::stemr( jobz, range, n, traits::vector_storage(d),
+ traits::vector_storage(e), vl, vu, il, iu, m,
+ traits::vector_storage(w), traits::matrix_storage(z),
+ traits::leading_dimension(z), nzc,
+ traits::vector_storage(isuppz), tryrac, &opt_size_work, -1,
+ &opt_size_iwork, -1, info );
+ traits::detail::array< real_type > tmp_work(
+ traits::detail::to_int( opt_size_work ) );
+ traits::detail::array< integer_t > tmp_iwork( opt_size_iwork );
+ invoke( jobz, range, n, d, e, vl, vu, il, iu, m, w, z, nzc, isuppz,
+ tryrac, info, workspace( tmp_work, tmp_iwork ) );
+ }
+
+ static integer_t min_size_work( integer_t const n, char const jobz ) {
+ if ( jobz == 'V' ) {
+ return std::max( 1, 18*n );
+ } else {
+ return std::max( 1, 12*n );
+ }
+ }
+
+ static integer_t min_size_iwork( integer_t const n, char const jobz ) {
+ if ( jobz == 'V' ) {
+ return std::max( 1, 10*n );
+ } else {
+ return std::max( 1, 8*n );
+ }
+ }
+};
+
+// complex specialization
+template< typename ValueType >
+struct stemr_impl< ValueType, typename boost::enable_if< traits::is_complex<ValueType> >::type > {
+
+ typedef ValueType value_type;
+ typedef typename traits::type_traits<ValueType>::real_type real_type;
+
+ // user-defined workspace specialization
+ template< typename VectorD, typename VectorE, typename VectorW,
+ typename MatrixZ, typename VectorISUPPZ, typename WORK,
+ typename IWORK >
+ static void invoke( char const jobz, char const range, integer_t const n,
+ VectorD& d, VectorE& e, real_type const vl, real_type const vu,
+ integer_t const il, integer_t const iu, integer_t& m, VectorW& w,
+ MatrixZ& z, integer_t const nzc, VectorISUPPZ& isuppz,
+ logical_t& tryrac, integer_t& info, detail::workspace2< WORK,
+ IWORK > work ) {
+ BOOST_STATIC_ASSERT( (boost::is_same< typename traits::vector_traits<
+ VectorD >::value_type, typename traits::vector_traits<
+ VectorE >::value_type >::value) );
+ BOOST_STATIC_ASSERT( (boost::is_same< typename traits::vector_traits<
+ VectorD >::value_type, typename traits::vector_traits<
+ VectorW >::value_type >::value) );
+ BOOST_ASSERT( jobz == 'N' || jobz == 'V' );
+ BOOST_ASSERT( range == 'A' || range == 'V' || range == 'I' );
+ BOOST_ASSERT( n >= 0 );
+ BOOST_ASSERT( traits::vector_size(d) >= n );
+ BOOST_ASSERT( traits::vector_size(e) >= n );
+ BOOST_ASSERT( traits::vector_size(w) >= n );
+ BOOST_ASSERT( traits::vector_size(work.select(real_type())) >=
+ min_size_work( n, jobz ));
+ BOOST_ASSERT( traits::vector_size(work.select(integer_t())) >=
+ min_size_iwork( n, jobz ));
+ detail::stemr( jobz, range, n, traits::vector_storage(d),
+ traits::vector_storage(e), vl, vu, il, iu, m,
+ traits::vector_storage(w), traits::matrix_storage(z),
+ traits::leading_dimension(z), nzc,
+ traits::vector_storage(isuppz), tryrac,
+ traits::vector_storage(work.select(real_type())),
+ traits::vector_size(work.select(real_type())),
+ traits::vector_storage(work.select(integer_t())),
+ traits::vector_size(work.select(integer_t())), info );
+ }
+
+ // minimal workspace specialization
+ template< typename VectorD, typename VectorE, typename VectorW,
+ typename MatrixZ, typename VectorISUPPZ >
+ static void invoke( char const jobz, char const range, integer_t const n,
+ VectorD& d, VectorE& e, real_type const vl, real_type const vu,
+ integer_t const il, integer_t const iu, integer_t& m, VectorW& w,
+ MatrixZ& z, integer_t const nzc, VectorISUPPZ& isuppz,
+ logical_t& tryrac, integer_t& info, minimal_workspace work ) {
+ traits::detail::array< real_type > tmp_work( min_size_work( n,
+ jobz ) );
+ traits::detail::array< integer_t > tmp_iwork( min_size_iwork( n,
+ jobz ) );
+ invoke( jobz, range, n, d, e, vl, vu, il, iu, m, w, z, nzc, isuppz,
+ tryrac, info, workspace( tmp_work, tmp_iwork ) );
+ }
+
+ // optimal workspace specialization
+ template< typename VectorD, typename VectorE, typename VectorW,
+ typename MatrixZ, typename VectorISUPPZ >
+ static void invoke( char const jobz, char const range, integer_t const n,
+ VectorD& d, VectorE& e, real_type const vl, real_type const vu,
+ integer_t const il, integer_t const iu, integer_t& m, VectorW& w,
+ MatrixZ& z, integer_t const nzc, VectorISUPPZ& isuppz,
+ logical_t& tryrac, integer_t& info, optimal_workspace work ) {
+ real_type opt_size_work;
+ integer_t opt_size_iwork;
+ detail::stemr( jobz, range, n, traits::vector_storage(d),
+ traits::vector_storage(e), vl, vu, il, iu, m,
+ traits::vector_storage(w), traits::matrix_storage(z),
+ traits::leading_dimension(z), nzc,
+ traits::vector_storage(isuppz), tryrac, &opt_size_work, -1,
+ &opt_size_iwork, -1, info );
+ traits::detail::array< real_type > tmp_work(
+ traits::detail::to_int( opt_size_work ) );
+ traits::detail::array< integer_t > tmp_iwork( opt_size_iwork );
+ invoke( jobz, range, n, d, e, vl, vu, il, iu, m, w, z, nzc, isuppz,
+ tryrac, info, workspace( tmp_work, tmp_iwork ) );
+ }
+
+ static integer_t min_size_work( integer_t const n, char const jobz ) {
+ if ( jobz == 'V' ) {
+ return std::max( 1, 18*n );
+ } else {
+ return std::max( 1, 12*n );
+ }
+ }
+
+ static integer_t min_size_iwork( integer_t const n, char const jobz ) {
+ if ( jobz == 'V' ) {
+ return std::max( 1, 10*n );
+ } else {
+ return std::max( 1, 8*n );
+ }
+ }
+};
+
+
+// template function to call stemr
+template< typename VectorD, typename VectorE, typename VectorW,
+ typename MatrixZ, typename VectorISUPPZ, typename Workspace >
+inline integer_t stemr( char const jobz, char const range,
+ integer_t const n, VectorD& d, VectorE& e,
+ typename traits::type_traits< typename traits::matrix_traits<
+ MatrixZ >::value_type >::real_type const vl,
+ typename traits::type_traits< typename traits::matrix_traits<
+ MatrixZ >::value_type >::real_type const vu, integer_t const il,
+ integer_t const iu, integer_t& m, VectorW& w, MatrixZ& z,
+ integer_t const nzc, VectorISUPPZ& isuppz, logical_t& tryrac,
+ Workspace work ) {
+ typedef typename traits::matrix_traits< MatrixZ >::value_type value_type;
+ integer_t info(0);
+ stemr_impl< value_type >::invoke( jobz, range, n, d, e, vl, vu, il,
+ iu, m, w, z, nzc, isuppz, tryrac, info, work );
+ return info;
+}
+
+// template function to call stemr, default workspace type
+template< typename VectorD, typename VectorE, typename VectorW,
+ typename MatrixZ, typename VectorISUPPZ >
+inline integer_t stemr( char const jobz, char const range,
+ integer_t const n, VectorD& d, VectorE& e,
+ typename traits::type_traits< typename traits::matrix_traits<
+ MatrixZ >::value_type >::real_type const vl,
+ typename traits::type_traits< typename traits::matrix_traits<
+ MatrixZ >::value_type >::real_type const vu, integer_t const il,
+ integer_t const iu, integer_t& m, VectorW& w, MatrixZ& z,
+ integer_t const nzc, VectorISUPPZ& isuppz, logical_t& tryrac ) {
+ typedef typename traits::matrix_traits< MatrixZ >::value_type value_type;
+ integer_t info(0);
+ stemr_impl< value_type >::invoke( jobz, range, n, d, e, vl, vu, il,
+ iu, m, w, z, nzc, isuppz, tryrac, info, optimal_workspace() );
+ return info;
+}
+
+}}}} // namespace boost::numeric::bindings::lapack
+
+#endif

Modified: sandbox/numeric_bindings/boost/numeric/bindings/lapack/detail/lapack.h
==============================================================================
--- sandbox/numeric_bindings/boost/numeric/bindings/lapack/detail/lapack.h (original)
+++ sandbox/numeric_bindings/boost/numeric/bindings/lapack/detail/lapack.h 2009-04-14 05:10:19 EDT (Tue, 14 Apr 2009)
@@ -1849,6 +1849,36 @@
         integer_t const* isplit, dcomplex_t* z, integer_t const* ldz,
         double* work, integer_t* iwork, integer_t* ifail, integer_t* info );
 
+// Value-type variants of stemr
+void LAPACK_SSTEMR( char const* jobz, char const* range, integer_t const* n,
+ float* d, float* e, float const* vl, float const* vu,
+ integer_t const* il, integer_t const* iu, integer_t* m, float* w,
+ float* z, integer_t const* ldz, integer_t const* nzc,
+ integer_t* isuppz, logical_t* tryrac, float* work,
+ integer_t const* lwork, integer_t* iwork, integer_t const* liwork,
+ integer_t* info );
+void LAPACK_DSTEMR( char const* jobz, char const* range, integer_t const* n,
+ double* d, double* e, double const* vl, double const* vu,
+ integer_t const* il, integer_t const* iu, integer_t* m, double* w,
+ double* z, integer_t const* ldz, integer_t const* nzc,
+ integer_t* isuppz, logical_t* tryrac, double* work,
+ integer_t const* lwork, integer_t* iwork, integer_t const* liwork,
+ integer_t* info );
+void LAPACK_CSTEMR( char const* jobz, char const* range, integer_t const* n,
+ float* d, float* e, float const* vl, float const* vu,
+ integer_t const* il, integer_t const* iu, integer_t* m, float* w,
+ fcomplex_t* z, integer_t const* ldz, integer_t const* nzc,
+ integer_t* isuppz, logical_t* tryrac, float* work,
+ integer_t const* lwork, integer_t* iwork, integer_t const* liwork,
+ integer_t* info );
+void LAPACK_ZSTEMR( char const* jobz, char const* range, integer_t const* n,
+ double* d, double* e, double const* vl, double const* vu,
+ integer_t const* il, integer_t const* iu, integer_t* m, double* w,
+ dcomplex_t* z, integer_t const* ldz, integer_t const* nzc,
+ integer_t* isuppz, logical_t* tryrac, double* work,
+ integer_t const* lwork, integer_t* iwork, integer_t const* liwork,
+ integer_t* info );
+
 // Value-type variants of steqr
 void LAPACK_SSTEQR( char const* compz, integer_t const* n, float* d, float* e,
         float* z, integer_t const* ldz, float* work, integer_t* info );

Modified: sandbox/numeric_bindings/boost/numeric/bindings/lapack/detail/lapack_names.h
==============================================================================
--- sandbox/numeric_bindings/boost/numeric/bindings/lapack/detail/lapack_names.h (original)
+++ sandbox/numeric_bindings/boost/numeric/bindings/lapack/detail/lapack_names.h 2009-04-14 05:10:19 EDT (Tue, 14 Apr 2009)
@@ -678,6 +678,12 @@
 #define LAPACK_CSTEIN FORTRAN_ID( cstein )
 #define LAPACK_ZSTEIN FORTRAN_ID( zstein )
 
+// Value-type variants of stemr
+#define LAPACK_SSTEMR FORTRAN_ID( sstemr )
+#define LAPACK_DSTEMR FORTRAN_ID( dstemr )
+#define LAPACK_CSTEMR FORTRAN_ID( cstemr )
+#define LAPACK_ZSTEMR FORTRAN_ID( zstemr )
+
 // Value-type variants of steqr
 #define LAPACK_SSTEQR FORTRAN_ID( ssteqr )
 #define LAPACK_DSTEQR FORTRAN_ID( dsteqr )

Modified: sandbox/numeric_bindings/libs/numeric/bindings/tools/lapack_generator.py
==============================================================================
--- sandbox/numeric_bindings/libs/numeric/bindings/tools/lapack_generator.py (original)
+++ sandbox/numeric_bindings/libs/numeric/bindings/tools/lapack_generator.py 2009-04-14 05:10:19 EDT (Tue, 14 Apr 2009)
@@ -521,7 +521,7 @@
 
 # based on LAPACK Users' Guide, table 2.10
 routines[ 'computational' ][ 'symmetric_eigen' ] = {}
-routines[ 'computational' ][ 'symmetric_eigen' ][ 'endings' ] = [ 'TRD', 'MTR', 'GTR', 'TEQR', 'ERF', 'EDC', 'EGR', 'EBZ', 'TEIN' ]
+routines[ 'computational' ][ 'symmetric_eigen' ][ 'endings' ] = [ 'TRD', 'MTR', 'GTR', 'TEQR', 'ERF', 'EDC', 'EGR', 'EBZ', 'TEIN', 'EMR' ]
 
 # based on LAPACK Users' Guide, table 2.11
 routines[ 'computational' ][ 'nonsymmetric_eigen' ] = {}

Added: sandbox/numeric_bindings/libs/numeric/bindings/tools/templates/computational/stemr.hpp
==============================================================================
--- (empty file)
+++ sandbox/numeric_bindings/libs/numeric/bindings/tools/templates/computational/stemr.hpp 2009-04-14 05:10:19 EDT (Tue, 14 Apr 2009)
@@ -0,0 +1,17 @@
+$TEMPLATE[stemr.all.min_size_work.args]
+N, JOBZ
+$TEMPLATE[stemr.all.min_size_work]
+if ( jobz == 'V' ) {
+ return std::max( 1, 18*n );
+} else {
+ return std::max( 1, 12*n );
+}
+$TEMPLATE[stemr.all.min_size_iwork.args]
+N,JOBZ
+$TEMPLATE[stemr.all.min_size_iwork]
+if ( jobz == 'V' ) {
+ return std::max( 1, 10*n );
+} else {
+ return std::max( 1, 8*n );
+}
+$TEMPLATE[end]


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk