[GRASS-SVN] r48981 - in grass-addons/grass7/raster/r.agent: . libagent

svn_grass at osgeo.org svn_grass at osgeo.org
Sat Oct 29 11:52:15 EDT 2011


Author: mic
Date: 2011-10-29 08:52:14 -0700 (Sat, 29 Oct 2011)
New Revision: 48981

Added:
   grass-addons/grass7/raster/r.agent/libagent/
   grass-addons/grass7/raster/r.agent/libagent/__init__.py
   grass-addons/grass7/raster/r.agent/libagent/aco.py
   grass-addons/grass7/raster/r.agent/libagent/agent.py
   grass-addons/grass7/raster/r.agent/libagent/alltests.py
   grass-addons/grass7/raster/r.agent/libagent/ant.py
   grass-addons/grass7/raster/r.agent/libagent/error.py
   grass-addons/grass7/raster/r.agent/libagent/layer.py
   grass-addons/grass7/raster/r.agent/libagent/overview.html
   grass-addons/grass7/raster/r.agent/libagent/playground.py
   grass-addons/grass7/raster/r.agent/libagent/rasterlayer.py
   grass-addons/grass7/raster/r.agent/libagent/vectorlayer.py
   grass-addons/grass7/raster/r.agent/libagent/world.py
   grass-addons/grass7/raster/r.agent/r.agent.aco
   grass-addons/grass7/raster/r.agent/r.agent.html
Log:
add initial version for r.agent

Added: grass-addons/grass7/raster/r.agent/libagent/__init__.py
===================================================================
Added: grass-addons/grass7/raster/r.agent/libagent/aco.py
===================================================================
--- grass-addons/grass7/raster/r.agent/libagent/aco.py	                        (rev 0)
+++ grass-addons/grass7/raster/r.agent/libagent/aco.py	2011-10-29 15:52:14 UTC (rev 48981)
@@ -0,0 +1,225 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+from math import sqrt
+from math import exp
+from random import randint
+import world
+import error
+import ant
+
+class ACO(world.World):
+    """Ant Colony Optimization Algorithm for Modelling an Agent Based World"""
+    def __init__(self):
+        world.World.__init__(self, ant.Ant)
+        ### auto/constant
+        self.agentclass = ant.Ant
+        self.ants = self.agents
+        self.artefacts.append([])
+        self.holes = self.artefacts[0]
+        self.artefacts.append([])
+        self.sugar = self.artefacts[1]
+        self.surfaceslope = None
+        self.costsurface = None
+        self.pherovapour = None
+        self.bounds = None
+        self.straight = 0
+        self.diagonal = sqrt(2)-1
+        # count paths
+        self.nrop = 0
+        ### user parameter
+        self.globalfreedom = 8
+        self.rounds = 0
+        self.outrounds = 0
+        self.outfilename = ""
+        self.maxpheromone = 2147483647
+        self.minpheromone = 10
+        self.volatilizationtime = 1
+        self.stepintensity = 10
+        self.pathintensity = 10000
+        self.decisionbase = "standard"
+        self.pheroweight = 1
+        self.randomweight = 1
+        self.validposition = "specials"
+# use fibonacci?
+        self.maxants = 100
+        self.antslife = 0
+    def checkvalues(self):
+        if self.costsurface == None:
+            raise error.DataError("aco.ACO.checkvalues()",
+                    "main input missing: costraster")
+        self.playground.setboundsfromlayer("costs")
+        self.playground.forcelayerbounds()
+        self.bounds = self.playground.getrelativebounds()
+        if self.costsurface == None:
+            raise error.DataError("aco.ACO.checkvalues()",
+                    "input layer missing: costsurface")
+        elif self.costsurface == []:
+            if self.surfaceslope == None:
+                raise error.DataError("aco.ACO.checkvalues()",
+                    "input layer missing: please provide cost or slope layer")
+            else:
+                self.calccostsurface()
+        if self.pherovapour == None:
+            raise error.DataError("aco.ACO.checkvalues()",
+                    "output layer missing: pheromoneraster")
+        if self.holes == None:
+            raise error.DataError("aco.ACO.checkvalues()",
+                    "input layer missing: vectorholes")
+        if self.rounds <= 0:
+            raise error.DataError("aco.ACO.checkvalues()",
+                    "number of rounds is zero or not set.")
+        if self.outrounds <= 0:
+            self.outrounds = self.rounds
+        if self.antslife == 0:
+            self.antslife = (self.bounds[4]+self.bounds[5])
+        if self.volatilizationtime > self.rounds:
+            self.volatilizationtime = self.rounds
+        elif self.volatilizationtime < 0:
+            self.volatilizationtime = 0
+        for hole in self.holes[:]:
+            if self.costsurface[hole[0]][hole[1]] < 0:
+                self.holes.remove(hole)
+            else:
+# TODO if two holes are close, choose outermost.. or so.
+                self.pherovapour[hole[0]][hole[1]] = -1
+    def addneighbour(self, positions, position):
+        position[2] = self.costsurface[position[0]][position[1]]
+# TODO > or >=
+        if position[2] >= 0:
+            position[3] = self.pherovapour[position[0]][position[1]]
+            positions.append(position)
+    def calccostsurface(self):
+        for x in range(self.bounds[2]):
+            for y in range(self.bounds[0]):
+                val = self.surfaceslope[x][y]
+                if self.surfaceslope > 0:
+                    self.costsurface[x][y] = (1/exp(-0.035*abs(val+5)))-1
+    def getneighbourpositions(self, position, freedom=None):
+        # position = [ x, y, surfacecost, special/phero, timecost, direction ]
+        if freedom == None:
+            freedom = self.globalfreedom
+        positions = []
+        if freedom >= 4:
+            #north = 1
+#TODO improve with not creating position in any case..
+            p = [position[0], position[1]+1, 0, 0, self.straight, 1]
+            if p[1] <= self.bounds[0]:
+                self.addneighbour(positions, p)
+            #south = 2
+            p = [position[0], position[1]-1, 0, 0, self.straight, 2]
+            if p[1] >= self.bounds[1]:
+                self.addneighbour(positions, p)
+            #east = 3
+            p = [position[0]+1, position[1], 0, 0, self.straight, 3]
+            if p[0] <= self.bounds[2]:
+                self.addneighbour(positions, p)
+            #west = 4
+            p = [position[0]-1, position[1], 0, 0, self.straight, 4]
+            if p[0] >= self.bounds[3]:
+                self.addneighbour(positions, p)
+        if freedom >= 8:
+            #northeast = 5
+            p = [position[0]+1, position[1]+1, 0, 0, self.diagonal, 5]
+            if p[1] <= self.bounds[0] and p[0] <= self.bounds[2]:
+                self.addneighbour(positions, p)
+            #northwest = 6
+            p = [position[0]-1, position[1]+1, 0, 0, self.diagonal, 6]
+            if p[1] <= self.bounds[0] and p[0] >= self.bounds[3]:
+                self.addneighbour(positions, p)
+            #southeast = 7
+            p = [position[0]+1, position[1]-1, 0, 0, self.diagonal, 7]
+            if p[1] >= self.bounds[1] and p[0] <= self.bounds[2]:
+                self.addneighbour(positions, p)
+            #southwest = 8
+            p = [position[0]-1, position[1]-1, 0, 0, self.diagonal, 8]
+            if p[1] >= self.bounds[1] and p[0] >= self.bounds[3]:
+                self.addneighbour(positions, p)
+        return positions
+    def letantsdance(self):
+        if 0 < self.outrounds < self.rounds:
+            mainloops = self.rounds/self.outrounds
+            loops = self.outrounds
+        else:
+            mainloops = 1
+            loops = self.rounds
+        nrofrounds = mainloops*loops
+        remember = loops
+        while mainloops > 0:
+            loops = remember
+            while loops > 0:
+                if len(self.ants) < self.maxants:
+                    position = self.holes[randint(0, len(self.holes)-1)][0:2]
+                    self.bear(None, self.antslife, position)
+                for ant in self.ants:
+                    ant.walk()
+                self.volatilize()
+                loops -= 1
+            self.export(str(mainloops))
+            print "nrofpaths:", self.nrop
+            mainloops -= 1
+        print "nrofrounds", nrofrounds
+    def volatilize(self):
+        if self.volatilizationtime > 0:
+            limit = self.minpheromone
+            halflife = self.volatilizationtime
+            for x in range(self.bounds[2]):
+                for y in range(self.bounds[0]):
+                    if self.pherovapour[x][y] > limit:
+                        val = int(self.pherovapour[x][y]*0.5**(1.0/halflife))
+                        if val > limit:
+                            self.pherovapour[x][y] = val
+    def export(self, suffix=""):
+        layer = self.playground.getlayer("phero")
+        if self.outfilename == "":
+            self.outfilename = layer.outfilename
+        layer.setoutfilename(self.outfilename+suffix)
+        layer.exportfile()
+
+def test(inraster=False, outraster=False, invector=False, slope=False):
+    """Test suite for ACO Class"""
+    print "creating a new ants world.."
+    w = ACO()
+    if inraster:
+        layer = w.importlayer("costs", "raster", inraster)
+        w.costsurface = layer.raster
+    elif slope:
+        layer = w.importlayer("slope", "raster", slope)
+        w.surfaceslope = layer.raster
+        w.playground.setboundsfromlayer("slope")
+        layer = w.createlayer("costs", "raster", None, None)
+        w.costsurface = layer.raster
+        w.calccostsurface()
+    print "start playing with it.."
+    if outraster and invector:
+        layer = w.createlayer("phero", "raster", None, outraster)
+        w.pherovapour = layer.raster
+        layer = w.importlayer("holes", "vector", invector)
+        w.holes = layer.objects
+        w.rounds = 1
+        w.checkvalues()
+        print "set, within:", w.playground.getbounds()
+        print "this translates to:", w.bounds
+        print " this are the holes:"
+        for hole in w.holes:
+            print str(hole)
+        print "neighbourpositions of [9,9]:", w.getneighbourpositions([9,9])
+        print "setting [9,9] to pheromone 999"
+        w.pherovapour[9][9] = 999
+        w.volatilize()
+        print " after some volatilization:",w.pherovapour[9][9]
+        print "playing with some ants"
+        w.letantsdance()
+        print "rock n' roll"
+        w.export()
+

