prober.py 4.2 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 23
import numpy as np

Martin Reinecke's avatar
Martin Reinecke committed
24
from ...field import Field, DomainTuple
25
from ... import nifty_utilities as utilities
Theo Steininger's avatar
Theo Steininger committed
26 27


28
class Prober(object):
Theo Steininger's avatar
Theo Steininger committed
29
    """
30 31 32 33 34 35
    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
36 37
    """

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

Martin Reinecke's avatar
Martin Reinecke committed
42
        self._domain = DomainTuple.make(domain)
43
        self._probe_count = self._parse_probe_count(probe_count)
Martin Reinecke's avatar
Martin Reinecke committed
44
        self._ncpu = self._parse_probe_count(ncpu)
45
        self._random_type = self._parse_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
    # ---Properties---
51

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

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

60 61
    def _parse_probe_count(self, probe_count):
        return int(probe_count)
62 63 64 65 66

    @property
    def random_type(self):
        return self._random_type

67
    def _parse_random_type(self, random_type):
68
        if random_type not in ["pm1", "normal"]:
69 70
            raise ValueError(
                "unsupported random type: '" + str(random_type) + "'.")
71
        return random_type
72 73 74

    # ---Probing methods---

Martin Reinecke's avatar
Martin Reinecke committed
75 76 77 78
    def gen_parallel_probe(self,callee):
        for i in range(self.probe_count):
            yield (callee, self.get_probe(i))

79
    def probing_run(self, callee):
80
        """ controls the generation, evaluation and finalization of probes """
81
        self.reset()
Martin Reinecke's avatar
PEP8  
Martin Reinecke committed
82
        if self._ncpu == 1:
Martin Reinecke's avatar
Martin Reinecke committed
83 84 85 86 87
            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
88 89 90 91 92 93 94 95 96 97
            from multiprocess import Pool
            pool = Pool(self._ncpu)
            for i in pool.imap_unordered(self.evaluate_probe_parallel,
                                         self.gen_parallel_probe(callee)):
                self.finish_probe(i[0],i[1])

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

99
    def reset(self):
100
        pass
101 102 103 104

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

Theo Steininger's avatar
Theo Steininger committed
106 107
    def generate_probe(self):
        """ a random-probe generator """
108
        f = Field.from_random(random_type=self.random_type,
Theo Steininger's avatar
Theo Steininger committed
109
                              domain=self.domain,
Martin Reinecke's avatar
tweaks  
Martin Reinecke committed
110
                              dtype=self.probe_dtype.type)
111 112
        uid = self._uid_counter
        self._uid_counter += 1
113
        return (uid, f)
Theo Steininger's avatar
Theo Steininger committed
114

115 116 117
    def process_probe(self, callee, probe, index):
        """ layer of abstraction for potential result-caching/recycling """
        return self.evaluate_probe(callee, probe[1])
118

119
    def evaluate_probe(self, callee, probe, **kwargs):
120
        """ processes a probe """
121
        return callee(probe, **kwargs)
122

Theo Steininger's avatar
Theo Steininger committed
123
    def finish_probe(self, probe, pre_result):
124
        pass
Theo Steininger's avatar
Theo Steininger committed
125

126 127
    def __call__(self, callee):
        return self.probing_run(callee)