Just another update

This commit is contained in:
Ingy döt Net 2015-02-20 00:35:01 -05:00
parent a25938f123
commit 00a190b0a6
6591 changed files with 94363 additions and 23227 deletions

View file

@ -1,6 +1,8 @@
Given a mapping between items, and items they depend on, a [[wp:Topological sorting|topological sort]] orders items so that no item precedes an item it depends upon.
The compiling of a library in the [[wp:VHDL|VHDL]] language has the constraint that a library must be compiled after any library it depends on. A tool exists that extracts library dependencies. The task is to '''write a function that will return a valid compile order of VHDL libraries from their dependencies.'''
The compiling of a library in the [[wp:VHDL|VHDL]] language has the constraint that a library must be compiled after any library it depends on.
A tool exists that extracts library dependencies.
The task is to '''write a function that will return a valid compile order of VHDL libraries from their dependencies.'''
* Assume library names are single words.
* Items mentioned as only dependants, (sic), have no dependants of their own, but their order of compiling must be given.

View file

@ -0,0 +1,93 @@
#include <unordered_map>
#include <string>
#include <sstream>
#include <vector>
#include <iostream>
using namespace std;
string input = {
"des_system_lib std synopsys std_cell_lib des_system_lib dw02 dw01 ramlib ieee\n"
"dw01 ieee dw01 dware gtech\n"
"dw02 ieee dw02 dware\n"
"dw03 std synopsys dware dw03 dw02 dw01 ieee gtech\n"
"dw04 dw04 ieee dw01 dware gtech\n"
"dw05 dw05 ieee dware\n"
"dw06 dw06 ieee dware\n"
"dw07 ieee dware\n"
"dware ieee dware\n"
"gtech ieee gtech\n"
"ramlib std ieee\n"
"std_cell_lib ieee std_cell_lib\n"
"synopsys\n"
"cycle_11 cycle_12\n"
"cycle_12 cycle_11\n"
"cycle_21 dw01 cycle_22 dw02 dw03\n"
"cycle_22 cycle_21 dw01 dw04" };
class TopSort {
public:
TopSort(const string& input){
stringstream ss(input);
string buf;
while(getline(ss, buf)){
stringstream ls(buf);
string target, subtarget;
ls >> target;
while(ls >> subtarget){
if(target.compare(subtarget) == 0)
continue;
dependencies.emplace(subtarget, 0);
parents[subtarget].push_back(target);
++dependencies[target];
}
}
}
void solve(){
for(const auto& pair : dependencies)
if(pair.second == 0)
sorted.push_back(pair.first);
for(unsigned int i = 0; i < sorted.size(); ++i){
string target = sorted[i];
for(string& parent : parents[target])
if(--dependencies[parent] == 0)
sorted.push_back(parent);
}
for(const auto& pair : dependencies)
if(pair.second != 0)
unorderable.push_back(pair.first);
}
friend ostream& operator<<(ostream& os, const TopSort& ts) {
for(const string& s : ts.sorted)
os << s << endl;
if(ts.unorderable.size() > 0){
cout << "Unorderable:" << endl;
for(const string& s : ts.unorderable)
os << s << endl;
}
return os;
}
private:
vector<string> sorted;
vector<string> unorderable;
unordered_map<string, int> dependencies;
unordered_map<string, vector<string>> parents;
};
int main () {
TopSort ts(input);
ts.solve();
cout << ts;
}

View file