Added: grass-addons/grass7/raster/r.agent/libagent/agent.py
===================================================================
--- grass-addons/grass7/raster/r.agent/libagent/agent.py	                        (rev 0)
+++ grass-addons/grass7/raster/r.agent/libagent/agent.py	2011-10-29 15:52:14 UTC (rev 48981)
@@ -0,0 +1,63 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+import world
+
+class Agent(object):
+    """standard agent"""
+    def __init__(self, timetolive, world, position=[]):
+        self.ttl = timetolive
+        self.world = world
+        self.position = position
+        self.knowscompass = False
+        self.freedom = 0
+    def setposition(self, position):
+        if position and position != []:
+            self.position[0] = position[0]
+            self.position[1] = position[1]
+    def getposition(self):
+        return self.position
+    def move(self, nrofsteps, direction):
+        pass
+    def age(self):
+        if self.ttl > 0:
+            self.ttl -= 1
+            return True
+        else:
+            self.snuffit()
+            return False
+    def snuffit(self):
+        """to die peacefully and without pain."""
+        self.world.kill(self)
+
+def test():
+    """Test suite for Agent Class"""
+    print "create a world with an agent in."
+    w = world.World(Agent)
+    w.bear(Agent,1,[0,0])
+    print "agent seems fine (for now). time to live:", str(w.agents[0].ttl)
+    print "fake-placing it somewhere ([0,1]).."
+    w.agents[0].setposition([0,1])
+    print "getting its position:", w.agents[0].getposition()
+    print "'cause this takes some time.."
+    w.agents[0].age()
+    print "agent should have grown older by now. time to live:", \
+         str(w.agents[0].ttl)
+    print "and now let agent die.."
+    w.agents[0].age()
+    try:
+        print "should be dead by now. time to live:", str(w.agents[0].ttl)
+    except IndexError:
+        print "IndexError catched: ant was not found in the world anymore."
+    print "all done."
+

Added: grass-addons/grass7/raster/r.agent/libagent/alltests.py
===================================================================
--- grass-addons/grass7/raster/r.agent/libagent/alltests.py	                        (rev 0)
+++ grass-addons/grass7/raster/r.agent/libagent/alltests.py	2011-10-29 15:52:14 UTC (rev 48981)
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      very basic test collection for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+import sys
+
+import error
+import agent
+import ant
+import layer
+import rasterlayer
+import vectorlayer
+import world
+import aco
+import playground
+
+def dotest(function, argv):
+    while True:
+        n = function.func_doc
+        o = str(argv)
+        if not n:
+            n = str(function)
+        t = str(raw_input("execute this now: '"+n+" - "+o+"'? [y/n/abort] "))
+        if t == "y":
+            if argv != None:
+                function(*argv)
+            else:
+                function()
+            break
+        elif t == "n":
+            break
+        elif t == "abort":
+            exit()
+
+files = ["elev.grid", "elev.grid.out", "arch.vect"]
+
+alltests = [[error.test, None],
+            [agent.test, None],
+            [ant.test, None],
+            [layer.test, [files[2]]],
+            [layer.test, [files[0]]],
+            [rasterlayer.test, [files[0]]],
+            [vectorlayer.test, [files[2]]],
+            [world.test, None],
+            [world.test, files],
+            [aco.test, files],
+            [playground.test, ["raster", files[0], "vector", files[2]]]]
+
+for test in alltests:
+    dotest(test[0], test[1])
+


Property changes on: grass-addons/grass7/raster/r.agent/libagent/alltests.py
___________________________________________________________________
Added: svn:executable
   + *

