prober.py 3.85 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
Theo Steininger's avatar
Theo Steininger committed
13 14 15 16 17
#
# Copyright(C) 2013-2017 Max-Planck-Society
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik
# and financially supported by the Studienstiftung des deutschen Volkes.
Theo Steininger's avatar
Theo Steininger committed
18

Martin Reinecke's avatar
Martin Reinecke committed
19 20 21
from builtins import str
from builtins import range
from builtins import object
22
import numpy as np
Martin Reinecke's avatar
Martin Reinecke committed
23
from ..field import Field, DomainTuple
Theo Steininger's avatar
Theo Steininger committed
24 25


26
class Prober(object):
Theo Steininger's avatar
Theo Steininger committed
27
    """
28 29 30 31 32
    See the following webpages for the principles behind the usage of
    mixin-classes

    https://www.python.org/download/releases/2.2.3/descrintro/#cooperation
    https://rhettinger.wordpress.com/2011/05/26/super-considered-super/
Theo Steininger's avatar
Theo Steininger committed
33 34
    """

Martin Reinecke's avatar
Martin Reinecke committed
35
    def __init__(self, domain=None, probe_count=8,
36
                 random_type='pm1', probe_dtype=np.float,
Martin Reinecke's avatar
Martin Reinecke committed
37
                 compute_variance=False, ncpu=1):
38

Martin Reinecke's avatar
Martin Reinecke committed
39
        self._domain = DomainTuple.make(domain)
Martin Reinecke's avatar
tweaks  
Martin Reinecke committed
40 41 42 43 44 45
        self._probe_count = int(probe_count)
        self._ncpu = int(ncpu)
        if random_type not in ["pm1", "normal"]:
            raise ValueError(
                "unsupported random type: '" + str(random_type) + "'.")
        self._random_type = random_type
Theo Steininger's avatar
Theo Steininger committed
46
        self.compute_variance = bool(compute_variance)
47
        self.probe_dtype = np.dtype(probe_dtype)
48
        self._uid_counter = 0
Theo Steininger's avatar
Theo Steininger committed
49

50
    @property
Theo Steininger's avatar
Theo Steininger committed
51
    def domain(self):
52 53
        return self._domain

Theo Steininger's avatar
Theo Steininger committed
54
    @property
55 56
    def probe_count(self):
        return self._probe_count
Theo Steininger's avatar
Theo Steininger committed
57

58 59 60 61
    @property
    def random_type(self):
        return self._random_type

Martin Reinecke's avatar
tweaks  
Martin Reinecke committed
62
    def gen_parallel_probe(self, callee):
Martin Reinecke's avatar
Martin Reinecke committed
63 64 65
        for i in range(self.probe_count):
            yield (callee, self.get_probe(i))

66
    def probing_run(self, callee):
67
        """ controls the generation, evaluation and finalization of probes """
68
        self.reset()
Martin Reinecke's avatar
PEP8  
Martin Reinecke committed
69
        if self._ncpu == 1:
Martin Reinecke's avatar
Martin Reinecke committed
70 71 72 73 74
            for index in range(self.probe_count):
                current_probe = self.get_probe(index)
                pre_result = self.process_probe(callee, current_probe, index)
                self.finish_probe(current_probe, pre_result)
        else:
Martin Reinecke's avatar
Martin Reinecke committed
75 76 77 78
            from multiprocess import Pool
            pool = Pool(self._ncpu)
            for i in pool.imap_unordered(self.evaluate_probe_parallel,
                                         self.gen_parallel_probe(callee)):
Martin Reinecke's avatar
tweaks  
Martin Reinecke committed
79
                self.finish_probe(i[0], i[1])
Martin Reinecke's avatar
Martin Reinecke committed
80 81 82 83 84

    def evaluate_probe_parallel(self, argtuple):
        callee = argtuple[0]
        probe = argtuple[1]
        return (probe, callee(probe[1]))
85

86
    def reset(self):
87
        pass
88 89 90 91

    def get_probe(self, index):
        """ layer of abstraction for potential probe-caching """
        return self.generate_probe()
Theo Steininger's avatar
Theo Steininger committed
92

Theo Steininger's avatar
Theo Steininger committed
93 94
    def generate_probe(self):
        """ a random-probe generator """
95
        f = Field.from_random(random_type=self.random_type,
Martin Reinecke's avatar
tweaks  
Martin Reinecke committed
96
                              domain=self.domain, dtype=self.probe_dtype)
97 98
        uid = self._uid_counter
        self._uid_counter += 1
99
        return (uid, f)
Theo Steininger's avatar
Theo Steininger committed
100

101 102 103
    def process_probe(self, callee, probe, index):
        """ layer of abstraction for potential result-caching/recycling """
        return self.evaluate_probe(callee, probe[1])
104

105
    def evaluate_probe(self, callee, probe, **kwargs):
106
        """ processes a probe """
107
        return callee(probe, **kwargs)
108

Theo Steininger's avatar
Theo Steininger committed
109
    def finish_probe(self, probe, pre_result):
110
        pass
Theo Steininger's avatar
Theo Steininger committed
111

112 113
    def __call__(self, callee):
        return self.probing_run(callee)