🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.lang.prolog
Article #598

Re: Duplicate Solutions

#598
From: Richard O'keefe
Date: Fri, 16 Mar 1990 08:12
78 lines
3382 bytes
In article <11500023@hpldola.HP.COM>,
patch@hpldola.HP.COM (Pat Chkoreff) writes:
> Occasionally I have written a predicate that yields duplicate solutions, and
> I've wondered how to make each solution occur uniquely.  For example, I have
> a multigraph:
> 	node(X).             % X is a node.
> 	edge(E, X, Y).       % E is a directed edge from node X to node Y.
> 	joined(X, Y).        % There exists an edge from node X to node Y.

The ideal thing, of course, would be to write down directly exactly what
you mean:

	joined(X, Y) :- E^edge(E, X, Y).

and have the system figure it out automatically.  Alas, even in NU Prolog
(where you write "some E edge(E, X, Y)" you still get the duplicates.
setof/3 *is* a good way to do it (bagof/3 won't do, precisely because
it *doesn't* eliminate duplicates):

	joined(X, Y) :-
		setof((X->Y), E^edge(E,X,Y), Arcs),
		member((X->Y), Arcs).

This is a quite general way of computing a projection without
duplicates:
	p(X1, ..., Xn) :-
		setof(*(X1,...,Xn), Y1^...^Ym^q(X1,...,Xn,Y1,...,Ym), L),
		member(*(X1,...,Xn), L).

This does not compute any unwanted answers, and it's even one of the few
cases where a broken setof/3 can get away with yielding L=[].

Don't knock this until you have tried it.  Any method which can handle
queries to joined(_,_) which are not ground is going to have to keep
track of the answers _somehow_.

Another approach is to distinguish between the repeated solutions
somehow, and return a particular representative.   For argument's sake,
let's suppose we add a new predicate
	representative(E)
which is to be true when E is the chosen representative for a group of
edges between the same nodes.  We have the constraint
	edge(E1, X, Y) & representative(E1) &
	edge(E2, X, Y) & representative(E2) -> E1 = E2
Then we can define
	joined(X, Y) :-
		edge(E, X, Y),
		representative(E).

This doesn't look at any solutions of edge/3 which are not relative,
and does not have to store or sort solutions.

Tim Finin wrote
:   You are correct, I think, in looking to change your data model
:   and/or algorithm to avoid generating duplicate solutions when
:   they are not appropriate.
Agreed.

:   joined(X, Y) :- edge(_, X, Y), !.
:   joined(X, Y) :- once(edge(_, X, Y)).
He also points out the problem, which is that these approaches only
work when called with X, Y both ground.

Sharon J Correll wrote
:   How about:
:   joined(X,Y) :- node(X), node(Y), an_edge(X, Y).
:   an_edge(X, Y) :- edge(_, X, Y), !.
which is fine.  This has no unexpected solutions.  The cost issue is
interesting, though.  Assuming that X and Y are both variables (the
worst case), that there are N nodes, E edges, and J solutions of
joined/2, we find

	setof method	cost = O(E + E.lg E + J)
	representative	cost = O(E + J)
	node/node/test	cost = O(N*N + J)

What the coefficients are depends on the Prolog you are using.  (A nice
fast setof wouldn't hurt).
Technical Details
Message-ID: <2986@goanna.oz.au>
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!swrinde!zaphod.mps.ohio-state.edu!samsung!munnari.oz.au!goanna!ok
References: <11500023@hpldola.HP.COM>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!swrinde!zaphod.mps.ohio-state.edu!samsung!munnari.oz.au!goanna!ok
From: ok@goanna.oz.au (Richard O'keefe)
Newsgroups: comp.lang.prolog
Subject: Re: Duplicate Solutions
Message-ID: <2986@goanna.oz.au>
Date: 16 Mar 90 08:12:04 GMT
References: <11500023@hpldola.HP.COM>
Organization: Comp Sci, RMIT, Melbourne, Australia
Lines: 78