Added: grass-addons/grass7/raster/r.agent/libagent/ant.py
===================================================================
--- grass-addons/grass7/raster/r.agent/libagent/ant.py	                        (rev 0)
+++ grass-addons/grass7/raster/r.agent/libagent/ant.py	2011-10-29 15:52:14 UTC (rev 48981)
@@ -0,0 +1,335 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+from random import choice, randint
+import agent
+import error
+
+class Ant(agent.Agent):
+    """custom"""
+    def __init__(self, timetolive, world, position):
+        agent.Agent.__init__(self, timetolive, world, position)
+        self.position.extend([None,None,0,0])
+        self.home = self.position[:]
+        self.laststeps = [self.position[:]]
+        self.visitedsteps = []
+        self.done = False
+        self.nextstep = [None,None,0,0,0,0]
+        self.goal = []
+        self.penalty = 0.0
+        self.steppaint = world.stepintensity
+        self.pathpaint = world.pathintensity
+        if world.decisionbase == "standard":
+            self.pickaposition = self.smellposition
+            self.pheroweight = self.world.pheroweight * 2
+            self.randomweight = self.world.randomweight * 2
+        elif world.decisionbase == "random":
+            self.pickaposition = self.randomposition
+        elif world.decisionbase == "test":
+            self.pickaposition = self.testposition
+            self.pheroweight = self.world.pheroweight * 2
+            self.randomweight = self.world.randomweight * 2
+        if world.validposition == "avoidloop":
+            self.haspositions = self.avoidloop
+        elif world.validposition == "forgetloop":
+            self.haspositions = self.forgetloop
+        elif world.validposition == "avoidorforgetloop":
+            self.haspositions = self.avoidorforgetloop
+        elif world.validposition == "specials":
+            self.haspositions = self.searchspecials
+    def paint(self, position, value):
+#TODO mv to tests:
+        if self.world.pherovapour[position[0]][position[1]] < 0:
+            print "home:", self.home, "paint:", position, ":", value
+            raise error.Error("Ant.paint()", "Not painting over specials.")
+        if self.world.maxpheromone-value > \
+         self.world.pherovapour[position[0]][position[1]]:
+            self.world.pherovapour[position[0]][position[1]] += value
+    def randomposition(self, positions):
+        self.nextstep = positions[randint(0, len(positions)-1)]
+    def testposition(self, positions):
+        i = 0
+        l = []
+        for pos in positions:
+            l.append([pos[3]/self.randomweight+randint(0,\
+                self.world.maxpheromone)/self.pheroweight, i])
+            i += 1
+        l.sort()
+        self.nextstep = positions[l[0][1]]
+#TODO add some position search alg that avoids high penalties..
+    def smellposition(self, positions):
+        self.nextstep = positions[0]
+        self.nextstep[3] = self.nextstep[3]/self.randomweight+ \
+                    randint(0,self.world.maxpheromone)/self.pheroweight
+        for pos in positions[1:]:
+            pos[3] = pos[3]/self.randomweight+ \
+                    randint(0,self.world.maxpheromone)/self.pheroweight
+            if self.nextstep[3] < pos[3]:
+                self.nextstep = pos
+    def avoidloop(self, positions):
+        ''' This method tries to avoid stepping on already passed
+            nodes. That it is basically. '''
+        # remember all positions for worst case..
+        temppositions = positions[:]
+        for last in self.laststeps[:]:
+            for pos in positions[:]:
+                if last[0] == pos[0] and last[1] == pos[1]:
+                    # position already visited once..
+                    try:
+                        positions.remove(pos)
+                    except ValueError:
+                        pass
+        if len(positions) == 0:
+            # can not be special value, because it would already be visited
+            # make sure it is not home
+            pos = choice(temppositions)
+            if pos[0] == self.home[0] and pos[1] == self.home[1]:
+                temppositions.remove(pos)
+                pos = choice(temppositions)
+            # if none was left: choose another one by chance
+            # no need to proceed with choosing from only one position
+            self.nextstep = pos
+            return True
+        else:
+            for pos in positions[:]:
+                if pos[3] < 0:
+                    # home is already handled because visited
+                    # goal node found. add one to the counter
+                    self.world.nrop += 1
+                    self.done = True
+                    # now, head back home..
+                    self.nextstep = self.laststeps.pop()
+                    return True
+        return False       
+    def avoidorforgetloop(self, positions):
+        ''' This method tries to avoid stepping on already passed
+            nodes. If this is not possible or if a path is coming
+            close to such nodes in the grid, it will grant not to
+            produce loops by deleting all intermediate steps.'''
+        # remember all positions for worst case..
+        temppositions = positions[:]
+        # initially start with no loop found
+        hasposition = False
+        # search for loops, but exclude last step from process (keep it)
+        for last in self.laststeps[:]:
+            if hasposition == True:
+                # remove loop, but remember visited steps
+                self.visitedsteps.append(last)
+                self.laststeps.remove(last)
+            else:
+                # search for loop in positions
+                for pos in positions[:]:
+                    if last[0] == pos[0] and last[1] == pos[1]:
+                        # shortcut found, so remove loop
+                        hasposition = True
+                        # remove that position from possible next ones
+                        positions.remove(pos)
+                        # change direction penalty to new shortcut
+                        self.laststeps[-1][4] = pos[4]
+        # remove all yet visited nodes from possible next positions
+        for visited in self.visitedsteps:
+            for pos in positions[:]:
+                if visited[0] == pos[0] and visited[1] == pos[1]:
+                    # do not step on visited nodes again
+                    positions.remove(pos)
+        if len(positions) == 0:
+            # can not be special value, because it would already be visited
+            # make sure it is not home
+            pos = choice(temppositions)
+            if pos[0] == self.home[0] and pos[1] == self.home[1]:
+                temppositions.remove(pos)
+                pos = choice(temppositions)
+            # if none was left: choose another one by chance
+            # no need to proceed with choosing from only one position
+            self.nextstep = pos
+            return True
+        else:
+            for pos in positions[:]:
+                if pos[3] < 0:
+                    # home is already handled because visited
+                    # goal node found. add one to the counter
+                    self.world.nrop += 1
+                    self.done = True
+                    # now, head back home..
+                    self.nextstep = self.laststeps.pop()
+                    return True
+        return False
+    def forgetloop(self, positions):
+        ''' This method deletes all positions that form a loop in the
+            path. It also prohibits to walk back one step both to the
+            true former position, and to the assumed last step on the
+            newly created shortcut.'''
+        # initially start with no loop found
+        hasposition = False
+        # search for loops, but exclude last step from process (keep it)
+        for last in self.laststeps[:-1]:
+            if hasposition == True:
+                # remove loop
+                self.laststeps.remove(last)
+            else:
+                # search for loop in positions
+                for pos in positions[:]:
+                    if last[0] == pos[0] and last[1] == pos[1]:
+                        # shortcut found, so remove loop
+                        hasposition = True
+                        # remove that position from possible next ones
+                        positions.remove(pos)
+                        # change direction penalty for laststep to new shortcut
+                        self.laststeps[-1][4] = pos[4]
+        for pos in positions[:]:
+            if pos[3] < 0:
+                # promissing, but home is not excluded (only loops are..)
+                if pos[0] == self.home[0] and pos[1] == self.home[1]:
+                    # so, make sure it is not home..
+                    positions.remove(pos)
+                else:
+                    # goal node found. add one to the counter
+                    self.world.nrop += 1
+                    self.done = True
+                    # now, head back home..
+                    self.nextstep = self.laststeps.pop()
+                    return True
+        return False
+    def searchspecials(self, positions):
+        for pos in positions[:]:
+            if pos[3] < 0:
+                # nice value found, goal might be reached
+                if pos[0] == self.home[0] and pos[1] == self.home[1]:
+                    # make sure it is not home..
+                    positions.remove(pos)
+                else:
+                    # this is it! add one to the counter
+                    self.world.nrop += 1
+                    self.done = True
+                    self.nextstep = self.laststeps.pop()
+                    return True
+        return False
+    def choose(self):
+        positions = self.world.getneighbourpositions(self.position)
+        # remove last step from possible neighbourpositions
+        try:
+            positions.remove(self.laststeps[len(self.laststeps)-1])
+        except ValueError:
+            pass
+        if not self.haspositions(positions):
+            self.pickaposition(positions)
+    def walk(self):
+        # we are all only getting older..
+        if self.age() == False:
+            return False
+        # if we do not have decided yet where to go to..
+        if self.nextstep[0] == None:
+            self.choose()
+        # if penalty is positive, wait one round
+        if self.penalty > 0:
+            self.penalty -= 1
+        else:
+            # add penalty from direction or underground
+# TODO: think about adding 1 to each and then multiplicate them ;)
+            self.penalty += self.nextstep[4] + self.nextstep[2]
+            # are we luckily walking home?
+            if self.done == True:
+                # walk back home one step
+                self.position = [self.nextstep[0],self.nextstep[1]]
+                # mark current position as a good choice
+                self.paint(self.position, self.pathpaint)
+                if len(self.laststeps) > 1:
+                    # next step towards back home
+                    self.nextstep = self.laststeps.pop()
+                else:
+                    # retire after work
+                    self.snuffit()
+            else:
+                # make a step
+                self.position = self.nextstep
+                # remember it
+                self.laststeps.append(self.position)
+                # clear nextstep for next round
+                self.nextstep = [None,None,0,0,0,0]
+                # mark current position
+                self.paint(self.position, self.steppaint)
+
+def test():
+    """Test suite for Ant Class"""
+    import aco
+    print "creating a new world"
+    w = aco.ACO()
+    w.bounds = [5,0,5,0,6,6]
+    w.playground.setbounds(5,0,5,0,6,6)
+    print " limits set:",w.playground.getbounds()
+    w.playground.setnewlayer("cost", "raster", True)
+    w.costsurface = w.playground.getlayer("cost").raster
+    w.playground.setnewlayer("phero", "raster", True)
+    w.pherovapour = w.playground.getlayer("phero").raster
+    print " playground looks like (cost+phero)"
+    print " #c#",w.costsurface
+    print " #p#",w.pherovapour
+    w.holes = [[0,0,1]]
+    print ""
+    print "let's put some life in it.."
+    w.bear(Ant,5,[0,0])
+    a = w.agents[0]
+    print " agent seems fine (for now). time to live:",str(a.ttl),\
+        ". location:",a.position
+    a.paint([0,0],500)
+    a.paint([1,1],800)
+    a.paint([1,2],900)
+    print " playground(phero) after some painting:"
+    print " ", w.pherovapour
+    print "look around on positions.."
+    positions = w.getneighbourpositions(a.position)
+    print " tmp positions: ", positions
+    print "- any special cells in raster? ",\
+        a.searchspecials(positions)
+    positions[1][3] = -1
+    print "- any special cells in raster (marking one)? ",\
+        a.searchspecials(positions)
+    print "now die."
+    a.snuffit()
+    print ""
+    print "new ant.."
+    w.bear(Ant,5,[0,0])
+    a = w.agents[0]
+    print " agent seems fine (for now). time to live:",str(a.ttl),\
+        ". location:",a.position
+    print "let's do some positioning..."
+    positions = w.getneighbourpositions(a.position)
+    print "- now pickaposition:"
+    a.randomposition(positions)
+    print " a random choice: ", a.nextstep
+    a.smellposition(positions)
+    print " in smell-mode we would choose: ", a.nextstep
+    a.testposition(positions)
+    print " alternative test:", a.nextstep
+    print "- hasposition alternatives"
+    print " avoid walking in loops:"
+    ps = positions[:]
+    a.avoidloop(ps)
+    print " ",ps
+    ps = positions[:]
+    print " forget loops:"
+    a.forgetloop(ps)
+    print " ",ps
+    ps = positions[:]
+    print " avoid or forget loops:"
+    a.avoidorforgetloop(ps)
+    print " ",ps
+    print "- regularly choose a position now.. based on .. why not: smell."
+    print positions
+    a.choose()
+    print " ant: I'd go there,", a.position
+    print "- make a step forward then.."
+    a.walk()
+    print " ant: I am here now,", a.position
+    print "all done."
+

