Artificial
A basic API for artificial intelligent agents described in the book "Artificial Intelligence: A Modern Approach", by Russell and Norvig.
Introduction
We want to solve problems, but to do so, we must first represent them in a
reasonable fashion. In artificial
, there are three basic classes used to
describe a problem (and its solution):
- World Encapsulates out-of-computer problem domains and translate them to a digital representation.
- State A model that holds data for both world and agents. It can be used to represent a state of the World or to predict states by agents.
- Agent Abstraction that presents an intelligent behavior.
Installing
artificial
is written on Python, and requires numpy
and scipy
.
You can install everything with:
git clone https://github.com/lucasdavid/artificial
cd artificial
python setup.py install --user
To run the examples, matplotlib and scikit-learn are required:
pip install -r docs/requirements-examples.txt --upgrade --user
cd examples
python dirt_cleaner.py
To run tests, additional packages are required:
pip install -r docs/requirements-dev.txt --upgrade --user
# Run tests!
nosetests
The coverage info will be placed inside coverage
folder.
Examples
Genetic Algorithm: Speller Agent
Let's say we want to create an agent that generate strings randomly until it
finds the word "hello world". We start by writing a GeneticState
and
Environment
that define our problem.
class WordIndividual(base.GeneticState):
def cross(self, other):
"""Simple crossover between two individuals"""
cross_point = random.randint(0, 11)
return WordIndividual(self.data[:cross_point] + other.data[cross_point:])
def mutate(self, factor, probability):
"""Mutation of an individual's genes"""
m = np.random.rand(len(self.data)) < factor * probability # Defines which genes will mutate.
if np.any(m):
data = np.array(list(self.data))
data[m] = [random.choice(string.ascii_lowercase + ' ') for mutated in m if mutated] # Mutate!
self.data = ''.join(data)
return self
@property
def is_goal(self):
return self.data == 'hello world'
@classmethod
def random(cls):
return cls(''.join(random.choice(string.ascii_lowercase + ' ') for _ in range(11))
class World(base.Environment):
state_class_ = WordIndividual
def update(self):
# My world consists on printing agents' solutions. Exciting.
for agent in self.agents:
print('Solution found: %s' % agent.act())
Now we define an UtilityBasedAgent
that considers samples similar to the
sentence "hello world"
as "good":
class Speller(agents.UtilityBasedAgent):
def utility(self, state):
"""Measures how "good" is a word (sum of the matching letters)"""
expected = 'hello world'
return sum(self.data[i] == expected[i] and 1 or 0 for i in range(11)))
def act(self):
# We aren't really interest in acting over the world, but more in
# finding solutions. Hence simply returns the solution candidate,
# which is the fittest individual for the `GeneticAlgorithm` case.
return self.search().solution_candidate_
The only thing left is to connect the dots! :-)
world = World(initial_state=WordCandidate.random())
env.agents += [
Speller(environment=world, search=GeneticAlgorithm,
search_params=dict(mutation_factor=.25, mutation_probability=1))]
print('Initial: {%s}' % str(env.current_state))
world.update()
Note: take a look at the examples folder to see more concrete usages of searches, optimizations, evolutions and other intelligent stuff.