Newsgroups: comp.lang.prolog
Path: cantaloupe.srv.cs.cmu.edu!bb3.andrew.cmu.edu!nntp.sei.cmu.edu!news.psc.edu!hudson.lm.com!news.math.psu.edu!psuvax1!uwm.edu!math.ohio-state.edu!howland.reston.ans.net!gatech!newsfeed.internetmci.com!news.mel.aone.net.au!inferno.mpx.com.au!news.unimelb.EDU.AU!cs.mu.OZ.AU!lee
From: lee@cs.mu.OZ.AU (Lee Naish)
Subject: Re: Help: subsumption test
Message-ID: <9523617.26004@mulga.cs.mu.OZ.AU>
Originator: lee@munta.cs.mu.OZ.AU
Sender: news@cs.mu.OZ.AU (CS-Usenet)
Reply-To: lee@cs.mu.OZ.AU (Lee Naish)
Organization: Computer Science, University Of Melbourne, Australia
References:  <199508200506.WAA03041@usc.edu>
Date: Thu, 24 Aug 1995 07:06:44 GMT
Lines: 128


In article <199508200506.WAA03041@usc.edu>, luutran@dragon.sci.csupomona.edu (Luu Tran) writes:
> Hello,
> 
> 1) I vaguely remember seeing somewhere a clever way to perform the
> subsumption test in Prolog.  (P subsumes Q if P is a "more general" instance
> of Q).  But now I've forgotten it.  Can someone help?

The following is very efficient but NU-Prolog specific.

        % fast subsumption check using gAll and ~=
        % gAll A A ~= B fails if and only if A and B can be unified
        % without binding any variables in B (otherwise it may succeed
        % or delay - we don't care which since its inside \+ anyway) 
        % Assumes A and B don't share vars (see qpsubsumes.nl comments)
subsumes(A, B) :-
        \+ (gAll A A ~= B).

Here is some more portable code to do it (the commented out bit gives the standard way to do it using numbervars, which doesn't always work):


% Newsgroups: comp.lang.prolog
% Path: cs.mu.OZ.AU!munnari.oz.au!news.Hawaii.Edu!ames!agate!spool.mu.edu!yale.edu!ira.uka.de!Germany.EU.net!ecrc!jacques
% From: jacques@ecrc.de (Jacques Noye)
% Subject: Re: Testing for subsumption
% Message-ID: <1993Mar2.160725.4812@ecrc.de>
% Sender: news@ecrc.de
% Organization: European Computer-Industry Research Centre GmbH, Munich, Germany
% References: <C2v4rF.260@gabriel.keele.ac.uk> <C2voxp.57r@comp.vuw.ac.nz> <8433@skye.ed.ac.uk> <9306111.12313@mulga.cs.mu.OZ.AU>
% Date: Tue, 2 Mar 1993 16:07:25 GMT
% Lines: 93
% 
% Lee Naish has previously mentioned that the 'numbervars implementation' of the 
% subsumption test has problems with terms containing '$VAR'/1 structures.
% There is an easy workaround: first rewrite the terms such that all the 
% compound terms are wrapped into a, let us say, '$COMP'/1 structure. 
% Variables can then be 'numbered' using '$VAR'/1 without any confusion 
% between an object structure '$VAR'(_), represented as '$COMP'('$VAR'(_)), and 
% a meta structure '$VAR'(_).
% 
% This is quite a generic way to avoid confusion between the meta and the object
% level (e.g. I have also used it in the compiler that I wrote for KCM).
% 
% Here is the corresponding code (for ECLiPSe):
% 
% subsumes_chk(General, Specific)
%
% Succeeds if all ground instantiations of Specific are instantiations
% of General.
% This is a variant of the code by R.A.O'Keefe from the DEC-10 library
% (file metutl.pl):
% 
% subsumes_chk(General, Specific) :-
%        \+  (   numbervars(Specific, 0, _),
%                \+ General = Specific
%            ).
%
% The code behaves correctly wrt '$VAR'/1 structures. That is, for instance,
% subsumes_chk('$VAR(_)', X) fails (with the original code, it succeeds).

subsumes_chk(G, S) :-
        \+((wrapcomp(S, S0),
		wrapcomp(G, G0),
		safe_numbervars(S0, 0, _),
		G0 \= S0)
	).

% wrapcomp(T, WT)

wrapcomp(T, WT) :-
        compound(T),
        !,
        functor(T, Atom, Arity),
        functor(NewT, Atom, Arity),
        WT = '$COMP'(Arity, NewT),
        wrapcomp_arguments(Arity, T, NewT).
wrapcomp(T, T).

% wrapcomp_arguments(Index, T, NewT)

wrapcomp_arguments(Index, T, NewT) :-
        arg(Index, T, Arg),
        wrapcomp(Arg, NewArg),
        arg(Index, NewT, NewArg),
        (Index \== 1 -> 
                Index1 is Index - 1,
                wrapcomp_arguments(Index1, T, NewT)
        ;
                true
        ).

% safe_numbervars(T, Id0, Id)

safe_numbervars(T, Id0, Id) :-
        var(T),
        !,
        T = '$VAR'(Id0),
        Id is Id0 + 1.
safe_numbervars('$VAR'(_), Id0, Id) :-
        !,
        Id0 = Id.
safe_numbervars('$COMP'(Arity, T), Id0, Id) :-
        !,
        safe_numbervars_arguments(Arity, T, Id0, Id).
safe_numbervars(_, Id, Id).

% safe_numbervars_arguments(Index, T, Id0, Id)

safe_numbervars_arguments(Index, T, Id0, Id) :-
        arg(Index, T, Arg),
        safe_numbervars(Arg, Id0, Id1),
        (Index \== 1 ->
                Index1 is Index - 1,
                safe_numbervars_arguments(Index1, T, Id1, Id)
        ;
                Id1 = Id
        ).


% -- Jacques NOYE

% ECRC GmbH					email: jacques@ecrc.de
% Arabellastr. 17					voice: +49 89 92 69 91 49
% D-8000 Munich 81				fax:   +49 89 92 69 91 70
% Germany