Added: grass-addons/grass7/raster/r.agent/libagent/error.py
===================================================================
--- grass-addons/grass7/raster/r.agent/libagent/error.py	                        (rev 0)
+++ grass-addons/grass7/raster/r.agent/libagent/error.py	2011-10-29 15:52:14 UTC (rev 48981)
@@ -0,0 +1,48 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+class Error(Exception):
+    """Base class for exceptions in this module."""
+    pass
+
+class DataError(Error):
+    """Exception raised for errors in the input.
+
+    Attributes:
+        expr -- Context expression in which the error occurred
+        msg  -- explanation of the error
+    """
+    def __init__(self, expr, msg):
+        self.expr = expr
+        self.msg = msg
+        print "DataError: " + expr + " " + msg
+
+class InputError(Error):
+    """Exception raised for errors in the input.
+
+    Attributes:
+        expr -- input expression in which the error occurred
+        msg  -- explanation of the error
+    """
+    def __init__(self, expr, msg):
+        self.expr = expr
+        self.msg = msg
+        print "InputError: " + expr + " " +msg
+
+def test():
+    """Test suite for Error Class"""
+    try:
+        raise InputError("Error Test Suite", "(no problem with this error)")
+    except InputError:
+        print "catched! all fine."
+

Added: grass-addons/grass7/raster/r.agent/libagent/layer.py
===================================================================
--- grass-addons/grass7/raster/r.agent/libagent/layer.py	                        (rev 0)
+++ grass-addons/grass7/raster/r.agent/libagent/layer.py	2011-10-29 15:52:14 UTC (rev 48981)
@@ -0,0 +1,140 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+import error
+
+class Layer():
+    """More like a meta/stub Class (or Interface).
+        To be inherited by children."""
+    def __init__(self):
+        self.infilename = None
+        self.outfilename = None
+        self.offset = [None,None]
+        self.limit = [None,None]
+        self.steps = []
+        self.resolution = [1,1]
+        self.fbuffer = None
+    def setinfilename(self, filename):
+        self.infilename = filename
+    def setoutfilename(self, filename):
+        self.outfilename = filename
+    def clearlayer(self):
+        self.offset = [None, None]
+        self.limit = [None, None]
+        if self.steps != []:
+            self.steps = [None, None]
+    def setbounds(self, north, south, east, west, rows=None, cols=None):
+        self.offset = [west,south]
+        self.limit = [east,north]
+        # here layer decides if steps shall be set (see Playground)
+        if self.steps != []:
+            self.steps = [cols,rows]
+            self.resolution[0] = (self.limit[0]-self.offset[0])/self.steps[0]
+            self.resolution[1] = (self.limit[1]-self.offset[1])/self.steps[1]
+    def getbounds(self):
+        if self.steps != []:
+            rows = self.steps[1]
+            cols = self.steps[0]
+        else:
+            rows = None
+            cols = None
+        return [self.limit[1], self.offset[1], self.limit[0],
+                 self.offset[0], rows, cols]
+    def shiftbound(self, direction, delta):
+        if delta < 0:
+            pass
+        elif delta > 0:
+            pass
+    def comparebounds(self, north, south, east, west, rows=None, cols=None):
+        if [west,south] == self.offset and [east,north] == self.limit:
+            if self.steps == []:
+                return True
+            elif [cols,rows] == self.steps:
+                return True
+        return False
+    def forcebounds(self, north, south, east, west, rows=None, cols=None):
+        if not self.comparebounds(north, south, east, west, rows, cols):
+            if self.resolution[0] and self.resolution[1]:
+                xres = self.resolution[0]
+                yres = self.resolution[1]
+            else:
+                xres = 1
+                yres = 1
+            self.shiftbound('north', (north-self.limit[1])/yres)
+            self.shiftbound('south', (south-self.offset[1])/yres)
+            self.shiftbound('east', (east-self.limit[0])/xres)
+            self.shiftbound('west', (west-self.offset[0])/xres)
+            self.setbounds(north, south, east, west, rows, cols)
+    def parsefile(self, fileh):
+        self.fbuffer = fileh.read()
+    def createfile(self, fileh):
+        if self.fbuffer:
+            fileh.write(self.fbuffer)
+    def importfile(self):
+        try:
+            with open(self.infilename, 'r') as fileh:
+                self.parsefile(fileh)
+        except IOError:
+            print "Error: Can not read " + self.infilename
+        except error.InputError:
+            print "Error: " + self.infilename + \
+                    " is not a valid ascii file"
+    def exportfile(self):
+        try:
+            with open(self.outfilename, "w") as fileh:
+                self.createfile(fileh)
+        except IOError:
+            print "Error: Can not write", self.infilename
+
+def test(infile, export=True, remove=True):
+    """Test suite for Layer Class"""
+    outfile = "out-" + infile
+    import os
+    if os.path.isfile(infile) and not os.path.isfile(outfile):
+        l = Layer()
+        print "setting files.."
+        l.setinfilename(infile)
+        l.setoutfilename(outfile)
+        print " import"
+        l.importfile()
+        if export == True:
+            print " export"
+            l.exportfile()
+            import filecmp
+            if filecmp.cmp(infile, outfile):
+                print "import/export seem ok"
+            else:
+                print "import/export failed"
+            if remove == True:
+                os.remove(outfile)
+        print "setting bounds"
+        l.setbounds(9,0,10,1)
+        print " bounds:", str(l.getbounds())
+        print " offset/limit:", str(l.offset), str(l.limit)
+        print "comparing bounds: "
+        print " True:",str(l.comparebounds(*l.getbounds()))
+        print " False:",str(l.comparebounds(l.offset[0]+1,l.offset[1],*l.limit))
+        print "clear all"
+        print "all again with steps:"
+        l.setbounds(9,0,10,1,1,1)
+        print " bounds:", str(l.getbounds())
+        print " offset/limit:", str(l.offset), str(l.limit)
+        print "comparing bounds: "
+        print " True:",str(l.comparebounds(*l.getbounds()))
+        print " False:",str(l.comparebounds(l.offset[0]+1,l.offset[1],*l.limit))
+        print "clear all"
+        l.clearlayer()
+        print " noting: "+str(l.offset)+str(l.limit)
+    else:
+        print "Error: no " + infile + " or " + outfile + " exists."
+

