For learning purpose I'm developping an application that in real life would work basically like Quartz Composer or the recent Vuo. I'm building the graph of nodes on a Core Data Framework basis.
Basically I have a Node entity with a to-many relationship with Input and Output entities (a node can have multiple inputs and multiple outputs). Input has a to-one relationship to a Connection entity, while Output has a to-many relationship with the latter (an input can have only one connection, while an output can have many).
To read the graph I'm using a Topological Sorting algorithm (Kahn's one), described here. The code is as follows :
/**
* Get all nodes.
*/
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Node"];
NSMutableArray *nodes = [[[_document managedObjectContext] executeFetchRequest:request error:nil] mutableCopy];
/**
* Reset the nodes 'visited' flag.
*/
[self reset:nodes];
/**
* Get sources: predicate for nodes without input ports or with input ports without connections.
*/
[request setPredicate:[NSPredicate predicateWithFormat:@"inputs == nil OR ALL inputs.connection == nil"]];
NSMutableArray *sources = [[[_document managedObjectContext] executeFetchRequest:request error:nil] mutableCopy];
/**
* Perform a topological sort.
*/
while ([sources count] > 0) {
/**
* While there are sources.
*/
NSManagedObject *node = [sources lastObject];
/**
* Add the node to the tail of the final graph (NSMutableArray).
*/
[_graph addObject:node];
[node setValue:@([_graph count] - 1) forKey:@"kNodeExecutionIndex"];
[sources removeLastObject];
/**
* Outputs.
*/
NSMutableSet *outputs = [node valueForKey:@"outputs"];
for (NSManagedObject *output in outputs) {
/**
* Get output connections.
*/
NSMutableSet *connections = [output valueForKey:@"connections"];
for (NSManagedObject *connection in connections) {
/**
* Set the connection as already visited.
*/
[connection setValue:@(YES) forKey:@"kConnectionVisited"];
NSManagedObject *n = [[connection valueForKey:@"destination"] valueForKey:@"node"];
/**
* Set the 'source' flag to YES by default.
*/
BOOL isNewSource = YES;
/**
* Get connected inputs.
*/
NSMutableSet *inputs = [n valueForKey:@"inputs"];
for (NSManagedObject *input in inputs) {
/**
* Check if one of the input connections was visited.
* If not, then we need to process this connection and
* don't add it to sources for next pass.
*/
if ([[[input valueForKey:@"connection"] valueForKey:@"kConnectionVisited"] isEqualTo:@(NO)]) {
isNewSource = NO;
break;
}
}
if (isNewSource) {
[sources addObject:n];
}
}
}
}
I'm trying to understand the logic of how (and where in this code) I'd have to compute reachability for each Node (therefore for each Input) entity, if it is possible.
My questions are :
- Is it possible to compute the reachability of nodes inside the Kahn's algorithm ?
- If appropriate, where and how to do it, so I can understand why it is working ?
Thank you.