[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 => 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)->listofedges
+</li><li>neighbours(coordinates)->mapofcoordinate=>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