Positional Features

References: Constituent Structure

Positional features are accessed through special bit-manipulation subprimitives. Here, we describe the links between the primitive operations provided to the grammar writer and the subprimitives that reference and set positional features.

Contents

Preliminaries
Adjunction

Preliminaries

posInfo type subprimitives are suffixed as follows:

Suffix Input
(None) Constituent
1 Feature complex

(For details on how constituents are organized, see constituent structure.)

Adjunction

Operations: adjoined/{1,2,3} / adjoin/4 / highestSegment/1 / lowestSegment/1

Subprimitives: posInfoAdjoined1 / posInfoProj1 / posInfoLSeg / posInfoLSeg1 / setPosDInfo

Adjunction Accessors

Bit 1 in Pn, the internal positional feature bitset, indicates whether there is something adjoined to this structure. posInfoAdjoined/posInfoAdjoined1 is the subprimitive that encodes this:
posInfoAdjoined([F|_]) :- arg(3,F,Pn), 2 is Pn /\ 2. % 2nd bit
posInfoAdjoined1(F) :- arg(3,F,Pn), 2 is Pn /\ 2.    % 2nd bit
Hence:
adjoined([F,_,_|_]) :- posInfoAdjoined1(F).
Using information about downwards projection, we can retrieve the adjunct and lower segment as follows:
adjoined([F,L,R],A) :-  
	posInfoAdjoined1(F),
	posInfoProj1(F,I),
	(I =:= 0 -> A = R ; A = L).		  % assume numeric

adjoined([F,L,R],A,S) :-
	posInfoAdjoined1(F),
	posInfoProj1(F,I),
	(I =:= 0 -> S = L, A = R ; S = R, A = L). % assume numeric
Bit 0 (LSB) in Pn indicates whether there is further downward projection. Bits 2 and up form an index into the head. posInfoProj/posInfoProj1 is the subprimitive that returns the index of the head:
% Phrase -> value(head) provided phrase projects
posInfoProj([F|_],I) :-	
	arg(3,F,Pn), 1 is Pn /\ 1,		% lsb
	I is Pn >> 2.				% skip lsb and 2nd bit

% FC -> value(head) provided phrase projects
posInfoProj1(F,I) :-	
	arg(3,F,Pn), 1 is Pn /\ 1,		% lsb
	I is Pn >> 2.				% skip lsb and 2nd bit


Segments

Bit 0 in Pd indicates whether the constituent is a lower segment in an adjunction structure. We can use this information to detect whether the constituent is the highest segment in an adjunction cascade:
% works for even non-adjoined phrases
highestSegment(X) :- \+ posInfoLSeg(X).
posInfoLSeg is the subprimitive that tests Pd bit 0:
posInfoLSeg([F|_]) :- arg(4,F,Pd), 1 is Pd /\ 1. % lsb
posInfoLSeg1(F) :- arg(4,F,Pd), 1 is Pd /\ 1.	 % lsb
Note that if no adjunction has taken place at all, bit 0 will be 0 anyway. This will give the correct result.

The actual code is a little more complex to allow testing to succeed for unattached constituents. In other words, highestSegment(X) holds if X is the top constituent:

% new version: Pd not set, let it pass
highestSegment([F|_]) :- 
	arg(4,F,Pd), (var(Pd) -> true ; \+ 1 is Pd /\ 1). % lsb
In the complementary case where we're testing for lowest segments, the criterion is: Pd lower segment bit must be set and Pn adjoined bit must be clear:
% requires adjunction
lowestSegment([F|_]) :- posInfoLSeg1(F), \+ posInfoAdjoined1(F).


Adjunction Constructors

adjoin(Dir,Adjunct,X,X') must not only create the larger constituent, but also set the internal positional features of the new constituent (Pn) as well as setting the attachment features of the adjunct and original phrase:
adjoin(left,A,X,[c(C,Fs,7,_,_),A,X]) :-		% proj:1 adjoined:1 head:1
	X = [c(C,Fs,_,1,_)|_],			% lseg:1 adjunct:0 ...
	setPosDInfo(0,1,0,0,0,0,A).		% lseg:0 adjunct:1 ...
	
adjoin(right,A,X,[c(C,Fs,3,_,_),X,A]) :-	% proj:1 adjoined:1 head:0
	X = [c(C,Fs,_,1,_)|_],			% lseg:1 adjunct:0 ...
	setPosDInfo(0,1,0,0,0,0,A).		% lseg:0 adjunct:1 ...
The positional features are set as follows:

Constituent Pn Pd
X N/A lseg:1 adjunct:0 apos:0 compl:0 ido:0
Adjunct N/A lseg;0 adjunct:1 apos:0 compl:0 ido:0
[X Adjunct X] proj:1 adjoined:1 head:1 Not specified
[X X Adjunct] proj:1 adjoined:1 head:0 Not specified

Pd features are set using the subprimitive setPosDInfo:

setPosDInfo(LSeg,Adjunct,Apos1,Apos2,Compl,IDO,[F|_]) :-
	Pd is LSeg + Adjunct + Adjunct 
    	      + ((Apos1 + Apos2 + Apos2 
	  	+ ((Compl + IDO + IDO) << 2)) << 2),
	arg(4,F,Pd).	
(The suffix 1 version is also provided but not shown here.)

Actually, Nmacros unrolls this computation at compile-time using:

translateNR(setPosDInfo,7,setPosDInfo(L,A,Ap1,Ap2,C,I,X),
	    setPosDInfo(Pd,X),[]) :-
	nonvar(L), nonvar(A), nonvar(Ap1), nonvar(Ap2), 
	nonvar(C), nonvar(I),
	!,
	Pd is L + A + A + ((Ap1 + Ap2 + Ap2 + ((C + I + I) << 2)) << 2).
Hence, the actual primitive used at run-time is:
setPosDInfo(Pd,[F|_]) :- arg(4,F,Pd).
setPosDInfo1(Pd,F) :- arg(4,F,Pd).