|
4 | 4 | import aima.core.agent.Agent; |
5 | 5 | import aima.core.agent.Percept; |
6 | 6 | import aima.core.probability.bayes.BayesInference; |
7 | | -import aima.core.probability.bayes.BayesianNetwork; |
8 | 7 | import aima.core.probability.domain.FiniteDomain; |
9 | 8 | import aima.core.probability.proposition.AssignmentProposition; |
10 | 9 |
|
11 | 10 | import java.util.ArrayList; |
12 | | -import java.util.Arrays; |
13 | 11 | import java.util.Collections; |
14 | 12 | import java.util.List; |
15 | 13 |
|
| 14 | +/** |
| 15 | + * Artificial Intelligence A Modern Approach (3rd Edition): Figure 16.9, page 632.<br> |
| 16 | + * </br> |
| 17 | + * <pre> |
| 18 | + * |
| 19 | + * function INFORMATION-GATHERING-AGENT(percept) returns an action |
| 20 | + * persistent: D, a decision network |
| 21 | + * |
| 22 | + * integrate percept into D |
| 23 | + * j ← the value that maximizes VPI(Ej) / Cost(Ej) |
| 24 | + * if VPI(Ej) > Cost(Ej) |
| 25 | + * return REQUEST(Ej) |
| 26 | + * else return the best action from D |
| 27 | + * |
| 28 | + * </pre> |
| 29 | + * <p> |
| 30 | + * Figure ?? Design of a simple information-gathering agent. |
| 31 | + * The agent works by repeatedly selecting the observation with |
| 32 | + * the highest information value, until the cost of the next |
| 33 | + * observation is greater than its expected benefit. |
| 34 | + * |
| 35 | + * @author samagra |
| 36 | + */ |
16 | 37 | public abstract class InformationGatheringAgent implements Agent { |
| 38 | + |
| 39 | + // To carry out conditional probability calculations |
17 | 40 | private BayesInference inferenceMethod; |
| 41 | + // persistent: D, a decision network |
18 | 42 | private DecisionNetwork decisionNetwork; |
| 43 | + // To store the information collected till now |
19 | 44 | private List<AssignmentProposition> observedEvidence; |
| 45 | + // To store the scope of information that can be collected |
20 | 46 | private List<RandomVariable> randomVars; |
21 | | - |
| 47 | + |
| 48 | + /** |
| 49 | + * Constructor for the agent. |
| 50 | + * |
| 51 | + * @param decisionNetwork The decision network which represents the problem |
| 52 | + * for which the information is to be collected |
| 53 | + * @param inferenceMethod To carry out various conditional probability calculations |
| 54 | + * @param initialEvidence The information which is available beforehand to the agent. |
| 55 | + */ |
22 | 56 | public InformationGatheringAgent(DecisionNetwork decisionNetwork, |
23 | 57 | BayesInference inferenceMethod, |
24 | | - List<AssignmentProposition> initialEvidence){ |
| 58 | + List<AssignmentProposition> initialEvidence) { |
25 | 59 | this.decisionNetwork = decisionNetwork; |
26 | 60 | this.inferenceMethod = inferenceMethod; |
27 | 61 | this.observedEvidence = initialEvidence; |
28 | 62 | this.randomVars = this.decisionNetwork.getNetwork().getVariablesInTopologicalOrder(); |
29 | 63 | } |
30 | 64 |
|
31 | 65 | public InformationGatheringAgent(DecisionNetwork decisionNetwork, |
32 | | - BayesInference inferenceMethod){ |
33 | | - this(decisionNetwork,inferenceMethod,new ArrayList<>()); |
| 66 | + BayesInference inferenceMethod) { |
| 67 | + this(decisionNetwork, inferenceMethod, new ArrayList<>()); |
34 | 68 | } |
35 | | - |
| 69 | + |
| 70 | + /** |
| 71 | + * function INFORMATION-GATHERING-AGENT(percept) returns an action |
| 72 | + * |
| 73 | + * @param percept The current percept of a sequence perceived by the Agent. |
| 74 | + * @return action to be executed by the agent |
| 75 | + */ |
36 | 76 | @Override |
37 | 77 | public Action execute(Percept percept) { |
38 | | - observedEvidence = integratePercept(observedEvidence,percept); |
| 78 | + // integrate percept into D |
| 79 | + observedEvidence = integratePercept(observedEvidence, percept); |
| 80 | + |
| 81 | + // j ← the value that maximizes VPI(Ej) / Cost(Ej) |
39 | 82 | List<Double> vpiPerUnitCosts = this.vpiPerUnitCost(this.randomVars); |
40 | 83 | int j = vpiPerUnitCosts.indexOf(Collections.max(vpiPerUnitCosts)); |
41 | 84 | RandomVariable randomVar = this.randomVars.get(j); |
42 | | - if (getVpi(randomVar)>getCost(randomVar)){ |
| 85 | + |
| 86 | + // if VPI(Ej) > Cost(Ej) |
| 87 | + if (getVpi(randomVar) > getCost(randomVar)) { |
| 88 | + // return REQUEST(Ej) |
43 | 89 | return this.request(randomVar); |
44 | 90 | } |
| 91 | + // else return the best action from D |
45 | 92 | return ((Action) decisionNetwork.getBestAction()); |
46 | 93 | } |
47 | 94 |
|
| 95 | + /** |
| 96 | + * We assume that the result of |
| 97 | + * the action Request (Ej ) is that the next percept provides the value of Ej . |
| 98 | + * |
| 99 | + * @param randomVar The random variable for which the information is needed. |
| 100 | + * @return The action which leads to the agent to the value of Ej. |
| 101 | + */ |
48 | 102 | protected abstract Action request(RandomVariable randomVar); |
49 | 103 |
|
50 | | - private List<Double> vpiPerUnitCost(List<RandomVariable> variablesInTopologicalOrder){ |
51 | | - List<Double> vpiPerUnitCost = new ArrayList<>(); |
| 104 | + /** |
| 105 | + * Calculates the vpi (value of perfect information) per unit cost |
| 106 | + * for all the random variables. |
| 107 | + * |
| 108 | + * @param variablesInTopologicalOrder The variables for which information is required. |
| 109 | + * @return A list of vpi values. |
| 110 | + */ |
| 111 | + private List<Double> vpiPerUnitCost(List<RandomVariable> variablesInTopologicalOrder) { |
| 112 | + List<Double> vpiPerUnitCost = new ArrayList<>(); |
52 | 113 | for (RandomVariable var : |
53 | 114 | variablesInTopologicalOrder) { |
54 | 115 | vpiPerUnitCost.add(getVpi(var) / getCost(var)); |
55 | 116 | } |
56 | 117 | return vpiPerUnitCost; |
57 | 118 | } |
58 | 119 |
|
59 | | - protected abstract double getCost(RandomVariable var); |
| 120 | + /** |
| 121 | + * Calculates the cost of obtaining information for |
| 122 | + * a particular variable. |
| 123 | + * |
| 124 | + * @param var |
| 125 | + * @return |
| 126 | + */ |
| 127 | + abstract double getCost(RandomVariable var); |
60 | 128 |
|
61 | | - protected double getVpi(RandomVariable var){ |
62 | | - double vpi =0; |
| 129 | + /** |
| 130 | + * Calculates VPI for a particular random variable. |
| 131 | + * |
| 132 | + * @param var |
| 133 | + * @return |
| 134 | + */ |
| 135 | + double getVpi(RandomVariable var) { |
| 136 | + double vpi = 0; |
63 | 137 | CategoricalDistribution distribution = inferenceMethod.ask((new RandomVariable[]{var}), |
64 | | - ((AssignmentProposition[])observedEvidence.toArray()),decisionNetwork.getNetwork()); |
| 138 | + ((AssignmentProposition[]) observedEvidence.toArray()), decisionNetwork.getNetwork()); |
65 | 139 | for (Object value : |
66 | 140 | ((FiniteDomain) var.getDomain()).getPossibleValues()) { |
67 | 141 | double posterierProb = distribution.getValue(value); |
68 | 142 | List<AssignmentProposition> modifiedEvidence = new ArrayList<>(observedEvidence); |
69 | | - modifiedEvidence.add(new AssignmentProposition(var,value)); |
| 143 | + modifiedEvidence.add(new AssignmentProposition(var, value)); |
70 | 144 | double expectedUtilityForParticularValue = decisionNetwork.getExpectedUtility(var, |
71 | 145 | modifiedEvidence); |
72 | | - vpi+= posterierProb*expectedUtilityForParticularValue; |
| 146 | + vpi += posterierProb * expectedUtilityForParticularValue; |
73 | 147 | } |
74 | | - vpi-=decisionNetwork.getExpectedUtility(var,observedEvidence); |
| 148 | + vpi -= decisionNetwork.getExpectedUtility(var, observedEvidence); |
75 | 149 | return vpi; |
76 | 150 | } |
77 | 151 |
|
| 152 | + /** |
| 153 | + * Extracts the information from the percepts and adds ot to our observed evidence. |
| 154 | + * |
| 155 | + * @param observedEvidence |
| 156 | + * @param percept |
| 157 | + * @return |
| 158 | + */ |
78 | 159 | abstract List<AssignmentProposition> integratePercept(List<AssignmentProposition> observedEvidence, Percept percept); |
79 | 160 |
|
80 | 161 |
|
|
0 commit comments