I'd like to group some nodes with the following code
digraph dataflow {
subgraph pipeline {
relations;
synonyms;
articles;
}
subgraph lucene {
index;
search;
}
training_data - > index;
relations - > search;
synonyms - > index;
articles - > index;
training_data - > evaluation;
}
But dot doesn't care about the subgraphs:
Try prefixing your subgraphs with 'cluster_':
digraph dataflow {
subgraph cluster_pipeline {
relations;
synonyms;
articles;
}
subgraph cluster_lucene {
index;
search;
}
training_data -> index;
relations -> search;
synonyms -> index;
articles -> index;
training_data -> evaluation;
}
Related
The task
I have a list of Objects "Point" and a filtered version of it: allPoints and pointsFromStepTwo, where stepTwo is an other method. I need to add to list, that i got from stepTwo, all Point, which are match to condition that aplied to allPoints and pointsFromStepTwo at the same time.
The code looks kind like:
public List<Point> stepThree(List<Point> pointsFromStepTwo, List<Point> allPoints) {
return allPoints.stream()
.filter(point -> point.getRadius() + {pointsFromStepTwo.stream().forEach(point1 -> point1.getRadius()); > smth })
}.collect(Collectors.toList());
where "smth" is a special condition.
The problem
I can't find a correct way to return values from pointsFromStepTwo to points from allPoint every time.
Basically it is a for loop inside a for loop. I think that will work:
public List<Point> stepThree(List<Point> pointsFromStepTwo, List<Point> allPoints) {
Set<Point> tmp = new HashSet<>();
for (Point point1 : allPoints) {
for (Point point2 : pointsFromStepTwo) {
if (point1.equals(point2) ||
point1.getRadius() + point2.getRadius() + getGap() + getErr() >= getL(point1, point2)) {
tmp.add(point2);
}
}
}
return new ArrayList<>(tmp);
}
where getL(point1, point2) is a special condition
Use anyMatch instead of forEach:
public List<Point> stepThree(List<Point> pointsFromStepTwo, List<Point> allPoints)
{
return allPoints.stream()
.filter(point2 -> pointsFromStepTwo.stream()
.anyMatch(point1 -> point1.getRadius() + point2.getRadius() >= getL(point1, point2)))
.collect(Collectors.toList());
}
EDIT: It looks like you want the output List to contain all the points of pointsFromStepTwo. If you don't care about the order, then (assuming all the points of pointsFromStepTwo belong to `allPoints), you can add a condition to the filter:
public List<Point> stepThree(List<Point> pointsFromStepTwo, List<Point> allPoints)
{
return allPoints.stream()
.filter(point2 -> pointsFromStepTwo.stream()
.anyMatch(point1 -> point2.equals(point1) || (point1.getRadius() + point2.getRadius() >= getL(point1, point2))))
.collect(Collectors.toList());
}
I am new to Binary Tree Search Tree. Using recursion, i am finding the distance between two nodes of binary search Tree. If there is better approach .Please share your suggestion. It will help me to learn more.
boolean found=false;
int distanceBetweenTwoNodeOfBST(Node node,int firstElement,int secondElement){
if(firstElement==secondElement){
return 0;
}
if(node==null){
return 0;
}else{
if(node.element==firstElement || node.element==secondElement){
int leftDis=distanceBetweenTwoNodeOfBST(node.left, firstElement, secondElement);
int rightDis=distanceBetweenTwoNodeOfBST(node.right, firstElement, secondElement);
if(leftDis>0 || rightDis>0){
found=true;
}
if(leftDis> 0){
--leftDis;
}
if(rightDis>0){
--rightDis;
}
return 1+leftDis+rightDis;
}
int firstElementCount=distanceBetweenTwoNodeOfBST(node.left, firstElement, secondElement); // Going to left Subtree
int secondELementCount=distanceBetweenTwoNodeOfBST(node.right, firstElement, secondElement); // Going to right Subtree
if(firstElementCount>0 && secondELementCount>0){ // It means Least Common Ancestor is found
found=true;
return firstElementCount+secondELementCount;
}else if(firstElementCount>0) {
if(found){
return firstElementCount;
}else
return firstElementCount+1;
}else if(secondELementCount>0){
if(found) return secondELementCount;
else return secondELementCount+1;
}else{
return 0;
}
}
}
Note -: If there is other better approach please share the suggestion. I am new to this.
I implemented the min-max algorithm on a tree. The algorithm I created is working as intented, returning the path in the tree that corresponds to the min and max values. But my problem is that it doesn't feel right. My question is , is that a correct implementation of the min-max algorithm?
I couldn't find a pure implementation of the algorithm in a tree structure that consists of nodes. On the examples I manages to find ,people implemented the algorithm to solve problems related to games (tic-tac-toe). To be honest I felt stupid I couldn't make the connection.
I used 2 functions ,
1->evaluations_function which traverses the tree and adds value to nodes that don't have (a.k.a. all nodes that are not leaves).
2->print_optimal which traverses the tree and returns the path .
public void evaluation_function(Node root, int maxHeight, int rootHeight) {
if (root.childrenList.Count != 0) {
foreach (Node node in root.childrenList) {
evaluation_function(node, maxHeight, rootHeight);
}
}
if (root.height != rootHeight) {
if ((root.height % 2) == 0) {
if (root.value < root.parent.value || root.parent.value == 123456) {
root.parent.value = root.value;
}
} else if ((root.height % 2) != 0) {
if (root.value > root.parent.value || root.parent.value == 123456) {
root.parent.value = root.value;
}
}
}
}
And here is print_optimal
public void print_optimal(Node root) {
int maxValue = 0;
int minValue = 9999;
if (root.childrenList.Count != 0) {
if (root.height % 2 == 0) {
foreach (Node child in root.childrenList) {
if (child.value > maxValue) { maxValue = child.value; }
}
foreach (Node child in root.childrenList) {
if (child.value == maxValue) {
Console.WriteLine("Selected node " + child.name
+ " with value = " + child.value + " as MAX player");
print_optimal(child);
}
}
} else {
foreach (Node child in root.childrenList) {
if (child.value < minValue) { minValue = child.value; }
}
foreach (Node child in root.childrenList) {
if (child.value == minValue) {
Console.WriteLine("Selected node " + child.name
+ " with value = " + child.value + " as MIN player");
print_optimal(child);
}
}
}
}
}
I don't want to swarm the question with code , as my question is theoretical. But if you want to see the data struct or want to test the algorithm you can find it here : https://github.com/AcidDreamer/AI_Exercises/tree/master/1.2.1/Exercise1_2_1/Exercise1_2_1
IMPROVEMENT
evaluation_function changed to
public void evaluation_function(Node root, int rootHeight) {
if (root.childrenList.Count != 0) {
foreach (Node node in root.childrenList) {
evaluation_function(node, rootHeight);
}
}
if (root.height != rootHeight || root.childrenList.Count != 0) {
int maxValue = 0, minValue = 999;
if ((root.height % 2) == 0) {
foreach (Node child in root.childrenList) {
if (maxValue < child.value) {
maxValue = child.value;
root.value = maxValue;
root.bestChild = child;
}
}
} else if ((root.height % 2) != 0) {
foreach (Node child in root.childrenList) {
if (minValue > child.value) {
minValue = child.value;
root.value = minValue;
root.bestChild = child;
}
}
}
}
}
giving values to the current nodes.
print_optimal had a huge improvement using a bestChild field and is changed to
public void print_optimal(Node root) {
if (root.bestChild != null) {
Console.Write(root.name + "->");
print_optimal(root.bestChild);
} else {
Console.WriteLine(root.name);
}
}
I find it a little unnatural that the evaluation_function, which receives a Node as input, actually updates the value for the parent node.
I feel that a better approach would be for that function to update the current node instead.
It should do nothing if the current node is a leaf.
Otherwise, it should iterate through all the children (as it currently does in the first loop), and after each recursive call for a child, it should also check whether the current node value should be updated (i.e. a better value was just encountered, for the current child).
In addition, it is possible to add an additional field to each node, e.g. bestChild, or bestMove, to avoid re-iterating through children when calling print-optimal.
Overall your code is good (which you knew, since it works), but I have some remarks about improvements:
evaluation_function: you do not use maxHeight at all. Use it or remove the parameter. It's weird (kind of bad practice) that the function changes the parents of the current node. It should rather look at the children's values (if not leaf), and update the current node's value depending on that. Besides, you could add a field to keep track of the best child (or even of the selected path to a leaf) to avoid the matching process in print_optimal.
print_optimal(): You currently have a problem if 2 children have the same values: you'll print both of them and explore both trees. Checking if (child.value < minValue) { minValue = child.value; } is useless since you assume you've already used evaluation_function(), and it is not enough to "replace" evaluation_function if you had forgotten to do so.
here is my problem,
I have a List<A> lista1, what I should do is :
map<key, List<A>> m = groupby(lista1);
m = lista.stream.collect(Collectors.groupingBy);
for every group, return one element with some condition, and make a new list List<A> lista2 = MakeListfromGroup(m)
List<A> lista2;
for (Map.Entry<key, List<A>> entry : m.entrySet()) {
A theOne;
for (A a : entry.getValue()) {
if(condition){
theOne = a;
}
}
lista2.add(theOne);
}
return lista2;
List<B> listb1 = makeListB(lista2); //here, I cant use stream.map.collect
List<Integer> b1Key;
List<Integer> b2Key;
for(A a : lista2){
b1key.add(a.b1key);
b2key.add(a.b2key);
}
mapb1 = gerfromBD(b1key);
mapb2 = gerfromBD(b2key);
List<B> listb1;
for(A a : lista2){
listb1.add(new B(mapb1.get(a.b1key),mapb2.get(a.b2key));
}
return listb1
B has member B1 b1 and B2 b2, create a new List<B> listb2= applyFilter(list<predicate<B1>>,list<predicate<B2>>)
List<B> listb2;
nextb:
for(B b : listb1){
for(Predicate p: filtreB1){
if(!p.accept(b.b1)){
continue nextb;
}
}
for(Predicate p: filtreB2){
if(!p.accept(b.b2)){
continue nextb;
}
}
listb2.add(b);
}
return listb2;
Is it possible to put all in one stream? or do the step 4 in a stream way?
thanks in advance
For the next question, please provide real code instead of incomplete, typo ridden pseudo code.
As you need the complete list of As for step 3, you have to collect any potential stream from step 2 into a list anyway. Step 2 and 4 can be simplified by using streams, though:
public static List<A> makeListfromGroup(Map<Object, List<A>> m, Predicate<A> condition)
{
return m.values()
.stream()
.map(as -> as.stream().filter(condition).findAny().orElse(null))
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
For step 4, you can read how to apply multiple conditions at once here:
public static List<B> applyFilter(List<B> list, List<Predicate<B1>> filtreB1, List<Predicate<B2>> filtreB2)
{
return list.stream()
.filter(b -> filtreB1.stream().allMatch(p -> p.test(b.getB1())))
.filter(b -> filtreB2.stream().allMatch(p -> p.test(b.getB2())))
.collect(Collectors.toList());
}
Let's say I have such map:
#####
..###
W.###
. is a discovered cell.
# is an undiscovered cell.
W is a worker. There can be many workers. Each of them can move once per turn. In one turn he can move by one cell in 4 directions (up, right, down or left). He discovers all 8 cells around him - turns # into .. In one turn, there can be maximum one worker on the same cell.
Maps are not always rectangular. In the beginning all cells are undiscovered, except the neighbours of W.
The goal is to make all the cells discovered, in as least turns as possible.
First approach
Find the nearest # and go towards it. Repeat.
To find the nearest # I start BFS from W and finish it when first # is found.
On exemplary map it can give such solution:
##### ##### ##### ##### ##... #.... .....
..### ...## ....# ..... ...W. ..W.. .W...
W.### .W.## ..W.# ...W. ..... ..... .....
6 turns. Pretty far from optimal:
##### ..### ...## ....# .....
..### W.### .W.## ..W.# ...W.
W.### ..### ...## ....# .....
4 turns.
Question
What is the algorithm that discovers all the cells with as least turns as possible?
Here is a basic idea that uses A*. It is probably quite time- and memory-consuming, but it is guaranteed to return an optimal solution and is definitely better than brute force.
The nodes for A* will be the various states, i.e. where the workers are positioned and the discovery state of all cells. Each unique state represents a different node.
Edges will be all possible transitions. One worker has four possible transitions. For more workers, you will need every possible combination (about 4^n edges). This is the part where you can constrain the workers to remain within the grid and not to overlap.
The cost will be the number of turns. The heuristic to approximate the distance to the goal (all cells discovered) can be developed as follows:
A single worker can discover at most three cells per turn. Thus, n workers can discover at most 3*n cells. The minimum number of remaining turns is therefore "number of undiscovered cells / (3 * worker count)". This is the heuristic to use. This could even be improved by determining the maximum number of cells that each worker can discover in the next turn (will be max. 3 per worker). So overall heuristic would be "(undiscorvered cells - discoverable cells) / (3 * workers) + 1".
In each step you examine the node with the least overall cost (turns so far + heuristic). For the examined node, you calculate the costs for each surrounding node (possible movements of all workers) and go on.
Strictly speaking, the main part of this answer may be considered as "Not An Answer". So to first cover the actual question:
What is the algorithm that discovers all the cells with as least turns as possible?
Answer: In each step, you can compute all possible successors of the current state. Then the successors of these successors. This can be repeated recursively, until one of the successors contains no more #-fields. The sequence of states through which this successor was reached is optimal regarding the number of moves that have been necessary to reach this state.
So far, this is trivial. But of course, this is not feasible for a "large" map and/or a "large" number of workers.
As mentioned in the comments: I think that finding the optimal solution may be an NP-complete problem. In any case, it's most likely at least a tremendously complicated optimization problem where you may employ some rather sophisticated techniques to find the optimal solution in optimal time.
So, IMHO, the only feasible approach for tackling this are heuristics.
Several approaches can be imagined here. However, I wanted to give it a try, with a very simple approach. The following MCVE accepts the definition of the map as a rectangular string (empty spaces represent "invalid" regions, so it's possible to represent non-rectangular maps with that). The workers are simply enumerated, from 0 to 9 (limited to this number, at the moment). The string is converted into a MapState that consists of the actual map, as well as the paths that the workers have gone through until then.
The actual search here is a "greedy" version of the exhaustive search that I described in the first paragraph: Given an initial state, it computes all successor states. These are the states where each worker has moved in either direction (e.g. 64 states for 3 workers - of course these are "filtered" to make sure that workers don't leave the map or move to the same field).
These successor states are stored in a list. Then it searches the list for the "best" state, and again computes all successors of this "best" state and stores them in the list. Sooner or later, the list contains a state where no fields are missing.
The definition of the "best" state is where the heuristics come into play: A state is "better" than another when there are fewer fields missing (unvisited). When two states have an equal number of missing fields, then the average distance of the workers to the next unvisited fields serves as the criterion to decide which one is "better".
This finds and a solution for the example that is contained in the code below rather quickly, and prints it as the lists of positions that each worker has to visit in each turn.
Of course, this will also not be applicable to "really large" maps or "many" workers, because the list of states will grow rather quickly (one could consider dropping the "worst" solutions to speed this up a little, but this may have caveats, like being stuck in local optima). Additionally, one can easily think of cases where the "greedy" strategy does not give optimal results. But until someone posts an MVCE that always computes the optimal solution in polynomial time, maybe someone finds this interesting or helpful.
import java.awt.Point;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class MapExplorerTest
{
public static void main(String[] args)
{
String mapString =
" ### ######"+"\n"+
" ### ###1##"+"\n"+
"###############"+"\n"+
"#0#############"+"\n"+
"###############"+"\n"+
"###############"+"\n"+
"###############"+"\n"+
"###############"+"\n"+
"###############"+"\n"+
"###############"+"\n"+
"##### #######"+"\n"+
"##### #######"+"\n"+
"##### #######"+"\n"+
"###############"+"\n"+
"###############"+"\n"+
"###############"+"\n"+
"### ######2##"+"\n"+
"### #########"+"\n";
MapExplorer m = new MapExplorer(mapString);
MapState solution = m.computeSolutionGreedy();
System.out.println(solution.createString());
}
}
class MapState
{
private int rows;
private int cols;
private char map[][];
List<List<Point>> workerPaths;
private int missingFields = -1;
MapState(String mapString)
{
workerPaths = new ArrayList<List<Point>>();
rows = countLines(mapString);
cols = mapString.indexOf("\n");
map = new char[rows][cols];
String s = mapString.replaceAll("\\n", "");
for (int r=0; r<rows; r++)
{
for (int c=0; c<cols; c++)
{
int i = c+r*cols;
char ch = s.charAt(i);
map[r][c] = ch;
if (Character.isDigit(ch))
{
int workerIndex = ch - '0';
while (workerPaths.size() <= workerIndex)
{
workerPaths.add(new ArrayList<Point>());
}
Point p = new Point(r, c);
workerPaths.get(workerIndex).add(p);
}
}
}
}
MapState(MapState other)
{
this.rows = other.rows;
this.cols = other.cols;
this.map = new char[other.map.length][];
for (int i=0; i<other.map.length; i++)
{
this.map[i] = other.map[i].clone();
}
this.workerPaths = new ArrayList<List<Point>>();
for (List<Point> otherWorkerPath : other.workerPaths)
{
this.workerPaths.add(MapExplorer.copy(otherWorkerPath));
}
}
int distanceToMissing(Point p0)
{
if (getMissingFields() == 0)
{
return -1;
}
List<Point> points = new ArrayList<Point>();
Map<Point, Integer> distances = new HashMap<Point, Integer>();
distances.put(p0, 0);
points.add(p0);
while (!points.isEmpty())
{
Point p = points.remove(0);
List<Point> successors = MapExplorer.computeSuccessors(p);
for (Point s : successors)
{
if (!isValid(p))
{
continue;
}
if (map[p.x][p.y] == '#')
{
return distances.get(p)+1;
}
if (!distances.containsKey(s))
{
distances.put(s, distances.get(p)+1);
points.add(s);
}
}
}
return -1;
}
double averageDistanceToMissing()
{
double d = 0;
for (List<Point> workerPath : workerPaths)
{
Point p = workerPath.get(workerPath.size()-1);
d += distanceToMissing(p);
}
return d / workerPaths.size();
}
int getMissingFields()
{
if (missingFields == -1)
{
missingFields = countMissingFields();
}
return missingFields;
}
private int countMissingFields()
{
int count = 0;
for (int r=0; r<rows; r++)
{
for (int c=0; c<cols; c++)
{
if (map[r][c] == '#')
{
count++;
}
}
}
return count;
}
void update()
{
for (List<Point> workerPath : workerPaths)
{
Point p = workerPath.get(workerPath.size()-1);
for (int dr=-1; dr<=1; dr++)
{
for (int dc=-1; dc<=1; dc++)
{
if (dr == 0 && dc == 0)
{
continue;
}
int nr = p.x + dr;
int nc = p.y + dc;
if (!isValid(nr, nc))
{
continue;
}
if (map[nr][nc] != '#')
{
continue;
}
map[nr][nc] = '.';
}
}
}
}
public void updateWorkerPosition(int w, Point p)
{
List<Point> workerPath = workerPaths.get(w);
Point old = workerPath.get(workerPath.size()-1);
char oc = map[old.x][old.y];
char nc = map[p.x][p.y];
map[old.x][old.y] = nc;
map[p.x][p.y] = oc;
}
boolean isValid(int r, int c)
{
if (r < 0) return false;
if (r >= rows) return false;
if (c < 0) return false;
if (c >= cols) return false;
if (map[r][c] == ' ')
{
return false;
}
return true;
}
boolean isValid(Point p)
{
return isValid(p.x, p.y);
}
private static int countLines(String s)
{
int count = 0;
while (s.contains("\n"))
{
s = s.replaceFirst("\\\n", "");
count++;
}
return count;
}
public String createMapString()
{
StringBuilder sb = new StringBuilder();
for (int r=0; r<rows; r++)
{
for (int c=0; c<cols; c++)
{
sb.append(map[r][c]);
}
sb.append("\n");
}
return sb.toString();
}
public String createString()
{
StringBuilder sb = new StringBuilder();
for (List<Point> workerPath : workerPaths)
{
Point p = workerPath.get(workerPath.size()-1);
int d = distanceToMissing(p);
sb.append(workerPath).append(", distance: "+d+"\n");
}
sb.append(createMapString());
sb.append("Missing "+getMissingFields());
return sb.toString();
}
}
class MapExplorer
{
MapState mapState;
public MapExplorer(String mapString)
{
mapState = new MapState(mapString);
mapState.update();
computeSuccessors(mapState);
}
static List<Point> copy(List<Point> list)
{
List<Point> result = new ArrayList<Point>();
for (Point p : list)
{
result.add(new Point(p));
}
return result;
}
public MapState computeSolutionGreedy()
{
Comparator<MapState> comparator = new Comparator<MapState>()
{
#Override
public int compare(MapState ms0, MapState ms1)
{
int m0 = ms0.getMissingFields();
int m1 = ms1.getMissingFields();
if (m0 != m1)
{
return m0-m1;
}
double d0 = ms0.averageDistanceToMissing();
double d1 = ms1.averageDistanceToMissing();
return Double.compare(d0, d1);
}
};
Set<MapState> handled = new HashSet<MapState>();
List<MapState> list = new ArrayList<MapState>();
list.add(mapState);
while (true)
{
MapState best = list.get(0);
for (MapState mapState : list)
{
if (!handled.contains(mapState))
{
if (comparator.compare(mapState, best) < 0)
{
best = mapState;
}
}
}
if (best.getMissingFields() == 0)
{
return best;
}
handled.add(best);
list.addAll(computeSuccessors(best));
System.out.println("List size "+list.size()+", handled "+handled.size()+", best\n"+best.createString());
}
}
List<MapState> computeSuccessors(MapState mapState)
{
int numWorkers = mapState.workerPaths.size();
List<Point> oldWorkerPositions = new ArrayList<Point>();
for (int i=0; i<numWorkers; i++)
{
List<Point> workerPath = mapState.workerPaths.get(i);
Point p = workerPath.get(workerPath.size()-1);
oldWorkerPositions.add(p);
}
List<List<Point>> successorPositionsForWorkers = new ArrayList<List<Point>>();
for (int w=0; w<oldWorkerPositions.size(); w++)
{
Point p = oldWorkerPositions.get(w);
List<Point> ps = computeSuccessors(p);
successorPositionsForWorkers.add(ps);
}
List<List<Point>> newWorkerPositionsList = new ArrayList<List<Point>>();
int numSuccessors = (int)Math.pow(4, numWorkers);
for (int i=0; i<numSuccessors; i++)
{
String s = Integer.toString(i, 4);
while (s.length() < numWorkers)
{
s = "0"+s;
}
List<Point> newWorkerPositions = copy(oldWorkerPositions);
for (int w=0; w<numWorkers; w++)
{
int index = s.charAt(w) - '0';
Point newPosition = successorPositionsForWorkers.get(w).get(index);
newWorkerPositions.set(w, newPosition);
}
newWorkerPositionsList.add(newWorkerPositions);
}
List<MapState> successors = new ArrayList<MapState>();
for (int i=0; i<newWorkerPositionsList.size(); i++)
{
List<Point> newWorkerPositions = newWorkerPositionsList.get(i);
if (workerPositionsValid(newWorkerPositions))
{
MapState successor = new MapState(mapState);
for (int w=0; w<numWorkers; w++)
{
Point p = newWorkerPositions.get(w);
successor.updateWorkerPosition(w, p);
successor.workerPaths.get(w).add(p);
}
successor.update();
successors.add(successor);
}
}
return successors;
}
private boolean workerPositionsValid(List<Point> workerPositions)
{
Set<Point> set = new HashSet<Point>();
for (Point p : workerPositions)
{
if (!mapState.isValid(p.x, p.y))
{
return false;
}
set.add(p);
}
return set.size() == workerPositions.size();
}
static List<Point> computeSuccessors(Point p)
{
List<Point> result = new ArrayList<Point>();
result.add(new Point(p.x+0, p.y+1));
result.add(new Point(p.x+0, p.y-1));
result.add(new Point(p.x+1, p.y+0));
result.add(new Point(p.x-1, p.y+0));
return result;
}
}