Exemplo n.º 1
0
 def test_standard_random_seed(self):
     """Test built-in random with seed."""
     rng = LocalRandom(TEST_SEED)
     sequence_valid = [22, 15, 21, 23, 14, 14, 11, 20, 17, 23]
     sequence_generated = [rng.standard.randint(11, 23) for i in range(10)]
     self.assertListEqual(sequence_valid, sequence_generated,
                          "Wrong sequence for seed '%s'." % TEST_SEED)
Exemplo n.º 2
0
 def test_numpy_rand_seed(self):
     """Test ``numpy`` random with seed."""
     rng = LocalRandom(TEST_SEED)
     sequence_valid = [19, 16, 22, 19, 15, 22, 20, 20, 13, 15]
     sequence_generated = list(rng.numpy.randint(11, 23, (10, )))
     self.assertListEqual(sequence_valid, sequence_generated,
                          "Wrong sequence for seed '%s'." % TEST_SEED)
Exemplo n.º 3
0
 def test_numpy_rand(self):
     """Test ``numpy`` random works."""
     rng = LocalRandom()
     val = rng.numpy.rand(11, )
     for i in range(10):
         self.assertNotEqual(val[i], val[i + 1],
                             "Not a random sequence: numbers repeating.")
Exemplo n.º 4
0
 def test_standard_random(self):
     """Test built-in random works."""
     rng = LocalRandom()
     val = rng.standard.random()
     for _ in range(10):
         new_val = rng.standard.random()
         self.assertNotEqual(val, new_val,
                             "Not a random sequence: numbers repeating.")
         val = new_val
Exemplo n.º 5
0
 def test_2d(self):
     """Test same field is generated with same seed."""
     bsca = GameOfLife(TestExperiment)
     vals = {'state': RandInt(0, 1)}
     seed = PrimordialSoup(vals=vals)
     cells = np.zeros((10000, ), dtype=np.int32)
     seed.random = LocalRandom("test")
     seed.generate(cells, bsca)
     self.assertEqual(binascii.crc32(cells[:10000]), 1648433356,
                      "Wrong field checksum.")
Exemplo n.º 6
0
 def __init__(self, experiment_class):
     """Initialize kernels, GPU arrays, and other stuff."""
     super().__init__()
     # visuals
     self.frame_buf = np.zeros((3, ), dtype=np.uint8)
     self.width, self.height = 0, 0
     # set up random stream
     self.random = LocalRandom(experiment_class.word)
     experiment_class.seed.random = self.random
     experiment_class.random = self.random
     # populate attributes from Experiment class
     for attr_name in dir(experiment_class):
         attr = getattr(experiment_class, attr_name)
         if (not callable(attr) and not attr_name.startswith("__")):
             if attr_name == 'seed':
                 continue
             if hasattr(self.meta, attr_name):
                 self.meta.__dict__[attr_name].__set__(self, attr)
                 continue
             setattr(self, attr_name, attr)
     # default simulation values
     self.speed = 1
     self.paused = False
     self.timestep = 0
     # CUDA kernel
     self.cells_num = functools.reduce(operator.mul, self.size)
     self.build_source()
     # print(self.cuda_source)
     # build seed
     init_colors = np.zeros((self.cells_num * 3, ), dtype=np.int32)
     cells_total = self.cells_num * (len(self.buffers) + 1) + 1
     init_cells = np.zeros((cells_total, ), dtype=self.main.dtype)
     experiment_class.seed.generate(init_cells, self)
     # initialize GPU stuff
     self.gpu = GPU(self.cuda_source, init_cells, init_colors)
     # bridge
     self.bridge = MoireBridge
     self.renderer.setup_actions(self.bridge)
     # lock
     self._lock = threading.Lock()
Exemplo n.º 7
0
 def __init__(self, seed=None):
     """Initialize ``LocalRandom``."""
     self.random = LocalRandom(seed)
