Tree Tricks
OSDC Melbourne 2010/11/24
Copyright(C) 2010 by David Fetter
All Rights Reserved.
Tuesday, November 23, 2010
What’s a Tree, Really?
Plant
Perennial
Woody
Secondary branches
Off ground
Apical Dominance
Tuesday, November 23, 2010
Tuesday, November 23, 2010
What’s a Tree, Really?
Graph
Directed
Connected
Acyclic
Max(indegree) = 1
Tuesday, November 23, 2010
What’s a Graph, Really?
Tuesday, November 23, 2010
What’s a Graph, Really?
Nodes
Tuesday, November 23, 2010
What’s a Graph, Really?
Nodes
Edges
Tuesday, November 23, 2010
Representing Graphs
CREATE TABLE message (
message_id SERIAL PRIMARY KEY,
parent_message_id INTEGER REFERENCES message,
sender email NOT NULL,
list TEXT NOT NULL,
...
);
Tuesday, November 23, 2010
FAIL!Tuesday, November 23, 2010
Separate Your Concerns.
Tuesday, November 23, 2010
Representing Graphs
CREATE TABLE message (
message_id SERIAL PRIMARY KEY,
sender email NOT NULL,
list TEXT NOT NULL,
...
);
CREATE TABLE edge (
tail INTEGER NOT NULL REFERENCES message,
head INTEGER NOT NULL REFERENCES message,
PRIMARY KEY(tail, head)
);
Tuesday, November 23, 2010
WIN!Tuesday, November 23, 2010
Mathematical Flashback
Tuesday, November 23, 2010
Binary Relations
Tuesday, November 23, 2010
Binary Relations
Reflexive
Tuesday, November 23, 2010
Binary Relations
Reflexive
Symmetric
Tuesday, November 23, 2010
Binary Relations
Reflexive
Symmetric
Transitive
Tuesday, November 23, 2010
CLOSURE
(need to get some)
Tuesday, November 23, 2010
Reflexive Closure
CREATE TABLE reflexive_closure (
tail INTEGER NOT NULL REFERENCES message,
head INTEGER NOT NULL REFERENCES message
);
INSERT INTO reflexive_closure
SELECT tail, head FROM edge UNION
SELECT tail, tail FROM edge UNION
SELECT head, head FROM edge;
Tuesday, November 23, 2010
Symmetric Closure
CREATE TABLE symmetric_closure (
tail INTEGER NOT NULL REFERENCES message,
head INTEGER NOT NULL REFERENCES message
);
INSERT INTO symmetric_closure
SELECT tail, head FROM edge UNION
SELECT head, tail FROM edge;
Tuesday, November 23, 2010
Transitive Closure
CREATE TABLE transitive_closure (
tail INTEGER NOT NULL REFERENCES message,
head INTEGER NOT NULL REFERENCES message
);
Tuesday, November 23, 2010
Transitive Closure
CREATE TABLE transitive_closure (
tail INTEGER NOT NULL REFERENCES message,
head INTEGER NOT NULL REFERENCES message
);
INSERT INTO transitive_closure
Tuesday, November 23, 2010
Transitive Closure
CREATE TABLE transitive_closure (
tail INTEGER NOT NULL REFERENCES message,
head INTEGER NOT NULL REFERENCES message
);
INSERT INTO transitive_closure
SELECT
Tuesday, November 23, 2010
Transitive Closure
CREATE TABLE transitive_closure (
tail INTEGER NOT NULL REFERENCES message,
head INTEGER NOT NULL REFERENCES message
);
INSERT INTO transitive_closure
SELECT
Er
Tuesday, November 23, 2010
Transitive Closure
CREATE TABLE transitive_closure (
tail INTEGER NOT NULL REFERENCES message,
head INTEGER NOT NULL REFERENCES message
);
INSERT INTO transitive_closure
SELECT
Er
Um
Tuesday, November 23, 2010
Transitive Closure
CREATE TABLE transitive_closure (
tail INTEGER NOT NULL REFERENCES message,
head INTEGER NOT NULL REFERENCES message
);
INSERT INTO transitive_closure
SELECT
Er
Um
Hrm...
Tuesday, November 23, 2010
Down the Rabbit Hole
Tuesday, November 23, 2010
Transitive Closure Query
WITH RECURSIVE t(tail, head, chain) AS (
SELECT tail, head, ARRAY[tail, head]
FROM edge
UNION ALL
SELECT e.tail, e.head, t.chain || e.head
FROM edge e JOIN t
ON (e.tail = t.head)
WHERE e.tail <> ANY(t.chain)
)
SELECT tail, head FROM t
Tuesday, November 23, 2010
Forest Constraints
?
Tuesday, November 23, 2010
What’s a Tree, Really?
Graph
Directed
Connected
Acyclic
Max(indegree) = 1
Tuesday, November 23, 2010
Max(indegree) = 1
CREATE TABLE edge (
tail INTEGER NOT NULL REFERENCES message,
head INTEGER NOT NULL REFERENCES message,
PRIMARY KEY(tail, head)
);
ALTER TABLE edge ADD UNIQUE(head)
Tuesday, November 23, 2010
No Cycles!
Tuesday, November 23, 2010
Cycle Finder
WITH RECURSIVE t(tail, head, chain) AS (
SELECT tail, head, ARRAY[tail, head]
FROM edge
UNION ALL
SELECT e.tail, e.head, t.chain || e.head
FROM edge e JOIN t
ON (t.head = e.tail)
WHERE e.tail = ANY(t.chain)
)
SELECT * FROM t
Tuesday, November 23, 2010
Cycle Finder Function
CREATE OR REPLACE FUNCTION has_cycle()
RETURNS BOOLEAN
LANGUAGE SQL AS $$
SELECT EXISTS (
WITH RECURSIVE t(tail, head, chain) AS (
SELECT tail, head, ARRAY[tail, head]
FROM edge
UNION ALL
SELECT e.tail, e.head, t.chain || e.head
FROM edge e JOIN t
ON (t.head = e.tail)
WHERE e.tail = ANY(t.chain)
)
SELECT * FROM t
)
Tuesday, November 23, 2010
Cyclotomic Trigger Function
CREATE OR REPLACE FUNCTION decyclifier()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
IF (has_cycle()) THEN
RAISE ERROR 'No cycles allowed!';
END IF;
RETURN NEW;
END;
Tuesday, November 23, 2010
Cyclotomic Trigger
CREATE TRIGGER edge_decyclifier
AFTER INSERT OR UPDATE ON edge
FOR EACH STATEMENT
EXECUTE PROCEDURE decyclifier();
Tuesday, November 23, 2010
Tree Constraint
Forest Constraint +
Unique Non-head Node
Tuesday, November 23, 2010
Tree Constraint
CREATE OR REPLACE FUNCTION count_only_heads()
RETURNS INTEGER
LANGUAGE SQL
AS $$
SELECT count(tail)
FROM edge e
WHERE NOT EXISTS (
SELECT 1 FROM edge
WHERE edge.head = e.tail
)
$$;
Tuesday, November 23, 2010
Tree Constraint
CREATE OR REPLACE FUNCTION one_head()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
IF count_only_heads() <> 1 THEN
RAISE EXCEPTION 'This is a tree!';
END IF;
RETURN NEW;
END;
$$;
Tuesday, November 23, 2010
Tree Constraint
CREATE TRIGGER edge_one_head
AFTER INSERT OR UPDATE OR DELETE
ON edge
EXECUTE PROCEDURE one_head();
Tuesday, November 23, 2010
Questions?
Comments?
Brickbats?
Tuesday, November 23, 2010
Thanks!
Copyright(C) 2010 by David Fetter
All Rights Reserved.
Tuesday, November 23, 2010

Tree tricks osdc_melbourne_20101124