Work in progress.

Able to read short survey, recipe book but crashing in Bayes Net code.
This commit is contained in:
Woody Folsom
2012-03-11 21:25:04 -04:00
parent 3046f68681
commit bb94356ec1
11 changed files with 999 additions and 37 deletions

521
data/short_recipebook.xml Normal file
View File

@@ -0,0 +1,521 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE recipeml PUBLIC "-//FormatData//DTD RecipeML 0.5//EN" "http://www.formatdata.com/recipeml/recipeml.dtd"><recipeml version="0.5" generator="Krecipes v2.0-beta1">
<recipe>
<head>
<title>Catalan Rice</title>
<source/>
<categories>
<cat>Fish</cat>
<cat>Casserole</cat>
<cat>Main dish</cat>
<cat>Pork</cat>
<cat>Clams</cat>
</categories>
<yield>6<unit>servings</unit>
</yield>
<preptime type="Total">
<time>
<qty>0</qty>
<timeunit>minutes</timeunit>
</time>
</preptime>
</head>
<ingredients>
<ing>
<amt>
<qty>2.5</qty>
<unit>cups</unit>
</amt>
<item>Fish stock</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>0.25</qty>
<unit>teaspoon</unit>
</amt>
<item>Saffron Threads</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>0.25</qty>
<unit>cup</unit>
</amt>
<item>Dry white wine</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>6</qty>
<unit>tablespoons</unit>
</amt>
<item>Lard</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>0.5</qty>
<unit>pound</unit>
</amt>
<item>Chorizo</item>
<prep>Sliced 1/4"</prep>
</ing>
<ing>
<amt>
<qty>1.5</qty>
<unit>pounds</unit>
</amt>
<item>Pork Loin</item>
<prep>1" Cubes</prep>
</ing>
<ing>
<amt>
<qty>1</qty>
<unit></unit>
</amt>
<item>onion</item>
<prep>thinly sliced</prep>
</ing>
<ing>
<amt>
<qty>2</qty>
<unit></unit>
</amt>
<item>Bell peppers</item>
<prep>julienned</prep>
</ing>
<ing>
<amt>
<qty>2</qty>
<unit></unit>
</amt>
<item>tomatoes</item>
<prep>peeled,seeded</prep>
</ing>
<ing>
<amt>
<qty>3</qty>
<unit></unit>
</amt>
<item>Large Squid</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>2</qty>
<unit>cups</unit>
</amt>
<item>Long-Grained Rice</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>0.75</qty>
<unit>cup</unit>
</amt>
<item>Blanched almonds</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>0.333333</qty>
<unit>cup</unit>
</amt>
<item>Pine Nuts</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>3</qty>
<unit></unit>
</amt>
<item>garlic cloves</item>
<prep>minced</prep>
</ing>
<ing>
<amt>
<qty>1</qty>
<unit>cup</unit>
</amt>
<item>Artichoke hearts</item>
<prep>drained</prep>
</ing>
<ing>
<amt>
<qty>18</qty>
<unit></unit>
</amt>
<item>Clams Or Mussels</item>
<prep>scrubbed</prep>
</ing>
<ing>
<amt>
<qty>0.5</qty>
<unit>cup</unit>
</amt>
<item>Peas</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>0.25</qty>
<unit>cup</unit>
</amt>
<item>Pimientos</item>
<prep>julienned</prep>
</ing>
<ing>
<amt>
<qty>2</qty>
<unit>tablespoons</unit>
</amt>
<item>Fresh parsley</item>
<prep>minced</prep>
</ing>
</ingredients>
<directions>
<step>Clean squid and cut body sacs into rings. Cut tentacles in half. In
a small saucepan, bring stock to a bare simmer. Crush saffron and
combine it with wine in a small bowl. In a flameproof casserole or
paella pan, heat the lard over moderately high heat. Saute the
chorizo and pork, turning them until they are browned. Add the
onion, bell peppers, tomatoes, and squid and cook the mixture over
moderate heat, stirring, for 15 minutes. Stir in the rice and cook
for 1 minute, stirring. Stir in almonds, pine nuts, garlic, saffron
mixture, and artichoke hearts. Ladle in enough stock to just cover
the rice mixture. Bring to a boil and simmer it, covered, for 20
minutes. Arrange the clams in the rice, add the peas, and simmer for
10-15 minutes, or until the rice is just tender and the clams open.
Discard any clams that do not open. Garnish with pimientos and
parsley. This is a recipe by Elizabeth David, appearing in an article
in 1972 by James Beard. It originated on Spain's Costa Brava. "not a
true paella, but it is quite good." A 1972 Gourmet Magazine Favorite.</step>
</directions>
</recipe>
<recipe>
<head>
<title>Hamburger Steak</title>
<source/>
<categories>
<cat>Beef</cat>
<cat>Penndutch</cat>
</categories>
<yield>1<unit>servings</unit>
</yield>
<preptime type="Total">
<time>
<qty>0</qty>
<timeunit>minutes</timeunit>
</time>
</preptime>
</head>
<ingredients>
<ing>
<amt>
<qty>1</qty>
<unit>pound</unit>
</amt>
<item>Beef</item>
<prep>ground</prep>
</ing>
<ing>
<amt>
<qty>0.5</qty>
<unit>teaspoon</unit>
</amt>
<item>salt</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>1</qty>
<unit></unit>
</amt>
<item>onion</item>
<prep>minced</prep>
</ing>
<ing>
<amt>
<qty>1</qty>
<unit></unit>
</amt>
<item>egg</item>
<prep>well beaten</prep>
</ing>
<ing>
<amt>
<qty>1</qty>
<unit>dash</unit>
</amt>
<item>pepper</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>0.25</qty>
<unit>cup</unit>
</amt>
<item>bread crumbs</item>
<prep></prep>
</ing>
</ingredients>
<directions>
<step>Mix in order given and shape into round cakes. Fry in butter until
nicely browned. Source: Pennsylvania Dutch Cook Book - Fine Old
Recipes, Culinary Arts Press, 1936.</step>
</directions>
</recipe>
<recipe>
<head>
<title>Potatoes in a Thick Sauce</title>
<source/>
<categories>
<cat>Main dish</cat>
<cat>Potatoes</cat>
<cat>Indian</cat>
<cat>Vegetarian</cat>
</categories>
<yield>6<unit>servings</unit>
</yield>
<preptime type="Total">
<time>
<qty>0</qty>
<timeunit>minutes</timeunit>
</time>
</preptime>
</head>
<ingredients>
<ing>
<amt>
<qty>5</qty>
<unit>medium</unit>
</amt>
<item>potatoes</item>
<prep>cubed &amp; cooked</prep>
</ing>
<ing>
<amt>
<qty>1</qty>
<unit>slice</unit>
</amt>
<item>ginger</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>1</qty>
<unit>tablespoon</unit>
</amt>
<item>Coriander</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>1</qty>
<unit>teaspoon</unit>
</amt>
<item>cumin</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>6</qty>
<unit>tablespoons</unit>
</amt>
<item>tomato sauce</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>6</qty>
<unit>tablespoons</unit>
</amt>
<item>vegetable oil</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>1</qty>
<unit>teaspoon</unit>
</amt>
<item>Fennel</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>1</qty>
<unit>teaspoon</unit>
</amt>
<item>Fenugreek</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>0.5</qty>
<unit>teaspoon</unit>
</amt>
<item>Black mustard seeds</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>3</qty>
<unit></unit>
</amt>
<item>Whole dried red chilies</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>1</qty>
<unit>teaspoon</unit>
</amt>
<item>salt</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>1.5</qty>
<unit>teaspoons</unit>
</amt>
<item>lemon juice</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>1</qty>
<unit>teaspoon</unit>
</amt>
<item>Garam masala</item>
<prep></prep>
</ing>
</ingredients>
<directions>
<step>Place ginger, coriander, cumin, tomato sauce &amp; 3 tb water in a
blender &amp; blend till smooth.
Break potatoes into bite sized pieces.
Heat oil (I use ghee) in a large pot. When hot, throw in fennel,
fenugreek &amp; mustard seeds. After 20 seconds, add red chilies. As
they darken, put in paste from blender. Fry for 5 minutes, stirring
frequently. Put in the potato pieces &amp; fry for 3 to 5 minutes. Add 1
1/2 c warm water. Bring to a boil. Add salt &amp; lemon juice. Simmer
for 20 minutes.
Before serving, sprinkle with garam masala.
Madhur Jaffrey, "An Invitation to Indian Cooking.</step>
</directions>
</recipe>
<recipe>
<head>
<title>Tomato-Zucchini Casserole</title>
<source/>
<categories>
<cat>Vegetarian</cat>
<cat>Casseroles</cat>
</categories>
<yield>4<unit>servings</unit>
</yield>
<preptime type="Total">
<time>
<qty>0</qty>
<timeunit>minutes</timeunit>
</time>
</preptime>
</head>
<ingredients>
<ing>
<amt>
<qty>1.5</qty>
<unit>teaspoons</unit>
</amt>
<item>chili powder</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>1</qty>
<unit>tablespoon</unit>
</amt>
<item>parsley flakes</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>0.5</qty>
<unit>teaspoon</unit>
</amt>
<item>garlic powder</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>0.5</qty>
<unit>teaspoon</unit>
</amt>
<item>onion powder</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>0.125</qty>
<unit>teaspoon</unit>
</amt>
<item>salt</item>
<prep></prep>
</ing>
<ing>
<amt>
<qty>0.125</qty>
<unit>teaspoon</unit>
</amt>
<item>black pepper</item>
<prep>ground</prep>
</ing>
<ing>
<amt>
<qty>3</qty>
<unit>cups</unit>
</amt>
<item>zucchini</item>
<prep>thinly sliced,fresh</prep>
</ing>
<ing>
<amt>
<qty>1</qty>
<unit>pound</unit>
</amt>
<item>tomatoes</item>
<prep>fresh,sliced</prep>
</ing>
<ing>
<amt>
<qty>0.25</qty>
<unit>cup</unit>
</amt>
<item>bread crumbs</item>
<prep>white,fresh</prep>
</ing>
<ing>
<amt>
<qty>1</qty>
<unit>tablespoon</unit>
</amt>
<item>vegetable oil</item>
<prep></prep>
</ing>
</ingredients>
<directions>
<step>1. Combine chili powder, 1 1/2 teaspooons parsley flakes, garlic and
onion powders, salt and pepper in a small bowl.~ 2. Place half the
zucchini in a lightly greased 6-cup casserole, or layer with half the
tomatoes.~ 3. Sprinkle with half the seasoning mixture.~ 4. Repeat
the layers.~ 5. Combine bread crumbs, oil and remaining parsley
flakes; sprinkle over vegetables.~ 6. Bake, uncovered, in preheated
375'F. oven, until vegetables are tender, about 40 minutes.~</step>
</directions>
</recipe>
</recipeml>