Added: grass-addons/grass7/raster/r.agent/libagent/overview.html
===================================================================
--- grass-addons/grass7/raster/r.agent/libagent/overview.html	                        (rev 0)
+++ grass-addons/grass7/raster/r.agent/libagent/overview.html	2011-10-29 15:52:14 UTC (rev 48981)
@@ -0,0 +1,85 @@
+<h2>general oversimplified abstract overview</h2>
+
+<ul><li>world
+<ul><li>e.g. an anthill, or a planet..
+</li><li>organizes how things work together
+</li><li>has:
+<ul><li>playground
+</li><li>list of agents
+<ul><li>killagent(agent)
+</li></ul></li><li>list of artefacts
+</li></ul></li></ul></li><li>aco - world
+<ul><li>is a:
+<ul><li>world
+</li></ul></li><li>for ants as agents with Ant Colony Optimization Algorithm as interaction rule
+</li><li>has:
+<ul><li>playground with
+<ul><li>penalty raster layer
+</li><li>pheromone raster layer
+</li><li>vector layer with holes/anthills
+</li></ul></li><li>list of ants
+</li><li>list of attractors..
+</li><li>list of holes/anthills..
+</li><li>several values that control the behaviour..
+</li></ul></li></ul></li><li>playground
+<ul><li>e.g. dirt, dead wood/leaves/needles, pheromone, etc.
+</li><li>manages layers =&gt; coordinates or graph(?)
+</li><li>has:
+<ul><li>layers
+<ul><li>knows its borders
+<ul><li>start/end coordinates
+</li><li>graph ...
+</li></ul></li><li>calcgraph(raster, degreeoffreedom, sizeofstep)
+</li><li>neighbours(node)-&gt;listofedges
+</li><li>neighbours(coordinates)-&gt;mapofcoordinate=&gt;value's
+</li></ul></li></ul></li></ul></li><li>layer (meta)
+<ul><li>one aspect from playground (one layer therefore..)
+</li></ul></li><li>rasterlayer - layer
+<ul><li>is a:
+<ul><li>layer
+</li></ul></li><li>e.g. pheromone "smell"
+</li><li>represents gis-rasterlayer
+</li><li>has:
+<ul><li>borders
+</li><li>matrix
+</li></ul></li></ul></li><li>vectorlayer - layer
+<ul><li>is a:
+<ul><li>layer
+</li></ul></li><li>e.g. holes in the ground
+</li><li>represents gis-vectorlayer
+</li><li>has:
+<ul><li>borders
+</li><li>list of vector objects/points/..
+</li></ul></li></ul></li><li>graph - layer (not yet available...)
+<ul><li>is a:
+<ul><li>layer
+</li></ul></li><li>made from raster-/vectorlayer
+</li><li>has:
+<ul><li>map of nodes
+<ul><li>node
+<ul><li>id
+</li><li>n:edges list
+</li></ul></li></ul></li><li>list of edges
+<ul><li>edge
+<ul><li>2:nodes
+</li><li>mapof'attribute=value's
+</li></ul></li></ul></li></ul></li></ul></li><li>agent
+<ul><li>e.g. a passenger or an ant
+</li><li>"lives" sort of in the world and on the playground
+</li><li>has:
+<ul><li>ttl
+</li><li>knowscompass
+</li><li>degreeoffreedom - (might be different from playground)
+</li><li>walk()
+</li></ul></li></ul></li><li>ant - agent
+<ul><li>is a:
+<ul><li>agent
+</li></ul></li><li>actor in an aco world
+</li><li>has:
+<ul><li>home position / position of origin / birthplace
+</li><li>list of its positions visited
+</li><li>pheromone intensity to use on certain circumstances
+</li><li>penalty value for its moving velocity
+</li><li>decisionbase for knowing how to find new positions
+</li><li>decisionbase for remembering visited positions
+</li></ul></li></ul></li></ul>

Added: grass-addons/grass7/raster/r.agent/libagent/playground.py
===================================================================
--- grass-addons/grass7/raster/r.agent/libagent/playground.py	                        (rev 0)
+++ grass-addons/grass7/raster/r.agent/libagent/playground.py	2011-10-29 15:52:14 UTC (rev 48981)
@@ -0,0 +1,120 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+import rasterlayer
+import vectorlayer
+
+class Playground(object):
+    """..."""
+    def __init__(self):
+        self.layers = dict()
+        self.offset = [None,None]
+        self.limit = [None,None]
+        self.steps = []
+    def setbounds(self, north=None, south=None, east=None, west=None,
+                     rows=None, cols=None):
+        self.offset = [west,south]
+        self.limit = [east,north]
+        # here always try to set steps (see Layer)
+        if rows:
+            self.steps = [cols,rows]
+    def setboundsfromlayer(self, layername):
+        self.setbounds(*self.layers[layername].getbounds())
+    def getbounds(self):
+        if self.steps:
+            rows = self.steps[1]
+            cols = self.steps[0]
+        else:
+            rows = None
+            cols = None
+        return [self.limit[1], self.offset[1], self.limit[0],
+                self.offset[0], rows, cols]
+    def getrelativebounds(self):
+        b = self.getbounds()
+        b = [b[4]-1,0,b[5]-1,0,b[4],b[5]]
+        return b
+    def setlayeralias(self, layername, layer):
+        self.layers[layername] = layer
+    def removelayer(self, layername):
+        del self.layers[layername]
+    def getlayer(self, layername):
+        return self.layers[layername]
+    def setlayer(self, layername, layer, force=False):
+        self.layers[layername] = layer
+        if force and self.offset[0] != None:
+            self.layers[layername].forcebounds(*self.getbounds())
+    def setnewlayer(self, layername, typename, force=False):
+        if typename == "raster":
+            layer = rasterlayer.RasterLayer()
+        elif typename == "vector":
+            layer = vectorlayer.VectorLayer()
+#        elif typename == "graph":
+#            self.layers[layername] = layer.Layer()
+        else:
+            print "layertype not supported (yet)."
+        self.setlayer(layername, layer, force)
+    def setlayerfromfile(self, layername, typename, filename):
+        self.setnewlayer(layername, typename)
+        self.layers[layername].setinfilename(filename)
+        self.layers[layername].importfile()
+        if self.offset[0] != None:
+            self.layers[layername].forcebounds(*self.getbounds())
+    def forcelayerbounds(self):
+        if self.offset[0] != None:
+            for layer in self.layers.itervalues():
+                layer.forcebounds(*self.getbounds())
+
+def test(layer0type=None, layer0=None, layer1type=None, layer1=None):
+    """Test suite for Playground Class"""
+    def testhelper(north=None, south=None, east=None, west=None,
+                     rows=None, cols=None):
+        print " It has this boundaries: "
+        print "  south: " + str(south)
+        print "  west: " + str(west)
+        print "  north: " + str(north)
+        print "  east: " + str(east)
+        print "  rows: " + str(rows)
+        print "  cols: " + str(cols)
+    print "creating new Playground.."
+    pg = Playground()
+    print "start filling it up.."
+    if layer0:
+        pg.setlayerfromfile("l0", layer0type, layer0)
+    else:
+        pg.setbounds(20, 0, 20, 0, 20, 20)
+        pg.setnewlayer("l0", "raster", True)
+        layer0type="raster"
+    print "Layer: "+"l0"+" ("+layer0type+")"
+    testhelper(*pg.layers["l0"].getbounds())
+    if layer1:
+        pg.setlayerfromfile("l1", layer1type, layer1)
+    else:
+        pg.setnewlayer("l1", "vector", True)
+        layer1type="vector"
+    print "Layer: "+"l1"+" ("+layer1type+")"
+    testhelper(*pg.layers["l1"].getbounds())
+    print "Setting global boundaries from layer l0"
+    pg.setboundsfromlayer("l0")
+    testhelper(*pg.getbounds())
+    print "adding new name/alias for l0"
+    pg.setlayeralias("newname", pg.getlayer("l0"))
+    print " " + str(pg.layers.keys())
+    testhelper(*pg.layers["newname"].getbounds())
+    print "remove new name"
+    pg.removelayer("newname")
+    print str(pg.layers.keys())
+    print "force global boundaries on layers"
+    pg.forcelayerbounds()
+    print " l1"
+    testhelper(*pg.layers["l1"].getbounds())
+

