42

Sorry for the stupid question. I'm programming on PHP but found some nice code on Python and want to "recreate" it on PHP. But I'm quite frustrated about the line

self.h = -0.1    
self.activity = numpy.zeros((512, 512)) + self.h
self.activity[:, :] = self.h

But I don't understand what does

[:, :]

mean.

Besides I wasn't able to "Google It".

Full code

import math
import numpy
import pygame
from scipy.misc import imsave
from scipy.ndimage.filters import gaussian_filter


class AmariModel(object):

    def __init__(self, size):
        self.h = -0.1
        self.k = 0.05
        self.K = 0.125
        self.m = 0.025
        self.M = 0.065

        self.stimulus = -self.h * numpy.random.random(size)
        self.activity = numpy.zeros(size) + self.h
        self.excitement = numpy.zeros(size)
        self.inhibition = numpy.zeros(size)

    def stimulate(self):
        self.activity[:, :] = self.activity > 0

        sigma = 1 / math.sqrt(2 * self.k)
        gaussian_filter(self.activity, sigma, 0, self.excitement, "wrap")
        self.excitement *= self.K * math.pi / self.k

        sigma = 1 / math.sqrt(2 * self.m)
        gaussian_filter(self.activity, sigma, 0, self.inhibition, "wrap")
        self.inhibition *= self.M * math.pi / self.m

        self.activity[:, :] = self.h
        self.activity[:, :] += self.excitement
        self.activity[:, :] -= self.inhibition
        self.activity[:, :] += self.stimulus


class AmariMazeGenerator(object):

    def __init__(self, size):
        self.model = AmariModel(size)

        pygame.init()
        self.display = pygame.display.set_mode(size, 0)
        pygame.display.set_caption("Amari Maze Generator")

    def run(self):
        pixels = pygame.surfarray.pixels3d(self.display)

        index = 0
        running = True
        while running:
            self.model.stimulate()

            pixels[:, :, :] = (255 * (self.model.activity > 0))[:, :, None]
            pygame.display.flip()

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    running = False
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE:
                        running = False
                    elif event.key == pygame.K_s:
                        imsave("{0:04d}.png".format(index), pixels[:, :, 0])
                        index = index + 1
                elif event.type == pygame.MOUSEBUTTONDOWN:
                    position = pygame.mouse.get_pos()
                    self.model.activity[position] = 1

        pygame.quit()


def main():
    generator = AmariMazeGenerator((512, 512))
    generator.run()


if __name__ == "__main__":
    main()
smci
  • 29,564
  • 18
  • 109
  • 144
user2432721
  • 425
  • 1
  • 4
  • 6
  • Here `self.activity[:, :] = self.h` is redundant because `self.activity` is already `self.h`. Think similar to this: `a = 0 + 2` and then `a = 2`. It is not really the same but might help to understand. – Mike Müller May 29 '13 at 14:16

3 Answers3

48

The [:, :] stands for everything from the beginning to the end just like for lists. The difference is that the first : stands for first and the second : for the second dimension.

a = numpy.zeros((3, 3))

In [132]: a
Out[132]: 
array([[ 0.,  0.,  0.],
       [ 0.,  0.,  0.],
       [ 0.,  0.,  0.]])

Assigning to second row:

In [133]: a[1, :] = 3

In [134]: a
Out[134]: 
array([[ 0.,  0.,  0.],
       [ 3.,  3.,  3.],
       [ 0.,  0.,  0.]])

Assigning to second column:

In [135]: a[:, 1] = 4

In [136]: a
Out[136]: 
array([[ 0.,  4.,  0.],
       [ 3.,  4.,  3.],
       [ 0.,  4.,  0.]])

Assigning to all:

In [137]: a[:] = 10

In [138]: a
Out[138]: 
array([[ 10.,  10.,  10.],
       [ 10.,  10.,  10.],
       [ 10.,  10.,  10.]])
Samuel Harmer
  • 4,016
  • 4
  • 29
  • 66
Mike Müller
  • 77,540
  • 18
  • 155
  • 159
19

numpy uses tuples as indexes. In this case, this is a detailed slice assignment.

[0]     #means line 0 of your matrix
[(0,0)] #means cell at 0,0 of your matrix
[0:1]   #means lines 0 to 1 excluded of your matrix
[:1]    #excluding the first value means all lines until line 1 excluded
[1:]    #excluding the last param mean all lines starting form line 1 
         included
[:]     #excluding both means all lines
[::2]   #the addition of a second ':' is the sampling. (1 item every 2)
[::]    #exluding it means a sampling of 1
[:,:]   #simply uses a tuple (a single , represents an empty tuple) instead 
         of an index.

It is equivalent to the simpler

self.activity[:] = self.h

(which also works for regular lists as well)

njzk2
  • 38,125
  • 7
  • 64
  • 103
11

This is slice assignment. Technically, it calls1

self.activity.__setitem__((slice(None,None,None),slice(None,None,None)),self.h)

which sets all of the elements in self.activity to whatever value self.h is storing. The code you have there really seems redundant. As far as I can tell, you could remove the addition on the previous line, or simply use slice assignment:

self.activity = numpy.zeros((512,512)) + self.h

or

self.activity = numpy.zeros((512,512))
self.activity[:,:] = self.h

Perhaps the fastest way to do this is to allocate an empty array and .fill it with the expected value:

self.activity = numpy.empty((512,512))
self.activity.fill(self.h)

1Actually, __setslice__ is attempted before calling __setitem__, but __setslice__ is deprecated, and shouldn't be used in modern code unless you have a really good reason for it.

mgilson
  • 283,004
  • 58
  • 591
  • 667
  • check this one http://stackoverflow.com/questions/509211/the-python-slice-notation – Zang MingJie May 29 '13 at 14:03
  • @ZangMingJie -- Yeah, that's the canonical answer for slice notation. however, most of those answers are (implicitly) focused on `__getitem__` rather than `__setitem__` so I thought it would be reasonable to re-answer from that different perspective. – mgilson May 29 '13 at 14:07
  • So I can suppose that PHP version of Python's arr[:] += 1 will be foreach($arr as $k=>$v){ $arr[$k] += 1; } Or at least close to it. – user2432721 May 29 '13 at 14:11
  • @user2432721 -- That really depends on the type of `arr` -- But for `numpy.ndarray`, yes. That's correct. – mgilson May 29 '13 at 14:13
  • @JochenRitzel -- "which sets all of the elements in `self.activity` to whatever value `self.h` is storing" ... – mgilson May 29 '13 at 14:14
  • It's not My code. I'm only trying to move it to another language – user2432721 May 29 '13 at 14:16
  • @user2432721 -- Note that numpy pushes all of the loops into a compiled C backend, so it is designed to be efficient when used this way. It is likely that the numpy version executes much faster than the PHP approximation you suggested. – mgilson May 29 '13 at 14:18