109
data/short_survey.xml Normal file
View File

@@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8" ?>
<survey>
<dishes>
<entry>
<int>0</int>
<string>Catalan Rice</string>
</entry>
<entry>
<int>1</int>
<string>Hamburger Steak</string>
</entry>
<entry>
<int>2</int>
<string>Potatoes in a Thick Sauce</string>
</entry>
<entry>
<int>3</int>
<string>Tomato-Zucchini Casserole</string>
</entry>
</dishes>
<categories>
<entry>
<int>0</int>
<string>
chocolate
</string>
</entry>
<entry>
<int>1</int>
<string>
nuts
</string>
</entry>
<entry>
<int>2</int>
<string>shellfish</string>
</entry>
</categories>
<diner>
<id>0</id>
<ratings>
<entry>
<int>0</int>
<int>10</int>
</entry>
<entry>
<int>1</int>
<int>2</int>
</entry>
<entry>
<int>2</int>
<int>5</int>
</entry>
<entry>
<int>3</int>
<int>5</int>
</entry>
</ratings>
<allergies>
<entry>
<int>0</int>
<boolean>false</boolean>
</entry>
<entry>
<int>1</int>
<boolean>false</boolean>
</entry>
<entry>
<int>2</int>
<boolean>false</boolean>
</entry>
</allergies>
</diner>
<diner>
<id>1</id>
<ratings>
<entry>
<int>0</int>
<int>10</int>
</entry>
<entry>
<int>1</int>
<int>2</int>
</entry>
<entry>
<int>2</int>
<int>5</int>
</entry>
<entry>
<int>3</int>
<int>5</int>
</entry>
</ratings>
<allergies>
<entry>
<int>0</int>
<boolean>false</boolean>
</entry>
<entry>
<int>1</int>
<boolean>false</boolean>
</entry>
<entry>
<int>2</int>
<boolean>false</boolean>
</entry>
</allergies>
</diner>
</survey>