Added: grass-addons/grass7/raster/r.agent/libagent/rasterlayer.py
===================================================================
--- grass-addons/grass7/raster/r.agent/libagent/rasterlayer.py	                        (rev 0)
+++ grass-addons/grass7/raster/r.agent/libagent/rasterlayer.py	2011-10-29 15:52:14 UTC (rev 48981)
@@ -0,0 +1,254 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+import layer
+import error
+
+class RasterLayer(layer.Layer):
+    """..."""
+    def __init__(self):
+        layer.Layer.__init__(self)
+        self.bkeys = ["north", "south", "east", "west", "rows", "cols"]
+        self.steps = [None,None]
+        self.resolution = [None,None]
+        self.raster = []
+        self.gisempty = "*"
+        self.emptyvalue = -1
+    def clearlayer(self):
+        layer.Layer.clearlayer(self)
+        self.raster = []
+    def xyflipmatrix(self, matrix):
+        newmatrix = []
+        for i in range(len(matrix[0])):
+            newrow = []
+            for j in range(len(matrix)):
+                newrow.append(matrix[j][i])
+            newmatrix.append(newrow)
+        return newmatrix
+    def xflipmatrix(self, matrix):
+        raster = []
+        for i in range(len(matrix)-1, -1, -1):
+            raster.append(matrix[i])
+        return raster
+    def shiftbound(self, direction, delta):
+        if delta < 0:
+            if direction == "east":
+                for i in range(delta, 0):
+                    del self.raster[-1]
+            elif direction == "west":
+                for i in range(delta, 0):
+                    self.raster.insert(0,
+                        [0 for i in range(len(self.raster[0]))])
+            elif direction == "north":
+                for i in range(delta, 0):
+                    for j in range(len(self.raster)):
+                        del self.raster[j][-1]
+            elif direction == "south":
+                for i in range(delta, 0):
+                    for j in range(len(self.raster)):
+                        self.raster[j].insert(0, 0)
+        if delta > 0:
+            if direction == "east":
+                for i in range(delta):
+                    self.raster.append([0 for i in range(len(self.raster[0]))])
+            elif direction == "west":
+                for i in range(delta):
+                    del self.raster[0]
+            elif direction == "north":
+                for i in range(delta):
+                    for j in range(len(self.raster)):
+                        self.raster[j].append(0)
+            elif direction == "south":
+                for i in range(delta):
+                    for j in range(len(self.raster)):
+                        del self.raster[j][0]
+    def testresolution(self, north, south, east, west, rows, cols):
+        if rows > 0 < cols:
+            xres = ( east - west ) / cols
+            yres = ( north - south ) / rows
+            if self.resolution[0] == xres and self.resolution[1] == yres:
+                return True
+        return False
+    def forcebounds(self, north, south, east, west, rows, cols):
+        if self.steps[0] == None and self.raster == []:
+            self.setbounds(north, south, east, west, rows, cols)
+            for i in range(cols):
+                self.raster.append([0 for j in range(rows)])
+        elif not self.testresolution(north, south, east, west, rows, cols):
+            raise error.DataError("raster.forcebounds", "wrong resolution")
+        else:
+            layer.Layer.forcebounds(self, north, south, east, west, rows, cols)
+    def parsefile(self, fileh):
+        self.clearlayer()
+        bounds = []
+        for key in self.bkeys:
+            keylength = len(key)
+            line = fileh.readline()
+            if line[0:keylength] in key:
+                bounds.append(int(line[keylength+2:-1]))
+            else:
+                raise error.InputError(self.infilename, "no valid raster")
+        self.setbounds(*bounds)
+        raster = []
+        for line in fileh:
+            rasterline = []
+            for word in line.split(" "):
+                if word.find(".") > 0:
+                    rasterline.append(float(word))
+                elif word.isdigit():
+                    rasterline.append(int(word))
+                elif word in '\r' '\n' '\r\n':
+                    pass
+                else:
+                    rasterline.append(self.emptyvalue)
+            raster.append(rasterline[:])
+        if not (len(raster) == self.steps[1] and
+                        len(raster[0]) == self.steps[0]):
+            raise error.InputError(self.infilename, "wrong # rows/cols")
+        self.raster = self.xyflipmatrix(self.xflipmatrix(raster))
+    def createfile(self, fileh):
+        if self.limit[0]:
+            raster = self.xflipmatrix(self.xyflipmatrix(self.raster))
+            bounds = self.getbounds()
+            bounds.reverse()
+            for key in self.bkeys:
+                line = key + ": " + str(bounds.pop()) + "\n"
+                fileh.writelines(line)
+            for line in raster:
+                for word in line:
+                    if word == self.emptyvalue:
+                        fileh.write(self.gisempty + " ")
+                    else:
+                        fileh.write(str(word) + " ")
+                fileh.write("\n")
+
+def test(infile, export=True, remove=True):
+    """Test suite for RasterLayer Class"""
+    outfile = "out-" + infile
+    import os
+    if os.path.isfile(infile) and not os.path.isfile(outfile):
+        print "create raster layer"
+        r = RasterLayer()
+        r.setinfilename(infile)
+        r.setoutfilename(outfile)
+        print "importing file.."
+        r.importfile()
+        print "file says:"
+        print " r:", str(r.steps[0])+"; c:", str(r.steps[1])
+        print "matrix:"
+        print " x:", str(len(r.raster))+"; y:", str(len(r.raster[0]))
+        if export == True:
+            r.exportfile()
+            import filecmp
+            if filecmp.cmp(infile, outfile):
+                print "import/export seem ok"
+            else:
+                print "import/export failed"
+            if remove == True:
+                os.remove(outfile)
+        print "properties are still:"
+        print " r:", str(r.steps[0])+"; c:", str(r.steps[1])
+        print "flipping raster on x:"
+        b = r.xflipmatrix(r.raster)               
+        print " x:", str(len(b))+"; y:", str(len(b[0]))
+        print "flipping raster on x/y:"
+        b = r.xyflipmatrix(r.raster)
+        print " x:", str(len(b))+"; y:", str(len(b[0]))
+        print "a little resolution test first (to be True):", \
+                str(r.testresolution(*r.getbounds()))
+        print "now force bounds on raster: "
+        print " the same as now"
+        r.forcebounds(*r.getbounds())
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                    str(r.steps)
+        print "  at position [0,0] we have now:", str(r.raster[0][0])
+        print " setting new values now: 100,0,100,0,1,1"
+        r.clearlayer()
+        r.forcebounds(100,0,100,0,1,1)
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                    str(r.steps)
+        print "  testing wheter they are set now (True):", \
+                str(r.testresolution(100,0,100,0,1,1))
+        print "  at position [0,0] we have now: ", str(r.raster[0][0])
+        print " momentary raster:"
+        print str(r.raster)
+        print " now reforcing these (correct) values: 200,100,200,100,1,1"
+        r.forcebounds(200,100,200,100,1,1)
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                    str(r.steps)
+        print " momentary raster:"
+        print str(r.raster)
+        print " now some wrong values, should throw Error.."
+        try:
+            r.forcebounds(0,0,1,1,1,10000)
+        except error.DataError:
+            print "expected Error received.."
+        print " momentary raster:"
+        print str(r.raster)
+        print " changeing value r[0][0] to 1"
+        r.raster[0][0] = 1
+        print " momentary raster:"
+        print str(r.raster)
+        print "adding some space in the north"
+        print " setting new values now: 400,100,200,100,3,1"
+        r.forcebounds(400,100,200,100,3,1)
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                str(r.steps), "::", str(len(r.raster[0]))+":"+str(len(r.raster))
+        print " momentary raster:"
+        print str(r.raster)
+        print "removing some space in the north"
+        print " setting new values now: 300,100,200,100,2,1"
+        r.forcebounds(300,100,200,100,2,1)
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                str(r.steps), "::", str(len(r.raster[0]))+":"+str(len(r.raster))
+        print " momentary raster:"
+        print str(r.raster)
+        print "adding some space in the east"
+        r.forcebounds(300,100,400,100,2,3)
+        print " momentary raster:"
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                str(r.steps), "::", str(len(r.raster[0]))+":"+str(len(r.raster))
+        print str(r.raster)
+        print "removing some space in the east"
+        r.forcebounds(300,100,300,100,2,2)
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                str(r.steps), "::", str(len(r.raster[0]))+":"+str(len(r.raster))
+        print " momentary raster:"
+        print str(r.raster)
+        print "adding some space in the south"
+        r.forcebounds(300,0,300,100,3,2)
+        print " momentary raster:"
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                str(r.steps), "::", str(len(r.raster[0]))+":"+str(len(r.raster))
+        print str(r.raster)
+        print "removing some space in the south"
+        r.forcebounds(300,100,300,100,2,2)
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                str(r.steps), "::", str(len(r.raster[0]))+":"+str(len(r.raster))
+        print " momentary raster:"
+        print str(r.raster)
+        print "adding some space in the west"
+        r.forcebounds(300,100,300,0,2,3)
+        print " momentary raster:"
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                str(r.steps), "::", str(len(r.raster[0]))+":"+str(len(r.raster))
+        print str(r.raster)
+        print "removing some space in the west"
+        r.forcebounds(300,100,300,100,2,2)
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                str(r.steps), "::", str(len(r.raster[0]))+":"+str(len(r.raster))
+        print " momentary raster:"
+        print str(r.raster)
+    else:
+        print "Failed: no", infile, "or", outfile, "exists."
+

