Beispiel #1
0
func TestHarderAStar(t *testing.T) {
	tg := graph.NewTileGraph(3, 3, true)

	path, cost, _ := graph.AStar(graph.GonumNode(0), graph.GonumNode(8), tg, nil, nil)

	if math.Abs(cost-4.0) > .00001 || !graph.IsPath(path, tg) {
		t.Error("Non-optimal or impossible path found for 3x3 grid")
	}

	tg = graph.NewTileGraph(1000, 1000, true)
	path, cost, _ = graph.AStar(graph.GonumNode(00), graph.GonumNode(999*1000+999), tg, nil, nil)
	if !graph.IsPath(path, tg) || cost != 1998.0 {
		t.Error("Non-optimal or impossible path found for 100x100 grid; cost:", cost, "path:\n"+tg.PathString(path))
	}
}
Beispiel #2
0
func TestSimpleAStar(t *testing.T) {
	tg, err := graph.GenerateTileGraph("▀  ▀\n▀▀ ▀\n▀▀ ▀\n▀▀ ▀")
	if err != nil {
		t.Fatal("Couldn't generate tilegraph")
	}

	path, cost, _ := graph.AStar(graph.GonumNode(1), graph.GonumNode(14), tg, nil, nil)
	if math.Abs(cost-4.0) > .00001 {
		t.Errorf("A* reports incorrect cost for simple tilegraph search")
	}

	if path == nil {
		t.Fatalf("A* fails to find path for for simple tilegraph search")
	} else {
		correctPath := []int{1, 2, 6, 10, 14}
		if len(path) != len(correctPath) {
			t.Fatalf("Astar returns wrong length path for simple tilegraph search")
		}
		for i, node := range path {
			if node.ID() != correctPath[i] {
				t.Errorf("Astar returns wrong path at step", i, "got:", node, "actual:", correctPath[i])
			}
		}
	}
}
Beispiel #3
0
// Transform uses graphs to add network interfaces to Seeds
func Transform(orig *seed.Seed) (*seed.Seed, error) {
	// build graph
	g := seedGraph.SeedAsGraph(orig)

	orig.Name = strings.Title(orig.Name) + "Server"

	for inputName, input := range orig.Collections {
		if input.Type != seed.CollectionInput {
			continue
		}
		input.Key = append([]string{"@address"}, input.Key...)

		start, ok := g.NodeFor(inputName)
		if !ok {
			panic("could not find node for " + inputName)
		}

		for outputName, output := range orig.Collections {
			if output.Type != seed.CollectionOutput {
				continue
			}
			goal, ok := g.NodeFor(outputName)
			if !ok {
				panic("could not find node for " + outputName)
			}
			path, cost, _ := graph.AStar(start, goal, g, cost, nil)
			if math.IsInf(cost, 0) {
				// there is no path (that does not go through a table)
				continue
			}

			outputAddress := outputName + "_addr"
			previousCollection := inputName
			for _, node := range path[:len(path)] {
				// unbox graph.internalNode;
				node = g.GetNode(node.ID())

				switch node := node.(type) {
				case seedGraph.CollectionNode:
					previousCollection = node.Name
					switch node.Collection.Type {
					case seed.CollectionInput, seed.CollectionScratch:
						node.Collection.Key = prependIfNotExists(node.Collection.Key, outputAddress)
					case seed.CollectionOutput:
						node.Collection.Key = prependIfNotExists(node.Collection.Key, "@"+outputAddress)
					case seed.CollectionChannel, seed.CollectionTable:
						panic("should not encounter these collection types")
					default:
						panic(fmt.Sprintf("unhandled type: %d", node.Collection.Type))
					}
				case seedGraph.RuleNode:
					exists := false
					for _, expression := range node.Rule.Intension {
						switch expression := expression.(type) {
						case seed.QualifiedColumn:
							if expression.Column == outputAddress {
								// if a reference to the outputAddress already exists (i.e., from being added by another flow)
								// then add a constraint to make the rows match up
								node.Rule.Predicate = append(node.Rule.Predicate, seed.Constraint{
									Left: expression,
									Right: seed.QualifiedColumn{
										Collection: previousCollection,
										Column:     outputAddress,
									},
								})
								exists = true
							}
						case seed.MapFunction, seed.ReduceFunction:
							continue
						default:
							panic(fmt.Sprintf("unhandled type: %v", reflect.TypeOf(expression).String()))
						}
					}
					if !exists {
						// add to the projection
						node.Rule.Intension = append([]seed.Expression{seed.QualifiedColumn{
							Collection: previousCollection,
							Column:     outputAddress,
						}}, node.Rule.Intension...)
					}
				default:
					panic(fmt.Sprintf("unhandled type: %v", reflect.TypeOf(node).String()))
				}
			}
		}
	}

	// change inputs and outputs to channels
	for _, collection := range orig.Collections {
		switch collection.Type {
		case seed.CollectionInput, seed.CollectionOutput:
			collection.Type = seed.CollectionChannel
		case seed.CollectionScratch, seed.CollectionTable, seed.CollectionChannel:
			// no-op
		default:
			panic(collection.Type)
		}
	}

	// rules supplying channels must be asynchronous
	for _, rule := range orig.Rules {
		collectionName := rule.Supplies
		collection, ok := orig.Collections[collectionName]
		if !ok {
			// should never happen
			panic(collectionName)
		}

		if collection.Type == seed.CollectionChannel {
			rule.Operation = "<~"
		}
	}

	return orig, nil
}