View File

@@ -0,0 +1,218 @@
package dkohl.bayes.builders;
import java.util.HashSet;
import net.woodyfolsom.cs6601.p2.Diner;
import net.woodyfolsom.cs6601.p2.Ingredient.TYPE;
import net.woodyfolsom.cs6601.p2.Ingredients;
import net.woodyfolsom.cs6601.p2.Recipe;
import net.woodyfolsom.cs6601.p2.RecipeBook;
import net.woodyfolsom.cs6601.p2.Survey;
import dkohl.bayes.bayesnet.BayesNet;
import dkohl.bayes.estimation.MaximumLikelihoodEstimation;
import dkohl.bayes.example.builders.FoodExampleBuilder;
import dkohl.bayes.probability.Assignment;
import dkohl.bayes.probability.Probability;
import dkohl.bayes.probability.Variable;
import dkohl.bayes.probability.distribution.ContinousDistribution;
import dkohl.bayes.probability.distribution.ProbabilityDistribution;
import dkohl.bayes.probability.distribution.ProbabilityTable;
import dkohl.bayes.statistic.DataPoint;
import dkohl.bayes.statistic.DataSet;
import dkohl.onthology.Ontology;
public class FoodNetBuilder {
public static final String TASTE = "Taste";
public static final String SOMEONE_VEGETARIAN = "Vegetarian";
public static final String CONTAINS_MEAT = "Meat";
public static final String CONTAINS_VEGETABLE = "Vegetable";
public static final String CONTAINS_BEEF = TYPE.BEEF.toString();
public static final String CONTAINS_PORK = TYPE.PORK.toString();
public static final String CONTAINS_TOMATOS = TYPE.TOMATO.toString();
public static final String CONTAINS_POTATOS = TYPE.POTATO.toString();
public static final String TRUE_VALUE = "true";
public static final String FALSE_VALUE = "false";
public static final String DOMAIN[] = { TRUE_VALUE, FALSE_VALUE };
public static final String RATING_DOMAIN[] = { "1", "2", "3", "4", "5",
"6", "7", "8", "9", "10" };
private static final String[] VARIABLES = { SOMEONE_VEGETARIAN,
CONTAINS_BEEF, CONTAINS_MEAT, CONTAINS_PORK, CONTAINS_POTATOS,
CONTAINS_TOMATOS, CONTAINS_VEGETABLE, TASTE };
private static final String[] OBSERVED = { CONTAINS_BEEF, CONTAINS_PORK,
CONTAINS_POTATOS, CONTAINS_TOMATOS, };
public static Ontology createOntology() {
HashSet<String> classes = new HashSet<String>();
classes.add(CONTAINS_MEAT);
classes.add(CONTAINS_VEGETABLE);
Ontology onthology = new Ontology(classes);
onthology.define(CONTAINS_PORK, CONTAINS_MEAT);
onthology.define(CONTAINS_BEEF, CONTAINS_MEAT);
onthology.define(CONTAINS_TOMATOS, CONTAINS_VEGETABLE);
onthology.define(CONTAINS_POTATOS, CONTAINS_VEGETABLE);
return onthology;
}
private static Assignment build(String varible, String value) {
return new Assignment(new Variable(varible, DOMAIN), value);
}
public static DataPoint normalize(DataPoint point, Ontology onto) {
// resolve onthology
DataPoint normPoint = new DataPoint(point);
for (String key : point.keySet()) {
if (onto.getInheritance().containsKey(key)) {
normPoint
.add(build(onto.getInheritance().get(key), TRUE_VALUE));
}
}
// implement closed world assumption
// everything unknown is false
for (String variable : VARIABLES) {
if (!normPoint.containsKey(variable)) {
normPoint.add(build(variable, FALSE_VALUE));
}
}
return normPoint;
}
public static DataSet getSurveyDataSet(Survey survey, RecipeBook recipeBook) {
DataSet data = FoodExampleBuilder.examples();
Ontology onto = createOntology();
int nDishes = survey.getDishCount();
for (int dinerIndex = 0; dinerIndex < survey.getDinerCount(); dinerIndex++) {
Diner diner = survey.getDiner(dinerIndex);
for (int dishIndex = 0; dishIndex < nDishes; dishIndex++) {
data.add(normalize(createDataPoint(recipeBook, survey.getDish(dishIndex), diner.getRating(dishIndex)),onto));
}
}
return data;
}
public static DataPoint createDataPoint(RecipeBook recipeBook, String recipeName, int weight) {
DataPoint point = new DataPoint();
Recipe recipe = recipeBook.getRecipe(recipeName);
Ingredients ingredients = recipe.getIngredients();
if (ingredients.contains(TYPE.BEEF)) {
point.add(build(CONTAINS_BEEF, TRUE_VALUE));
}
if (ingredients.contains(TYPE.PORK)) {
point.add(build(CONTAINS_PORK, TRUE_VALUE));
}
if (ingredients.contains(TYPE.POTATO)) {
point.add(build(CONTAINS_POTATOS, TRUE_VALUE));
}
if (ingredients.contains(TYPE.TOMATO)) {
point.add(build(CONTAINS_TOMATOS, TRUE_VALUE));
}
point.add(build(TASTE, "" + weight));
return point;
}
public static ProbabilityDistribution vegi() {
String names[] = { SOMEONE_VEGETARIAN };
ProbabilityTable table = new ProbabilityTable(names);
table.setProbabilityForAssignment("true;", new Probability(0));
table.setProbabilityForAssignment("false;", new Probability(1));
return table;
}
public static ProbabilityDistribution beef() {
String names[] = { CONTAINS_MEAT, CONTAINS_BEEF };
ProbabilityTable table = new ProbabilityTable(names);
return table;
}
public static ProbabilityDistribution pork() {
String names[] = { CONTAINS_MEAT, CONTAINS_PORK };
ProbabilityTable table = new ProbabilityTable(names);
return table;
}
public static ProbabilityDistribution meet() {
String names[] = { SOMEONE_VEGETARIAN, CONTAINS_MEAT };
ProbabilityTable table = new ProbabilityTable(names);
return table;
}
public static ProbabilityDistribution tomatos() {
String names[] = { CONTAINS_VEGETABLE, CONTAINS_TOMATOS };
ProbabilityTable table = new ProbabilityTable(names);
return table;
}
public static ProbabilityDistribution potatos() {
String names[] = { CONTAINS_VEGETABLE, CONTAINS_POTATOS };
ProbabilityTable table = new ProbabilityTable(names);
return table;
}
public static ProbabilityDistribution vegetables() {
String names[] = { CONTAINS_VEGETABLE, SOMEONE_VEGETARIAN };
ProbabilityTable table = new ProbabilityTable(names);
return table;
}
public static ProbabilityDistribution taste() {
String names[] = { TASTE, CONTAINS_BEEF, CONTAINS_PORK,
CONTAINS_POTATOS, CONTAINS_TOMATOS };
ContinousDistribution distribution = new ContinousDistribution(names, 0);
return distribution;
}
public static BayesNet createDishNet(Survey survey, RecipeBook recipeBook) {
BayesNet net = new BayesNet(VARIABLES);
net.setDistribution(new Variable(SOMEONE_VEGETARIAN, DOMAIN), vegi());
net.setDistribution(new Variable(CONTAINS_MEAT, DOMAIN), meet());
net.setDistribution(new Variable(CONTAINS_VEGETABLE, DOMAIN),
vegetables());
net.setDistribution(new Variable(CONTAINS_BEEF, DOMAIN), beef());
net.setDistribution(new Variable(CONTAINS_PORK, DOMAIN), pork());
net.setDistribution(new Variable(CONTAINS_POTATOS, DOMAIN), potatos());
net.setDistribution(new Variable(CONTAINS_TOMATOS, DOMAIN), tomatos());
net.setDistribution(new Variable(TASTE, RATING_DOMAIN), taste());
Ontology ontology = createOntology();
for (String category : ontology.getClasses()) {
net.connect(category, SOMEONE_VEGETARIAN);
}
for (String thing : OBSERVED) {
net.connect(thing, ontology.getInheritance().get(thing));
net.connect(TASTE, thing);
}
DataSet dataSet = getSurveyDataSet(survey, recipeBook);
for (String category : ontology.getClasses()) {
MaximumLikelihoodEstimation.estimate(dataSet, net, category);
for (String thing : ontology.getClasses2thing().get(category)) {
MaximumLikelihoodEstimation.estimate(dataSet, net, thing);
}
}
MaximumLikelihoodEstimation.estimate(dataSet, net, TASTE);
ContinousDistribution distribturion = (ContinousDistribution) net
.getNodes().get(TASTE);
distribturion.estimate();
return net;
}
}

