Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r48756 - branches/release/boost/numeric/ublas
From: guwi17_at_[hidden]
Date: 2008-09-12 15:17:58


Author: guwi17
Date: 2008-09-12 15:17:57 EDT (Fri, 12 Sep 2008)
New Revision: 48756
URL: http://svn.boost.org/trac/boost/changeset/48756

Log:
- fixed ADL problem with std::abs and std::sqrt
- fixed problem that iterator1 and iterator2 of triangular matrices (and related) sometimes
  pointed to wrong element or outside the storage

Text files modified:
   branches/release/boost/numeric/ublas/functional.hpp | 339 ++++++++++++++++++---------------------
   branches/release/boost/numeric/ublas/hermitian.hpp | 16 +
   branches/release/boost/numeric/ublas/symmetric.hpp | 8
   branches/release/boost/numeric/ublas/traits.hpp | 22 +
   branches/release/boost/numeric/ublas/triangular.hpp | 32 ++
   5 files changed, 218 insertions(+), 199 deletions(-)

Modified: branches/release/boost/numeric/ublas/functional.hpp
==============================================================================
--- branches/release/boost/numeric/ublas/functional.hpp (original)
+++ branches/release/boost/numeric/ublas/functional.hpp 2008-09-12 15:17:57 EDT (Fri, 12 Sep 2008)
@@ -1722,6 +1722,7 @@
         bool other (size_type /* i */, size_type /* j */) {
             return true;
         }
+ // FIXME: this should not be used at all
         static
         BOOST_UBLAS_INLINE
         size_type restrict1 (size_type i, size_type j) {
@@ -1744,6 +1745,84 @@
         }
     };
 
+ namespace detail {
+ template < class L >
+ struct transposed_structure {
+ typedef typename L::size_type size_type;
+
+ template<class LAYOUT>
+ static
+ BOOST_UBLAS_INLINE
+ size_type packed_size (LAYOUT l, size_type size_i, size_type size_j) {
+ return L::packed_size(l, size_j, size_i);
+ }
+
+ static
+ BOOST_UBLAS_INLINE
+ bool zero (size_type i, size_type j) {
+ return L::zero(j, i);
+ }
+ static
+ BOOST_UBLAS_INLINE
+ bool one (size_type i, size_type j) {
+ return L::one(j, i);
+ }
+ static
+ BOOST_UBLAS_INLINE
+ bool other (size_type i, size_type j) {
+ return L::other(j, i);
+ }
+ template<class LAYOUT>
+ static
+ BOOST_UBLAS_INLINE
+ size_type element (LAYOUT l, size_type i, size_type size_i, size_type j, size_type size_j) {
+ return L::element(l, j, size_j, i, size_i);
+ }
+
+ static
+ BOOST_UBLAS_INLINE
+ size_type restrict1 (size_type i, size_type j, size_type size1, size_type size2) {
+ return L::restrict2(j, i, size2, size1);
+ }
+ static
+ BOOST_UBLAS_INLINE
+ size_type restrict2 (size_type i, size_type j, size_type size1, size_type size2) {
+ return L::restrict1(j, i, size2, size1);
+ }
+ static
+ BOOST_UBLAS_INLINE
+ size_type mutable_restrict1 (size_type i, size_type j, size_type size1, size_type size2) {
+ return L::mutable_restrict2(j, i, size2, size1);
+ }
+ static
+ BOOST_UBLAS_INLINE
+ size_type mutable_restrict2 (size_type i, size_type j, size_type size1, size_type size2) {
+ return L::mutable_restrict1(j, i, size2, size1);
+ }
+
+ static
+ BOOST_UBLAS_INLINE
+ size_type global_restrict1 (size_type index1, size_type size1, size_type index2, size_type size2) {
+ return L::global_restrict2(index2, size2, index1, size1);
+ }
+ static
+ BOOST_UBLAS_INLINE
+ size_type global_restrict2 (size_type index1, size_type size1, size_type index2, size_type size2) {
+ return L::global_restrict1(index2, size2, index1, size1);
+ }
+ static
+ BOOST_UBLAS_INLINE
+ size_type global_mutable_restrict1 (size_type index1, size_type size1, size_type index2, size_type size2) {
+ return L::global_mutable_restrict2(index2, size2, index1, size1);
+ }
+ static
+ BOOST_UBLAS_INLINE
+ size_type global_mutable_restrict2 (size_type index1, size_type size1, size_type index2, size_type size2) {
+ return L::global_mutable_restrict1(index2, size2, index1, size1);
+ }
+ };
+ }
+
     template <class Z>
     struct basic_lower {
         typedef Z size_type;
@@ -1777,80 +1856,56 @@
             return L::lower_element (i, size_i, j, size_j);
         }
 
