graph/encoding/dot: fix line visit marking
diff --git a/graph/encoding/dot/decode_test.go b/graph/encoding/dot/decode_test.go
index 4d652c7..9d1e880 100644
--- a/graph/encoding/dot/decode_test.go
+++ b/graph/encoding/dot/decode_test.go
@@ -393,6 +393,77 @@
 	}
 }
 
+func TestMultigraphLineIDsharing(t *testing.T) {
+	for i, test := range []struct {
+		directed bool
+		lines    []multi.Line
+		expected string
+	}{
+		{
+			directed: true,
+			lines: []multi.Line{
+				{F: multi.Node(0), T: multi.Node(1), UID: 0},
+				{F: multi.Node(0), T: multi.Node(1), UID: 1},
+				{F: multi.Node(0), T: multi.Node(2), UID: 0},
+				{F: multi.Node(2), T: multi.Node(0), UID: 0},
+			},
+			expected: directedMultigraph,
+		},
+		{
+			directed: false,
+			lines: []multi.Line{
+				{F: multi.Node(0), T: multi.Node(1), UID: 0},
+				{F: multi.Node(0), T: multi.Node(1), UID: 1},
+				{F: multi.Node(0), T: multi.Node(2), UID: 0},
+				{F: multi.Node(0), T: multi.Node(2), UID: 1},
+			},
+			expected: undirectedMultigraph,
+		},
+		{
+			directed: true,
+			lines: []multi.Line{
+				{F: multi.Node(0), T: multi.Node(0), UID: 0},
+				{F: multi.Node(0), T: multi.Node(0), UID: 1},
+				{F: multi.Node(1), T: multi.Node(1), UID: 0},
+				{F: multi.Node(1), T: multi.Node(1), UID: 1},
+			},
+			expected: directedSelfLoopMultigraph,
+		},
+		{
+			directed: false,
+			lines: []multi.Line{
+				{F: multi.Node(0), T: multi.Node(0), UID: 0},
+				{F: multi.Node(0), T: multi.Node(0), UID: 1},
+				{F: multi.Node(1), T: multi.Node(1), UID: 0},
+				{F: multi.Node(1), T: multi.Node(1), UID: 1},
+			},
+			expected: undirectedSelfLoopMultigraph,
+		},
+	} {
+		var dst encoding.MultiBuilder
+		if test.directed {
+			dst = multi.NewDirectedGraph()
+		} else {
+			dst = multi.NewUndirectedGraph()
+		}
+
+		for _, l := range test.lines {
+			dst.SetLine(l)
+		}
+
+		buf, err := MarshalMulti(dst, "", "", "\t")
+		if err != nil {
+			t.Errorf("i=%d: unable to marshal graph; %v", i, dst)
+			continue
+		}
+		actual := string(buf)
+		if actual != test.expected {
+			t.Errorf("i=%d: graph content mismatch; want:\n%s\n\nactual:\n%s", i, test.expected, actual)
+			continue
+		}
+	}
+}
+
 const directedMultigraph = `digraph {
 	// Node definitions.
 	0;
diff --git a/graph/encoding/dot/encode.go b/graph/encoding/dot/encode.go
index 3e3955c..1cba7c1 100644
--- a/graph/encoding/dot/encode.go
+++ b/graph/encoding/dot/encode.go
@@ -220,7 +220,7 @@
 					continue
 				}
 				p.visited[edge{inGraph: name, from: nid, to: tid}] = true
-				p.visited[edge{inGraph: name, from: tid, to: n.ID()}] = true
+				p.visited[edge{inGraph: name, from: tid, to: nid}] = true
 			}
 
 			if !havePrintedEdgeHeader {
@@ -432,6 +432,8 @@
 
 type line struct {
 	inGraph string
+	from    int64
+	to      int64
 	id      int64
 }
 
@@ -510,10 +512,18 @@
 
 			for _, l := range lines {
 				lid := l.ID()
-				if p.visited[line{inGraph: name, id: lid}] {
-					continue
+				if isDirected {
+					if p.visited[line{inGraph: name, from: nid, to: tid, id: lid}] {
+						continue
+					}
+					p.visited[line{inGraph: name, from: nid, to: tid, id: lid}] = true
+				} else {
+					if p.visited[line{inGraph: name, from: nid, to: tid, id: lid}] {
+						continue
+					}
+					p.visited[line{inGraph: name, from: nid, to: tid, id: lid}] = true
+					p.visited[line{inGraph: name, from: tid, to: nid, id: lid}] = true
 				}
-				p.visited[line{inGraph: name, id: lid}] = true
 
 				if !havePrintedEdgeHeader {
 					p.buf.WriteByte('\n')