View File

@@ -27,8 +27,8 @@ public class EnumerateAll {
* a set of assignments in this net. * a set of assignments in this net.
* @return * @return
*/ */
public static LinkedList<ProbabilityAssignment> enumerateAsk( public static List<ProbabilityAssignment> enumerateAsk(
Variable query, BayesNet net, LinkedList<Assignment> assignments) { Variable query, BayesNet net, List<Assignment> assignments) {
LinkedList<Variable> variables = net.getVariables(); LinkedList<Variable> variables = net.getVariables();
LinkedList<ProbabilityAssignment> result = new LinkedList<ProbabilityAssignment>(); LinkedList<ProbabilityAssignment> result = new LinkedList<ProbabilityAssignment>();

View File

@@ -1,61 +1,112 @@
package net.woodyfolsom.cs6601.p2; package net.woodyfolsom.cs6601.p2;
import java.io.File; import java.io.File;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.math3.stat.regression.SimpleRegression; import net.woodyfolsom.cs6601.p2.Ingredient.TYPE;
import dkohl.bayes.bayesnet.BayesNet;
import dkohl.bayes.builders.FoodNetBuilder;
import dkohl.bayes.example.builders.FoodExampleBuilder;
import dkohl.bayes.inference.EnumerateAll;
import dkohl.bayes.probability.Assignment;
import dkohl.bayes.probability.ProbabilityAssignment;
import dkohl.bayes.probability.Variable;
public class BayesChef { public class BayesChef {
public static void main(String... args) { public static void main(String... args) {
System.out.println("Reading recipe book."); System.out.println("Reading recipe book.");
RecipeBook recipeBook = RecipeBookReader.readRecipeBook(new File("data/survey_recipes.xml")); RecipeBook recipeBook = RecipeBookReader.readRecipeBook(new File("data/short_recipebook.xml"));
System.out.println("Read data for " + recipeBook.getSize() + " recipes.");
System.out.println("Reading survey data."); System.out.println("Reading survey data.");
Survey survey = SurveyReader.readSurvey(new File("data/survey.xml")); Survey survey = SurveyReader.readSurvey(new File("data/short_survey.xml"));
System.out.println("Read data for " + survey.getDinerCount() + " diner(s)."); new BayesChef().reportBestMeal(recipeBook,survey);
}
private void reportBestMeal(RecipeBook recipeBook, Survey survey) {
int numRecipes = recipeBook.getSize();
System.out.println("Read data for " + numRecipes + " recipes.");
int numDiners = survey.getDinerCount();
System.out.println("Read data for " + numDiners + " diner(s).");
/*
System.out.println("Setting evidence for first 11 recipes."); System.out.println("Setting evidence for first 11 recipes.");
System.out.println("Evaluating preference for remaining recipes."); System.out.println("Evaluating preference for remaining recipes.");
//read survey prefs from survey.xml //read survey prefs from survey.xml
double[][] surveyPrefs = new double[5][]; double[][] surveyPrefs = new double[numDiners][];
for (int i = 0; i < 5; i++) { for (int i = 0; i < numDiners; i++) {
surveyPrefs[i] = new double[11]; surveyPrefs[i] = new double[numRecipes/2];
for (int j = 0; j < 11; j++) { for (int j = 0; j < numRecipes/2; j++) {
surveyPrefs[i][j] = survey.getDiner(i).getRating(j); surveyPrefs[i][j] = survey.getDiner(i).getRating(j);
} }
} }
//generating stub evaluated preferences to test RMSE calculation //generating stub evaluated preferences to test RMSE calculation
double[][] calculatedPrefs = new double[5][]; double[][] calculatedPrefs = new double[numDiners][];
calculatedPrefs[0] = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; calculatedPrefs[0] = new double[numRecipes/2];
calculatedPrefs[1] = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
calculatedPrefs[2] = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
calculatedPrefs[3] = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
calculatedPrefs[4] = new double[] { 10.0, 10.0, 0.0, 10.0, 10.0, 4.0, 10.0, 10.0, 10.0, 10.0, 10.0 };
System.out.println("RMSE for recipes #12-22 (calculated vs. surveyed preference):"); System.out.println("RMSE for recipes #" + numRecipes/2 + "-" + numRecipes +" (calculated vs. surveyed preference):");
for (int dinerIndex = 0; dinerIndex < survey.getDinerCount(); dinerIndex++) { for (int dinerIndex = 0; dinerIndex < survey.getDinerCount(); dinerIndex++) {
SimpleRegression simpleRegression = new SimpleRegression(); SimpleRegression simpleRegression = new SimpleRegression();
for (int i = 0; i < 11; i++) { for (int i = 0; i < numRecipes/2; i++) {
simpleRegression.addData(i,calculatedPrefs[dinerIndex][i]); simpleRegression.addData(i,calculatedPrefs[dinerIndex][i]);
} }
double calculatedMSE = simpleRegression.getMeanSquareError(); double calculatedMSE = simpleRegression.getMeanSquareError();
simpleRegression.clear(); simpleRegression.clear();
for (int i = 0; i < 11; i++) { for (int i = 0; i < numRecipes/2; i++) {
simpleRegression.addData(i,surveyPrefs[dinerIndex][i]); simpleRegression.addData(i,surveyPrefs[dinerIndex][i]);
} }
double surveyMSE = simpleRegression.getMeanSquareError(); double surveyMSE = simpleRegression.getMeanSquareError();
System.out.println("Diner # " + (dinerIndex + 1) + ": " + calculatedMSE + " vs. "+ surveyMSE); System.out.println("Diner # " + (dinerIndex + 1) + ": " + calculatedMSE + " vs. "+ surveyMSE);
}*/
BayesNet net = FoodNetBuilder.createDishNet(survey, recipeBook);
//BayesNet net = FoodExampleBuilder.dishNet();
printPreference(net, TYPE.PORK);
printPreference(net, TYPE.BEEF);
printPreference(net, TYPE.POTATO);
printPreference(net, TYPE.TOMATO);
} }
void printPreference(BayesNet net, TYPE type) {
List<ProbabilityAssignment> probs = EnumerateAll.enumerateAsk(new Variable(
FoodNetBuilder.TASTE, FoodNetBuilder.RATING_DOMAIN),
net, createQuery(type));
double max_val = 0.0;
String max_arg = "N/A";
for (ProbabilityAssignment p : probs) {
if (p.getProbability() > max_val) {
max_val = p.getProbability();
max_arg = p.getValue();
}
}
System.out.println("TASTE " + type + ": " + max_arg + " " + max_val);
}
List<Assignment> createQuery(TYPE type) {
List<Assignment> assignment = new LinkedList<Assignment>();
switch (type) {
case PORK:
case BEEF:
case POTATO:
case TOMATO:
assignment.add(new Assignment(new Variable(type.toString(), FoodNetBuilder.DOMAIN),
FoodNetBuilder.TRUE_VALUE));
break;
default:
}
return assignment;
} }
} }

View File

@@ -4,7 +4,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
@XStreamAlias("ing") @XStreamAlias("ing")
public class Ingredient { public class Ingredient {
public enum TYPE { ALCOHOL, DAIRY, EGGS, FISH, GLUTEN, GRAIN, NUTS, PORK, POULTRY, RED_MEAT, SHELLFISH, SPICE, SUGAR} public enum TYPE { ALCOHOL, BEEF, DAIRY, EGGS, FISH, GLUTEN, GRAIN, NUTS, PORK, POULTRY, POTATO, SHELLFISH, SPICE, SUGAR, TOMATO}
private String item; private String item;
@@ -14,20 +14,31 @@ public class Ingredient {
public boolean isType(TYPE type) { public boolean isType(TYPE type) {
switch (type) { switch (type) {
case BEEF :
return item.contains("beef");
case DAIRY : case DAIRY :
return item.contains("margarine"); return item.contains("margarine");
case EGGS : case EGGS :
return item.equals("egg") || item.equals("eggs"); return item.equals("egg") || item.equals("eggs");
case GLUTEN : case GLUTEN :
return item.contains("flour"); return item.contains("flour");
case RED_MEAT : case PORK :
return item.contains("beef"); return item.contains("pork");
case POTATO :
return item.contains("potato");
case SPICE : case SPICE :
return item.endsWith("cinnamon") || item.endsWith("nutmeg") || item.endsWith("cloves"); return item.endsWith("cinnamon") || item.endsWith("nutmeg") || item.endsWith("cloves");
case SUGAR : case SUGAR :
return item.endsWith("sugar"); return item.endsWith("sugar");
case TOMATO :
return item.contains("tomato");
default : //unknown ingredient, e.g. coffee, bananas, honey default : //unknown ingredient, e.g. coffee, bananas, honey
return false; return false;
} }
} }
public Object readResolve() {
item = item.toLowerCase();
return this;
}
} }

View File

@@ -15,6 +15,16 @@ public class RecipeBook {
return recipes.get(index); return recipes.get(index);
} }
//TODO build an index of recipes by name?
public Recipe getRecipe(String recipeName) {
for (Recipe recipe : recipes) {
if (recipeName.equalsIgnoreCase(recipe.getHead().getTitle())) {
return recipe;
}
}
return null;
}
public int getSize() { public int getSize() {
return recipes.size(); return recipes.size();
} }

View File

@@ -4,7 +4,7 @@ import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.util.LinkedList; import java.util.List;
import org.junit.Test; import org.junit.Test;
@@ -22,7 +22,7 @@ public class AlarmExampleTest {
BayesNet sprinkler = AlarmNetBuilderTable.alarm(); BayesNet sprinkler = AlarmNetBuilderTable.alarm();
sprinkler = AlarmNetBuilderTree.sprinkler(); sprinkler = AlarmNetBuilderTree.sprinkler();
// P(B | j, m) // P(B | j, m)
LinkedList<ProbabilityAssignment> probs = EnumerateAll.enumerateAsk( List<ProbabilityAssignment> probs = EnumerateAll.enumerateAsk(
new Variable(AlarmNetBuilderTable.BURGLARY, new Variable(AlarmNetBuilderTable.BURGLARY,
AlarmNetBuilderTable.DOMAIN), sprinkler, AlarmNetBuilderTable.DOMAIN), sprinkler,
AlarmNetBuilderTable.completeQueryBulgary()); AlarmNetBuilderTable.completeQueryBulgary());

View File

@@ -1,11 +1,11 @@
package dkohl.bayes.example; package dkohl.bayes.example;
import java.util.LinkedList;
import static org.hamcrest.core.IsEqual.equalTo; import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.util.List;
import org.junit.Test; import org.junit.Test;
import dkohl.bayes.bayesnet.BayesNet; import dkohl.bayes.bayesnet.BayesNet;
@@ -119,7 +119,7 @@ public class FoodExampleTest {
+ dist.getAssignments().get(assignment)); + dist.getAssignments().get(assignment));
} }
LinkedList<ProbabilityAssignment> probs = EnumerateAll.enumerateAsk( List<ProbabilityAssignment> probs = EnumerateAll.enumerateAsk(
new Variable(FoodExampleBuilder.TASTE, new Variable(FoodExampleBuilder.TASTE,
FoodExampleBuilder.RATING_DOMAIN), net, FoodExampleBuilder.RATING_DOMAIN), net,
FoodExampleBuilder.completeQueryTasteBeef()); FoodExampleBuilder.completeQueryTasteBeef());
@@ -145,7 +145,7 @@ public class FoodExampleTest {
} }
} }
System.out.println("TASE PORK: " + max_arg + " " + max_val); System.out.println("TASTE PORK: " + max_arg + " " + max_val);
assertThat(max_arg, equalTo("10")); assertThat(max_arg, equalTo("10"));
assertTrue("Error: max_val for TASTE_PORK should be > 2.6%", max_val > 0.026); assertTrue("Error: max_val for TASTE_PORK should be > 2.6%", max_val > 0.026);
} }

