Teuchos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
default_blas_rot.cpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Teuchos: Common Tools Package
4 //
5 // Copyright 2004 NTESS and the Teuchos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
21 
22 #include <Teuchos_as.hpp>
23 #include <Teuchos_BLAS.hpp>
27 
28 // Anonymous namespace to avoid name collisions.
29 namespace {
30 
34  template<class OrdinalType, class ScalarType>
35  class GivensTester {
36  public:
37  typedef ScalarType scalar_type;
38  typedef typename Teuchos::ScalarTraits<ScalarType>::magnitudeType MagnitudeType;
39  typedef MagnitudeType magnitude_type;
40 
41  private:
43  std::ostream& out_;
44 
49  MagnitudeType trigErrorBound_;
50 
53 
55  MagnitudeType norm2 (const ScalarType a, const ScalarType& b)
56  {
57  const MagnitudeType scale = STS::magnitude(a) + STS::magnitude(b);
58 
59  if (scale == STM::zero()) {
60  return STM::zero();
61  } else {
62  const ScalarType a_scaled = a / scale;
63  const ScalarType b_scaled = b / scale;
64  return scale * STM::squareroot (a_scaled*a_scaled + b_scaled*b_scaled);
65  }
66  }
67 
77  static MagnitudeType trigErrorBound ()
78  {
79  // NOTE (mfh 12 Oct 2011) I'm not sure if this error bound holds
80  // for complex arithmetic. Does STS report the right machine
81  // precision for complex numbers?
82  const MagnitudeType u = STS::eps();
83 
84  // In Higham's notation, $\gamma_k = ku / (1 - ku)$.
85  return 2 * (4*u) / (1 - 4*u);
86  }
87 
88  public:
92  GivensTester (std::ostream& out) :
93  out_ (out), trigErrorBound_ (trigErrorBound())
94  {}
95 
97  bool compare (ScalarType a, ScalarType b)
98  {
99  using std::endl;
100  typedef Teuchos::DefaultBLASImpl<int, ScalarType> generic_blas_type;
101  typedef Teuchos::BLAS<int, ScalarType> library_blas_type;
102 
103  out_ << "Comparing Givens rotations for [a; b] = ["
104  << a << "; " << b << "]" << endl;
105 
106  generic_blas_type genericBlas;
107  library_blas_type libraryBlas;
108 
109  // ROTG overwrites its input arguments.
110  ScalarType a_generic = a;
111  ScalarType b_generic = b;
112  MagnitudeType c_generic;
113  ScalarType s_generic;
114  genericBlas.ROTG (&a_generic, &b_generic, &c_generic, &s_generic);
115 
116  ScalarType a_library = a;
117  ScalarType b_library = b;
118  MagnitudeType c_library;
119  ScalarType s_library;
120  libraryBlas.ROTG (&a_library, &b_library, &c_library, &s_library);
121 
122  out_ << "-- DefaultBLASImpl results: a,b,c,s = "
123  << a_generic << ", " << b_generic << ", "
124  << c_generic << ", " << s_generic << endl;
125  out_ << "-- (Library) BLAS results: a,b,c,s = "
126  << a_library << ", " << b_library << ", "
127  << c_library << ", " << s_library << endl;
128 
129  bool success = true; // Innocent until proven guilty.
130 
131  // Test the difference between the computed cosines.
132  out_ << "-- |c_generic - c_library| = "
133  << STS::magnitude(c_generic - c_library) << endl;
134  if (STS::magnitude(c_generic - c_library) > trigErrorBound_) {
135  success = false;
136  out_ << "---- Difference exceeded error bound " << trigErrorBound_ << endl;
137  }
138 
139  // Test the difference between the computed sines.
140  out_ << "-- |s_generic - s_library| = "
141  << STS::magnitude(s_generic - s_library) << endl;
142  if (STS::magnitude(s_generic - s_library) > trigErrorBound_) {
143  success = false;
144  out_ << "---- Difference exceeded error bound " << trigErrorBound_ << endl;
145  }
146 
147  // Test the forward error of applying the Givens rotation.
148  // Remember that ROTG applies the rotation to its input
149  // arguments [a; b], overwriting them with the resulting [r; z].
150  //
151  // See Higham's Lemma 19.8.
152  const MagnitudeType inputNorm = norm2 (a, b);
153  const MagnitudeType outputDiffNorm =
154  norm2 (a_generic - a_library, b_generic - b_library);
155 
156  out_ << "-- ||[a; b]||_2 = " << inputNorm << endl;
157  out_ << "-- ||[a_generic - a_library; b_generic - b_library]||_2 = "
158  << outputDiffNorm << endl;
159 
160  // Multiply by a fudge factor of the base, just in case the
161  // forward error bound wasn't computed accurately. Also
162  // multiply by 2, since we don't know the exact result. The
163  // latter is because the two computed results could be on either
164  // side of the exact result: sqrt((2 * x_diff)^2 + (2 *
165  // y_diff)^2) = sqrt(4) * sqrt(x_diff^2 + y_diff^2).
166  const MagnitudeType two = STM::one() + STM::one();
167  const MagnitudeType fwdErrorBound =
168  2 * STS::base() * STM::squareroot(two) * (6*STS::eps() / (1 - 6*STS::eps()));
169 
170  if (outputDiffNorm > fwdErrorBound * inputNorm) {
171  success = false;
172  out_ << "---- Forward error exceeded relative error bound "
173  << fwdErrorBound << endl;
174  }
175  return success;
176  }
177 
181  bool test ()
182  {
183  using Teuchos::as;
184 
185  const ScalarType zero = STS::zero();
186  const ScalarType one = STS::one();
187  //const ScalarType two = one + one;
188  //const ScalarType four = two + two;
189 
190  bool success = true; // Innocent until proven guilty.
191 
192  // First test the corner cases: [\pm 1, 0] and [0, \pm 1].
193  success = success && compare (one, zero);
194  success = success && compare (zero, one);
195  success = success && compare (-one, zero);
196  success = success && compare (zero, -one);
197 
198  // Test a range of other values.
199  {
200  const ScalarType incr = one / as<ScalarType> (10);
201  for (int k = -30; k < 30; ++k) {
202  const ScalarType a = as<ScalarType> (k) * incr;
203  const ScalarType b = one - as<ScalarType> (k) * incr;
204  success = success && compare (a, b);
205  }
206  }
207 
208  //
209  // Try some big values just to see whether ROTG correctly
210  // scales its inputs to avoid overflow.
211  //
212  //success = success && compare (STS::rmax() / four, STS::rmax() / four);
213  //success = success && compare (-STS::rmax() / four, STS::rmax() / four);
214  //success = success && compare (STS::rmax() / four, -STS::rmax() / four);
215 
216  //success = success && compare (STS::rmax() / two, STS::rmax() / two);
217  //success = success && compare (-STS::rmax() / two, STS::rmax() / two);
218  //success = success && compare (-STS::rmax() / two, -STS::rmax() / two);
219 
220  //success = success && compare (STS::rmax() / two, zero);
221  //success = success && compare (zero, STS::rmax() / two);
222  //success = success && compare (-STS::rmax() / two, zero);
223  //success = success && compare (zero, -STS::rmax() / two);
224 
225  //success = success && compare (STS::rmax() / two, one);
226  //success = success && compare (one, STS::rmax() / two);
227  //success = success && compare (-STS::rmax() / two, one);
228  //success = success && compare (one, -STS::rmax() / two);
229 
230  return success;
231  }
232  };
233 } // namespace (anonymous)
234 
235 
236 int
237 main (int argc, char *argv[])
238 {
239  using std::endl;
241 
242  Teuchos::GlobalMPISession mpiSession (&argc, &argv, NULL);
243  const int myRank = mpiSession.getRank();
244  Teuchos::oblackholestream blackHole;
245  std::ostream& out = (myRank == 0) ? std::cout : blackHole;
246 
247  bool verbose = true;
248  CommandLineProcessor cmdp(false,true);
249  cmdp.setOption ("verbose", "quiet", &verbose, "Print messages and results.");
250 
251  // Parse the command-line arguments.
252  {
253  const CommandLineProcessor::EParseCommandLineReturn parseResult =
254  cmdp.parse (argc,argv);
255  // If the caller asks us to print the documentation, let the
256  // "test" pass trivially.
257  if (parseResult == CommandLineProcessor::PARSE_HELP_PRINTED) {
258  out << "End Result: TEST PASSED" << endl;
259  return EXIT_SUCCESS;
260  }
261  TEUCHOS_TEST_FOR_EXCEPTION(parseResult != CommandLineProcessor::PARSE_SUCCESSFUL,
262  std::invalid_argument,
263  "Failed to parse command-line arguments");
264  }
265 
266  // Only let the tester print if in verbose mode.
267  GivensTester<int, double> tester (verbose ? out : blackHole);
268  const bool success = tester.test ();
269 
270  if (success) {
271  out << "End Result: TEST PASSED" << endl;
272  return EXIT_SUCCESS;
273  } else {
274  out << "End Result: TEST FAILED" << endl;
275  return EXIT_FAILURE;
276  }
277 }
278 
static int getRank()
The rank of the calling process in MPI_COMM_WORLD.
T magnitudeType
Mandatory typedef for result of magnitude.
Templated interface class to BLAS routines.
static magnitudeType eps()
Returns relative machine precision.
static T squareroot(T x)
Returns a number of magnitudeType that is the square root of this scalar type x.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
basic_ostream&lt;&gt; subclass that does nothing but discard output.
Templated BLAS wrapper.
static magnitudeType base()
Returns the base of the machine.
Initialize, finalize, and query the global MPI session.
TypeTo as(const TypeFrom &t)
Convert from one value type to another.
int main(int argc, char *argv[])
static magnitudeType magnitude(ScalarTypea)
Returns the magnitudeType of the scalar type a.
Default implementation for BLAS routines.
A MPI utilities class, providing methods for initializing, finalizing, and querying the global MPI se...
void ROTG(ScalarType *da, ScalarType *db, rotg_c_type *c, ScalarType *s) const
Computes a Givens plane rotation.
Basic command line parser for input from (argc,argv[])
static T zero()
Returns representation of zero for this scalar type.
Definition of Teuchos::as, for conversions between types.
static T one()
Returns representation of one for this scalar type.
Class that helps parse command line input arguments from (argc,argv[]) and set options.