1% This file is part of the Attempto Parsing Engine (APE).
    2% Copyright 2008-2013, Attempto Group, University of Zurich (see http://attempto.ifi.uzh.ch).
    3%
    4% The Attempto Parsing Engine (APE) is free software: you can redistribute it and/or modify it
    5% under the terms of the GNU Lesser General Public License as published by the Free Software
    6% Foundation, either version 3 of the License, or (at your option) any later version.
    7%
    8% The Attempto Parsing Engine (APE) is distributed in the hope that it will be useful, but WITHOUT
    9% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
   10% PURPOSE. See the GNU Lesser General Public License for more details.
   11%
   12% You should have received a copy of the GNU Lesser General Public License along with the Attempto
   13% Parsing Engine (APE). If not, see http://www.gnu.org/licenses/.
   14
   15:- module(drs_to_coreace, [
   16		drs_to_coreace/2,
   17		bigdrs_to_coreace/2
   18	]).

DRS to Core ACE verbalizer

Translates an Attempto DRS into the Core ACE fragment of Attempto Controlled English (ACE).

author
- Kaarel Kaljurand
version
- 2012-07-15

The setup: we have DRS-boxes and discourse referents, such that

Each referent lives-in exactly 1 box. For each box at least 1 referent lives-in it. Each referent has a unique ID and maps-to a set of conditions. Each box has a unique ID and has a name (if, then, '', or, `it is false that', etc.)

The task: verbalize each discourse referent, i.e. the conditions of each discourse referent. And do it in the context of

  1. the box,
  2. whether the referent has been verbalized already,
  3. whether some other referent from the same box has been verbalized already.

The order is important. It is set by referents_to_orderedreferents/2.

For the developer: to see the internals, use:

?- drs_to_coreace:ref2conds(Referent, Conditions, BoxId, SentenceId).
To be done
- URGENT: Use "Is it true that ... ?" for Yes/No questions
- Reorder conditions in OR-contructs so that the implications always come last Every dog barks and it is false that a cat sleeps or there is a man. (3711) There is a man or it is false a cat sleeps and if there is a dog ...
- Every pet is a dog or is a cat ,and is not a cow. # Support for mixing 'and' and 'or' is buggy.
- A customer enters every card or enters every code. # Serious scoping problem.
- Every book is something that an author that a publisher that John hates knows writes. (can be improved)
- What does every man like?
- What does no man like?
- There are less than 3 men and less than 3 women.
- Less than 3 men and John wait.
- /for-each-of plural constructions/
- Make `less than' and `at most' work in general
- Maybe use reflexive pronouns also when definite NPs are available: himself, herself, itself.

*/

   67:- use_module(morphgen, [
   68		clear_vars/0,
   69		add_var/1,
   70		remove_singletons/2,
   71		listlist_listatom/2,
   72		surface_noun/4,
   73		surface_verb/3,
   74		surface_property/3,
   75		surface_property/6,
   76		surface_adverb/3,
   77		surface_quotedstring/2,
   78		get_di_marker/4
   79	]).   80
   81:- use_module(drs_utils, [
   82		get_toplevel_object_referents/2
   83	]).   84
   85:- use_module(drs_to_drslist, [
   86		drs_to_drslist/2
   87	]).   88
   89/*
   90:- debug(verbose).
   91:- debug(that).
   92:- debug(toplevel).
   93:- debug(npcoord).
   94*/
   95
   96% Operators used in the DRS
   97:- op(400, fy, -).   98:- op(400, fy, ~).   99:- op(500, xfx, =>).  100:- op(500, xfx, v).  101:- op(500, xfx, '--').  102
  103
  104:- dynamic is_rep/1, ref2conds/4.  105
  106
  107% @tbd rename
  108bigdrs_to_coreace(Drs, AceList) :-
  109	drs_to_drslist(Drs, DrsList),
  110	drslist_to_coreace(DrsList, AceList).
  111
  112
  113drslist_to_coreace([], []).
  114
  115drslist_to_coreace([Drs | DrsList], [Ace | AceList]) :-
  116	drs_to_coreace(Drs, Ace),
  117	drslist_to_coreace(DrsList, AceList).
 drs_to_coreace(+Drs:drs, -AceSentenceList:list) is det
 Empty DRS -> []
 Unsupported DRS -> []
 Supported DRS -> [sentence1, sentence2, ..., sentenceN], where sentence is an atom
Arguments:
Drs- is an Attempto DRS
AceSentenceList- is a verbalization of the input DRS in Core ACE (a list of Core ACE sentences)
  131drs_to_coreace(drs([], []), []) :- !.
  132
  133drs_to_coreace(DRS, AceSentenceList) :-
  134	retractall(is_rep(_)),
  135	clear_vars,
  136	% BUG: why do we need the next line?
  137	assert(is_rep(nil)),
  138
  139	% Make a copy to preserve the variables in the caller.
  140	copy_term(DRS, DRSCopy),
  141
  142	DRSCopy = drs(Dom, ConditionList),
  143
  144	get_toplevel_object_referents(ConditionList, toplevel(ToplevelReferentList, UnsortedSubjectList, UnsortedObjectList, NamedList)),
  145	numbervars(DRSCopy, 0, _),
  146
  147	drs_to_coreace_nvar_wrapper(drs(Dom, ConditionList), [ToplevelReferentList, UnsortedSubjectList, UnsortedObjectList, NamedList], Result),
  148	!,
  149	post_process(Result, AceSentenceList),
  150	!.
  151
  152drs_to_coreace(_Drs, []).
  153% TODO: Throw an exception
  154%drs_to_coreace(Drs, _) :-
  155%	throw(error('Not implemented', context(drs_to_coreace/2, Drs))).
 drs_to_coreace_nvar_wrapper(Drs, List, Result)
  161drs_to_coreace_nvar_wrapper(Drs, List, Result) :-
  162	retractall(ref2conds(_, _, _, _)),
  163	reset_counter(box_counter),
  164	make_boxid(BoxId),
  165	catch(drs_to_coreace_nvar(Drs, BoxId, List, []--_, Result), _, fail).
Apply some post-processing on the generated tokens.
  172post_process -->
  173	remove_singletons,
  174	find_sentencelist,
  175	listlist_listatom.
 drs_to_coreace_nvar(+Drs:drs, +BoxId:term, +Toplevel:list, +RefInRefOut:term, -AceList:list) is det
Arguments:
Drs- is an Attempto DRS with variables nvard
BoxId- is a DRS box identifier
Toplevel- is a list of 4 lists containing referents of various types
RefInRefOut- list of referents in--out
AceText- is a verbalization of the DRS in Core ACE
  186drs_to_coreace_nvar(Drs, BoxId, [ToplevelReferentList, UnsortedSubjectList, UnsortedObjectList, NamedList], RI--RO, Result1) :-
  187
  188	debug(toplevel, "toplevel referents:
  189	ToplevelReferentList: ~W
  190	UnsortedSubjectList: ~W
  191	UnsortedObjectList: ~W
  192	NamedList: ~W~n",
  193	[ToplevelReferentList, [numbervars(true)], UnsortedSubjectList, [numbervars(true)], UnsortedObjectList, [numbervars(true)], NamedList, [numbervars(true)]]),
  194
  195	% We assert the DRS conditions.
  196	% The DRS itself is not used anymore below.
  197	make_ref2conds(Drs, BoxId),
  198
  199	% The next line means, that we use the `there is' construction
  200	% only if needed. If there is a verb that calls a noun
  201	% then the noun will not be verbalized by `there is'.
  202	findall(Referent, use_there_is(Referent), ThereIsReferents),
  203
  204	debug(verbose, "ThereIsReferents: ~W~n", [ThereIsReferents, [numbervars(true)]]),
  205
  206	% Remove syntactic objects because we do not want to use 'there is' with objects.
  207	% E.g. There is a cat. John hates the cat. --> John hates a cat.
  208	subtract(ToplevelReferentList, UnsortedObjectList, List1),
  209
  210	% Add syntactic subjects because we want to use 'there is' with subjects.
  211	% E.g. A cat sees John. --> There is a cat X1. The cat X1 sees John.
  212	append(List1, UnsortedSubjectList, List2),
  213
  214	% Remove named-objects to avoid e.g. "There is John.", regardless
  215	% of whether `John' is later used as a subject or as an object.
  216	subtract(List2, NamedList, UnnamedList2),
  217
  218	% Remove duplicates
  219	list_to_set(UnnamedList2, InitialReferents),
  220
  221	debug(verbose, "InitialReferents: ~w~n", [InitialReferents]),
  222
  223	append(InitialReferents, ThereIsReferents, List3),
  224	list_to_set(List3, Refs),
  225	referents_to_orderedreferents(Refs, OrderedRefs),
  226
  227	debug(verbose, "input to call_referents_to_acetexts/2: ~W~n", [OrderedRefs, [numbervars(true)]]),
  228
  229	call_referents_to_acetexts(OrderedRefs, RI--RO, Result1).
 referents_to_orderedreferents(+Refs:list, -OrderedRefs:list) is det
Sorts the list of referents so that the resulting verbalization would be most natural. There are three levels of keys:
  1. The referents are sorted by their sentence ID (ascending);
  2. The referents are sorted by their box counter (depth first);
  3. The referents are sorted by the subject argument of their corresponding predicate (if the referent has a corresponding predicate).

    @tbd The 3rd point needs rethinking.

    @param Refs is a list of discourse referents @param OrderedRefs is the list ordered

  247referents_to_orderedreferents(Refs, OrderedRefs) :-
  248	findall((SentenceId, BoxCounter, N)-Referent, (
  249		member(Referent, Refs),
  250		ref2conds(Referent, Conditions, id(BoxCounter, _, _), SentenceId),
  251		get_orderer(Conditions, N)
  252	), List1),
  253	debug(verbose, "Keys          : ~W~n", [List1, [numbervars(true)]]),
  254	keysort(List1, List2),
  255	debug(verbose, "Keys (sorted) : ~W~n", [List2, [numbervars(true)]]),
  256	findall(Referent, member(_Key-Referent, List2), OrderedRefs).
 get_orderer(+Conditions:list, -N:integer) is det
Returns an integer that is a sum of subject, object and direct object recency. The idea is to order the (predicate) conditions that are in the same box and have the same ID, so that they reflect the order of respective verbs in the original sentence. We exploit the fact that variable creation recency reflects the order of the original words. Note also that object-conditions get a smaller ranking than predicate conditions. This means that a 'there is'-object is placed before an object with a verb, e.g.
 It is false that a dog barks and that there is a man.

is paraphrased as:

 It is false that there is a man and that a dog barks.
Arguments:
Conditions- is a list of DRS condition
N- is a ranking number that determines how the referent is positioned in the verbalization
To be done
- This predicate is a hack. The DRS verbalizer should not rely on the variable creation times, and it should not try to reflect any "original order". Instead it should find the most natural way to order the predicates, e.g. by trying to chain them (as does the NP APE verbalizer).
  284get_orderer(Conditions, N) :-
  285	memberchk(predicate(_, _, '$VAR'(N)), Conditions),
  286	!.
  287
  288get_orderer(Conditions, N) :-
  289	memberchk(predicate(_, _, '$VAR'(N1), '$VAR'(N2)), Conditions),
  290	!,
  291	N is N1 + N2.
  292
  293get_orderer(Conditions, N) :-
  294	memberchk(predicate(_, _, '$VAR'(N1), '$VAR'(N2), '$VAR'(N3)), Conditions),
  295	!,
  296	N is N1 + N2 + N3.
  297
  298get_orderer(Conditions, N) :-
  299	memberchk(object('$VAR'(N1), _, _, _, _, _), Conditions),
  300	N is (-1 * (1 / (N1 + 1))),
  301	!.
  302
  303get_orderer(_Conditions, 0).
 find_sentencelist(+TokenList:list, -SentenceList:list) is det
Arguments:
TokenList- is a list of ACE tokens
SentenceList- is a list of sentences (where a sentence is a list of ACE tokens)
  311find_sentencelist([], []).
  312
  313find_sentencelist(TokenList, [Sentence | SentenceList]) :-
  314	find_sentence(TokenList, Sentence, RestTokenList),
  315	find_sentencelist(RestTokenList, SentenceList).
 find_sentence(+TokenList:list, -Sentence:list, -RestTokenList:list) is det
Arguments:
TokenList- is a list of ACE tokens
Sentence- is a list of sentences (where a sentence is a list of ACE tokens)
RestTokenList- is a list of ACE tokens
  324find_sentence(['.' | RestTokenList], [], RestTokenList) :- !.
  325
  326find_sentence([Token | RestTokenList], [Token | RestSentence], RestTokenList2) :-
  327	find_sentence(RestTokenList, RestSentence, RestTokenList2).
 use_there_is(+Referent:nvar) is det
Succeeds if the referent is a toplevel referent.

Referent is toplevel if:

  1. Its condition list is not empty. (BUG: redundant?)
  2. It is not called by any other Referent in the same box.
  3. It is called by another Referent in the same box, BUT it is toplevel, and it is (first) called by an embedded box.

    The 3rd clause was added to correctly paraphrase: There is a man who does not sleep. John sees the man.

    @param Referent is a discourse referent

  346use_there_is(Referent) :-
  347	ref2conds(Referent, [Condition | ConditionList], BoxId, _SentenceId),
  348	\+ is_called(Referent, [Condition | ConditionList], BoxId, _).
  349
  350% Handles the case: There is a man who does not sleep. John sees the man.
  351use_there_is(Referent) :-
  352	toplevel_id(ToplevelId),
  353	% Referent is top-level
  354	ref2conds(Referent, [Condition | ConditionList], ToplevelId, _SId1),
  355	% Referent is called by a top-level referent.
  356	is_called(Referent, [Condition | ConditionList], ToplevelId, SId2),
  357	% Referent is called from an embedded box.
  358	is_called(Referent, [Condition | ConditionList], BoxId, SId3),
  359	\+ toplevel_id(BoxId),
  360	% The embedded box is introduced before the other caller (in terms of the sentence Id).
  361	SId3 < SId2.
 toplevel_id(?ToplevelId)
Defines the form of the ID of the topmost DRS
  368toplevel_id(id(0, top, [])).
 is_called(+Referent:nvar, +ReferentConditions:list, +BoxId:term, -SentenceId:integer) is det
Succeeds if Referent corresponds to a proper name (because proper names are always called). Succeeds if Referent is used as a non-first argument (i.e. "called") in any condition in the given box.
Arguments:
Referent- is a discourse referent
ReferentConditions- is a list of conditions whose first argument this referent is.
BoxId- is a DRS box identifier
  380is_called(Referent, _, BoxId, SentenceId) :-
  381	ref2conds(Referent2, ConditionList, BoxId, SentenceId),
  382	Referent \= Referent2,
  383	member(Condition, ConditionList),
  384	Condition \= formula(_, _, _),
  385	arg(Num, Condition, Referent),
  386	Num > 1.
 call_referents_to_acetext(+RefList:list, +RefInRefOut:term, -Result:list) is det
Arguments:
RefList- is a list of top-level DRS referents
RefInRefOut- list of referents in--out
Result- is an ACE text (list of tokens)
  395call_referents_to_acetexts(RefList, RI--RO, Result) :-
  396	(
  397		referents_to_acetexts(RefList, RI--RO, ACETexts)
  398	->
  399		flatten(ACETexts, Result)
  400	;
  401		Result = []
  402	).
 referents_to_acetexts(+RefList:list, +RefInRefOut:term, -AceText:list) is det
Arguments:
RefList- is a list of top-level DRS referents
RefInRefOut- list of referents in--out
AceText- is an ACE text (list of tokens)
  411referents_to_acetexts([], RI--RI, '.').
  412
  413referents_to_acetexts([Referent | ReferentsTail], RI--RO, [Text | TextTail]) :-
  414	debug(verbose, "used referents: ~W~n", [RI, [numbervars(true)]]),
  415	referent_text(Referent, top, RI--RTmp, Text, _),
  416	debug(verbose, "top referent: ~W; text: ~W; used referents: ~W~n", [Referent, [numbervars(true)], Text, [numbervars(true)], RTmp, [numbervars(true)]]),
  417	!,
  418	referents_to_acetexts(ReferentsTail, RTmp--RO, TextTail).
 referent_text(+Referent:nvar, -Text:list, -Features:list) is det
 referent_text(+Referent:nvar, +TopDeep:atom, -Text:list, -Features:list) is det
Arguments:
Referent- is a discourse referent or data item
TopDeep- is in {top, deep}
Text- is an ACE text that corresponds to the discourse referent
Features- is in {f(sg, subj), f(sg, obj), f(pl, subj), f(pl, obj)}, for number and case sharing
  429referent_text(Referent, RI--RO, Text, Features) :-
  430	referent_text(Referent, deep, RI--RO, Text, Features).
  431
  432
  433referent_text(named(Name), _, RI--RI, NameText, f(SgPl, _)) :-
  434	surface_noun(pn, Name, SgPl, NameText),
  435	!.
  436
  437% Recursively call drs_to_coreace_nvar on the embedded DRS.
  438referent_text(Referent, deep, RI--RO, [that | SentenceListCoord], _) :-
  439	ref2conds(Referent, [Referent:drs(Dom, CondList)], _BoxId, _SentenceId),
  440	debug(that, "THAT: drs: ~W~n", [drs(Dom, CondList), [numbervars(true)]]),
  441	retractall(ref2conds(_, _, _, _)),
  442	reset_counter(box_counter),
  443	make_boxid(NewBoxId),
  444	drs_to_coreace_nvar(drs(Dom, CondList), NewBoxId, [[], [], [], []], RI--RO, Result),
  445	debug(that, "THAT: result: ~q~n", [Result]),
  446	find_sentencelist(Result, [_Ignore_BUG | SentenceList]),
  447	debug(that, "THAT: sentence(s): ~W~n", [SentenceList, [numbervars(true)]]),
  448	sentencelist_sentencelistcoord(SentenceList, SentenceListCoord).
  449
  450referent_text(formula(Expr1, Eq, Expr2), top, RI--RO, [BoxMarker, Expr1Text, Eq, Expr2Text], _) :-
  451	!,
  452	expr_exprpp(Expr1, RI--RTmp, Expr1Text),
  453	expr_exprpp(Expr2, RTmp--RO, Expr2Text),
  454	ref2conds(formula(Expr1, Eq, Expr2), _, BoxId, _SentenceId),
  455	get_box_prefix(BoxId, BoxMarker).
  456
  457% Support for query pronouns: 'who' and 'what'.
  458% Note: 'how' and 'which' are not covered by this rule.
  459% Note: the question mark is added later.
  460% Note: we only support top-level query-conditions.
  461% Note: this rule generates "there is who?" and never "there are who?"
  462referent_text(Referent, TopDeep, RI--[Referent | RI], [ThereIs, QueryWord], _Features) :-
  463	toplevel_id(ToplevelId),
  464	ref2conds(Referent, [Query], ToplevelId, _SentenceId),
  465	query(Referent, Query, _, QueryWord),
  466	get_box_prefix(ToplevelId, BoxPrefix),
  467	get_thereis(TopDeep, sg, BoxPrefix, ThereIs),
  468	\+ memberchk(Referent, RI).
  469
  470referent_text(Referent, TopDeep, RI--RO, Text, Features) :-
  471	get_type(Referent, Type, BoxId),
  472	get_box_prefix(BoxId, BoxPrefix),
  473	debug(that, 'referent_text: ~W ~W ~w ~w~n', [Referent, [numbervars(true)], Type, [numbervars(true)], BoxId, BoxPrefix]),
  474	!,
  475	conds_text(Type, BoxPrefix, TopDeep, RI--RO, Text, Features),
  476	debug(verbose, "referent_text_out: ~W; used referents: ~W~n", [Text, [numbervars(true)], RO, [numbervars(true)]]).
  477
  478referent_text(Expression, deep, RI--RO, ExpressionText, f(sg, _)) :-
  479	expr_exprpp(Expression, RI--RO, ExpressionText).
 get_type(+Referent:nvar, -Type:term, -BoxId:term) is det
Type is a structured representation of the conditions, e.g. we group all properties and modifiers together into a list and represent as one argument.
Arguments:
Referent- is a discourse referent
Type- is a structured form of Conditions
BoxId- is an identifier of the DRS box
  492get_type(Referent, Type, BoxId) :-
  493	ref2conds(Referent, Conditions, BoxId, _SentenceId),
  494	conditions_type(Conditions, Type).
 conditions_type(+Conditions:list, -Type:term) is det
Arguments:
Conditions- is a list of DRS conditions that correspond to a referent
Type- is a structured form of those conditions

There are three types of referents:

  1. Those that have an object-condition
  2. Those that have a predicate-condition
  3. Those that have no conditions (i.e. the that-subordination referent)
  508conditions_type(Conditions, noun(Mains, parts(Parts), owners(Owners), adjectives(Adjectives))) :-
  509	member(Condition, Conditions),
  510	functor(Condition, object, _),
  511	!,
  512	conditions_nountype(Conditions, Mains, Parts, Owners, Adjectives).
  513
  514conditions_type(Conditions, verb(Predicates, adverbs(Adverbs), pps(PPs))) :-
  515	member(Condition, Conditions),
  516	is_predicate(Condition),
  517	!,
  518	conditions_verbtype(Conditions, Predicates, Adverbs, PPs).
  519
  520conditions_type(Conditions, Conditions).
 conditions_nountype(+Conditions:list, -Mains:list, -Parts:list, -Owners:list, -Adjectives:list) is det
Arguments:
Conditions-
Mains-
Parts-
Owners-
Adjectives-
  531conditions_nountype([], [], [], [], []).
  532
  533conditions_nountype([H | T], Mains, [Part | Parts], Owners, Adjectives) :-
  534	H = has_part(_, Part),
  535	!,
  536	conditions_nountype(T, Mains, Parts, Owners, Adjectives).
  537
  538conditions_nountype([H | T], Mains, Parts, [H | Owners], Adjectives) :-
  539	functor(H, relation, _),
  540	!,
  541	conditions_nountype(T, Mains, Parts, Owners, Adjectives).
  542
  543conditions_nountype([H | T], Mains, Parts, Owners, [H | Adjectives]) :-
  544	functor(H, Functor, _),
  545	(
  546		Functor = property
  547	;
  548		Functor = query
  549	),
  550	!,
  551	conditions_nountype(T, Mains, Parts, Owners, Adjectives).
  552
  553% BUG: Here we convert those atoms that are in fact numbers (e.g. '5') into actual numbers (e.g. 5).
  554% APE does not generate such "atom numbers", but other DRS generators might.
  555conditions_nountype(
  556		[object(Referent, Value, Quantisation, Unit, Operator, Count) | T],
  557		[object(Referent, Value, Quantisation, Unit, Operator, NCount) | Mains], Parts, Owners, Adjectives
  558	) :-
  559	atom(Count), Count \= na,
  560	!,
  561	atom_number(Count, NCount),
  562	conditions_nountype(T, Mains, Parts, Owners, Adjectives).
  563
  564% Fall back: other conditions go to Mains.
  565conditions_nountype([H | T], [H | Mains], Parts, Owners, Adjectives) :-
  566	conditions_nountype(T, Mains, Parts, Owners, Adjectives).
 conditions_verbtype(+Conditions:list, -Predicates:list, -Adverbs:list, -PPs:list) is det
Arguments:
Conditions-
Predicates-
Adverbs-
PPs-
  576conditions_verbtype([], [], [], []).
  577
  578conditions_verbtype([H | T], Predicates, [H | Adverbs], PPs) :-
  579	functor(H, Functor, _),
  580	(
  581		Functor = modifier_adv
  582	;
  583		Functor = query
  584	),
  585	!,
  586	conditions_verbtype(T, Predicates, Adverbs, PPs).
  587
  588conditions_verbtype([H | T], Predicates, Adverbs, [H | PPs]) :-
  589	functor(H, Functor, _),
  590	(
  591		Functor = modifier_pp
  592	),
  593	!,
  594	conditions_verbtype(T, Predicates, Adverbs, PPs).
  595
  596% Fall back: other conditions go to Predicates.
  597conditions_verbtype([H | T], [H | Predicates], Adverbs, PPs) :-
  598	conditions_verbtype(T, Predicates, Adverbs, PPs).
 counter(+Name:atom, -N:integer) is det
Generate integers. If no integer has been generated yet then start with 1.
Arguments:
Name- is the name of the counter
N- is an integer
To be done
- This is a general predicate, move somewhere else.
  611counter(Name, N) :-
  612	catch(
  613		(nb_getval(Name, N0), succ(N0, N), nb_setval(Name, N)),
  614		_,
  615		(N = 1, nb_setval(Name, N))
  616	).
 reset_counter(+Name:atom) is det
Reset the named counter to 0.
To be done
- This is a general predicate, move somewhere else.
  625reset_counter(Name) :-
  626	nb_setval(Name, 0).
 make_ref2conds(+Drs:drs, +BoxId:term) is det
We assert all discourse referents from DRS into ref2conds/4 to speed up lookup later.
Arguments:
Drs- is an Attempto DRS
  635make_ref2conds(drs(Dom, Conds), BoxId) :-
  636	assert_referents(Dom, Conds, BoxId),
  637	process_conds(Conds, BoxId).
 assert_referents(+Referents:list, +ConditionList:list, +BoxId:term) is det
Finds all the conditions in the ConditionList that have the same Referent as the first argument. Asserts the predicate ref2conds/4 containing information about the shared Referent, the conditions that share the Referent, and the DRS-box ID. Finally processes separately the remaining conditions: in case the remaining conditions have the form formula/3 then they are asserted as they are. In case the remaining conditions are complex conditions then they are just ignored. Otherwise (e.g. in case of relation/3) a failure is triggered.

flatten/3 is used to remove the DRS embedded lists

Arguments:
Referents- are discourse referents of the DRS box
ConditionList- are conditions of the DRS box
BoxId- is a unique ID of the box
bug
- Maybe complex conditions should not reach this rule.
  659assert_referents([], Conditions, BoxId) :-
  660	assert_rest(Conditions, BoxId).
  661
  662assert_referents([Referent | ReferentsTail], Conditions, BoxId) :-
  663	flatten(Conditions, FlatConditions),
  664	mypartition(Referent, FlatConditions, Included, Excluded, Id),
  665	assert(ref2conds(Referent, Included, BoxId, Id)),
  666	assert_referents(ReferentsTail, Excluded, BoxId).
  667
  668
  669first_argument_is_referent(Referent, Condition) :-
  670	Condition \= formula(_, _, _),
  671	arg(1, Condition, Referent).
 mypartition(+Referent, +Conditions, ?Included, ?Excluded, ?Id) is det
  677mypartition(_Referent, [], [], [], _).
  678
  679mypartition(Referent, [Condition-STId | Conditions], [Condition | Included], Excluded, SId) :-
  680	first_argument_is_referent(Referent, Condition),
  681	!,
  682	get_sentence_id(STId, SId),
  683	mypartition(Referent, Conditions, Included, Excluded, SId).
  684
  685mypartition(Referent, [ConditionWithId | Conditions], Included, [ConditionWithId | Excluded], SId) :-
  686	mypartition(Referent, Conditions, Included, Excluded, SId).
 assert_rest(+CondList:list, +BoxId:term) is det
  692assert_rest([], _).
  693
  694assert_rest([formula(Expr1, Eq, Expr2)-STId | CondList], BoxId) :-
  695	get_sentence_id(STId, SId),
  696	assert(ref2conds(formula(Expr1, Eq, Expr2), [formula(Expr1, Eq, Expr2)], BoxId, SId)),
  697	assert_rest(CondList, BoxId).
  698
  699assert_rest([relation(_, _, _)-_ | _CondList], _BoxId) :-
  700	!,
  701	fail.
  702
  703assert_rest([has_part(_, _)-_ | _CondList], _BoxId) :-
  704	!,
  705	fail.
  706
  707assert_rest([_Cond | CondList], BoxId) :-
  708	assert_rest(CondList, BoxId).
 process_conds(+Conditions:list, +BoxId:term) is det
Traverses the DRS to assert all the referents together with their conditions. We also generate an ID for each embedded DRS (i.e. a box).

The conditions are first sorted to make sure that less complex conditions (e.g. negations) are verbalized before more complex ones (e.g. implications).

Arguments:
Conditions- are conditions of the DRS box
BoxId- is a unique ID of the box
  722process_conds(Cs, BoxId) :-
  723	sort(Cs, CsSorted),
  724	process_conds_loop(CsSorted, BoxId).
  725
  726
  727process_conds_loop([], _).
  728
  729process_conds_loop([C | Cs], BoxId) :-
  730	walk_cond(C, BoxId),
  731	process_conds_loop(Cs, BoxId).
 walk_cond(+Condition:term, +BoxId:term) is det
Arguments:
Condition- is a DRS (complex) condition
BoxId- is a unique ID of the box
  739walk_cond(_-_, _). % ignoring simple conditions
  740
  741walk_cond([C | Cs], _BoxId) :-
  742	include(is_complex_or_predicate, [C | Cs], Predicates),
  743	length(Predicates, Len),
  744	Len > 1,
  745	!,
  746	throw(error('Predicate group is too complex', context(walk/2, Predicates))).
  747
  748walk_cond([C | Cs], BoxId) :-
  749	!,
  750	process_conds([C | Cs], BoxId).
  751
  752walk_cond(question(drs(QDom, QConds)), BoxId) :-
  753	!,
  754	memberchk(query(_, _)-_, QConds),
  755	assert_referents(QDom, QConds, BoxId),
  756	process_conds(QConds, BoxId).
  757
  758walk_cond(Label:drs(Dom, Conds), BoxId) :-
  759	!,
  760	assert(ref2conds(Label, [Label:drs(Dom, Conds)], BoxId, 'BUG')).
  761
  762% BUG: handling of relation/3 alone in the then-box
  763% IN:  A dog of every man who waits barks.
  764% OUT: A dog that every man who waits OF-RELATION barks.
  765% BUG: UniqueRef should actually be a numbervard variable
  766walk_cond(drs(Dom1, Conds) => drs([], [relation(Owned, of, Owner)-STId]), ParentBoxId) :-
  767	!,
  768	make_boxid(if, ParentBoxId, BoxId1),
  769	assert_referents(Dom1, Conds, BoxId1),
  770	process_conds(Conds, BoxId1),
  771	make_boxid(then, ParentBoxId, BoxId2),
  772	counter(ref, UniqueRef),
  773	assert_referents([UniqueRef], [predicate(UniqueRef, 'OF-RELATION', Owner, Owned)-STId], BoxId2).
  774
  775walk_cond(drs(Dom1, Conds1) => drs(Dom2, Conds2), ParentBoxId) :-
  776	make_boxid(if, ParentBoxId, BoxId1),
  777	assert_referents(Dom1, Conds1, BoxId1),
  778	process_conds(Conds1, BoxId1),
  779	make_boxid(then, ParentBoxId, BoxId2),
  780	assert_referents(Dom2, Conds2, BoxId2),
  781	process_conds(Conds2, BoxId2).
  782
  783% Every disjunction has two DRSs. If the first DRS
  784% is complex (e.g. implication, negation, ...) then the conditions
  785% of the second DRS cannot share discourse referents with it.
  786% This property allows us to safely change the order the DRSs providing
  787% a more readable paraphrase and/or avoiding scope problems,
  788% e.g. naively paraphrasing
  789%   {Every man eats} or John drinks.
  790% as
  791%   If there is a man X1 then {the man X1 eats or John drinks}.
  792%
  793% @tbd We could relax the requirement that a complex condition
  794% must contain a single condition that embeds a DRS. Instead we should
  795% simply require that the OR boxes do not share variables that are
  796% not declared on a higher level. Unfortunately at this stage we have
  797% already numbervared the variables which makes this check difficult to implement.
  798% So we currently only check that the variables-list is empty in the 1st DRS
  799% but non-empty in the 2nd.
  800walk_cond(drs([], Conds1) v Drs2, BoxId) :-
  801	Drs2 = drs([_|_], _),
  802	!,
  803	walk_cond(Drs2 v drs([], Conds1), BoxId).
  804
  805walk_cond(drs(Dom1, Conds1) v drs(Dom2, Conds2), ParentBoxId) :-
  806	make_boxid(or1, ParentBoxId, BoxId1),
  807	assert_referents(Dom1, Conds1, BoxId1),
  808	process_conds(Conds1, BoxId1),
  809	make_boxid(or2, ParentBoxId, BoxId2),
  810	assert_referents(Dom2, Conds2, BoxId2),
  811	process_conds(Conds2, BoxId2).
  812
  813walk_cond(Cond, ParentBoxId) :-
  814	parse_unary(Cond, Type, Dom, Conds),
  815	!,
  816	make_boxid(Type, ParentBoxId, BoxId),
  817	assert_referents(Dom, Conds, BoxId),
  818	process_conds(Conds, BoxId).
  819
  820
  821% @tbd document
  822make_boxid(ToplevelId) :-
  823	toplevel_id(ToplevelId).
  824make_boxid(Type, ParentBoxId, id(Id, Type, ParentBoxId)) :-
  825	counter(box_counter, Id).
 get_box_prefix(BoxId:term, BoxPrefix:list) is det
In case any Referent from a given box has already been verbalized then we conjoin the verbalization of the current Referent.

In case no Referent from a given box has been verbalized, then the current Referent is the first one and we initiate the box. Then we check the outer box to come up for the name of the box (and do this recursively).

Arguments:
BoxId- is ...
BoxPrefix- is ...
  841% Not the first Referent in the top-box to be verbalized.
  842get_box_prefix(ToplevelId, ['.']) :-
  843	toplevel_id(ToplevelId),
  844	is_rep(0),
  845	!.
  846
  847% First Referent in the top-box to be verbalized.
  848get_box_prefix(ToplevelId, []) :-
  849	toplevel_id(ToplevelId),
  850	assert(is_rep(0)),
  851	!.
  852
  853% Not the first Referent in the OR1-box to be verbalized.
  854% Given that the OR1 V OR2 is in the NOT-box.
  855% Ex?: It is false that there is a cat and that there is a mouse or that there is a dog.
  856get_box_prefix(id(Id, or1, id(_, Marker, _)), [and, that]) :-
  857	is_unary_modifier(Marker),
  858	is_rep(Id),
  859	!.
  860
  861% Not the first Referent in the NOT-box to be verbalized.
  862get_box_prefix(id(Id, Marker, _), [and, that]) :-
  863	is_unary_modifier(Marker),
  864	is_rep(Id),
  865	!.
  866
  867% BUG: ???
  868% Not the first Referent in the any box to be verbalized.
  869get_box_prefix(id(Id, _, _), [and]) :-
  870	is_rep(Id),
  871	!.
  872
  873% The first Referent in the THEN-box to be verbalized.
  874get_box_prefix(id(Id, then, _), [then]) :-
  875	assert(is_rep(Id)),
  876	!.
  877
  878% The first Referent in the OR2-box to be verbalized.
  879% Given that the OR1 V OR2 is in the NOT-box.
  880% BUG: do we have to worry about any higher-level NOT-boxes
  881% or is checking just for the parent NOT-box OK?
  882% Ex: It is false that there is a cat or that there is a dog.
  883get_box_prefix(id(Id, or2, id(_, Marker, _)), [or, that]) :-
  884	is_unary_modifier(Marker),
  885	assert(is_rep(Id)),
  886	!.
  887
  888% The first Referent in the OR1-box.
  889% The parent is the NOT-box.
  890% The parent has already a Referent.
  891% @tbd Examples
  892get_box_prefix(id(Id, or1, id(ParentId, Marker, _)), [',', and, that]) :-
  893	is_unary_modifier(Marker),
  894	is_rep(ParentId),
  895	assert(is_rep(Id)),
  896	!.
  897
  898% The first Referent in the OR1-box.
  899% The parent is not the NOT-box and is not the top-box.
  900% The parent has already a Referent.
  901get_box_prefix(id(Id, or1, id(ParentId, _, _)), [',', and]) :-
  902	ParentId \= 0,
  903	is_rep(ParentId),
  904	assert(is_rep(Id)),
  905	!.
  906
  907% The first Referent in the OR2-box to be verbalized.
  908% Given that the parent is not a NOT-box.
  909get_box_prefix(id(Id, or2, _), [or]) :-
  910	assert(is_rep(Id)),
  911	!.
  912
  913% The general case. The first Referent to be verbalized in either:
  914% IF-box, OR1-box, NOT-box.
  915get_box_prefix(id(Id, BoxMarker, OuterBoxId), [OuterBoxPrefix | BoxPrefix]) :-
  916	assert(is_rep(Id)),
  917	get_box_name(BoxMarker, BoxPrefix),
  918	get_box_prefix(OuterBoxId, OuterBoxPrefix).
 is_unary_modifier(+Type:atom) is det
Arguments:
Type- is in {not, naf, can, must, should}
  925is_unary_modifier(not).
  926is_unary_modifier(naf).
  927is_unary_modifier(can).
  928is_unary_modifier(must).
  929is_unary_modifier(should).
  930is_unary_modifier(may).
 get_box_name(+BoxMarker:atom, -BoxPrefix:list) is det
Arguments:
BoxMarker- is ...
BoxPrefix- is a list of ACE tokens associated with the box

This is the conjunction with a preceding box.

  940get_box_name(if, [if]).
  941%%get_box_name(then, [then]).
  942get_box_name(or1, []).
  943%%get_box_name(or2, [or]).
  944get_box_name(not, [it, is, false, that]).
  945get_box_name(naf, [it, is, not, provable, that]).
  946get_box_name(can, [it, is, possible, that]).
  947get_box_name(must, [it, is, necessary, that]).
  948get_box_name(should, [it, is, recommended, that]).
  949get_box_name(may, [it, is, admissible, that]).
 conds_text(+Conds:term, +BoxPrefix:atom, +TopDeep:atom, -Text:list, -Features:list) is det
Note: some discourse referents don't have surface representation. We don't call such referents at all.

Note: some objects can have an owner, but in this case max 1 owner. ProperName objects cannot have an owner.

Arguments:
Conds- is a complex term with all the conditions grouped
BoxPrefix- is a prefix of tokens to be inserted in front of the verbalization (e.g. `and if it is false that')
TopDeep- is in {top, deep}
Text- is an ACE text that corresponds to the discourse referent
Features- is in {f(sg, subj), f(sg, obj), f(pl, subj), f(pl, obj)}, for number and case sharing
  967% Old somebody and something are referred to by a variable only.
  968conds_text(noun([object(A, somebody, countable, na, eq, 1)], parts([]), owners([]), adjectives([])), _, deep, RI--RI, [A], f(sg, _)) :-
  969	memberchk(A, RI),
  970	add_var(A),
  971	!.
  972
  973conds_text(noun([object(A, something, dom, na, na, na)], parts([]), owners([]), adjectives([])), _, deep, RI--RI, [A], f(sg, _)) :-
  974	memberchk(A, RI),
  975	add_var(A),
  976	!.
  977
  978
  979% New somebody and something (with 'there is')
  980conds_text(noun([object(A, somebody, countable, na, eq, 1)], parts([]), owners([]), adjectives([])),
  981BoxPrefix, top, RI--[A | RI], [BoxPrefix, there, is, somebody, A], f(sg, _)) :-
  982	\+ memberchk(A, RI),
  983	add_var(A),
  984	!.
  985
  986conds_text(noun([object(A, something, dom, na, na, na)], parts([]), owners([]), adjectives([])),
  987BoxPrefix, top, RI--[A | RI], [BoxPrefix, there, is, something, A], f(sg, _)) :-
  988	\+ memberchk(A, RI),
  989	add_var(A),
  990	!.
  991
  992% New somebody and something.
  993conds_text(noun([object(A, somebody, countable, na, eq, 1)], parts([]), owners([]), adjectives([])), _, deep, RI--[A | RI], [somebody, A], f(sg, _)) :-
  994	\+ memberchk(A, RI),
  995	add_var(A),
  996	!.
  997
  998conds_text(noun([object(A, something, dom, na, na, na)], parts([]), owners([]), adjectives([])), _, deep, RI--[A | RI], [something, A], f(sg, _)) :-
  999	\+ memberchk(A, RI),
 1000	add_var(A),
 1001	!.
 1002
 1003
 1004% NP conjunction. This is the only case where parts/1 has a non-empty list as an argument
 1005% Old plural object, refer to it by 'they' (and 'them'). E.g.
 1006% John and Mary wait. They talk.
 1007% John and Mary wait. Bill sees them.
 1008% * John and Mary wait. John and Mary talk. (this is not supported by refres)
 1009%
 1010% BUG: `them' is not supported
 1011conds_text(noun([object(A, na, countable, _, _, _)], parts([_ | _]), _Owner, _Adjectives), _BoxPrefix, deep, RI--RI, [they], f(pl, subj)) :-
 1012	memberchk(A, RI),
 1013	!.
 1014
 1015conds_text(noun([object(A, na, countable, _, _, _)], parts([_ | _]), _Owner, _Adjectives), _BoxPrefix, deep, RI--RI, [them], f(pl, obj)) :-
 1016	memberchk(A, RI),
 1017	!.
 1018
 1019% NP conjunction.
 1020% Note that we require that parts/1 has a non-empty list as an argument and that the number of
 1021% arguments matches the number specified in the object-condition (QNum).
 1022% In the DRSs generated by APE, this is not always the case. Consider DRSs where the
 1023% has_part/2 condition is embedded into negation, such as the ones generated from:
 1024% There are less than 3 men and less than 3 women.
 1025% Less than 3 men and John wait.
 1026conds_text(noun([object(A, na, countable, _, eq, QNum)], parts(ListOfObjects), _Owner, _Adjectives), BoxPrefix, TopDeep, RI--RO, [Prefix, ListOfObjectsText], f(pl, _)) :-
 1027	!,
 1028	debug(npcoord, 'npcoord: QNum: ~w; ListOfObjects: ~w~n', [QNum, ListOfObjects]),
 1029	length(ListOfObjects, QNum),
 1030	surface_det(A, RI, pl, TopDeep, BoxPrefix, countable, dummy, dummy, Prefix),
 1031	objects_to_text(ListOfObjects, [A | RI]--RO, ListOfObjectsText),
 1032	debug(verbose, 'top:~w prefix:~w result:~w~n', [TopDeep, BoxPrefix, Prefix]).
 1033
 1034% Plural `which'
 1035% Example: which men wait?
 1036% Example: there are which men of John?
 1037% `how many' (+ plural noun)
 1038% Example: how many men wait?
 1039% Example: there are how many men of John?
 1040conds_text(noun([object(A, Agent, countable, na, geq, 2)], parts([]), Owner, adjectives([Query])),
 1041BoxPrefix, TopDeep, RI--RO, [ThereIs, QueryWord, AgentText, OwnerText], f(pl, _)) :-
 1042	query(A, Query, pl, QueryWord),
 1043	!,
 1044	\+ memberchk(A, RI),
 1045	toplevel_id(ToplevelId),
 1046	ref2conds(A, _, ToplevelId, _SentenceId),
 1047	get_thereis(TopDeep, pl, BoxPrefix, ThereIs),
 1048	surface_noun(cn, Agent, pl, AgentText),
 1049	verbalize_owners(A, RI--RO, Owner, OwnerText).
 1050
 1051% BUG: temporary handling of "less than" and "at most"
 1052conds_text(noun([object(_, _, countable, na, na, na)], parts([]), _, adjectives(_)), _, _, _, _, _) :-
 1053	!,
 1054	fail.
 1055
 1056conds_text(noun([object(A, Agent, countable, na, Comp, Number)], parts([]), Owner, adjectives(Adjectives)),
 1057	BoxPrefix, TopDeep, RI--RO, [SurfaceDeterminer, AdjectivesText, AgentText, A, OwnerText], f(pl, _)) :-
 1058	(Number = 0 ; Number > 1),
 1059	surface_det(A, RI, pl, TopDeep, BoxPrefix, countable, Comp, Number, SurfaceDeterminer),
 1060	surface_noun(cn, Agent, pl, AgentText),
 1061	conds_to_andlist(adjective_to_text, Adjectives, AdjectivesText),
 1062	verbalize_owners(A, RI--RO, Owner, OwnerText),
 1063	add_var(A).
 1064
 1065
 1066% Singular and mass nouns
 1067%
 1068% 1. Indefinite pronouns (somebody, something) can have owners but not properties.
 1069%
 1070% Everything of John is red.
 1071% If there is something B of John then B is red.
 1072%
 1073% Note that this wouldn't work with quoted strings since they cannot have attached variables:
 1074%
 1075% Everything "Go!" of John is red. -> If there is something "Go!" of John then ??? is red.
 1076%
 1077% (Fortunately we don't support quoted strings in apposition anymore.)
 1078%
 1079% 2. Regular nouns
 1080% 3. BUG: measurement nouns
 1081
 1082% If there is somebody of John then ...
 1083conds_text(noun([object(A, Value, _, _, _, _)], parts([]), Owner, _Adjectives), BoxPrefix, top,
 1084	RI--RO, [BoxPrefix, there, is, Value, A, OwnerText], f(sg, _)) :-
 1085	(Value = somebody ; Value = something),
 1086	verbalize_owners(A, RI--RO, Owner, OwnerText),
 1087	add_var(A).
 1088
 1089
 1090% somebody of John waits ...
 1091conds_text(noun([object(A, Value, _, _, _, _)], parts([]), Owner, _Adjectives), _BoxPrefix, deep,
 1092	RI--RO, [Name, A, OwnerText], f(sg, _)) :-
 1093	(Value = somebody ; Value = something),
 1094	(
 1095		memberchk(A, RI)
 1096	->
 1097		Name = []
 1098	;
 1099		Name = Value
 1100	),
 1101	verbalize_owners(A, RI--RO, Owner, OwnerText),
 1102	add_var(A).
 1103
 1104
 1105% Singular `which'
 1106% (Note that `which' is not possible with mass nouns, qeneralized quantifiers,
 1107% and indefinite pronouns.)
 1108% Which man waits?
 1109% There is which man of John?
 1110conds_text(noun([object(A, Agent, countable, na, eq, 1)], parts([]), Owner, adjectives([Query])),
 1111BoxPrefix, TopDeep, RI--RO, [ThereIs, QueryWord, AgentText, OwnerText], f(sg, _)) :-
 1112	query(A, Query, sg, QueryWord),
 1113	!,
 1114	\+ memberchk(A, RI),
 1115	toplevel_id(ToplevelId),
 1116	ref2conds(A, _, ToplevelId, _SentenceId),
 1117	get_thereis(TopDeep, sg, BoxPrefix, ThereIs),
 1118	surface_noun(cn, Agent, sg, AgentText),
 1119	verbalize_owners(A, RI--RO, Owner, OwnerText).
 1120
 1121
 1122% 'how much' (+ mass noun)
 1123% Example: John eats how much food?
 1124conds_text(noun([object(A, Agent, mass, na, na, na)], parts([]), Owner, adjectives([Query])),
 1125BoxPrefix, TopDeep, RI--RO, [ThereIs, QueryWord, AgentText, OwnerText], f(sg, _)) :-
 1126	query(A, Query, mass, QueryWord),
 1127	!,
 1128	\+ memberchk(A, RI),
 1129	toplevel_id(ToplevelId),
 1130	ref2conds(A, _, ToplevelId, _SentenceId),
 1131	get_thereis(TopDeep, sg, BoxPrefix, ThereIs),
 1132	surface_noun(cn, Agent, mass, AgentText),
 1133	verbalize_owners(A, RI--RO, Owner, OwnerText).
 1134
 1135
 1136% Countable: a man
 1137conds_text(noun([object(A, Agent, countable, na, eq, 1)], parts([]), Owner, adjectives(Adjectives)),
 1138	BoxPrefix, TopDeep, RI--RO, [SurfaceDeterminer, AdjectivesText, AgentText, A, OwnerText], f(sg, _)) :-
 1139	surface_noun(cn, Agent, sg, AgentText),
 1140	conds_to_andlist(adjective_to_text, Adjectives, AdjectivesText),
 1141	surface_det(A, RI, sg, TopDeep, BoxPrefix, countable, _, _, SurfaceDeterminer),
 1142	verbalize_owners(A, RI--RO, Owner, OwnerText),
 1143	add_var(A).
 1144
 1145
 1146% Countable: At least 1 man
 1147conds_text(noun([object(A, Value, countable, na, Eq, 1)], parts([]), Owner, adjectives(Adjectives)),
 1148	BoxPrefix, TopDeep, RI--RO, [SurfaceDeterminer, AdjectivesText, AgentText, A, OwnerText], f(sg, _)) :-
 1149	Eq \= eq,
 1150	surface_noun(cn, Value, sg, AgentText),
 1151	conds_to_andlist(adjective_to_text, Adjectives, AdjectivesText),
 1152	surface_det(A, RI, sg, TopDeep, BoxPrefix, countable, Eq, 1, SurfaceDeterminer),
 1153	verbalize_owners(A, RI--RO, Owner, OwnerText),
 1154	add_var(A).
 1155
 1156
 1157% Mass: some rice
 1158conds_text(noun([object(A, Agent, mass, na, na, na)], parts([]), Owner, adjectives(Adjectives)),
 1159BoxPrefix, TopDeep, RI--RO, [SurfaceDeterminer, AdjectivesText, AgentText, A, OwnerText], f(sg, _)) :-
 1160	surface_noun(cn, Agent, mass, AgentText),
 1161	conds_to_andlist(adjective_to_text, Adjectives, AdjectivesText),
 1162	surface_det(A, RI, sg, TopDeep, BoxPrefix, mass, _, _, SurfaceDeterminer),
 1163	verbalize_owners(A, RI--RO, Owner, OwnerText),
 1164	add_var(A).
 1165
 1166% Measurement constructs, e.g.
 1167% More than 3 kg of white rice rots.
 1168% 2 kg of water boils. The water is warm.
 1169% 2 kg of apples are ripe. The apples rot.
 1170conds_text(noun([object(A, Agent, Quant, Unit, QType, QNum)], parts([]), Owner, adjectives(Adjectives)),
 1171BoxPrefix, TopDeep, RI--RO, [ThereIs, Specifier, AdjectivesText, AgentText, A, OwnerText], f(SgPl, _)) :-
 1172	(Unit \= na),
 1173	(
 1174		Quant = countable
 1175	->
 1176		SgPl = pl
 1177	;
 1178		SgPl = sg
 1179	),
 1180	(
 1181		memberchk(A, RI)
 1182	->
 1183		ThereIs = [],
 1184		surface_determiner(old, _, _, Specifier),
 1185		RO = RI,
 1186		OwnerText = []
 1187	;
 1188		get_thereis(TopDeep, SgPl, BoxPrefix, ThereIs),
 1189		surface_determiner(new, QType, QNum, Q),
 1190		Specifier = [Q, Unit, of],
 1191		verbalize_owners(A, RI--RO, Owner, OwnerText)
 1192	),
 1193	conds_to_andlist(adjective_to_text, Adjectives, AdjectivesText),
 1194	surface_noun(cn, Agent, SgPl, AgentText),
 1195	add_var(A).
 1196
 1197
 1198% Intransitive verbs with (adverb | pp)* attachment.
 1199conds_text(verb([predicate(_, Predicate, Argument)], adverbs(Adverbs), pps(PPs)), Box, _,
 1200	RI--RO, [Box, ArgumentText, PredicateText, AdverbsText, PPsText], _) :-
 1201	referent_text(Argument, RI--RTmp, ArgumentText, f(SgPl, subj)),
 1202	surface_verb(SgPl, Predicate, PredicateText),
 1203	conds_to_andlist(adverb_to_text, Adverbs, AdverbsText),
 1204	pps_to_text(PPs, RTmp--RO, PPsText).
 1205
 1206% Transitive verbs with (adverb | pp)* attachment.
 1207% BUG: Comment is currently not returned.
 1208conds_text(verb([predicate(_, Predicate, Argument1, Argument2)], adverbs(Adverbs), pps(PPs)), Box, _,
 1209	RI--RO, [Box, Argument1Text, PredicateText, Argument2Text, AdverbsText, PPsText], _) :-
 1210	debug(verbose, "transitive verb: referents in: ~W~n", [RI, [numbervars(true)]]),
 1211	referent_text(Argument1, RI--RTmp1, Argument1Text, f(SgPl, subj)),
 1212	surface_verb(SgPl, Predicate, PredicateText),
 1213	referent_text(Argument2, RTmp1--RTmp2, Argument2Text, f(_, obj)),
 1214	conds_to_andlist(adverb_to_text, Adverbs, AdverbsText),
 1215	pps_to_text(PPs, RTmp2--RO, PPsText),
 1216	make_comment(PredicateText, PPsText, _Comment).
 1217
 1218% Ditransitive verbs with (adverb | pp)* attachment.
 1219% Note: the order of calling referent_text/4 is important as assert/1 is performed by this call.
 1220% Test it with "A man gives a dog the dog.", in the paraphrase the order of indef-NP and def-NP must be correct.
 1221%
 1222conds_text(verb([predicate(_, Lemma, Argument1, Argument2, Argument3)], adverbs(Adverbs), pps(PPs)), Box, _,
 1223	RI--RO, DiText, _) :-
 1224	referent_text(Argument1, RI--RTmp1, Argument1Text, f(SgPl, subj)),
 1225	get_di_marker(SgPl, Lemma, SurfaceForm, DiMarker),
 1226	di_text(DiMarker, RTmp1--RTmp2, Box, Argument1Text, SurfaceForm, Argument2, Argument3, AdverbsText, PPsText, DiText),
 1227	conds_to_andlist(adverb_to_text, Adverbs, AdverbsText),
 1228	pps_to_text(PPs, RTmp2--RO, PPsText).
 1229
 1230
 1231% Properties as copula arguments.
 1232% Must have at least 1 element.
 1233conds_text([FirstProperty | RestProperties], _, _, RI--RO, [PropertiesText], _) :-
 1234	properties_to_text([FirstProperty | RestProperties], RI--RO, PropertiesText).
 di_text
Two versions of the surface form of ditransitive constructs: (1) dative shift, (2) with prepositional marker.
 1242di_text('', RI--RO, Box, Argument1Text, PredicateText, Argument2, Argument3, AdverbsText, PPsText, [Box, Argument1Text, PredicateText, Argument3Text, Argument2Text, AdverbsText, PPsText]) :-
 1243	!,
 1244	referent_text(Argument3, RI--RTmp, Argument3Text, f(_, obj)),
 1245	referent_text(Argument2, RTmp--RO, Argument2Text, f(_, obj)).
 1246
 1247di_text(Marker, RI--RO, Box, Argument1Text, PredicateText, Argument2, Argument3, AdverbsText, PPsText, [Box, Argument1Text, PredicateText, Argument2Text, Marker, Argument3Text, AdverbsText, PPsText]) :-
 1248	referent_text(Argument2, RI--RTmp, Argument2Text, f(_, obj)),
 1249	referent_text(Argument3, RTmp--RO, Argument3Text, f(_, obj)).
 verbalize_owners(+Referent:nvar, +Owners:term, -TokenList:list) is det
Arguments:
Referent- is a discourse referent
Owners- is a term owners([relation(_, of, OwnerReferent)]). Note that is always contains just one relation/3 condition.
TokenList- is a list of resulting ACE tokens

Note that we verbalize the of-constructions only in case the NP is not anaphoric, i.e. we never output "the dog X of the man Y" but simply "the dog X".

 1264verbalize_owners(Ref, RI--RI, owners([]), []) :-
 1265	memberchk(Ref, RI),
 1266	!.
 1267
 1268verbalize_owners(Ref, RI--[Ref | RI], owners([]), []) :-
 1269	!.
 1270
 1271verbalize_owners(Ref, RI--RI, owners([_]), []) :-
 1272	memberchk(Ref, RI),
 1273	!.
 1274
 1275verbalize_owners(Ref, RI--RO, owners([relation(_, of, OwnerReferent)]), [of, OwnerText]) :-
 1276	referent_text(OwnerReferent, [Ref | RI]--RO, OwnerText, _Features).
 conds_to_andlist(:Goal, +Conds:list, -AndList:list) is det
Maps a list of DRS conditions to an ACE conjunction, e.g.
Arguments:
Goal- maps a condition to ACE text (a word or two)
Conds- is a list of DRS conditions
AndList- is list of ACE words conjoined by 'and'
 1289conds_to_andlist(_, [], []).
 1290
 1291conds_to_andlist(Cond_To_Text, [Cond], [Text]) :-
 1292	!,
 1293	call(Cond_To_Text, Cond, Text).
 1294
 1295conds_to_andlist(Cond_To_Text, [Cond | Conds], [Text, 'and' | Texts]) :-
 1296	call(Cond_To_Text, Cond, Text),
 1297	conds_to_andlist(Cond_To_Text, Conds, Texts).
 adjective_to_text(+AdjCond:term, -AdjToken:term) is det
Arguments:
AdjCond- is a DRS condition that corresponds to an ACE adjective
AdjToken- is the corresponding token (or possibly a list of tokens)
 1305adjective_to_text(property(_, Property, Comparison), PropertyText) :-
 1306	surface_property(Property, Comparison, PropertyText).
 adverb_to_text(+AdverbCond:term, -AdverbToken:term) is det
Arguments:
AdverbCond- is a DRS condition that corresponds to an ACE adverb or how/where/when query word
AdverbToken- is the corresponding token (or possibly a list of tokens)
To be done
- Note that we currently only support top-level query-conditions ('how', 'where', 'when'), because we cannot correctly handle e.g. "John how believes that Mary sleeps?"
 1318adverb_to_text(modifier_adv(_, Adverb, Comparison), AdverbText) :-
 1319	!,
 1320	surface_adverb(Adverb, Comparison, AdverbText).
 1321
 1322adverb_to_text(Query, QueryWord) :-
 1323	query(Referent, Query, _, QueryWord),
 1324	toplevel_id(ToplevelId),
 1325	ref2conds(Referent, _, ToplevelId, _SentenceId).
 pps_to_text(+Modifiers:list, -TokenList:list) is det
Arguments:
Modifiers- is a list of modifier_pp- or query-conditions
TokenList- is a list of ACE tokens
 1333pps_to_text([], RI--RI, []).
 1334
 1335pps_to_text([modifier_pp(_, Prep, Modifier) | PPs], RI--RO, [Prep, ModifierText | PPsText]) :-
 1336	referent_text(Modifier, RI--RTmp, ModifierText, _Features),
 1337	pps_to_text(PPs, RTmp--RO, PPsText).
 properties_to_text(+Properties:list, -TokenList:list) is det
Arguments:
Properties- is a list of property-conditions
TokenList- is a list of ACE tokens
 1345properties_to_text([], RI--RI, []).
 1346
 1347properties_to_text([property(_, Property, Comparison)], RI--RI, PropertyText) :-
 1348	!,
 1349	surface_property(Property, Comparison, PropertyText).
 1350
 1351properties_to_text([property(_, Property, Comparison, Argument)], RI--RO, [PropertyText, ArgumentText]) :-
 1352	!,
 1353	surface_property(Property, Comparison, PropertyText),
 1354	referent_text(Argument, RI--RO, ArgumentText, _Features).
 1355
 1356properties_to_text([property(_Ref1, Adjective, Ref2, Comparison, ComparisonTarget, Ref3)], RI--RO, PropertyText) :-
 1357	!,
 1358	referent_text(Ref2, RI--RTmp, Ref2Text, _),
 1359	referent_text(Ref3, RTmp--RO, Ref3Text, _),
 1360	surface_property(Adjective, Comparison, ComparisonTarget, Ref2Text, Ref3Text, PropertyText).
 1361
 1362properties_to_text([property(_, Property, Comparison) | Properties], RI--RO, [PropertyText, 'and' | PropertiesText]) :-
 1363	!,
 1364	surface_property(Property, Comparison, PropertyText),
 1365	properties_to_text(Properties, RI--RO, PropertiesText).
 objects_to_text(+ListOfObjects:list, -ListOfObjectsVerbalized:list) is det
Arguments:
ListOfObjects- is a list of variables and/or data items
ListOfObjectsVerbalized- is a list of ACE tokens

Handling of plural objects which are built from several NPs.

 1375objects_to_text([Agent], RI--RO, [AgentText]) :-
 1376	referent_text(Agent, RI--RO, AgentText, _Features).
 1377
 1378objects_to_text([Agent | Agents], RI--RO, [AgentText, 'and' | AgentsText]) :-
 1379	referent_text(Agent, RI--RTmp, AgentText, _Features),
 1380	objects_to_text(Agents, RTmp--RO, AgentsText).
 surface_det(+Referent:term, +SgPl:atom, +TopDeep:atom, +BoxPrefix:list, +NounType:atom, +Comp:atom, +Number:atom, -Result:list) is det
Arguments:
Referent- is a discourse referent
SgPl- is in {sg, pl}
TopDeep- {top, deep, BUG}
BoxPrefix- BUG
NounType- {mass, countable}
Comp- is in {eq, geq, leq, greater, less}
Number- is an integer or 'na' or 'dummy'
Result- is a list of ACE tokens (can also be an atom)

BUG: "top" means always "new"?

 1396surface_det(Referent, RI, SgPl, TopDeep, BoxPrefix, NounType, Comp, Number, Result) :-
 1397	(
 1398		memberchk(Referent, RI)
 1399	->
 1400		OldNew = old
 1401	;
 1402		OldNew = new
 1403	),
 1404	surface_det_x(SgPl, TopDeep, BoxPrefix, NounType, OldNew, Comp, Number, Result).
 1405
 1406
 1407surface_det_x(sg, top, BoxPrefix, countable, new, eq, 1, [BoxPrefix, there, is, a]).
 1408
 1409surface_det_x(sg, top, BoxPrefix, mass, new, na, na, [BoxPrefix, there, is, some]).
 1410
 1411surface_det_x(sg, deep, _, countable, new, eq, 1, [a]) :- !.
 1412surface_det_x(sg, deep, _, mass, new, na, na, [some]).
 1413surface_det_x(sg, deep, _, mass, old, _, _, [the]).
 1414
 1415
 1416% There are John and Mary.
 1417surface_det_x(pl, top, BoxPrefix, _, _, dummy, dummy, [BoxPrefix, there, are]) :- !.
 1418
 1419% John and Mary wait.
 1420surface_det_x(pl, deep, _, _, _, dummy, dummy, []) :- !.
 1421
 1422
 1423surface_det_x(sg, top, BoxPrefix, countable, Det, Comp, Number, [BoxPrefix, there, is, SurfaceDeterminer]) :-
 1424	surface_determiner(Det, Comp, Number, SurfaceDeterminer).
 1425
 1426surface_det_x(sg, deep, _, countable, Det, Comp, Number, SurfaceDeterminer) :-
 1427	surface_determiner(Det, Comp, Number, SurfaceDeterminer).
 1428
 1429
 1430surface_det_x(pl, top, BoxPrefix, _, Det, Comp, Number, [BoxPrefix, there, are, SurfaceDeterminer]) :-
 1431	surface_determiner(Det, Comp, Number, SurfaceDeterminer).
 1432
 1433surface_det_x(pl, deep, _, _, Det, Comp, Number, SurfaceDeterminer) :-
 1434	surface_determiner(Det, Comp, Number, SurfaceDeterminer).
 surface_determiner(+OldNew:atom, +Operator:atom, +Count:atomic, -SurfaceDeterminer:list) is det
Arguments:
OldNew-
Operator- is in {eq, geq, leq, greater, less, exactly, na}
Count- is a positive integer or 'na'
SurfaceDeterminer- is a list of tokens corresponding the an ACE determiner
 1444surface_determiner(old, _, _, the).
 1445
 1446surface_determiner(new, eq, Number, [Number]).
 1447
 1448surface_determiner(new, geq, Number, [at, least, Number]).
 1449
 1450surface_determiner(new, leq, Number, [at, most, Number]).
 1451
 1452surface_determiner(new, greater, Number, [more, than, Number]).
 1453
 1454surface_determiner(new, less, Number, [less, than, Number]).
 1455
 1456surface_determiner(new, exactly, Number, [exactly, Number]).
 1457
 1458surface_determiner(new, na, na, []).
 get_thereis(+TopDeep:atom, +SgPl:atom, +BoxPrefix:list, -ThereIs:list) is det
Arguments:
TopDeep- is in {top, deep}
SgPl- is in {sg, pl}
BoxPrefix-
ThereIs- is a list of tokens containing the BoxPrefix and 'there is/are' is needed
 1468get_thereis(top, sg, BoxPrefix, [BoxPrefix, there, is]).
 1469get_thereis(top, pl, BoxPrefix, [BoxPrefix, there, are]).
 1470get_thereis(deep, _, _, []).
 make_comment(+VerbText:list, +PpText:list, -Comment:list) is det
On the basis of the PP construct a comment for novices.
To be done
- Experimental
 1479make_comment(_, [], []).
 1480make_comment(PredicateText, [H | Tail], ['/*', 'Did you know that in ACE prepositional phrases always modify the verb? I.e.', PredicateText, [H | Tail], '*/']).
 expr_exprpp(+Expression:term, -ExpressionText:list) is det
Arguments:
Expression-
ExpressionText-
 1488expr_exprpp(string(String), RI--RI, StringText) :-
 1489	!,
 1490	atomic(String), % the content of string/1 is either an atom or a number
 1491	surface_quotedstring(String, StringText).
 1492
 1493expr_exprpp(int(Number), RI--RI, NumberText) :-
 1494	!,
 1495	integer(Number),
 1496	with_output_to(atom(NumberText), format("~w", [Number])).
 1497
 1498expr_exprpp(real(Number), RI--RI, NumberText) :-
 1499	!,
 1500	float(Number),
 1501	with_output_to(atom(NumberText), format("~w", [Number])).
 1502
 1503expr_exprpp(int(Number, Unit), RI--RI, [NumberText, Unit]) :-
 1504	!,
 1505	integer(Number),
 1506	with_output_to(atom(NumberText), format("~w", [Number])).
 1507
 1508expr_exprpp(real(Number, Unit), RI--RI, [NumberText, Unit]) :-
 1509	!,
 1510	float(Number),
 1511	with_output_to(atom(NumberText), format("~w", [Number])).
 1512
 1513expr_exprpp(named(Name), RI--RI, NameText) :-
 1514	surface_noun(pn, Name, _, NameText),
 1515	!.
 1516
 1517% Note: it's ok to call findall where RI--RI because sets cannot introduce new referents
 1518expr_exprpp(set(Set), RI--RI, ['{', CommaSetText, '}']) :-
 1519	!,
 1520	findall(ElText, (member(El, Set), expr_exprpp(El, RI--RI, ElText)), SetText),
 1521	list_commalist(SetText, CommaSetText).
 1522
 1523% Note: it's ok to call findall where RI--RI because lists cannot introduce new referents
 1524expr_exprpp(list(List), RI--RI, ['[', CommaListText, ']']) :-
 1525	!,
 1526	findall(ElText, (member(El, List), expr_exprpp(El, RI--RI, ElText)), ListText),
 1527	list_commalist(ListText, CommaListText).
 1528
 1529expr_exprpp(expr(Op, Expr1, Expr2), RI--RO, ['(', Expr1Text, Op, Expr2Text, ')']) :-
 1530	!,
 1531	expr_exprpp(Expr1, RI--RTmp, Expr1Text),
 1532	expr_exprpp(Expr2, RTmp--RO, Expr2Text).
 1533
 1534expr_exprpp(Referent, RI--RO, Variable) :-
 1535	get_type(Referent, Type, BoxId),
 1536	get_box_prefix(BoxId, BoxPrefix),
 1537	conds_text(Type, BoxPrefix, deep, RI--RO, Text, _),
 1538	flatten(Text, FlatText),
 1539	last(FlatText, Variable),
 1540	debug(verbose, "NP in expr: ~w ~w~n", [Text, Variable]).
 list_commalist(?List:list, ?CommaList:list) is nondet
Arguments:
List- is a list of elements
CommaList- is a list where the elements are separated by explicit commas
 1548list_commalist([], []).
 1549list_commalist([X], [X]).
 1550list_commalist([X1, X2 | Tail], [X1, ',' | Text]) :-
 1551	list_commalist([X2 | Tail], Text).
 sentencelist_sentencelistcoord(+SentenceList:list, -SentenceListCoord:list) is det
Note that sentencelist cannot be empty.
 1558sentencelist_sentencelistcoord([Sentence], [Sentence]).
 1559sentencelist_sentencelistcoord([Sentence1, Sentence2 | SentenceList], [Sentence1, [and, that] | SentenceListCoord]) :-
 1560	sentencelist_sentencelistcoord([Sentence2 | SentenceList], SentenceListCoord).
Returns the sentence ID. Supports two formats:
 1571get_sentence_id(SId/_TId, SId) :- !.
 1572get_sentence_id(SId, SId).
 is_complex_or_predicate(+Condition:term)
 1578is_complex_or_predicate([_ | _]) :-
 1579	!.
 1580is_complex_or_predicate(Condition) :-
 1581	is_predicate(Condition),
 1582	!.
 1583is_complex_or_predicate(Condition) :-
 1584	embeds_drs(Condition).
 is_predicate(+Condition:term)
Arguments:
Condition- DRS condition with or without the sentence ID
 1591is_predicate(Condition-_) :-
 1592	!,
 1593	functor(Condition, predicate, _).
 1594
 1595is_predicate(Condition) :-
 1596	functor(Condition, predicate, _).
 embeds_drs(+Condition:term)
Succeeds if the condition embeds a DRS, e.g. negation embeds a single DRS, implication embeds two DRSs. Simple conditions (e.g. predicate) and list-conditions (that are derived e.g. from "at most n") do not embed DRSs.
To be done
- this predicate is quite general, move it somewhere else
 1608embeds_drs(_Label:drs(_, _)).
 1609embeds_drs(=>(_, _)).
 1610embeds_drs(v(_, _)).
 1611embeds_drs(-(_)).
 1612embeds_drs(~(_)).
 1613embeds_drs(can(_)).
 1614embeds_drs(must(_)).
 1615embeds_drs(should(_)).
 1616embeds_drs(may(_)).
 1617
 1618
 1619% is_complex_drs(+Drs:drs)
 1620%
 1621% @bug Currently not used
 1622%
 1623% DRS is complex iff
 1624% at least one of its conditions embeds a DRS.
 1625%
 1626/*
 1627is_complex_drs(drs(_, Cs)) :-
 1628	member(C, Cs),
 1629	embeds_drs(C),
 1630	!.
 1631*/
 1632
 1633is_complex_drs(drs(_, [Cond])) :-
 1634	embeds_drs(Cond).
 parse_unary(+Condition:term, -Type:atom, -Dom:list, -Conds:list)
 1639parse_unary(-(drs(Dom, Conds)), not, Dom, Conds).
 1640parse_unary(~(drs(Dom, Conds)), naf, Dom, Conds).
 1641parse_unary(can(drs(Dom, Conds)), can, Dom, Conds).
 1642parse_unary(must(drs(Dom, Conds)), must, Dom, Conds).
 1643parse_unary(should(drs(Dom, Conds)), should, Dom, Conds).
 1644parse_unary(may(drs(Dom, Conds)), may, Dom, Conds).
 query(+Ref, +QueryTerm:term, +SgPl:atom, -QueryPhrase:atom) is det
 1650query(X, query(X, QLemma), SgPl, qp(QPhrase)) :-
 1651	query_(QLemma, SgPl, QPhrase),
 1652	!.
 1653
 1654query_(which, sg, [which]).
 1655query_(which, pl, [which]).
 1656query_(howm, pl, [how, many]).
 1657query_(howm, mass, [how, much]).
 1658query_(Word, _, [Word])