Exemplo n.º 8
0
class CellularAutomaton(Translator, metaclass=BSCA):
    """
    The base class for all Xentica models.

    Generates GPU kernels source code, compiles them, initializes
    necessary GPU arrays and populates them with the seed.

    After initialization, you can run a step-by-step simulation and
    render the field at any moment::

        from xentica import core
        import moire

        class MyCA(core.CellularAutomaton):
            # ...

        class MyExperiment(core.Experiment):
            # ...

        ca = MyCA(MyExperiment)
        ca.set_viewport((320, 200))

        # run CA manually for 100 steps
        for i in range(100):
            ca.step()
        # render current timestep
        frame = ca.render()

        # or run the whole process interactively with Moire
        gui = moire.GUI(runnable=ca)
        gui.run()

    :param experiment_class:
        :class:`Experiment <xentica.core.experiments.Experiment>`
        instance, holding all necessary parameters for the field
        initialization.

    """
    def __init__(self, experiment_class):
        """Initialize kernels, GPU arrays, and other stuff."""
        super().__init__()
        # visuals
        self.frame_buf = np.zeros((3, ), dtype=np.uint8)
        self.width, self.height = 0, 0
        # set up random stream
        self.random = LocalRandom(experiment_class.word)
        experiment_class.seed.random = self.random
        experiment_class.random = self.random
        # populate attributes from Experiment class
        for attr_name in dir(experiment_class):
            attr = getattr(experiment_class, attr_name)
            if (not callable(attr) and not attr_name.startswith("__")):
                if attr_name == 'seed':
                    continue
                if hasattr(self.meta, attr_name):
                    self.meta.__dict__[attr_name].__set__(self, attr)
                    continue
                setattr(self, attr_name, attr)
        # default simulation values
        self.speed = 1
        self.paused = False
        self.timestep = 0
        # CUDA kernel
        self.cells_num = functools.reduce(operator.mul, self.size)
        self.build_source()
        # print(self.cuda_source)
        # build seed
        init_colors = np.zeros((self.cells_num * 3, ), dtype=np.int32)
        cells_total = self.cells_num * (len(self.buffers) + 1) + 1
        init_cells = np.zeros((cells_total, ), dtype=self.main.dtype)
        experiment_class.seed.generate(init_cells, self)
        # initialize GPU stuff
        self.gpu = GPU(self.cuda_source, init_cells, init_colors)
        # bridge
        self.bridge = MoireBridge
        self.renderer.setup_actions(self.bridge)
        # lock
        self._lock = threading.Lock()

    def apply_speed(self, dval):
        """
        Change the simulation speed.

        Usable only in conduction with Moire, although you can use the
        ``speed`` value in your custom GUI too.

        :param dval: Delta by which speed is changed.

        """
        self.speed = max(1, (self.speed + dval))

    def toggle_pause(self):
        """
        Toggle ``paused`` flag.

        When paused, the ``step()`` method does nothing.

        """
        self.paused = not self.paused

    def set_viewport(self, size):
        """
        Set the viewport (camera) size and initialize GPU array for it.

        :param size: tuple with the width and height in pixels.

        """
        self.width, self.height = size
        num_cells = self.width * self.height * 3
        self.gpu.arrays.init_img(num_cells)

    def step(self):
        """
        Perform a single simulation step.

        ``timestep`` attribute will hold the current step number.

        """
        if self.paused:
            return
        # pylint: disable=protected-access
        # This is "hack" to get block/grid sizes, it's vital to us.
        # No way to get it correctly with PyCuda right now.
        block, grid = self.gpu.arrays.cells._block, self.gpu.arrays.cells._grid
        with self._lock:
            args = [param.dtype(param.value) for param in self._emit_params]
            self.gpu.kernels.emit(self.gpu.arrays.cells,
                                  *args,
                                  np.int32(self.cells_num),
                                  block=block,
                                  grid=grid)
            args = [param.dtype(param.value) for param in self._absorb_params]
            self.gpu.kernels.absorb(self.gpu.arrays.cells,
                                    self.gpu.arrays.colors,
                                    *args,
                                    np.int32(self.cells_num),
                                    block=block,
                                    grid=grid)
            self.timestep += 1

    def render(self):
        """
        Render the field at the current timestep.

        You must call :meth:`set_viewport` before do any rendering.

        :returns:
            NumPy array of ``np.uint8`` values, ``width * height * 3``
            size. The RGB values are consecutive.

        """
        # pylint: disable=protected-access
        # This is "hack" to get block/grid sizes, it's vital to us.
        # No way to get it correctly with PyCuda right now.
        if self.gpu.arrays.img is None:
            msg = "Viewport is not set, call set_viewport() before rendering."
            raise XenticaException(msg)
        block, grid = self.gpu.arrays.img._block, self.gpu.arrays.img._grid
        with self._lock:
            args = self.renderer.get_args_vals(self)
            args += [param.dtype(param.value) for param in self._render_params]
            args.append(np.int32(self.width * self.height))
            self.gpu.kernels.render(*args, block=block, grid=grid)
            return self.gpu.arrays.img.get().astype(np.uint8)

    def save(self, filename):
        """Save the CA state into ``filename`` file."""
        with open(filename, "wb") as ca_file:
            ca_state = {
                "cells": self.gpu.arrays.cells.get(),
                "colors": self.gpu.arrays.colors.get(),
                "random": self.random,
            }
            pickle.dump(ca_state, ca_file)

    def load(self, filename):
        """Load the CA state from ``filename`` file."""
        with open(filename, "rb") as ca_file:
            ca_state = pickle.load(ca_file)
            self.gpu.arrays.cells = gpuarray.to_gpu(ca_state['cells'])
            self.gpu.arrays.colors = gpuarray.to_gpu(ca_state['colors'])
            self.random.load(ca_state['random'])