LSSTApplications  10.0-2-g4f67435,11.0.rc2+1,11.0.rc2+12,11.0.rc2+3,11.0.rc2+4,11.0.rc2+5,11.0.rc2+6,11.0.rc2+7,11.0.rc2+8
LSSTDataManagementBasePackage
comparison.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 # Copyright 2008-2013 LSST Corporation.
4 #
5 # This product includes software developed by the
6 # LSST Project (http://www.lsst.org/).
7 #
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the LSST License Statement and
19 # the GNU General Public License along with this program. If not,
20 # see <http://www.lsstcorp.org/LegalNotices/>.
21 #
22 """
23 Helper functions for comparing Configs.
24 
25 The function here should be use for any comparison in a Config.compare
26 or Field._compare implementation, as they take care of writing messages
27 as well as floating-point comparisons and shortcuts.
28 """
29 
30 import numpy
31 
32 __all__ = ("getComparisonName", "compareScalars", "compareConfigs")
33 
34 def getComparisonName(name1, name2):
35  if name1 != name2:
36  return "%s / %s" % (name1, name2)
37  return name1
38 
39 def compareScalars(name, v1, v2, output, rtol=1E-8, atol=1E-8, dtype=None):
40  """Helper function for Config.compare; used to compare two scalar values for equality.
41 
42  @param[in] name Name to use when reporting differences
43  @param[in] dtype Data type for comparison; may be None if it's definitely not floating-point.
44  @param[in] v1 LHS value to compare
45  @param[in] v2 RHS value to compare
46  @param[in] output If not None, a callable that takes a string, used (possibly repeatedly)
47  to report inequalities.
48  @param[in] rtol Relative tolerance for floating point comparisons.
49  @param[in] atol Absolute tolerance for floating point comparisons.
50  @param[in] dtype Data type for comparison; may be None if it's definitely not floating-point.
51 
52  Floating point comparisons are performed by numpy.allclose; refer to that for details.
53  """
54  if v1 is None or v2 is None:
55  result = (v1 == v2)
56  elif dtype in (float, complex):
57  result = numpy.allclose(v1, v2, rtol=rtol, atol=atol) or (numpy.isnan(v1) and numpy.isnan(v2))
58  else:
59  result = (v1 == v2)
60  if not result and output is not None:
61  output("Inequality in %s: %r != %r" % (name, v1, v2))
62  return result
63 
64 def compareConfigs(name, c1, c2, shortcut=True, rtol=1E-8, atol=1E-8, output=None):
65  """Helper function for Config.compare; used to compare two Configs for equality.
66 
67  If the Configs contain RegistryFields or ConfigChoiceFields, unselected Configs
68  will not be compared.
69 
70  @param[in] name Name to use when reporting differences
71  @param[in] c1 LHS config to compare
72  @param[in] c2 RHS config to compare
73  @param[in] shortcut If True, return as soon as an inequality is found.
74  @param[in] rtol Relative tolerance for floating point comparisons.
75  @param[in] atol Absolute tolerance for floating point comparisons.
76  @param[in] output If not None, a callable that takes a string, used (possibly repeatedly)
77  to report inequalities.
78 
79  Floating point comparisons are performed by numpy.allclose; refer to that for details.
80  """
81  assert name is not None
82  if c1 is None:
83  if c2 is None:
84  return True
85  else:
86  if output is not None:
87  output("LHS is None for %s" % name)
88  return False
89  else:
90  if c2 is None:
91  if output is not None:
92  output("RHS is None for %s" % name)
93  return False
94  if type(c1) != type(c1):
95  if output is not None:
96  output("Config types do not match for %s: %s != %s" % (name, type(c1), type(c2)))
97  return False
98  equal = True
99  for field in c1._fields.itervalues():
100  result = field._compare(c1, c2, shortcut=shortcut, rtol=rtol, atol=atol, output=output)
101  if not result and shortcut:
102  return False
103  equal = equal and result
104  return equal