bdi4jade

Utility-based Agent

9/22/2013 8:30:08 PM

Changes

Details

diff --git a/bdi-jade/src/br/ufrgs/inf/bdi4jade/core/BDIAgent.java b/bdi-jade/src/br/ufrgs/inf/bdi4jade/core/BDIAgent.java
index fe58077..e367a4a 100644
--- a/bdi-jade/src/br/ufrgs/inf/bdi4jade/core/BDIAgent.java
+++ b/bdi-jade/src/br/ufrgs/inf/bdi4jade/core/BDIAgent.java
@@ -115,6 +115,7 @@ public class BDIAgent extends Agent {
 			synchronized (intentions) {
 				Map<Goal, GoalStatus> goalStatus = new HashMap<Goal, GoalStatus>();
 				Iterator<Intention> it = intentions.iterator();
+				List<Intention> doneIntentions = new LinkedList<>();
 				while (it.hasNext()) {
 					Intention intention = it.next();
 					GoalStatus status = intention.getStatus();
@@ -122,7 +123,7 @@ public class BDIAgent extends Agent {
 					case ACHIEVED:
 					case NO_LONGER_DESIRED:
 					case UNACHIEVABLE:
-						intention.fireGoalFinishedEvent();
+						doneIntentions.add(intention);
 						it.remove();
 						break;
 					default:
@@ -130,6 +131,9 @@ public class BDIAgent extends Agent {
 						break;
 					}
 				}
+				for (Intention intention : doneIntentions) {
+					intention.fireGoalFinishedEvent();
+				}
 
 				Set<Goal> generatedGoals = optionGenerationFunction
 						.generateGoals(goalStatus);
diff --git a/bdi-jade/src/br/ufrgs/inf/bdi4jade/softgoal/NamedSoftgoal.java b/bdi-jade/src/br/ufrgs/inf/bdi4jade/softgoal/NamedSoftgoal.java
new file mode 100644
index 0000000..40bd762
--- /dev/null
+++ b/bdi-jade/src/br/ufrgs/inf/bdi4jade/softgoal/NamedSoftgoal.java
@@ -0,0 +1,72 @@
+/**
+ * 
+ */
+package br.ufrgs.inf.bdi4jade.softgoal;
+
+/**
+ * @author ingrid
+ * 
+ */
+public class NamedSoftgoal implements Softgoal {
+
+	private static final long serialVersionUID = 3958189054716876043L;
+
+	private final String name;
+
+	public NamedSoftgoal(String name) {
+		this.name = name;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		NamedSoftgoal other = (NamedSoftgoal) obj;
+		if (name == null) {
+			if (other.name != null)
+				return false;
+		} else if (!name.equals(other.name))
+			return false;
+		return true;
+	}
+
+	/**
+	 * @return the name
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#hashCode()
+	 */
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((name == null) ? 0 : name.hashCode());
+		return result;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString() {
+		return name;
+	}
+
+}
diff --git a/bdi-jade/src/br/ufrgs/inf/bdi4jade/util/reasoning/UtilityBasedPlanSelectionStrategy.java b/bdi-jade/src/br/ufrgs/inf/bdi4jade/util/reasoning/UtilityBasedPlanSelectionStrategy.java
index c7fe22a..53db146 100644
--- a/bdi-jade/src/br/ufrgs/inf/bdi4jade/util/reasoning/UtilityBasedPlanSelectionStrategy.java
+++ b/bdi-jade/src/br/ufrgs/inf/bdi4jade/util/reasoning/UtilityBasedPlanSelectionStrategy.java
@@ -23,8 +23,12 @@
 package br.ufrgs.inf.bdi4jade.util.reasoning;
 
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
 import br.ufrgs.inf.bdi4jade.core.BDIAgent;
 import br.ufrgs.inf.bdi4jade.goal.Goal;
 import br.ufrgs.inf.bdi4jade.plan.Plan;
@@ -42,16 +46,18 @@ import br.ufrgs.inf.bdi4jade.softgoal.Softgoal;
  */
 public class UtilityBasedPlanSelectionStrategy implements PlanSelectionStrategy {
 
+	private final Log log;
 	private final BDIAgent myAgent;
 
 	public UtilityBasedPlanSelectionStrategy(BDIAgent myAgent) {
+		this.log = LogFactory.getLog(getClass());
 		this.myAgent = myAgent;
 	}
 
 	@SuppressWarnings("unchecked")
 	private double calculateExpectedUtility(Plan plan, Softgoal softgoal) {
-		List<PlanContribution> contributions = (List<PlanContribution>) plan
-				.getMetadata(Plan.DefaultMetadata.CONTRIBUTIONS);
+		List<PlanContribution> contributions = ((Map<Softgoal, List<PlanContribution>>) plan
+				.getMetadata(Plan.DefaultMetadata.CONTRIBUTIONS)).get(softgoal);
 
 		double expectedUtility = 0;
 		if (contributions != null) {
@@ -90,13 +96,14 @@ public class UtilityBasedPlanSelectionStrategy implements PlanSelectionStrategy 
 				Double preference = preferences
 						.getPreferenceForSoftgoal(softgoal);
 				if (preference != null) {
-
 					double expectedUtility = calculateExpectedUtility(plan,
 							softgoal);
 					utility += preference * expectedUtility;
-
 				}
 			}
+
+			log.debug("EU[" + plan.getId() + "] = " + utility);
+
 			if (selectedPlan == null || maxUtility < utility) {
 				selectedPlan = plan;
 				maxUtility = utility;
diff --git a/bdi-jade/src/log4j.properties b/bdi-jade/src/log4j.properties
index 1a4ee8a..d5b9fde 100644
--- a/bdi-jade/src/log4j.properties
+++ b/bdi-jade/src/log4j.properties
@@ -29,6 +29,5 @@ log4j.logger.org.apache.struts2=FATAL
 # Spring Stuff
 log4j.logger.org.springframework=FATAL
 
-log4j.logger.br.ufrgs.inf.bdi4jade=INFO
-log4j.logger.br.ufrgs.inf.bdi4jade.examples=DEBUG
+log4j.logger.br.ufrgs.inf.bdi4jade=DEBUG
 
diff --git a/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/AgentStarter.java b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/AgentStarter.java
index 51e54c6..a29db1c 100644
--- a/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/AgentStarter.java
+++ b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/AgentStarter.java
@@ -36,6 +36,7 @@ import java.util.Map;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.log4j.PropertyConfigurator;
 
 import br.ufrgs.inf.bdi4jade.examples.helloworld.HelloWorldAgent;
 
@@ -55,6 +56,8 @@ public class AgentStarter {
 	};
 
 	public static void main(String[] args) {
+		PropertyConfigurator.configure(AgentStarter.class
+				.getResource("log4j.properties"));
 		new AgentStarter();
 	}
 
diff --git a/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/helloworld/HelloWorldPlan.java b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/helloworld/HelloWorldPlan.java
index 1ce0f81..3cee61f 100644
--- a/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/helloworld/HelloWorldPlan.java
+++ b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/helloworld/HelloWorldPlan.java
@@ -17,13 +17,15 @@ public class HelloWorldPlan extends OneShotBehaviour implements PlanBody {
 	private static final long serialVersionUID = -9039447524062487795L;
 
 	private String name;
+	private EndState endState;
 
 	public void action() {
 		System.out.println("Hello, " + name + "!");
+		this.endState = EndState.SUCCESSFUL;
 	}
 
 	public EndState getEndState() {
-		return EndState.SUCCESSFUL;
+		return endState;
 	}
 
 	public void init(PlanInstance planInstance) {
diff --git a/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/log4j.properties b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/log4j.properties
new file mode 100644
index 0000000..1a4ee8a
--- /dev/null
+++ b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/log4j.properties
@@ -0,0 +1,34 @@
+#
+# Log4J Settings for log4j 1.2.x (via jakarta-commons-logging)
+#
+# The five logging levels used by Log are (in order):
+#
+#   1. DEBUG (the least serious)
+#   2. INFO
+#   3. WARN
+#   4. ERROR
+#   5. FATAL (the most serious)
+
+
+# Set root logger level to WARN and append to stdout
+log4j.rootLogger=WARN, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+
+# Pattern to output the caller's file name and line number.
+log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss,SSS} %5p (%c{1}:%L) - %m%n
+
+# Print only messages of level ERROR or above in the package noModule.
+log4j.logger.noModule=FATAL
+
+# OpenSymphony Stuff
+log4j.logger.com.opensymphony=FATAL
+log4j.logger.org.apache.struts2=FATAL
+
+# Spring Stuff
+log4j.logger.org.springframework=FATAL
+
+log4j.logger.br.ufrgs.inf.bdi4jade=INFO
+log4j.logger.br.ufrgs.inf.bdi4jade.examples=DEBUG
+
diff --git a/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/ping/PongPlan.java b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/ping/PongPlan.java
index 420e234..8463982 100644
--- a/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/ping/PongPlan.java
+++ b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/ping/PongPlan.java
@@ -43,6 +43,7 @@ public class PongPlan extends OneShotBehaviour implements PlanBody {
 
 	private Log log;
 	private ACLMessage pingMsg;
+	private EndState endState;
 
 	@Override
 	public void action() {
@@ -52,11 +53,12 @@ public class PongPlan extends OneShotBehaviour implements PlanBody {
 		reply.setContent(PingPongCapability.PONG);
 		this.myAgent.send(reply);
 		log.info("Pong sent to agent" + pingMsg.getSender().getName() + "!");
+		this.endState = EndState.SUCCESSFUL;
 	}
 
 	@Override
 	public EndState getEndState() {
-		return EndState.SUCCESSFUL;
+		return endState;
 	}
 
 	@Override
diff --git a/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/ExperimentRunner.java b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/ExperimentRunner.java
new file mode 100644
index 0000000..dc64c3b
--- /dev/null
+++ b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/ExperimentRunner.java
@@ -0,0 +1,96 @@
+/**
+ * 
+ */
+package br.ufrgs.inf.bdi4jade.examples.planselection;
+
+import jade.BootProfileImpl;
+import jade.core.ProfileImpl;
+import jade.wrapper.AgentContainer;
+import jade.wrapper.AgentController;
+import jade.wrapper.PlatformController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.log4j.PropertyConfigurator;
+
+import br.ufrgs.inf.bdi4jade.event.GoalEvent;
+import br.ufrgs.inf.bdi4jade.event.GoalFinishedEvent;
+import br.ufrgs.inf.bdi4jade.event.GoalListener;
+import br.ufrgs.inf.bdi4jade.examples.AgentStarter;
+
+/**
+ * @author ingrid
+ * 
+ */
+public class ExperimentRunner implements GoalListener {
+
+	public static final int ITERATIONS = 5;
+
+	public static void main(String[] args) {
+		ExperimentRunner runner = new ExperimentRunner();
+		runner.run();
+	}
+
+	private ProfileImpl bootProfile;
+	private int iteration;
+	private final Log log;
+	private jade.core.Runtime runtime;
+
+	private final TransportationAgent transportationAgent;
+
+	public ExperimentRunner() {
+		PropertyConfigurator.configure(AgentStarter.class
+				.getResource("log4j.properties"));
+		this.log = LogFactory.getLog(this.getClass());
+
+		List<String> params = new ArrayList<String>();
+		params.add("-gui");
+		params.add("-detect-main:false");
+
+		log.info("Plataform parameters: " + params);
+
+		this.bootProfile = new BootProfileImpl(params.toArray(new String[0]));
+
+		this.runtime = jade.core.Runtime.instance();
+		PlatformController controller = runtime
+				.createMainContainer(bootProfile);
+
+		this.transportationAgent = new TransportationAgent();
+		try {
+			AgentController ac = ((AgentContainer) controller).acceptNewAgent(
+					transportationAgent.getClass().getSimpleName(),
+					transportationAgent);
+			ac.start();
+		} catch (Exception e) {
+			log.error(e);
+		}
+
+		this.iteration = 0;
+	}
+
+	@Override
+	public void goalPerformed(GoalEvent event) {
+		if (event instanceof GoalFinishedEvent
+				&& event.getGoal() instanceof TransportationGoal) {
+			if (iteration < ITERATIONS) {
+				run();
+			} else {
+				log.info("Iterations finished!!");
+				log.info(((GenericValueFunction<?>) transportationAgent
+						.getRootCapability().getBeliefBase()
+						.getBelief(TransportationAgent.SATISFACTION).getValue())
+						.stats());
+			}
+		}
+	}
+
+	public void run() {
+		transportationAgent.updatedPreferences();
+		transportationAgent.addGoal(new TransportationGoal(), this);
+		iteration++;
+	}
+
+}
diff --git a/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/GenericValueFunction.java b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/GenericValueFunction.java
new file mode 100644
index 0000000..344237c
--- /dev/null
+++ b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/GenericValueFunction.java
@@ -0,0 +1,153 @@
+/*
+ * Created on 30 Jul 2011 20:14:49 
+ */
+package br.ufrgs.inf.bdi4jade.examples.planselection;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author ingrid
+ * 
+ */
+public class GenericValueFunction<T> {
+
+	private Double average;
+	private Pair<Double> minMax;
+	private Double standardDeviation;
+	private Double total;
+	private Map<T, Double> values;
+
+	public GenericValueFunction() {
+		this.values = new HashMap<T, Double>();
+		this.minMax = null;
+		this.total = null;
+		this.average = null;
+		this.standardDeviation = null;
+	}
+
+	public synchronized void addValue(T key, Double value) {
+		this.values.put(key, value);
+		if (minMax == null) {
+			this.minMax = new Pair<Double>(value, value);
+		} else {
+			if (minMax.getValue1() > value)
+				minMax.setValue1(value);
+			if (minMax.getValue2() < value)
+				minMax.setValue2(value);
+		}
+
+		total = null;
+		average = null;
+		standardDeviation = null;
+	}
+
+	private synchronized void calculateAverage() {
+		average = (values.size() == 0) ? null : getTotal() / values.size();
+	}
+
+	private synchronized void calculateStandardDeviation() {
+		Double variance = getVariance();
+		standardDeviation = (variance == null) ? null : Math.pow(variance, 0.5);
+	}
+
+	/**
+	 * @return the average
+	 */
+	public synchronized Double getAverage() {
+		if (average == null)
+			calculateAverage();
+		return average;
+	}
+
+	public int getCount() {
+		return values.size();
+	}
+
+	public Double getMax() {
+		return minMax == null ? null : minMax.getValue2();
+	}
+
+	public Double getMin() {
+		return minMax == null ? null : minMax.getValue1();
+	}
+
+	/**
+	 * @return the standardDeviation
+	 */
+	public synchronized Double getStandardDeviation() {
+		if (standardDeviation == null)
+			calculateStandardDeviation();
+		return standardDeviation;
+	}
+
+	/**
+	 * @return the total
+	 */
+	public synchronized Double getTotal() {
+		if (total == null) {
+			this.total = 0.0;
+			for (Double value : values.values()) {
+				total += value;
+			}
+		}
+		return total;
+	}
+
+	public Double getValue(T key) {
+		return values.get(key);
+	}
+
+	public synchronized Double getVariance() {
+		long n = 0;
+		double mean = 0;
+		double s = 0.0;
+
+		for (Double x : values.values()) {
+			n++;
+			double delta = x - mean;
+			mean += delta / n;
+			s += delta * (x - mean);
+		}
+		// if you want to calculate std deviation
+		// of a sample change this to (s/(n-1))
+		return n == 0 ? null : (s / n);
+	}
+
+	public Set<T> keySet() {
+		return values.keySet();
+	}
+
+	public String stats() {
+		StringBuffer sb = new StringBuffer();
+		sb.append("Total = ").append(getTotal()).append("\n");
+		sb.append("Count = ").append(getCount()).append("\n");
+		sb.append("Min = ").append(getMin()).append("\n");
+		sb.append("Max = ").append(getMax()).append("\n");
+		sb.append("Average = ").append(getAverage()).append("\n");
+		sb.append("Standard Deviation = ").append(getStandardDeviation());
+		return sb.toString();
+	}
+
+	public String toString() {
+		StringBuffer sb = new StringBuffer();
+		for (T key : values.keySet()) {
+			sb.append("R(").append(key).append(") = ").append(values.get(key))
+					.append("\n");
+		}
+		sb.append(stats());
+		return sb.toString();
+	}
+
+	public String toStringTab() {
+		StringBuffer sb = new StringBuffer();
+		sb.append("Key\tValue\n");
+		for (T key : values.keySet()) {
+			sb.append(key).append("\t").append(values.get(key)).append("\n");
+		}
+		sb.append(stats());
+		return sb.toString();
+	}
+
+}
diff --git a/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/Pair.java b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/Pair.java
new file mode 100644
index 0000000..352e79a
--- /dev/null
+++ b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/Pair.java
@@ -0,0 +1,20 @@
+/*
+ * Created on 22 Jul 2011 11:35:52 
+ */
+package br.ufrgs.inf.bdi4jade.examples.planselection;
+
+/**
+ * @author ingridn
+ * 
+ */
+public class Pair<T> extends PairT<T, T> {
+
+	public Pair() {
+		super();
+	}
+
+	public Pair(T value1, T value2) {
+		super(value1, value2);
+	}
+
+}
\ No newline at end of file
diff --git a/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/PairT.java b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/PairT.java
new file mode 100644
index 0000000..d430660
--- /dev/null
+++ b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/PairT.java
@@ -0,0 +1,87 @@
+/*
+ * Created on 30 Jul 2011 10:29:17 
+ */
+package br.ufrgs.inf.bdi4jade.examples.planselection;
+
+/**
+ * @author ingrid
+ * 
+ */
+public class PairT<T1, T2> {
+
+	protected T1 value1;
+	protected T2 value2;
+
+	public PairT() {
+		this.value1 = null;
+		this.value2 = null;
+	}
+
+	public PairT(T1 value1, T2 value2) {
+		this.value1 = value1;
+		this.value2 = value2;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		PairT other = (PairT) obj;
+		if (value1 == null) {
+			if (other.value1 != null)
+				return false;
+		} else if (!value1.equals(other.value1))
+			return false;
+		if (value2 == null) {
+			if (other.value2 != null)
+				return false;
+		} else if (!value2.equals(other.value2))
+			return false;
+		return true;
+	}
+
+	public T1 getValue1() {
+		return value1;
+	}
+
+	public T2 getValue2() {
+		return value2;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#hashCode()
+	 */
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((value1 == null) ? 0 : value1.hashCode());
+		result = prime * result + ((value2 == null) ? 0 : value2.hashCode());
+		return result;
+	}
+
+	public void setValue1(T1 value1) {
+		this.value1 = value1;
+	}
+
+	public void setValue2(T2 value2) {
+		this.value2 = value2;
+	}
+
+	@Override
+	public String toString() {
+		return "<" + value1 + ", " + value2 + ">";
+	}
+
+}
\ No newline at end of file
diff --git a/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/Plans.java b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/Plans.java
new file mode 100644
index 0000000..cfaeeab
--- /dev/null
+++ b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/Plans.java
@@ -0,0 +1,24 @@
+/**
+ * 
+ */
+package br.ufrgs.inf.bdi4jade.examples.planselection;
+
+/**
+ * @author ingrid
+ * 
+ */
+public interface Plans {
+
+	public static final TransportationPlan BIKE_PLAN = new TransportationPlan(
+			"Bike", 0.05, 0.20, false, 0.10, 0.20, 86, 90);
+	public static final TransportationPlan BUS_PLAN = new TransportationPlan(
+			"Bus", 0.10, 0.18, true, 0.35, 0.40, 50, 60);
+	public static final TransportationPlan CAR_PLAN = new TransportationPlan(
+			"Car", 0.15, 0.15, false, 0.90, 0.80, 20, 35);
+	public static final TransportationPlan MOTORCYCLE_PLAN = new TransportationPlan(
+			"Moto", 0.30, 0.20, false, 0.55, 0.50, 10, 20);
+
+	public static final TransportationPlan PLANS[] = { BIKE_PLAN, BUS_PLAN,
+			CAR_PLAN, MOTORCYCLE_PLAN };
+
+}
diff --git a/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/Softgoals.java b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/Softgoals.java
new file mode 100644
index 0000000..919cfe7
--- /dev/null
+++ b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/Softgoals.java
@@ -0,0 +1,24 @@
+/**
+ * 
+ */
+package br.ufrgs.inf.bdi4jade.examples.planselection;
+
+import br.ufrgs.inf.bdi4jade.softgoal.NamedSoftgoal;
+import br.ufrgs.inf.bdi4jade.softgoal.Softgoal;
+
+/**
+ * @author ingrid
+ * 
+ */
+public interface Softgoals {
+
+	public static final Softgoal COMFORT = new NamedSoftgoal("COMFORT");
+	public static final Softgoal COST = new NamedSoftgoal("COST");
+	public static final Softgoal PERFORMANCE = new NamedSoftgoal("PERFORMANCE");
+	public static final Softgoal SAFETY = new NamedSoftgoal("SAFETY");
+	public static final Softgoal SECURITY = new NamedSoftgoal("SECURITY");
+
+	public static final Softgoal SOFTGOALS[] = { COMFORT, COST, PERFORMANCE,
+			SAFETY, SECURITY };
+
+}
diff --git a/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/TransportationAgent.java b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/TransportationAgent.java
new file mode 100644
index 0000000..580bb01
--- /dev/null
+++ b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/TransportationAgent.java
@@ -0,0 +1,68 @@
+/**
+ * 
+ */
+package br.ufrgs.inf.bdi4jade.examples.planselection;
+
+import java.util.Random;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import br.ufrgs.inf.bdi4jade.belief.TransientBelief;
+import br.ufrgs.inf.bdi4jade.plan.Plan;
+import br.ufrgs.inf.bdi4jade.preference.SoftgoalPreferences;
+import br.ufrgs.inf.bdi4jade.softgoal.Softgoal;
+import br.ufrgs.inf.bdi4jade.util.agent.UtilityBasedBDIAgent;
+
+/**
+ * @author ingrid
+ * 
+ */
+public class TransportationAgent extends UtilityBasedBDIAgent {
+
+	private static final long serialVersionUID = 2712019445290687786L;
+	public static final String SATISFACTION = "Satisfaction";
+
+	private final Random rand;
+	private final Log log;
+
+	public TransportationAgent() {
+		this.log = LogFactory.getLog(this.getClass());
+		this.rand = new Random(System.currentTimeMillis());
+	}
+
+	protected void init() {
+		for (Softgoal softgoal : Softgoals.SOFTGOALS) {
+			this.addSoftgoal(softgoal);
+		}
+		for (Plan plan : Plans.PLANS) {
+			this.getRootCapability().getPlanLibrary().addPlan(plan);
+		}
+		this.getRootCapability()
+				.getBeliefBase()
+				.addBelief(
+						new TransientBelief<GenericValueFunction<Integer>>(
+								SATISFACTION,
+								new GenericValueFunction<Integer>()));
+	}
+
+	public void updatedPreferences() {
+		SoftgoalPreferences preferences = (SoftgoalPreferences) this
+				.getRootCapability().getBeliefBase()
+				.getBelief(SoftgoalPreferences.NAME);
+
+		double total = 0;
+		for (Softgoal softgoal : Softgoals.SOFTGOALS) {
+			double value = rand.nextDouble();
+			total += value;
+			preferences.setPreferenceForSoftgoal(softgoal, value);
+		}
+		for (Softgoal softgoal : Softgoals.SOFTGOALS) {
+			double value = preferences.getPreferenceForSoftgoal(softgoal);
+			double normValue = value / total;
+			preferences.setPreferenceForSoftgoal(softgoal, normValue);
+		}
+		log.debug("Preferences: " + preferences);
+	}
+
+}
diff --git a/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/TransportationGoal.java b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/TransportationGoal.java
new file mode 100644
index 0000000..a705405
--- /dev/null
+++ b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/TransportationGoal.java
@@ -0,0 +1,16 @@
+/**
+ * 
+ */
+package br.ufrgs.inf.bdi4jade.examples.planselection;
+
+import br.ufrgs.inf.bdi4jade.goal.Goal;
+
+/**
+ * @author ingrid
+ * 
+ */
+public class TransportationGoal implements Goal {
+
+	private static final long serialVersionUID = 5008348479798066431L;
+
+}
diff --git a/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/TransportationPlan.java b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/TransportationPlan.java
new file mode 100644
index 0000000..231a9fc
--- /dev/null
+++ b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/TransportationPlan.java
@@ -0,0 +1,135 @@
+/**
+ * 
+ */
+package br.ufrgs.inf.bdi4jade.examples.planselection;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import br.ufrgs.inf.bdi4jade.plan.PlanContribution;
+import br.ufrgs.inf.bdi4jade.softgoal.Softgoal;
+import br.ufrgs.inf.bdi4jade.util.plan.SimplePlan;
+
+/**
+ * @author ingrid
+ * 
+ */
+public class TransportationPlan extends SimplePlan {
+
+	public static final double MAX_TIME_TAKEN = 90;
+
+	private double beingRobbedProbability;
+	private double comfort;
+	private double cost;
+	private boolean costConstant;
+	private double crashProbability;
+	private int maxTime;
+	private int minTime;
+
+	public TransportationPlan(String id, double crashProbability,
+			double beingRobbedProbability, boolean costConstant, double cost,
+			double comfort, int minTime, int maxTime) {
+		super(id, TransportationGoal.class, TransportationPlanBody.class);
+
+		this.beingRobbedProbability = beingRobbedProbability;
+		this.comfort = comfort;
+		this.cost = cost;
+		this.costConstant = costConstant;
+		this.crashProbability = crashProbability;
+		this.maxTime = maxTime;
+		this.minTime = minTime;
+
+		Map<Softgoal, List<PlanContribution>> contributions = (Map<Softgoal, List<PlanContribution>>) getMetadata(DefaultMetadata.CONTRIBUTIONS);
+
+		List<PlanContribution> sgContributions = new ArrayList<PlanContribution>();
+		sgContributions.add(new PlanContribution(Softgoals.SAFETY,
+				crashProbability, 0.0));
+		sgContributions.add(new PlanContribution(Softgoals.SAFETY,
+				1 - crashProbability, 1.0));
+		contributions.put(Softgoals.SAFETY, sgContributions);
+
+		sgContributions = new ArrayList<PlanContribution>();
+		if (costConstant) {
+			sgContributions.add(new PlanContribution(Softgoals.COST, 1.0,
+					1 - cost));
+		} else {
+			sgContributions.add(new PlanContribution(Softgoals.COST,
+					crashProbability, 0.0));
+			sgContributions.add(new PlanContribution(Softgoals.COST,
+					1 - crashProbability, 1 - cost));
+		}
+		contributions.put(Softgoals.COST, sgContributions);
+
+		sgContributions = new ArrayList<PlanContribution>();
+		sgContributions.add(new PlanContribution(Softgoals.COMFORT, 1.0,
+				comfort));
+		contributions.put(Softgoals.COMFORT, sgContributions);
+
+		sgContributions = new ArrayList<PlanContribution>();
+		sgContributions.add(new PlanContribution(Softgoals.SECURITY,
+				beingRobbedProbability, 0.0));
+		sgContributions.add(new PlanContribution(Softgoals.SECURITY,
+				1 - beingRobbedProbability, 1.0));
+		contributions.put(Softgoals.SECURITY, sgContributions);
+
+		sgContributions = new ArrayList<PlanContribution>();
+		sgContributions.add(new PlanContribution(Softgoals.PERFORMANCE,
+				crashProbability, 0.0));
+		sgContributions.add(new PlanContribution(Softgoals.PERFORMANCE,
+				(1 - crashProbability) * 0.5, 1 - (minTime / MAX_TIME_TAKEN)));
+		sgContributions.add(new PlanContribution(Softgoals.PERFORMANCE,
+				(1 - crashProbability) * 0.5, 1 - (maxTime / MAX_TIME_TAKEN)));
+		contributions.put(Softgoals.PERFORMANCE, sgContributions);
+	}
+
+	/**
+	 * @return the beingRobbedProbability
+	 */
+	public double getBeingRobbedProbability() {
+		return beingRobbedProbability;
+	}
+
+	/**
+	 * @return the comfort
+	 */
+	public double getComfort() {
+		return comfort;
+	}
+
+	/**
+	 * @return the cost
+	 */
+	public double getCost() {
+		return cost;
+	}
+
+	/**
+	 * @return the crashProbability
+	 */
+	public double getCrashProbability() {
+		return crashProbability;
+	}
+
+	/**
+	 * @return the maxTime
+	 */
+	public int getMaxTime() {
+		return maxTime;
+	}
+
+	/**
+	 * @return the minTime
+	 */
+	public int getMinTime() {
+		return minTime;
+	}
+
+	/**
+	 * @return the costConstant
+	 */
+	public boolean isCostConstant() {
+		return costConstant;
+	}
+
+}
diff --git a/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/TransportationPlanBody.java b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/TransportationPlanBody.java
new file mode 100644
index 0000000..0a21531
--- /dev/null
+++ b/bdi-jade-test/src/br/ufrgs/inf/bdi4jade/examples/planselection/TransportationPlanBody.java
@@ -0,0 +1,133 @@
+/**
+ * 
+ */
+package br.ufrgs.inf.bdi4jade.examples.planselection;
+
+import jade.core.behaviours.OneShotBehaviour;
+
+import java.util.Random;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import br.ufrgs.inf.bdi4jade.belief.TransientBelief;
+import br.ufrgs.inf.bdi4jade.plan.PlanBody;
+import br.ufrgs.inf.bdi4jade.plan.PlanInstance;
+import br.ufrgs.inf.bdi4jade.plan.PlanInstance.EndState;
+import br.ufrgs.inf.bdi4jade.preference.SoftgoalPreferences;
+
+/**
+ * @author ingrid
+ * 
+ */
+public class TransportationPlanBody extends OneShotBehaviour implements
+		PlanBody {
+
+	class Scenario {
+
+		Double comfort;
+		Double cost;
+		Boolean crashed;
+		Random rand;
+		Boolean robbed;
+		Double timeTaken;
+
+		public Scenario() {
+			this.rand = new Random(System.currentTimeMillis());
+			this.crashed = occurred(rand, plan.getCrashProbability());
+			this.comfort = plan.getComfort();
+			this.timeTaken = TransportationPlan.MAX_TIME_TAKEN;
+			this.cost = plan.getCost();
+			if (!crashed) {
+				this.timeTaken = new Double(rand.nextInt(plan.getMaxTime()
+						- plan.getMinTime())
+						+ plan.getMinTime());
+			} else {
+				if (!plan.isCostConstant())
+					this.cost = 1.0;
+			}
+			this.robbed = occurred(rand, plan.getBeingRobbedProbability());
+		}
+
+		public Double getSatisfaction() {
+			double safetySatisfaction = crashed ? 0.0 : 1.0;
+			log.debug("safetySatisfaction = " + safetySatisfaction);
+
+			double costSatisfaction = 1 - cost;
+			log.debug("costSatisfaction = " + costSatisfaction);
+
+			double comfortSatisfaction = comfort;
+			log.debug("comfortSatisfaction = " + comfortSatisfaction);
+
+			double performanceSatisfaction = crashed ? 0.0
+					: 1 - (timeTaken / TransportationPlan.MAX_TIME_TAKEN);
+			log.debug("performanceSatisfaction = " + performanceSatisfaction);
+
+			double securitySatisfaction = robbed ? 0.0 : 1.0;
+			log.debug("securitySatisfaction = " + securitySatisfaction);
+
+			double satisfaction = preferences
+					.getPreferenceForSoftgoal(Softgoals.SAFETY)
+					* safetySatisfaction
+					+ preferences.getPreferenceForSoftgoal(Softgoals.COST)
+					* costSatisfaction
+					+ preferences.getPreferenceForSoftgoal(Softgoals.COMFORT)
+					* comfortSatisfaction
+					+ preferences
+							.getPreferenceForSoftgoal(Softgoals.PERFORMANCE)
+					* performanceSatisfaction
+					+ preferences.getPreferenceForSoftgoal(Softgoals.SECURITY)
+					* securitySatisfaction;
+			log.debug("Total Satisfaction = " + satisfaction);
+			return satisfaction;
+		}
+
+		private boolean occurred(Random rand, double probability) {
+			double number = rand.nextDouble();
+			return (number < probability);
+		}
+
+		@Override
+		public String toString() {
+			StringBuffer sb = new StringBuffer();
+			sb.append("[ crashed = ").append(crashed).append(", cost = ")
+					.append(cost).append(", time taken = ").append(timeTaken)
+					.append(", robbed = ").append(robbed).append(" ]");
+			return sb.toString();
+		}
+
+	}
+
+	private static final long serialVersionUID = -9039447524062487795L;
+
+	private Log log;
+	private TransportationPlan plan;
+	private SoftgoalPreferences preferences;
+	private GenericValueFunction<Integer> satisfaction;
+	private EndState endState = null;
+
+	public void action() {
+		log.debug("Plan executed: " + this.plan.getId());
+		Scenario scenario = new Scenario();
+		double satisfaction = scenario.getSatisfaction();
+		this.satisfaction.addValue(this.satisfaction.getCount() + 1,
+				satisfaction);
+		log.debug("Plan finished!");
+		this.endState = EndState.SUCCESSFUL;
+	}
+
+	public EndState getEndState() {
+		return endState;
+	}
+
+	@SuppressWarnings("unchecked")
+	public void init(PlanInstance planInstance) {
+		this.log = LogFactory.getLog(this.getClass());
+		this.plan = (TransportationPlan) planInstance.getPlan();
+		this.satisfaction = ((TransientBelief<GenericValueFunction<Integer>>) planInstance
+				.getBeliefBase().getBelief(TransportationAgent.SATISFACTION))
+				.getValue();
+		this.preferences = (SoftgoalPreferences) planInstance.getBeliefBase()
+				.getBelief(SoftgoalPreferences.NAME);
+	}
+}