@ -1,17 +1,17 @@
import std.stdio, std.string, std.algorithm, std.range;
alias string[][string] TDependencies;
final class ArgumentException : Exception {
this(string text) {
this(string text) pure nothrow @safe /*@nogc*/ {
super(text);
}
}
string[][] topoSort(TDependencies d) {
foreach (k, v; d)
d[k] = v.sort().uniq().filter!(s => s != k)().array();
foreach (s; d.values.join().sort().uniq())
alias TDependencies = string[][string];
string[][] topoSort(TDependencies d) pure /*nothrow @safe*/ {
foreach (immutable k, v; d)
d[k] = v.sort().uniq.filter!(s => s != k).array;
foreach (immutable s; d.byValue.join.sort().uniq)
if (s !in d)
d[s] = [];
@ -19,22 +19,22 @@ string[][] topoSort(TDependencies d) {
while (true) {
string[] ordered;
foreach (item, dep; d)
foreach (immutable item, const dep; d)
if (dep.empty)
ordered ~= item;
if (!ordered.empty)
sorted ~= ordered.sort().release();
sorted ~= ordered.sort().release;
else
break;
TDependencies dd;
foreach (item, dep; d)
if (!canFind(ordered, item))
dd[item] = dep.filter!(s => !ordered.canFind(s))()
.array();
foreach (immutable item, const dep; d)
if (!ordered.canFind(item))
dd[item] = dep.filter!(s => !ordered.canFind(s)).array;
d = dd;
}
//if (!d.empty)
if (d.length > 0)
throw new ArgumentException(format(
"A cyclic dependency exists amongst:\n%s", d));
@ -59,16 +59,16 @@ std_cell_lib ieee std_cell_lib
synopsys";
TDependencies deps;
foreach (line; data.splitLines())
deps[line.split()[0]] = line.split()[1 .. $];
foreach (immutable line; data.splitLines)
deps[line.split[0]] = line.split[1 .. $];
auto depw = deps.dup;
foreach (idx, subOrder; topoSort(depw))
foreach (immutable idx, const subOrder; depw.topoSort)
writefln("#%d : %s", idx + 1, subOrder);
writeln();
writeln;
depw = deps.dup;
depw["dw01"] ~= "dw04";
foreach (subOrder; topoSort(depw)) // should throw
writeln(subOrder);
foreach (const subOrder; depw.topoSort) // Should throw.
subOrder.writeln;
}

View file

@ -0,0 +1,140 @@
package main
import (
"fmt"
"strings"
)
var data = `
LIBRARY LIBRARY DEPENDENCIES
======= ====================
des_system_lib std synopsys std_cell_lib des_system_lib dw02 dw01 ramlib ieee
dw01 ieee dw01 dware gtech
dw02 ieee dw02 dware
dw03 std synopsys dware dw03 dw02 dw01 ieee gtech
dw04 dw04 ieee dw01 dware gtech
dw05 dw05 ieee dware
dw06 dw06 ieee dware
dw07 ieee dware
dware ieee dware
gtech ieee gtech
ramlib std ieee
std_cell_lib ieee std_cell_lib
synopsys `
func main() {
g, in, err := parseLibComp(data)
if err != nil {
fmt.Println(err)
return
}
order, cyclic := topSortKahn(g, in)
if cyclic != nil {
fmt.Println("Cyclic:", cyclic)
return
}
fmt.Println("Order:", order)
}
type graph map[string][]string
type inDegree map[string]int
// parseLibComp parses the text format of the task and returns a graph
// representation and a list of the in-degrees of each node. The returned graph
// represents compile order rather than dependency order. That is, for each map
// map key n, the map elements are libraries that depend on n being compiled
// first.
func parseLibComp(data string) (g graph, in inDegree, err error) {
// small sanity check on input
lines := strings.Split(data, "\n")
if len(lines) < 3 || !strings.HasPrefix(lines[2], "=") {
return nil, nil, fmt.Errorf("data format")
}
// toss header lines
lines = lines[3:]
// scan and interpret input, build graph
g = graph{}
in = inDegree{}
for _, line := range lines {
libs := strings.Fields(line)
if len(libs) == 0 {
continue // allow blank lines
}
lib := libs[0]
g[lib] = g[lib]
for _, dep := range libs[1:] {
in[dep] = in[dep]
if dep == lib {
continue // ignore self dependencies
}
successors := g[dep]
for i := 0; ; i++ {
if i == len(successors) {
g[dep] = append(successors, lib)
in[lib]++
break
}
if dep == successors[i] {
break // ignore duplicate dependencies
}
}
}
}
return g, in, nil
}
// General purpose topological sort, not specific to the application of
// library dependencies. Adapted from Wikipedia pseudo code, one main
// difference here is that this function does not consume the input graph.
// WP refers to incoming edges, but does not really need them fully represented.
// A count of incoming edges, or the in-degree of each node is enough. Also,
// WP stops at cycle detection and doesn't output information about the cycle.
// A little extra code at the end of this function recovers the cyclic nodes.
func topSortKahn(g graph, in inDegree) (order, cyclic []string) {
var L, S []string
// rem for "remaining edges," this function makes a local copy of the
// in-degrees and consumes that instead of consuming an input.
rem := inDegree{}
for n, d := range in {
if d == 0 {
// accumulate "set of all nodes with no incoming edges"
S = append(S, n)
} else {
// initialize rem from in-degree
rem[n] = d
}
}
for len(S) > 0 {
last := len(S) - 1 // "remove a node n from S"
n := S[last]
S = S[:last]
L = append(L, n) // "add n to tail of L"
for _, m := range g[n] {
// WP pseudo code reads "for each node m..." but it means for each
// node m *remaining in the graph.* We consume rem rather than
// the graph, so "remaining in the graph" for us means rem[m] > 0.
if rem[m] > 0 {
rem[m]-- // "remove edge from the graph"
if rem[m] == 0 { // if "m has no other incoming edges"
S = append(S, m) // "insert m into S"
}
}
}
}
// "If graph has edges," for us means a value in rem is > 0.
for c, in := range rem {
if in > 0 {
// recover cyclic nodes
for _, nb := range g[c] {
if rem[nb] > 0 {
cyclic = append(cyclic, c)
break
}
}
}
}
if len(cyclic) > 0 {
return nil, cyclic
}
return L, nil
}

View file

@ -0,0 +1,48 @@
// General purpose topological sort, not specific to the application of
// library dependencies. Also adapted from Wikipedia pseudo code.
func topSortDFS(g graph) (order, cyclic []string) {
L := make([]string, len(g))
i := len(L)
temp := map[string]bool{}
perm := map[string]bool{}
var cycleFound bool
var cycleStart string
var visit func(string)
visit = func(n string) {
switch {
case temp[n]:
cycleFound = true
cycleStart = n
return
case perm[n]:
return
}
temp[n] = true
for _, m := range g[n] {
visit(m)
if cycleFound {
if cycleStart > "" {
cyclic = append(cyclic, n)
if n == cycleStart {
cycleStart = ""
}
}
return
}
}
delete(temp, n)
perm[n] = true
i--
L[i] = n
}
for n := range g {
if perm[n] {
continue
}
visit(n)
if cycleFound {
return nil, cyclic
}
}
return L, nil
}

View file

@ -1,107 +0,0 @@
package main
import (
"fmt"
"strings"
)
var data = `
LIBRARY LIBRARY DEPENDENCIES
======= ====================
des_system_lib std synopsys std_cell_lib des_system_lib dw02 dw01 ramlib ieee
dw01 ieee dw01 dware gtech
dw02 ieee dw02 dware
dw03 std synopsys dware dw03 dw02 dw01 ieee gtech
dw04 dw04 ieee dw01 dware gtech
dw05 dw05 ieee dware
dw06 dw06 ieee dware
dw07 ieee dware
dware ieee dware
gtech ieee gtech
ramlib std ieee
std_cell_lib ieee std_cell_lib
synopsys `
func main() {
// validate that data is positioned in string as expected
lines := strings.Split(data, "\n")
if lines[2][0] != '=' || strings.TrimSpace(lines[len(lines)-1]) == "" {
panic("data format")
}
// toss header lines
lines = lines[3:]
// scan and interpret input, build directed graph
dg := make(map[string][]string)
for _, line := range lines {
def := strings.Fields(line)
if len(def) == 0 {
continue // handle blank lines
}
lib := def[0] // dependant (with an a) library
list := dg[lib] // handle additional dependencies
scan:
for _, pr := range def[1:] { // (pr for prerequisite)
if pr == lib {
continue // ignore self dependencies
}
for _, known := range list {
if known == pr {
continue scan // ignore duplicate dependencies
}
}
// build: this curious looking assignment establishess a node
// for the prerequisite library if it doesn't already exist.
dg[pr] = dg[pr]
// build: add edge (dependency)
list = append(list, pr)
}
// build: add or update node for dependant library
dg[lib] = list
}
// topological sort on dg
for len(dg) > 0 {
// collect libs with no dependencies
var zero []string
for lib, deps := range dg {
if len(deps) == 0 {
zero = append(zero, lib)
delete(dg, lib) // remove node (lib) from dg
}
}
// cycle detection
if len(zero) == 0 {
fmt.Println("libraries with un-orderable dependencies:")
// collect un-orderable dependencies
cycle := make(map[string]bool)
for _, deps := range dg {
for _, dep := range deps {
cycle[dep] = true
}
}
// print libs with un-orderable dependencies
for lib, deps := range dg {
if cycle[lib] {
fmt.Println(lib, deps)
}
}
return
}
// output a set that can be processed concurrently
fmt.Println(zero)
// remove edges (dependencies) from dg
for _, remove := range zero {
for lib, deps := range dg {
for i, dep := range deps {
if dep == remove {
copy(deps[i:], deps[i+1:])
dg[lib] = deps[:len(deps)-1]
break
}
}
}
}
}
}

View file

@ -0,0 +1,37 @@
sub print_topo_sort ( %deps ) {
my %ba;
for %deps.kv -> $before, @afters {
for @afters -> $after {
%ba{$before}{$after} = 1 if $before ne $after;
%ba{$after} //= {};
}
}
while %ba.grep( not *.value )».key -> @afters {
say ~@afters.sort;
%ba{@afters}:delete;
for %ba.values { .{@afters}:delete }
}
say %ba ?? "Cycle found! {%ba.keys.sort}" !! '---';
}
my %deps =
des_system_lib => < std synopsys std_cell_lib des_system_lib dw02
dw01 ramlib ieee >,
dw01 => < ieee dw01 dware gtech >,
dw02 => < ieee dw02 dware >,
dw03 => < std synopsys dware dw03 dw02 dw01 ieee gtech >,
dw04 => < dw04 ieee dw01 dware gtech >,
dw05 => < dw05 ieee dware >,
dw06 => < dw06 ieee dware >,
dw07 => < ieee dware >,
dware => < ieee dware >,
gtech => < ieee gtech >,
ramlib => < std ieee >,
std_cell_lib => < ieee std_cell_lib >,
synopsys => < >;
print_topo_sort(%deps);
%deps<dw01>.push: 'dw04'; # Add unresolvable dependency
print_topo_sort(%deps);