Added: grass-addons/grass7/raster/r.agent/libagent/vectorlayer.py
===================================================================
--- grass-addons/grass7/raster/r.agent/libagent/vectorlayer.py	                        (rev 0)
+++ grass-addons/grass7/raster/r.agent/libagent/vectorlayer.py	2011-10-29 15:52:14 UTC (rev 48981)
@@ -0,0 +1,161 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+import layer
+import error
+
+class VectorLayer(layer.Layer):
+    """..."""
+    def __init__(self):
+        layer.Layer.__init__(self)
+        self.objects = []
+        self.gissplit = "|"
+    def clearlayer(self):
+        layer.Layer.clearlayer(self)
+        self.objects = []
+    def shiftbound(self, direction, delta):
+# TODO off by one?
+        for obj in self.objects[:]:
+            if direction == "north":
+                if obj[1] > self.limit[1]+delta:
+                    self.objects.remove(obj)
+            elif direction == "east":
+                if obj[0] > self.limit[0]+delta:
+                    self.objects.remove(obj)
+            elif direction == "south":
+                if obj[1] < self.offset[1]+delta:
+                    self.objects.remove(obj)
+                else:
+                    obj[1] = obj[1]-delta
+            elif direction == "west":
+                if obj[0] < self.offset[0]+delta:
+                    self.objects.remove(obj)
+                else:
+                    obj[0] = obj[0]-delta
+    def reclassify(self, oldres, newres):
+# TODO if nothing changes..?
+# TODO goes to world??
+        dx = (newres[0] + 0.0) / oldres[0]
+        dy = (newres[1] + 0.0) / oldres[1]
+        for obj in self.objects:
+            obj[0] = int(round(obj[0] / dx))
+            obj[1] = int(round(obj[1] / dy))
+    def forcebounds(self, north, south, east, west, norows=None, nocols=None):
+        if self.offset[0] == None or self.offset[0] == self.limit[0]:
+            self.setbounds(north, south, east, west)
+        else:
+            layer.Layer.forcebounds(self, north, south, east, west)
+            if norows != None:
+                newres = [((east-west)/nocols),((north-south)/norows)]
+                self.reclassify(self.resolution, newres)
+                self.resolution = newres
+    def parsefile(self, fileh):
+        self.clearlayer()
+        vectorlist = []
+        self.offset = [0,0]
+        self.limit = [0,0]
+        for line in fileh:
+            if line[-1] in '\r' '\n' '\r\n':
+                line = line[:-1]
+            line = line.split(self.gissplit)
+            avector = []
+            for e in line:
+                avector.append(int(e))
+            vectorlist.append(avector)
+            if avector[0] > int(self.limit[0]):
+                self.limit[0] = avector[0]
+            if avector[1] > int(self.limit[1]):
+                self.limit[1] = avector[1]
+        self.objects = vectorlist
+    def createfile(self, fileh):
+        if self.limit[0] != None:
+            for obj in self.objects:
+                text = ""
+                for element in obj:
+                    if text:
+                        text = text + self.gissplit + str(element)
+                    else:
+                        text = str(element)
+                fileh.write(text + "\n")
+
+def test(infile, export=True, remove=True):
+    """Test suite for VectorLayer Class"""
+    outfile = "out-" + infile
+    import os
+    if os.path.isfile(infile) and not os.path.isfile(outfile):
+        print "create vector layer"
+        v = VectorLayer()
+        v.setinfilename(infile)
+        v.setoutfilename(outfile)
+        print "importing file"
+        v.importfile()
+        print "entries # " + str(len(v.objects))
+        for o in v.objects:
+            print " obj is: x=" + str(o[0]) + " y=" + str(o[1]) + \
+                " cat=" + str(o[2])
+        print "all between:"
+        print " south: " + str(v.offset[1])
+        print " west: " + str(v.offset[0])
+        print " north: " + str(v.limit[1])
+        print " east: " + str(v.limit[0])
+        if export == True:
+            v.exportfile()
+            import filecmp
+            if filecmp.cmp(infile, outfile):
+                print "import/export seem ok"
+            else:
+                print "import/export failed"
+            if remove == True:
+                os.remove(outfile)
+
+        print "creating new example:"
+        print " clear all"
+        v.clearlayer()
+        print " set new values"        
+        print "  setting new boundaries: n9, s0, e9, w0"
+        v.forcebounds( 9, 0, 9, 0 )
+        print "  setting new vectors: 0:5, 5:0, 9:5, 5:9, 5:5"
+        v.objects.append([0, 5, 0])
+        v.objects.append([5, 0, 1])
+        v.objects.append([9, 5, 2])
+        v.objects.append([5, 9, 3])
+        v.objects.append([5, 5, 4])
+        print " set:"
+        print "  south: " + str(v.offset[1])
+        print "  west: " + str(v.offset[0])
+        print "  north: " + str(v.limit[1])
+        print "  east: " + str(v.limit[0])
+        print " entries # " + str(len(v.objects))
+        for o in v.objects:
+            print "  obj is: x=" + str(o[0]) + " y=" + str(o[1]) + " cat=" + \
+                str(o[2])
+        print " set new values"
+        print "  setting new boundaries: n6, s4, e6, w4"
+        v.forcebounds( 6, 4, 6, 4 )
+        print " set:"
+        print "  south: " + str(v.offset[1])
+        print "  west: " + str(v.offset[0])
+        print "  north: " + str(v.limit[1])
+        print "  east: " + str(v.limit[0])
+        print " remaining entries # " + str(len(v.objects))
+        for o in v.objects:             
+            print "  obj is: x=" + str(o[0]) + " y=" + str(o[1]) + " cat=" + \
+                str(o[2])
+        print " again with the old boundaries: n9, s0, e9, w0"
+        v.forcebounds( 9, 0, 9, 0 )
+        for o in v.objects:
+            print "  obj is: x=" + str(o[0]) + " y=" + str(o[1]) + " cat=" + \
+                str(o[2])
+    else:
+        print "Error: no " + infile + " or " + outfile + " exists."
+

Added: grass-addons/grass7/raster/r.agent/libagent/world.py
===================================================================
--- grass-addons/grass7/raster/r.agent/libagent/world.py	                        (rev 0)
+++ grass-addons/grass7/raster/r.agent/libagent/world.py	2011-10-29 15:52:14 UTC (rev 48981)
@@ -0,0 +1,128 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+import error
+import agent
+import playground
+
+class World(object):
+    """meta class"""
+    def __init__(self, agenttype=None, pg=None):
+        if pg == None:
+            self.playground = playground.Playground()
+        else:
+            self.playground = pg
+        self.agentclass = agent.Agent
+        if agenttype == None:
+            self.agenttype = self.agentclass
+        else:
+            self.setagenttype(agenttype)
+        self.agents = []
+        self.artefacts = []
+    def importlayer(self, name, typename=None, filename=None):
+        if typename != None:
+            self.playground.setlayerfromfile(name, typename, filename)
+        elif filename != None:
+            self.playground.getlayer(name).setinfilename(filename)
+            self.playground.getlayer(name).importfile()
+        else:
+            self.playground.getlayer(name).importfile()
+        return self.playground.getlayer(name)
+    def createlayer(self, name, typename, infile=None, outfile=None):
+        self.playground.setnewlayer(name, typename, False)
+        if infile:
+            self.playground.getlayer(name).setinfilename(infile)
+        if outfile:
+            self.playground.getlayer(name).setoutfilename(outfile)
+        return self.playground.getlayer(name)
+    def exportlayer(self, name, typename=None, filename=None):
+        if filename == None:
+            self.playground.getlayer(name).exportfile()
+        elif typename == None:
+            self.playground.getlayer(name).setoutfilename(filename)
+        else:
+            if not self.playground.getlayer(name):
+                self.playground.setnewlayer(name, typename)
+            self.playground.getlayer(name).setoutfilename(filename)
+            self.playground.getlayer(name).exportfile()
+    def setagenttype(self, agenttype):
+        if issubclass(agenttype, self.agentclass):
+            self.agenttype = agenttype
+    def getagenttype(self):
+        return self.agenttype
+    def bear(self, agenttype=None, timetolife=0, position=[]):
+        if agenttype == None:
+            agenttype = self.agenttype
+        if issubclass(agenttype, self.agentclass):
+            self.agents.append(agenttype(timetolife, self, position))
+    def moveto(self, agent, position):
+        pass
+    def move(self, agent, nrofsteps, direction="random"):
+        pass
+#        print "moving " + self.agent + self.nrofsteps + \
+#            " steps towards " + self.direction
+#    def letwalk(self, agent, nrofsteps=1, direction="random"):
+#        position = agent.getposition()
+#        npositions = self.playground.getneighbourpositions("costs", position)
+        #agent.move()
+    def kill(self, agent):
+        self.agents.remove(agent)
+#    def build(self, artefact):
+#        self.artefacts.add(artefact)
+#    def place(self, artefact, position):
+#        pass
+#    def destroy(self, artefact):
+#        self.artefacts.remove(artefact)
+
+def test(inraster=None, outraster=None, invector=None):
+    """Test suite for World Class"""
+    print "creating world"
+    w = World()
+    print "playing with agents"
+    print " nothing changed.."
+    print "  Agenttype is:", w.getagenttype()
+    print " illegaly overwriting agent.."
+    w.agenttype = ""
+    print "  Agenttype is:", w.getagenttype()
+    print " set new agenttype.."
+    w.setagenttype(agent.Agent)
+    print "  Agenttype is:", w.getagenttype()
+    print "giving birth to some agents"
+    w.bear()
+    w.bear(agent.Agent)
+    print " Agentlist:", w.agents
+    print "killing an agent"
+    w.kill(w.agents[0])
+    print " Agentlist:", w.agents
+#??    w.build()..
+#??    w.moveto()..
+#??    w.move()..
+#??    w.place()..
+#??    w.letwalk()..
+#??    w.destroy()..
+    print "adding layers?"
+    if inraster:
+        print "  adding raster"
+        w.importlayer("raster", "raster", inraster)
+        print "  re-adding again in diffrent way"
+        w.createlayer("raster", "raster", inraster, inraster)
+        w.importlayer("raster")
+        print "  is set."
+        if outraster:
+            w.exportlayer("raster", "raster", outraster)
+            print "  exported to:", str(outraster), "- check and remove.."
+        if invector:
+            print "  adding vectors"
+            w.importlayer("vector", "vector", invector)
+            print "  is set."
+