+ // return nearest valid index in column j
         static
         BOOST_UBLAS_INLINE
- size_type restrict1 (size_type i, size_type j) {
- return (std::max) (i, j);
+ size_type restrict1 (size_type i, size_type j, size_type size1, size_type size2) {
+ return (std::max)(j, (std::min) (size1, i));
         }
+ // return nearest valid index in row i
         static
         BOOST_UBLAS_INLINE
- size_type restrict2 (size_type i, size_type j) {
- return (std::min) (i + 1, j);
+ size_type restrict2 (size_type i, size_type j, size_type /* size1 */, size_type /* size2 */) {
+ return (std::max)(size_type(0), (std::min) (i+1, j));
         }
+ // return nearest valid mutable index in column j
         static
         BOOST_UBLAS_INLINE
- size_type mutable_restrict1 (size_type i, size_type j) {
- return (std::max) (i, j);
+ size_type mutable_restrict1 (size_type i, size_type j, size_type size1, size_type size2) {
+ return (std::max)(j, (std::min) (size1, i));
         }
+ // return nearest valid mutable index in row i
         static
         BOOST_UBLAS_INLINE
- size_type mutable_restrict2 (size_type i, size_type j) {
- return (std::min) (i + 1, j);
+ size_type mutable_restrict2 (size_type i, size_type j, size_type /* size1 */, size_type /* size2 */) {
+ return (std::max)(size_type(0), (std::min) (i+1, j));
         }
- };
- template <class Z>
- struct basic_upper {
- typedef Z size_type;
 
- template<class L>
- static
- BOOST_UBLAS_INLINE
- size_type packed_size (L, size_type size_i, size_type size_j) {
- return L::triangular_size (size_i, size_j);
- }
+ // return an index between the first and (1+last) filled row
+ static
+ BOOST_UBLAS_INLINE
+ size_type global_restrict1 (size_type index1, size_type size1, size_type index2, size_type size2) {
+ return (std::max)(size_type(0), (std::min)(size1, index1) );
+ }
+ // return an index between the first and (1+last) filled column
+ static
+ BOOST_UBLAS_INLINE
+ size_type global_restrict2 (size_type index1, size_type size1, size_type index2, size_type size2) {
+ return (std::max)(size_type(0), (std::min)(size2, index2) );
+ }
 
- static
- BOOST_UBLAS_INLINE
- bool zero (size_type i, size_type j) {
- return j < i;
- }
- static
- BOOST_UBLAS_INLINE
- bool one (size_type /* i */, size_type /* j */) {
- return false;
- }
- static
- BOOST_UBLAS_INLINE
- bool other (size_type i, size_type j) {
- return j >= i;
- }
- template<class L>
- static
- BOOST_UBLAS_INLINE
- size_type element (L, size_type i, size_type size_i, size_type j, size_type size_j) {
- return L::upper_element (i, size_i, j, size_j);
- }
-
- static
- BOOST_UBLAS_INLINE
- size_type restrict1 (size_type i, size_type j) {
- return (std::min) (i, j + 1);
- }
- static
- BOOST_UBLAS_INLINE
- size_type restrict2 (size_type i, size_type j) {
- return (std::max) (i, j);
- }
- static
- BOOST_UBLAS_INLINE
- size_type mutable_restrict1 (size_type i, size_type j) {
- return (std::min) (i, j + 1);
- }
- static
- BOOST_UBLAS_INLINE
- size_type mutable_restrict2 (size_type i, size_type j) {
- return (std::max) (i, j);
- }
+ // return an index between the first and (1+last) filled mutable row
+ static
+ BOOST_UBLAS_INLINE
+ size_type global_mutable_restrict1 (size_type index1, size_type size1, size_type index2, size_type size2) {
+ return (std::max)(size_type(0), (std::min)(size1, index1) );
+ }
+ // return an index between the first and (1+last) filled mutable column
+ static
+ BOOST_UBLAS_INLINE
+ size_type global_mutable_restrict2 (size_type index1, size_type size1, size_type index2, size_type size2) {
+ return (std::max)(size_type(0), (std::min)(size2, index2) );
+ }
     };
 
     // the first row only contains a single 1. Thus it is not stored.
@@ -1888,64 +1943,33 @@
 
         static
         BOOST_UBLAS_INLINE
- size_type mutable_restrict1 (size_type i, size_type j) {
- return (std::max) ( (std::max<size_type>)(1, i), j);
+ size_type mutable_restrict1 (size_type i, size_type j, size_type size1, size_type size2) {
+ return (std::max)(j+1, (std::min) (size1, i));
         }
         static
         BOOST_UBLAS_INLINE
- size_type mutable_restrict2 (size_type i, size_type j) {
- return (std::min) ( (std::max<size_type>)(1, i), j);
- }
- };
-
- // the last row only contains a single 1. Thus it is not stored.
- template <class Z>
- struct basic_unit_upper : public basic_upper<Z> {
- typedef Z size_type;
-
- template<class L>
- static
- BOOST_UBLAS_INLINE
- size_type packed_size (L, size_type size_i, size_type size_j) {
- // Zero size strict triangles are bad at this point
- BOOST_UBLAS_CHECK (size_i != 0 && size_j != 0, bad_index ());
- return L::triangular_size (size_i - 1, size_j - 1);
+ size_type mutable_restrict2 (size_type i, size_type j, size_type size1, size_type size2) {
+ return (std::max)(size_type(0), (std::min) (i, j));
         }
 
- static
- BOOST_UBLAS_INLINE
- bool one (size_type i, size_type j) {
- return j == i;
- }
- static
- BOOST_UBLAS_INLINE
- bool other (size_type i, size_type j) {
- return j > i;
- }
- template<class L>
- static
- BOOST_UBLAS_INLINE
- size_type element (L, size_type i, size_type size_i, size_type j, size_type size_j) {
- // Zero size strict triangles are bad at this point
- BOOST_UBLAS_CHECK (size_i != 0 && size_j != 0 && j != 0, bad_index ());
- return L::upper_element (i, size_i - 1, j-1, size_j - 1);
- }
-
- static
- BOOST_UBLAS_INLINE
- size_type mutable_restrict1 (size_type i, size_type j) {
- return (std::min) (i, (std::max<size_type>)(1, j));
- }
- static
- BOOST_UBLAS_INLINE
- size_type mutable_restrict2 (size_type i, size_type j) {
- return (std::max) (i, (std::max<size_type>)(1, j));
- }
+ // return an index between the first and (1+last) filled mutable row
+ static
+ BOOST_UBLAS_INLINE
+ size_type global_mutable_restrict1 (size_type index1, size_type size1, size_type index2, size_type size2) {
+ return (std::max)(size_type(1), (std::min)(size1, index1) );
+ }
+ // return an index between the first and (1+last) filled mutable column
+ static
+ BOOST_UBLAS_INLINE
+ size_type global_mutable_restrict2 (size_type index1, size_type size1, size_type index2, size_type size2) {
+ BOOST_UBLAS_CHECK( size2 >= 1 , external_logic() );
+ return (std::max)(size_type(0), (std::min)(size2-1, index2) );
+ }
     };
 
- // the first row only contains a single 1. Thus it is not stored.
+ // the first row only contains no element. Thus it is not stored.
     template <class Z>
- struct basic_strict_lower : public basic_lower<Z> {
+ struct basic_strict_lower : public basic_unit_lower<Z> {
         typedef Z size_type;
 
         template<class L>
@@ -1983,85 +2007,42 @@
 
         static
         BOOST_UBLAS_INLINE
- size_type restrict1 (size_type i, size_type j) {
- return (std::max) ( (std::max<size_type>)(1, i), j);
- }
- static
- BOOST_UBLAS_INLINE
- size_type restrict2 (size_type i, size_type j) {
- return (std::min) ( (std::max<size_type>)(1, i), j);
- }
- static
- BOOST_UBLAS_INLINE
- size_type mutable_restrict1 (size_type i, size_type j) {
- return (std::max) ( (std::max<size_type>)(1, i), j);
+ size_type restrict1 (size_type i, size_type j, size_type size1, size_type size2) {
+ return mutable_restrict1(i, j, size1, size2);
         }
         static
         BOOST_UBLAS_INLINE
- size_type mutable_restrict2 (size_type i, size_type j) {
- return (std::min) ( (std::max<size_type>)(1, i), j);
+ size_type restrict2 (size_type i, size_type j, size_type size1, size_type size2) {
+ return mutable_restrict2(i, j, size1, size2);
         }
+
+ // return an index between the first and (1+last) filled row
+ static
+ BOOST_UBLAS_INLINE
+ size_type global_restrict1 (size_type index1, size_type size1, size_type index2, size_type size2) {
+ return global_mutable_restrict1(index1, size1, index2, size2);
+ }
+ // return an index between the first and (1+last) filled column
+ static
+ BOOST_UBLAS_INLINE
+ size_type global_restrict2 (size_type index1, size_type size1, size_type index2, size_type size2) {
+ return global_mutable_restrict2(index1, size1, index2, size2);
+ }
     };
 
- // the last row only contains a single 1. Thus it is not stored.
+
     template <class Z>
- struct basic_strict_upper : public basic_upper<Z> {
- typedef Z size_type;
+ struct basic_upper : public detail::transposed_structure<basic_lower<Z> >
+ { };
 
- template<class L>
- static
- BOOST_UBLAS_INLINE
- size_type packed_size (L, size_type size_i, size_type size_j) {
- // Zero size strict triangles are bad at this point
- BOOST_UBLAS_CHECK (size_i != 0 && size_j != 0, bad_index ());
- return L::triangular_size (size_i - 1, size_j - 1);
- }
+ template <class Z>
+ struct basic_unit_upper : public detail::transposed_structure<basic_unit_lower<Z> >
+ { };
 
- static
- BOOST_UBLAS_INLINE
- bool zero (size_type i, size_type j) {
- return j <= i;
- }
- static
- BOOST_UBLAS_INLINE
- bool one (size_type /*i*/, size_type /*j*/) {
- return false;
- }
- static
- BOOST_UBLAS_INLINE
- bool other (size_type i, size_type j) {
- return j > i;
- }
- template<class L>
- static
- BOOST_UBLAS_INLINE
- size_type element (L, size_type i, size_type size_i, size_type j, size_type size_j) {
- // Zero size strict triangles are bad at this point
- BOOST_UBLAS_CHECK (size_i != 0 && size_j != 0 && j != 0, bad_index ());
- return L::upper_element (i, size_i - 1, j-1, size_j - 1);
- }
+ template <class Z>
+ struct basic_strict_upper : public detail::transposed_structure<basic_strict_lower<Z> >
+ { };
 
- static
- BOOST_UBLAS_INLINE
- size_type restrict1 (size_type i, size_type j) {
- return (std::min) (i, (std::max<size_type>)(1, j));
- }
- static
- BOOST_UBLAS_INLINE
- size_type restrict2 (size_type i, size_type j) {
- return (std::max) (i, (std::max<size_type>)(1, j));
- }
- static
- BOOST_UBLAS_INLINE
- size_type mutable_restrict1 (size_type i, size_type j) {
- return (std::min) (i, (std::max<size_type>)(1, j));
- }
- static
- BOOST_UBLAS_INLINE
- size_type mutable_restrict2 (size_type i, size_type j) {
- return (std::max) (i, (std::max<size_type>)(1, j));
- }
- };
 
 }}}
 

Modified: branches/release/boost/numeric/ublas/hermitian.hpp
==============================================================================
--- branches/release/boost/numeric/ublas/hermitian.hpp (original)
+++ branches/release/boost/numeric/ublas/hermitian.hpp 2008-09-12 15:17:57 EDT (Fri, 12 Sep 2008)
@@ -498,7 +498,9 @@
         BOOST_UBLAS_INLINE
         iterator1 find1 (int rank, size_type i, size_type j) {
             if (rank == 1)
- i = triangular_type::mutable_restrict1 (i, j);
+ i = triangular_type::mutable_restrict1 (i, j, size1(), size2());
+ if (rank == 0)
+ i = triangular_type::global_mutable_restrict1 (i, size1(), j, size2());
             return iterator1 (*this, i, j);
         }
         BOOST_UBLAS_INLINE
@@ -508,7 +510,9 @@
         BOOST_UBLAS_INLINE
         iterator2 find2 (int rank, size_type i, size_type j) {
             if (rank == 1)
- j = triangular_type::mutable_restrict2 (i, j);
+ j = triangular_type::mutable_restrict2 (i, j, size1(), size2());
+ if (rank == 0)
+ j = triangular_type::global_mutable_restrict2 (i, size1(), j, size2());
             return iterator2 (*this, i, j);
         }
 
@@ -1416,7 +1420,9 @@
         BOOST_UBLAS_INLINE
         iterator1 find1 (int rank, size_type i, size_type j) {
             if (rank == 1)
- i = triangular_type::mutable_restrict1 (i, j);
+ i = triangular_type::mutable_restrict1 (i, j, size1(), size2());
+ if (rank == 0)
+ i = triangular_type::global_mutable_restrict1 (i, size1(), j, size2());
             return iterator1 (*this, data ().find1 (rank, i, j));
         }
         BOOST_UBLAS_INLINE
@@ -1446,7 +1452,9 @@
         BOOST_UBLAS_INLINE
         iterator2 find2 (int rank, size_type i, size_type j) {
             if (rank == 1)
- j = triangular_type::mutable_restrict2 (i, j);
+ j = triangular_type::mutable_restrict2 (i, j, size1(), size2());
+ if (rank == 0)
+ j = triangular_type::global_mutable_restrict2 (i, size1(), j, size2());
             return iterator2 (*this, data ().find2 (rank, i, j));
         }
 

Modified: branches/release/boost/numeric/ublas/symmetric.hpp
==============================================================================
--- branches/release/boost/numeric/ublas/symmetric.hpp (original)
+++ branches/release/boost/numeric/ublas/symmetric.hpp 2008-09-12 15:17:57 EDT (Fri, 12 Sep 2008)
@@ -281,7 +281,9 @@
         BOOST_UBLAS_INLINE
         iterator1 find1 (int rank, size_type i, size_type j) {
             if (rank == 1)
- i = triangular_type::mutable_restrict1 (i, j);
+ i = triangular_type::mutable_restrict1 (i, j, size1(), size2());
+ if (rank == 0)
+ i = triangular_type::global_mutable_restrict1 (i, size1(), j, size2());
             return iterator1 (*this, i, j);
         }
         BOOST_UBLAS_INLINE
@@ -291,7 +293,9 @@
         BOOST_UBLAS_INLINE
         iterator2 find2 (int rank, size_type i, size_type j) {
             if (rank == 1)
- j = triangular_type::mutable_restrict2 (i, j);
+ j = triangular_type::mutable_restrict2 (i, j, size1(), size2());
+ if (rank == 0)
+ j = triangular_type::global_mutable_restrict2 (i, size1(), j, size2());
             return iterator2 (*this, i, j);
         }
 

Modified: branches/release/boost/numeric/ublas/traits.hpp
==============================================================================
--- branches/release/boost/numeric/ublas/traits.hpp (original)
+++ branches/release/boost/numeric/ublas/traits.hpp 2008-09-12 15:17:57 EDT (Fri, 12 Sep 2008)
@@ -24,6 +24,20 @@
 #include <boost/type_traits.hpp>
 #include <complex>
 
+// anonymous namespace to avoid ADL issues
+namespace {
+ template<class T> T boost_numeric_ublas_sqrt (const T& t) {
+ using namespace std;
+ // we'll find either std::sqrt or else another version via ADL:
+ return sqrt (t);
+ }
+ template<class T> T boost_numeric_ublas_abs (const T& t) {
+ using namespace std;
+ // we'll find either std::abs or else another version via ADL:
+ return abs (t);
+ }
+}
+
 namespace boost { namespace numeric { namespace ublas {
 
     // Use Joel de Guzman's return type deduction
@@ -84,17 +98,13 @@
         static
         BOOST_UBLAS_INLINE
         real_type type_abs (const_reference t) {
- // we'll find either std::abs or else another version via ADL:
- using namespace std;
- return abs (t);
+ return boost_numeric_ublas_abs (t);
         }
         static
         BOOST_UBLAS_INLINE
         value_type type_sqrt (const_reference t) {
- using namespace std;
             // force a type conversion back to value_type for intgral types
- // we'll find either std::sqrt or else another version via ADL:
- return value_type (sqrt (t));
+ return value_type (boost_numeric_ublas_sqrt (t));
         }
 
         static

Modified: branches/release/boost/numeric/ublas/triangular.hpp
==============================================================================
--- branches/release/boost/numeric/ublas/triangular.hpp (original)
+++ branches/release/boost/numeric/ublas/triangular.hpp 2008-09-12 15:17:57 EDT (Fri, 12 Sep 2008)
@@ -295,25 +295,33 @@
         BOOST_UBLAS_INLINE
         const_iterator1 find1 (int rank, size_type i, size_type j) const {
             if (rank == 1)
- i = triangular_type::restrict1 (i, j);
+ i = triangular_type::restrict1 (i, j, size1_, size2_);
+ if (rank == 0)
+ i = triangular_type::global_restrict1 (i, size1_, j, size2_);
             return const_iterator1 (*this, i, j);
         }
         BOOST_UBLAS_INLINE
         iterator1 find1 (int rank, size_type i, size_type j) {
             if (rank == 1)
- i = triangular_type::mutable_restrict1 (i, j);
+ i = triangular_type::mutable_restrict1 (i, j, size1_, size2_);
+ if (rank == 0)
+ i = triangular_type::global_mutable_restrict1 (i, size1_, j, size2_);
             return iterator1 (*this, i, j);
         }
         BOOST_UBLAS_INLINE
         const_iterator2 find2 (int rank, size_type i, size_type j) const {
             if (rank == 1)
- j = triangular_type::restrict2 (i, j);
+ j = triangular_type::restrict2 (i, j, size1_, size2_);
+ if (rank == 0)
+ j = triangular_type::global_restrict2 (i, size1_, j, size2_);
             return const_iterator2 (*this, i, j);
         }
         BOOST_UBLAS_INLINE
         iterator2 find2 (int rank, size_type i, size_type j) {
             if (rank == 1)
- j = triangular_type::mutable_restrict2 (i, j);
+ j = triangular_type::mutable_restrict2 (i, j, size1_, size2_);
+ if (rank == 0)
+ j = triangular_type::global_mutable_restrict2 (i, size1_, j, size2_);
             return iterator2 (*this, i, j);
         }
 
@@ -1145,25 +1153,33 @@
         BOOST_UBLAS_INLINE
         const_iterator1 find1 (int rank, size_type i, size_type j) const {
             if (rank == 1)
- i = triangular_type::restrict1 (i, j);
+ i = triangular_type::restrict1 (i, j, size1(), size2());
+ if (rank == 0)
+ i = triangular_type::global_restrict1 (i, size1(), j, size2());
             return const_iterator1 (*this, data ().find1 (rank, i, j));
         }
         BOOST_UBLAS_INLINE
         iterator1 find1 (int rank, size_type i, size_type j) {
             if (rank == 1)
- i = triangular_type::mutable_restrict1 (i, j);
+ i = triangular_type::mutable_restrict1 (i, j, size1(), size2());
+ if (rank == 0)
+ i = triangular_type::global_mutable_restrict1 (i, size1(), j, size2());
             return iterator1 (*this, data ().find1 (rank, i, j));
         }
         BOOST_UBLAS_INLINE
         const_iterator2 find2 (int rank, size_type i, size_type j) const {
             if (rank == 1)
- j = triangular_type::restrict2 (i, j);
+ j = triangular_type::restrict2 (i, j, size1(), size2());
+ if (rank == 0)
+ j = triangular_type::global_restrict2 (i, size1(), j, size2());
             return const_iterator2 (*this, data ().find2 (rank, i, j));
         }
         BOOST_UBLAS_INLINE
         iterator2 find2 (int rank, size_type i, size_type j) {
             if (rank == 1)
- j = triangular_type::mutable_restrict2 (i, j);
+ j = triangular_type::mutable_restrict2 (i, j, size1(), size2());
+ if (rank == 0)
+ j = triangular_type::global_mutable_restrict2 (i, size1(), j, size2());
             return iterator2 (*this, data ().find2 (rank, i, j));
         }
 


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