View File

@@ -3,6 +3,8 @@ package dkohl.bayes.example.builders;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import net.woodyfolsom.cs6601.p2.Ingredient.TYPE;
import dkohl.bayes.bayesnet.BayesNet; import dkohl.bayes.bayesnet.BayesNet;
import dkohl.bayes.estimation.MaximumLikelihoodEstimation; import dkohl.bayes.estimation.MaximumLikelihoodEstimation;
import dkohl.bayes.probability.Assignment; import dkohl.bayes.probability.Assignment;
@@ -21,13 +23,13 @@ public class FoodExampleBuilder {
public static final String SOMEONE_VEGETARIAN = "Vegetarian"; public static final String SOMEONE_VEGETARIAN = "Vegetarian";
public static final String CONTAINS_MEAT = "Meat"; public static final String CONTAINS_MEAT = "Meat";
public static final String CONTAINS_VEGETABLE = "Vegetable"; public static final String CONTAINS_VEGETABLE = "Vegetable";
public static final String CONTAINS_BEEF = "Beef"; public static final String CONTAINS_BEEF = TYPE.BEEF.toString();
public static final String CONTAINS_PORK = "Pork"; public static final String CONTAINS_PORK = TYPE.PORK.toString();
public static final String CONTAINS_TOMATOS = "Tomatos"; public static final String CONTAINS_TOMATOS = TYPE.TOMATO.toString();
public static final String CONTAINS_POTATOS = "Potatos"; public static final String CONTAINS_POTATOS = TYPE.POTATO.toString();
public static final String TRUE_VALUE = "true"; public static final String TRUE_VALUE = Boolean.TRUE.toString();
public static final String FALSE_VALUE = "false"; public static final String FALSE_VALUE = Boolean.FALSE.toString();
public static final String DOMAIN[] = { TRUE_VALUE, FALSE_VALUE }; public static final String DOMAIN[] = { TRUE_VALUE, FALSE_VALUE };

View File

@@ -29,7 +29,7 @@ public class RecipeBookReaderTest {
assertTrue(recipe.getIngredients().contains(TYPE.EGGS)); assertTrue(recipe.getIngredients().contains(TYPE.EGGS));
assertTrue(recipe.getIngredients().contains(TYPE.GLUTEN)); assertTrue(recipe.getIngredients().contains(TYPE.GLUTEN));
assertTrue(recipe.getIngredients().contains(TYPE.SPICE)); assertTrue(recipe.getIngredients().contains(TYPE.SPICE));
assertFalse(recipe.getIngredients().contains(TYPE.RED_MEAT)); assertFalse(recipe.getIngredients().contains(TYPE.BEEF));
assertFalse(recipe.getIngredients().contains(TYPE.POULTRY)); assertFalse(recipe.getIngredients().contains(TYPE.POULTRY));
assertFalse(recipe.getIngredients().contains(TYPE.SHELLFISH)); assertFalse(recipe.getIngredients().contains(TYPE.SHELLFISH));
@@ -37,4 +37,44 @@ public class RecipeBookReaderTest {
System.out.println(recipeBook.getRecipe(rIndex).getHead().getTitle()); System.out.println(recipeBook.getRecipe(rIndex).getHead().getTitle());
} }
} }
@Test
public void testReadShortSurveyDataset() {
RecipeBook recipeBook = RecipeBookReader.readRecipeBook(new File("data/short_recipebook.xml"));
assertNotNull(recipeBook);
assertThat(recipeBook.getSize(), is(equalTo(4)));
for (int i = 0; i < 4; i++) {
Recipe recipe = recipeBook.getRecipe(i);
System.out.println(i + ": " +recipe.getHead().getTitle());
}
Recipe recipe = recipeBook.getRecipe(0);
assertThat(recipe.getHead().getTitle(), is(equalTo("Catalan Rice")));
assertTrue(recipe.getIngredients().contains(TYPE.PORK));
assertFalse(recipe.getIngredients().contains(TYPE.BEEF));
assertFalse(recipe.getIngredients().contains(TYPE.POTATO));
assertTrue(recipe.getIngredients().contains(TYPE.TOMATO));
recipe = recipeBook.getRecipe(1);
assertThat(recipe.getHead().getTitle(), is(equalTo("Hamburger Steak")));
assertFalse(recipe.getIngredients().contains(TYPE.PORK));
assertTrue(recipe.getIngredients().contains(TYPE.BEEF));
assertFalse(recipe.getIngredients().contains(TYPE.POTATO));
assertFalse(recipe.getIngredients().contains(TYPE.TOMATO));
recipe = recipeBook.getRecipe(2);
assertThat(recipe.getHead().getTitle(), is(equalTo("Potatoes in a Thick Sauce")));
assertFalse(recipe.getIngredients().contains(TYPE.PORK));
assertFalse(recipe.getIngredients().contains(TYPE.BEEF));
assertTrue(recipe.getIngredients().contains(TYPE.POTATO));
assertTrue(recipe.getIngredients().contains(TYPE.TOMATO));
recipe = recipeBook.getRecipe(3);
assertThat(recipe.getHead().getTitle(), is(equalTo("Tomato-Zucchini Casserole")));
assertFalse(recipe.getIngredients().contains(TYPE.PORK));
assertFalse(recipe.getIngredients().contains(TYPE.BEEF));
assertFalse(recipe.getIngredients().contains(TYPE.POTATO));
assertTrue(recipe.getIngredients().contains(TYPE.TOMATO));
}
} }