Added: grass-addons/grass7/raster/r.agent/r.agent.aco
===================================================================
--- grass-addons/grass7/raster/r.agent/r.agent.aco	                        (rev 0)
+++ grass-addons/grass7/raster/r.agent/r.agent.aco	2011-10-29 15:52:14 UTC (rev 48981)
@@ -0,0 +1,104 @@
+#!/usr/bin/env python
+############################################################################
+#
+# MODULE:       r.agent.aco
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      r.agent.aco is used to organize ant-like agents in a raster
+#               based playground. As decribed by the Ant Colony Optimization
+#               algorithm, the ants wander around looking for attractors,
+#               marking their paths if they find any.
+# COPYRIGHT:    (C) 2011 by the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+import sys
+
+from libagent import error, aco
+
+world = aco.ACO()
+
+for arg in sys.argv[1:]:
+    arglist = arg.split("=")
+    if arglist[0] == "output":
+        if world.pherovapour == None:
+            layer = world.createlayer("phero", "raster", None, str(arglist[1]))
+            world.pherovapour = layer.raster
+        else:
+            world.exportlayer("phero", None, str(arglist[1]))
+    elif arglist[0] == "costoutput":
+        if world.costsurface == None:
+            layer = world.createlayer("costs", "raster", None, str(arglist[1]))
+            world.costsurface = layer.raster
+        else:
+            world.exportlayer("phero", None, str(arglist[1]))
+    elif arglist[0] == "costraster":
+        if world.costsurface == None:
+            layer = world.importlayer("costs", "raster", str(arglist[1]))
+            world.costsurface = layer.raster
+        else:
+            world.importlayer("costs", None, str(arglist[1]))
+        world.playground.setboundsfromlayer("costs")
+    elif arglist[0] == "sloperaster":
+        layer = world.importlayer("slope", "raster", str(arglist[1]))
+        world.surfaceslope = layer.raster
+        world.playground.setboundsfromlayer("slope")
+        if world.costsurface == None:
+            layer = world.createlayer("costs", "raster", None, None)
+            world.costsurface = layer.raster
+    elif arglist[0] == "vectorholes":
+        layer = world.importlayer("holes", "vector", str(arglist[1]))
+        world.holes = layer.objects
+    elif arglist[0] == "pheroraster":
+        if world.pherovapour == None:
+            layer = world.importlayer("phero", "raster", str(arglist[1]))
+            world.pherovapour = layer.raster
+        else:
+            world.importlayer("phero", None, str(arglist[1]))
+    elif arglist[0] == "rounds":
+        world.rounds = int(arglist[1])
+    elif arglist[0] == "outrounds" or arglist[0] == "outputrounds":
+        world.outrounds = int(arglist[1])
+    elif arglist[0] == "maxpheromone":
+        world.maxpheromone = int(arglist[1])
+    elif arglist[0] == "minpheromone":
+        world.minpheromone = int(arglist[1])
+    elif arglist[0] == "volatilizationtime":
+        world.volatilizationtime = int(arglist[1])
+    elif arglist[0] == "stepintensity":
+        world.stepintensity = int(arglist[1])
+    elif arglist[0] == "pathintensity":
+        world.pathintensity = int(arglist[1])
+    elif arglist[0] == "maxants":
+        world.maxants = int(arglist[1])
+    elif arglist[0] == "antslife":
+        world.antslife = int(arglist[1])
+    elif arglist[0] == "decisionalgorithm":
+        world.decisionbase = str(arglist[1])
+    elif arglist[0] == "neighbourposition":
+        world.validposition = str(arglist[1])
+    elif arglist[0] == "agentfreedom":
+        world.globalfreedom = int(arglist[1])
+    elif arglist[0] == "pheromoneweight":
+        world.pheroweight = int(arglist[1])
+    elif arglist[0] == "randomnessweight":
+        world.randomweight = int(arglist[1])
+    elif arglist[0] == "costweight":
+        world.costweight = int(arglist[1])
+    elif arglist[0] == "stability":
+        #TODO ask silvia..
+        pass
+    else:
+        print "parameter", arglist[0], "not supported.."
+
+try:
+    world.checkvalues()
+    world.letantsdance()
+    print "FINISH"
+except error.DataError:
+    print "Failed to parse args.."
+    sys.exit(1)
+


Property changes on: grass-addons/grass7/raster/r.agent/r.agent.aco
___________________________________________________________________
Added: svn:executable
   + *

Added: grass-addons/grass7/raster/r.agent/r.agent.html
===================================================================
--- grass-addons/grass7/raster/r.agent/r.agent.html	                        (rev 0)
+++ grass-addons/grass7/raster/r.agent/r.agent.html	2011-10-29 15:52:14 UTC (rev 48981)
@@ -0,0 +1,93 @@
+<h2>DESCRIPTION</h2>
+
+<em>r.agent</em> shall provide an inital base for organizing worlds
+with raster playgrounds and agents in.
+<p>
+As this is only a first implementation the encapsulation that grants
+a modular usage is still suffering..
+<p>
+<em>r.agent</em> is written in python for more transparency and
+better extendability.
+<p>
+As a first world example there is an ACO-based
+environement
+(see <a href="http://en.wikipedia.org/wiki/Ant_colony_optimization_algorithms">Ant Colony Optimization</a>)
+available.
+<p>
+The basic concept of such an ACO world, is to take some cost surface
+and transform it to a penalty layer - where for human ants for example
+this penalty layer may be expressed by the walking velocity, e.g. calculated
+with the algorithm proposed by
+<a href="http://www.geodyssey.com/papers/tobler93.html">Tobler1993</a>.
+The actors on the playground will wander around on the playground
+using the time for their paths that correspond with the values in the penalty
+grid.
+If they find some attractor, they walk home to the position they
+originated, marking their way with pheromones. While this
+pheromone vanishes over time, the following agents are more likely
+to choose their next steps to a position that smells most.
+
+<p>
+This toolset was partly developed at the
+<a href="http://www.topoi.org/">Topoi / FU Berlin</a> with
+inspirations from previous work conducted at the
+<a href="http://www.unibe.ch//">Uni Bern</a>.
+
+
+<h2>NOTES</h2>
+
+The state of this software is: "first do it".
+This is work in progress and its structure will probably change quite a lot
+in the future due to a better integration in GRASS and other refactoring.
+<p>
+Unfortunately this script colletion is not very well included in GRASS yet.
+At the moment <em>r.agent</em> only handles ASCII grid and vector in- and
+output data. With a better GRASS integration not only will the code
+get lighter but also this drawbacks shall vanish.
+<p>
+ACO works best on dynamic maps -- it constantly tries to improve paths...
+
+
+<h2>EXAMPLE</h2>
+
+A fictive usecase could look something like this:
+<p>
+# ./r.agent.aco output=out.map costraster=penalty.grid vectorholes=sites.vect rounds=10 outputrounds=10 volatilizationtime=5000 antslife=2000 maxants=400 pathintensity=1000000
+<p>
+For running the total test suite on the libraries,
+i.e. to run all the tests that are at the end
+of each python file, use this test collection
+(for certain tests, the following files must exist though:
+ "elev.grid", and "arch.vect"):
+<p>
+# cd library
+<p>
+# ./alltests.py
+
+
+<h2>TODO</h2>
+
+Add GRASS headers (?).
+<p>
+Cleanup.
+<p>
+Integrate it directly within grass.
+<p>
+Improve encapsulation of classes.
+<p>
+Find good parameters, or parameter finding strategies for the ACO part.
+Try to avoid high penalty fields.
+Think about heuristics too.
+<p>
+Implement other ABM scenarios.
+
+
+<h2>SEE ALSO</h2>
+
+<h2>AUTHORS</h2>
+
+Michael Lustenberger inofix.ch
+
+<p><i>Last changed: $Date$</i>
+
+



More information about the grass-commit mailing list