Skip to content

Commit

Permalink
Merge branch 'spcl:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
hodelcl authored Jan 3, 2024
2 parents 2590215 + f4662ae commit 3dd9f69
Show file tree
Hide file tree
Showing 13 changed files with 1,771 additions and 1,255 deletions.
49 changes: 49 additions & 0 deletions .github/workflows/gh-pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Deploy to Pages

on:
# Runs on pushes targeting the default branch
push:
branches: ["master"]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write

# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false

jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
strategy:
matrix:
node-version: [18.4]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run build-prod
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Upload artifact
uses: actions/upload-pages-artifact@v2
with:
path: '.'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v3
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"type": "chrome",
"request": "launch",
"name": "Launch",
"url": "http://localhost:3000/sdfv.html",
"url": "http://localhost:3000",
"sourceMaps": true,
"webRoot": "${workspaceFolder}",
"preLaunchTask": "npm: serve",
Expand Down
File renamed without changes.
2,243 changes: 1,228 additions & 1,015 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@spcl/sdfv",
"version": "1.1.2",
"version": "1.1.5",
"description": "A standalone viewer for SDFGs",
"homepage": "https://github.com/spcl/dace-webclient",
"main": "out/index.js",
Expand Down
3 changes: 3 additions & 0 deletions sdfv.css
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,9 @@ pre.code code {
--loop-background-color: #ffffff;
--loop-background-simple-color: #e0e0e0;
--loop-foreground-color: #000000;
--control-flow-region-background-color: #ffffff;
--control-flow-region-background-simple-color: #e0e0e0;
--control-flow-region-foreground-color: #000000;
--interstate-edge-color: #86add9;
--connector-scoped-color: #c1dfe690;
--connector-unscoped-color: #f0fdff;
Expand Down
143 changes: 57 additions & 86 deletions src/layouter/graphlib/algorithms/cycles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ export function allBackedges(
g: DiGraph<unknown, unknown>, start?: string, strict: boolean = false
): [Set<[string, string]>, Set<[string, string]>] {
const backedges = new Set<[string, string]>();
const backedgesCheckSet = new Set<string>();
const backedgeMap = new Map<string, Set<[string, string]>>();
const eclipsedBackedges = new Set<[string, string]>();

if (start === undefined) {
Expand All @@ -145,13 +145,44 @@ export function allBackedges(
if (start === undefined)
throw new Error('No start node specified and none could be found');

// Gather all cycles in the graph. Cycles are represented as a sequence of
// nodes.
const visited = new Set<string>();
const locked = new Set<string>();

const dfsWalk = (node: string) => {
visited.add(node);
locked.add(node);

for (const succ of g.successorsIter(node)) {
if (!visited.has(succ)) {
dfsWalk(succ);
} else if (locked.has(succ)) {
// Backedge found.
const be: [string, string] = [node, succ];
backedges.add(be);
if (strict) {
if (!backedgeMap.has(succ))
backedgeMap.set(succ, new Set([be]));
else
backedgeMap.get(succ)!.add(be);
}
}
}

locked.delete(node);
};

dfsWalk(start);

if (!strict)
return [backedges, eclipsedBackedges];

backedges.clear();
eclipsedBackedges.clear();

const allCycles = new Set<NodeCycle<string>>();
for (const cycle of simpleCycles(g))
allCycles.add(new NodeCycle(cycle[0], cycle[1]));

// Construct a dictionary mapping a node to the cycles containing that node.
const cycleMap = new Map<string, Set<NodeCycle<string>>>();
for (const cycle of allCycles) {
for (const node of cycle.nodes) {
Expand All @@ -161,92 +192,32 @@ export function allBackedges(
}
}

// Do a BFS traversal of the graph to detect the back edges.
const bfsFrontier = [start];
const visited = new Set<string>([start]);
while (bfsFrontier.length > 0) {
const node = bfsFrontier.shift()!;
const predecessors = [];
for (const p of g.predecessors(node)) {
if (!visited.has(p))
predecessors.push(p);
}
const cycles = cycleMap.get(node);

// For the current node, find the incoming edge which belongs to the
// cycle and has not been visited yet, which indicates a backedge.
const nodeBackedgeCandidates = new Set<[
[[string, string], unknown], NodeCycle<string>
]>();
const nodeBackedgeCandidatesCheckSet = new Set<string>();
for (const cycle of cycles ?? []) {
const backedgeCandidates = g.inEdges(node);
for (const candidate of backedgeCandidates) {
const src = candidate[0][0];
const dst = candidate[0][1];
if (cycle.edges.has([src, dst].toString()) &&
(src == dst || !visited.has(src))) {
if (!nodeBackedgeCandidatesCheckSet.has(
candidate.toString()
)) {
nodeBackedgeCandidatesCheckSet.add(
candidate.toString()
);
nodeBackedgeCandidates.add([candidate, cycle]);
}
const candStr = candidate[0].toString();
if (strict === false && !backedgesCheckSet.has(candStr)) {
backedges.add(candidate[0]);
backedgesCheckSet.add(candStr);
for (const target of backedgeMap.keys()) {
const nodeBackedges = backedgeMap.get(target) ?? new Set([]);
if (nodeBackedges.size === 1) {
backedges.add(Array.from(nodeBackedges)[0]);
} else {
let longestEdge = undefined;
let maxLen = 0;
for (const be of nodeBackedges) {
for (const cycle of cycleMap.get(target) ?? []) {
if (cycle.edges.has(be.toString())) {
if (cycle.length > maxLen) {
maxLen = cycle.length;
if (longestEdge !== undefined && longestEdge !== be)
eclipsedBackedges.add(longestEdge);
longestEdge = be;
} else {
eclipsedBackedges.add(be);
}
}
}
}
}

// If strict is set, we only report the longest cycle's back edges for
// any given node, and separately return any other backedges as
// 'eclipsed' backedges. In the case of a while-loop, for example,
// the loop edge is considered a backedge, while a continue inside the
// loop is considered an 'eclipsed' backedge.
if (strict) {
let longestCandidate = undefined;
const eclipsedCandidates = new Set<[string, string]>();
for (const candidate of nodeBackedgeCandidates) {
if (!longestCandidate) {
longestCandidate = candidate;
} else if (longestCandidate[1].length < candidate[1].length) {
eclipsedCandidates.add(longestCandidate[0][0]);
longestCandidate = candidate;
} else {
eclipsedCandidates.add(candidate[0][0]);
}
}

if (longestCandidate) {
const candStr = longestCandidate[0][0].toString();
if (!backedgesCheckSet.has(candStr)) {
backedges.add(longestCandidate[0][0]);
backedgesCheckSet.add(candStr);
}
}

if (eclipsedCandidates.size > 0) {
for (const candidate of eclipsedCandidates)
eclipsedBackedges.add(candidate);
}
}

// Continue the BFS.
for (const neighbor of g.successors(node)) {
if (!visited.has(neighbor)) {
visited.add(neighbor);
bfsFrontier.push(neighbor);
}
if (longestEdge === undefined)
throw Error('No backedge candidate for target node ' + target);
backedges.add(longestEdge);
}
}

if (strict)
return [backedges, eclipsedBackedges];
else
return [backedges, new Set<[string, string]>()];
return [backedges, eclipsedBackedges];
}
13 changes: 13 additions & 0 deletions src/layouter/graphlib/di_graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,19 @@ export class DiGraph<NodeT, EdgeT> extends Graph<NodeT, EdgeT> {
return this.succ.get(u)?.has(v) ?? false;
}

public* successorsIterSelective(
id: string, ignoreEdges: [string, string][]
): Generator<string> {
const ignoredTargets = new Set<string>();
for (const ie of ignoreEdges)
if (ie[0] == id)
ignoredTargets.add(ie[1]);
for (const v of this.succ.get(id)?.keys() ?? []) {
if (!ignoredTargets.has(v))
yield v;
}
}

public successorsIter(id: string): IterableIterator<string> {
return this.succ.get(id)?.keys() ?? new Map().keys();
}
Expand Down
Loading

0 comments on commit 3dd9f69

Please sign in to comment.