1#  ___________________________________________________________________________
2#
3#  Pyomo: Python Optimization Modeling Objects
4#  Copyright 2017 National Technology and Engineering Solutions of Sandia, LLC
5#  Under the terms of Contract DE-NA0003525 with National Technology and
6#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
7#  rights in this software.
8#  This software is distributed under the 3-clause BSD License.
9#  ___________________________________________________________________________
10
11__all__ = ['BuildCheck']
12
13import logging
14import types
15
16from pyomo.common.log import is_debug_set
17from pyomo.common.timing import ConstructionTimer
18from pyomo.core.base.component import ModelComponentFactory
19from pyomo.core.base.indexed_component import IndexedComponent
20from pyomo.core.base.misc import apply_indexed_rule
21
22logger = logging.getLogger('pyomo.core')
23
24
25@ModelComponentFactory.register("A component that performs tests during model construction.  The action rule is applied to every index value.")
26class BuildCheck(IndexedComponent):
27    """
28    A build check, which executes a rule for all valid indices.  If
29    the function returns False an exception is raised.
30
31    Constructor arguments:
32        rule         The rule that is executed for every indice.
33
34    Private class attributes:
35        _rule       The rule that is executed for every indice.
36    """
37
38    def __init__(self, *args, **kwd):
39        self._rule = kwd.pop('rule', None)
40        kwd['ctype'] = BuildCheck
41        IndexedComponent.__init__(self, *args, **kwd)
42        #
43        if not type(self._rule) is types.FunctionType:
44            raise ValueError("BuildCheck  must have an 'rule' option specified whose value is a function")
45
46    def _pprint(self):
47        return ([], None, None, None)
48
49    def construct(self, data=None):
50        """ Apply the rule to construct values in this set """
51        if is_debug_set(logger):   #pragma:nocover
52                logger.debug("Constructing Check, name="+self.name)
53        #
54        if self._constructed:                                  #pragma:nocover
55            return
56        timer = ConstructionTimer(self)
57        self._constructed=True
58        #
59        if not self.is_indexed():
60            # Scalar component
61            res = self._rule(self._parent())
62            if not res:
63                raise ValueError("BuildCheck %r identified error" % self.name)
64        else:
65            # Indexed component
66            for index in self._index:
67                res = apply_indexed_rule(self, self._rule, self._parent(), index)
68                if not res:
69                    raise ValueError("BuildCheck %r identified error with index %r" % (self.name, str(index)))
70        timer.report()
71