private GraphNet LoadGraphNet() { //1: create a GraphNet for predicting if a super is good or bad var supers = new GraphNet("supers", maxPathLenght: 20); supers.LimitNumberOfPaths = true; supers.RegisterDynamic("enitiy", (node, graph) => { graph.Node(node, "word", node.ToString().Split('_')); Node.BaseOnAdd(node, graph); }); supers.AddDynamic("enitiy", "spider_man", "is_a", "hero"); supers.AddDynamic("enitiy", "hulk", "is_a", "hero"); supers.AddDynamic("enitiy", "green_goblin", "is_a", "villain"); supers.AddDynamic("enitiy", "red_king", "is_a", "villain"); supers.Add("red", "a", "colour"); supers.Add("green", "a", "colour"); supers.Add("blue", "a", "colour"); supers.Add("hero", "is", "good", true); supers.Add("villain", "is", "bad", true); //2: create a GraphNet that knows about cities var cities = new GraphNet("cities", maxNumberOfPaths: 20); cities.Add("london", "is_a", "city"); cities.Add("paris", "is_a", "city"); cities.Add("uk", "is_a", "country"); cities.Add("france", "is_a", "country"); cities.Add("paris", "capital_of", "france"); cities.Add("london", "capital_of", "uk"); var yes = cities.Node(cities.Node(true), "input", "country", "city", "london", "paris", "uk", "france"); var no = cities.Node(cities.Node(false), "input", "country", "city", "london", "paris", "uk", "france"); cities.Add(yes, true); cities.Add(no, true); //3: create a GraphNet that can do caculations var calc = new GraphNet("calc", maxPathLenght: 20, maxNumberOfPaths: 20); calc.LimitNumberOfPaths = true; calc.Add("add_opp", "lable", "+"); calc.Add("times_opp", "lable", "*"); calc.Add("times_opp", "lable", "x"); calc.Add("minus_opp", "lable", "-"); calc.Add(new Node("number")); calc.Add(new Node("a")); calc.Add(new Node("word")); Func <List <NodePath>, IEnumerable <int> > pullNumbers = (paths) => { var numbers = paths.Where(p => p[2].Value.ToString() != "" && p[2].Value.ToString().All(char.IsDigit) && p[4].Equals(calc.Node("number"))) .Select(p => int.Parse(p[2].Value.ToString())).Distinct(); return(numbers); }; var sum = new DynamicNode("sum" , onProcess: (node, graph, input, paths) => node.Result = pullNumbers(paths).Sum()); sum.AddEdge("input", "number", calc); sum.AddEdge("opp", "add_opp", calc); calc.Add(sum, true); //subtract var minus = (new DynamicNode("minus" , onProcess: (node, graph, input, paths) => { var n = pullNumbers(paths); if (n.Count() > 0) { node.Result = n.Aggregate((a, b) => a - b); } })); minus.AddEdge("input", "number", calc); minus.AddEdge("opp", "minus_opp", calc); calc.Add(minus, true); //multiply var times = new DynamicNode("times" , onProcess: (node, graph, input, paths) => node.Result = pullNumbers(paths).Aggregate(1, (acc, val) => acc * val)); times.AddEdge("input", "number", calc); times.AddEdge("opp", "times_opp", calc); calc.Add(times, true); //4: create a GraphNet for parsing text var nlp = new GraphNet("nlp", maxNumberOfPaths: 10, maxPathLenght: 10); nlp.Add(new DynamicNode("nlp_out", (node, graph) => { node.Result = graph.AllEdges(); }), true); nlp.RegisterDynamic("parse", (node, graph) => { //add word nodes and mark if they are numbers nlp.Node(node, "word", node.ToString().Split(' ')); foreach (var word in node.Edges.Select(e => e.Obj).ToList()) { if (word.ToString().All(char.IsDigit)) { var edge = new Edge(word, nlp.Node("a"), nlp.Node("number")) { Internal = true }; word.Edges.Add(edge); } } Node.BaseOnAdd(node, graph); }); //5: create the master GraphNet that contains the other GraphNets as nodes within it var gn = new GraphNet("Master", maxNumberOfPaths: 20, maxPathLenght: 20); gn.LimitNumberOfPaths = true; gn.RegisterDynamic("ask", (node, graph) => { Node ask = nlp.DynamicNode("parse")(node.Value.ToString()); //TODO: this would be better: node.AddEdge(graph.Node("nlp"), ask); nlp.Add(ask); node.Edges = nlp.AllEdges(); nlp.Remove(ask); Node.BaseOnAdd(node, graph); }); gn.DefaultInput = "ask"; gn.Add(supers, true); gn.Add(cities, true); gn.Add(calc, true); gn.LimitNumberOfPaths = true; //train the master GraphNet with some examples gn.Train( new Example(gn.Node("spider man"), "good"), new Example(gn.Node("green goblin"), "bad"), new Example(gn.Node("4 + 1"), 5), new Example(gn.Node("12 - 10"), 2), new Example(gn.Node("5 * 3"), 15), new Example(gn.Node("london is a city"), true), new Example(gn.Node("london is a country"), false), new Example(gn.Node("uk is a country"), true), new Example(gn.Node("uk is a city"), false) ); return(gn); }
public void TestNestedGraphNets() { //GraphNets are nodes themselves so they can be added into another GraphNets //1: create a GraphNet for predicting if a super is good or bad var supers = new GraphNet("supers", maxPathLenght: 20); supers.RegisterDynamic("enitiy", (node, graph) => { graph.Node(node, "word", node.ToString().Split('_')); Node.BaseOnAdd(node, graph); }); supers.AddDynamic("enitiy", "spider_man", "is_a", "hero"); supers.AddDynamic("enitiy", "hulk", "is_a", "hero"); supers.AddDynamic("enitiy", "green_goblin", "is_a", "villain"); supers.AddDynamic("enitiy", "red_king", "is_a", "villain"); supers.Add("hero", "is", "good", true); supers.Add("villain", "is", "bad", true); //2: create a GraphNet that knows about cities var cities = new GraphNet("cities", maxNumberOfPaths: 20); cities.Add("london", "is_a", "city"); cities.Add("paris", "is_a", "city"); cities.Add("uk", "is_a", "country"); cities.Add("france", "is_a", "country"); cities.Add("paris", "capital_of", "france"); cities.Add("london", "capital_of", "uk"); var yes = cities.Node(cities.Node(true), "input", "country", "city", "london", "paris", "uk", "france"); var no = cities.Node(cities.Node(false), "input", "country", "city", "london", "paris", "uk", "france"); cities.Add(yes, true); cities.Add(no, true); //3: create a GraphNet that can do caculations var calc = new GraphNet("calc", maxPathLenght: 20); calc.Add("add_opp", "lable", "+"); calc.Add(new Node("number")); Func <List <NodePath>, IEnumerable <int> > pullNumbers = (paths) => { var numbers = paths.Where(p => p[2].Value.ToString().All(char.IsDigit) && p[4].Equals(calc.Node("number"))) .Select(p => int.Parse(p[2].Value.ToString())) .Distinct(); return(numbers); }; var sum = new DynamicNode("sum" , onProcess: (node, graph, input, paths) => node.Result = pullNumbers(paths).Sum()); sum.AddEdge("input", "number", calc); sum.AddEdge("opp", "add_opp", calc); calc.Add(sum, true); //4: create a GraphNet for parsing text var nlp = new GraphNet("nlp", maxNumberOfPaths: 5, maxPathLenght: 20); nlp.Add(new DynamicNode("nlp_out", (node, graph) => { node.Result = graph.AllEdges(); }), true); nlp.RegisterDynamic("parse", (node, graph) => { //add word nodes and mark if they are numbers nlp.Node(node, "word", node.ToString().Split(' ')); foreach (var word in node.Edges.Select(e => e.Obj).ToList()) { if (word.ToString().All(char.IsDigit)) { var edge = new Edge(word, nlp.Node("a"), nlp.Node("number")) { Internal = true }; word.Edges.Add(edge); } } Node.BaseOnAdd(node, graph); }); //5: create the master GraphNet that contains the other GraphNets as nodes within it var gn = new GraphNet("gn", maxNumberOfPaths: 20, maxPathLenght: 20); gn.RegisterDynamic("ask", (node, graph) => { Node ask = nlp.DynamicNode("parse")(node.Value.ToString()); //TODO: this would be better: node.AddEdge(graph.Node("nlp"), ask); nlp.Add(ask); node.Edges = nlp.AllEdges(); nlp.Remove(ask); Node.BaseOnAdd(node, graph); }); gn.DefaultInput = "ask"; gn.Add(supers, true); gn.Add(cities, true); gn.Add(calc, true); //gn.LimitNumberOfPaths = true; //train the master GraphNet with some examples gn.Train( new Example(gn.Node("spider man"), "good"), new Example(gn.Node("4 + 1"), 5), new Example(gn.Node("10 + 12"), 22), new Example(gn.Node("green goblin"), "bad"), new Example(gn.Node("london is a city"), true), new Example(gn.Node("london is a country"), false), new Example(gn.Node("uk is a country"), true), new Example(gn.Node("uk is a city"), false) ); //this master GraphNet can parse text and answer different types of questions: Assert.AreEqual("good", gn.Predict("hulk")); Assert.AreEqual("bad", gn.Predict("red king")); Assert.AreEqual(17, gn.Predict("5 + 12")); Assert.AreEqual(27, gn.Predict("7 + 20")); Assert.AreEqual(false, gn.Predict("paris is a country")); Assert.AreEqual(true, gn.Predict("paris is a city")); //TODO: Assert.AreEqual(27, gn.Predict("7 + 7")); }
private GraphNet LoadCalcGraph() { var calc = new GraphNet("calc", maxPathLenght: 20, maxNumberOfPaths: 20); calc.LimitNumberOfPaths = true; calc.Add("add_opp", "lable", "+"); calc.Add("times_opp", "lable", "*"); calc.Add("times_opp", "lable", "x"); calc.Add("minus_opp", "lable", "-"); calc.Add(new Node("number")); calc.Add(new Node("a")); calc.Add(new Node("word")); Func <List <NodePath>, IEnumerable <int> > pullNumbers = (paths) => { var numbers = paths.Where(p => p[2].Value.ToString() != "" && p[2].Value.ToString().All(char.IsDigit) && p[4].Equals(calc.Node("number"))) .Select(p => int.Parse(p[2].Value.ToString())).Distinct(); return(numbers); }; var sum = new DynamicNode("sum" , onProcess: (node, graph, input, paths) => node.Result = pullNumbers(paths).Sum()); sum.AddEdge("input", "number", calc); sum.AddEdge("opp", "add_opp", calc); calc.Add(sum, true); //subtract var minus = (new DynamicNode("minus" , onProcess: (node, graph, input, paths) => { var n = pullNumbers(paths); if (n.Count() > 0) { node.Result = n.Aggregate((a, b) => a - b); } })); minus.AddEdge("input", "number", calc); minus.AddEdge("opp", "minus_opp", calc); calc.Add(minus, true); //multiply var times = new DynamicNode("times" , onProcess: (node, graph, input, paths) => node.Result = pullNumbers(paths).Aggregate(1, (acc, val) => acc * val)); times.AddEdge("input", "number", calc); times.AddEdge("opp", "times_opp", calc); calc.Add(times, true); calc.RegisterDynamic("parse", (node, graph) => { //add nodes for words var words = node.Value.ToString().Split(' '); graph.Node(node, "word", words); //mark any of those words that are numbers by adding an edge to the number node foreach (var e in node.Edges.ToArray().Where(e => e.Obj.ToString().All(char.IsDigit))) { e.Obj.AddEdge(graph.Node("a"), graph.Node("number")); } Node.BaseOnAdd(node, graph); }); calc.DefaultInput = "parse"; calc.Train(new Example(calc.Node("4 + 1"), 5), new Example(calc.Node("12 - 10"), 2), new Example(calc.Node("5 * 3"), 15)); return(calc); }
public void Calculator() { //create small graph of maths operators var gn = new GraphNet("calc"); gn.Add("add_opp", "lable", "+"); gn.Add("times_opp", "lable", "*"); gn.Add("times_opp", "lable", "x"); gn.Add("minus_opp", "lable", "-"); gn.Add(new Node("number")); gn.Add(new Node("a")); gn.Add(new Node("word")); //and some output nodes that can do maths opperations (add,subtract and multiply) //these nodes pull all the numbers from the paths through the graph and apply their operation on them Func <List <NodePath>, IEnumerable <int> > pullNumbers = (paths) => { var numbers = paths.Where(p => p[2].Value.ToString().All(char.IsDigit) && p[4].Equals(gn.Node("number"))) .Select(p => int.Parse(p[2].Value.ToString())); return(numbers); }; //add var sum = new DynamicNode("sum", onProcess: (node, graph, input, paths) => node.Result = pullNumbers(paths).Sum()); sum.AddEdge("input", "number", gn); sum.AddEdge("opp", "add_opp", gn); gn.Add(sum, true); //subtract var minus = new DynamicNode("minus" , onProcess: (node, graph, input, paths) => { var n = pullNumbers(paths); if (n.Count() > 0) { node.Result = n.Aggregate((a, b) => a - b); } }); minus.AddEdge("input", "number", gn); minus.AddEdge("opp", "minus_opp", gn); gn.Add(minus, true); //multiply var times = new DynamicNode("times", onProcess: (node, graph, input, paths) => node.Result = pullNumbers(paths).Aggregate(1, (acc, val) => acc * val)); times.AddEdge("input", "number", gn); times.AddEdge("opp", "times_opp", gn); gn.Add(times, true); //then we register a tokeniser that adds the word nodes and marks any numbers gn.RegisterDynamic("parse", (node, graph) => { //add nodes for words var words = node.Value.ToString().Split(' '); gn.Node(node, "word", words); //mark any of those words that are numbers by adding an edge to the number node foreach (var e in node.Edges.Where(e => e.Obj.ToString().All(char.IsDigit))) { e.Obj.AddEdge(gn.Node("a"), gn.Node("number")); } Node.BaseOnAdd(node, graph); }); //teach it the basic math funcitons gn.Train( new NodeExample(gn.DynamicNode("parse")("1 + 2"), gn.Node("sum")) , new NodeExample(gn.DynamicNode("parse")("1 - 2"), gn.Node("minus")) , new NodeExample(gn.DynamicNode("parse")("1 * 2"), gn.Node("times")) ); //test Assert.AreEqual(15, gn.Predict(gn.DynamicNode("parse")("5 + 10"))); Assert.AreEqual(2, gn.Predict(gn.DynamicNode("parse")("5 - 3"))); Assert.AreEqual(4, gn.Predict(gn.DynamicNode("parse")("what is 5 - 1"))); Assert.AreEqual(21, gn.Predict(gn.DynamicNode("parse")("3 * 7"))); Assert.AreEqual(15, gn.Predict(gn.DynamicNode("parse")("3 x 5"))); }