

%% This file (incremental_analysis) contains all the predicates 
%% directly serving incremental analysis, including those for 
%% actually applying two level rules incrementally, and also 
%% those for the incremental command loop. (but not for actually
%% recognising inputted commands). 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


%% An important data structure is the `block' which 
%% consists of a 3 element list: 
%% 
%%     [Real_surface, Incremental_surface, Config]
%%     
%% Config is a  `config' is as defined in the file `rule_interpreter', 
%% i.e. a list of all the bits of information that go to make up a 
%% `configuration' at any stage in processing.
%% 
%% Real_surface is the actual input sequence of surface segments 
%% being analysed. However, for incremental analysis, the analysis 
%% process is not directly applied to the input sequence, as this 
%% would make available right context information, constraining 
%% possible analyses, that should not be available when only 
%% only some initial substring of the overall input has been 
%% supplied (the assumed scenario for a partial stage in 
%% incremental processing). Instead, analysis is applied to 
%% Incremental_surface, which is initially uninstantiated. As 
%% processing proceeds, segments from Real_surface are 
%% instantiated across into Incremental_surface, but only as 
%% many as is appropriate to the current stage of assumed 
%% incremental input. Note that the matching of two level rules
%% may bring about instantiation of Incremental_surface beyond the 
%% assumed current point of incremental input, and so 
%% Incremental_surface itself acts as a store of constraints that
%% arise from the two level mapping, that may serve to rule out a 
%% partial analysis when an attempt is made to instantiate across 
%% more segments from Real_surface. 
   

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Do incremental analsis on surface segment 
% sequence Surf. 

incremental_analysis(Surf):- 
   macro_eval_list(Surf,Surf1),                    % Do macro expansion
   write('Surface sequence: '), write(Surf),nl, 
   (\+(Surf = Surf1)                                 % Print result of macro expansion
         -> (nl, write('Macro evaluation gives: '),  % (if its changed anything). 
             print_segment_list(Surf1), nl)
	  ; true), 
   Blocks = [[Surf1,Surf2,[0,initial,[],Surf2,[],_,[]]]],  % Construct initial set of blocks, 
                                                           % containing just the one initial block. 
   nextloop_incremental(0,Blocks).            % proceed with incremental processing. 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% nextloop_incremental/2: <limit> <blocks> 
%
% The <limit> is the number of input segments that have been incrementally processed. 
% <blocks> is a set of partial states in processing. 
% nextloop_incremental requests command from user as to how to proceed in
% incremental processing. 

nextloop_incremental(Limit,Blocks):- 
   write('Number of segments to advance? [default 1]'), nl,
   write('(commands - to list other commands)'),
   get_command(incremental,Command),                 % Get command as to what to do next.
   loop_incremental(Command,Limit,Blocks).           % Go as commanded. 


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% loop_incremental/3: <command> <limit> <blocks> 
%
% The <limit> is the number of input segments that have been incrementally processed. 
% <blocks> is a set of partial states in processing. 
%
% loop_incremental/3 covers all the cases for what must be done next
% in incremental process -- most cases being to act in accordance with 
% a command that the user has inputted, and which has been passed in as 
% the predicate's first argument. 

loop_incremental([quit],_,_):- !,               % Command = quit, 
   nl, write('quitting incremental loop'), nl.  % finish. 

loop_incremental(_,_,[]):- !, nl,               % The blocks set is empty -> no more possible 
   write('analysis options exhausted.'), nl,    % configs to pursue. Quit. 
   write('quitting incremental loop'), nl.  

loop_incremental([list],Limit,Blocks):- !,      % Command = list, 
   nl, write('Listing possible words: '), nl, 
   enumerate_possible_words(Blocks), nl, nl,    % Lookup and print out all morphs in lexicon that 
                                                % are possible continuations of current configs. 
   nextloop_incremental(Limit,Blocks).     % Get next command and proceed. 


loop_incremental([switches],Limit,Blocks):- !,    % Command = switches, 
   switches,                                      % Allow user to flip switches governing 
                                                  % printing of answers. 
   nextloop_incremental(Limit,Blocks).     % Get next command and proceed. 


loop_incremental([commands],Limit,Blocks):- !,    % Command = commands. 
   command_options(incremental), nl,              % Print out a list of command options. 
   nextloop_incremental(Limit,Blocks).     % Get next command and proceed. 


loop_incremental([answers],Limit,Blocks):- !,      % Command = answers. 
   nl, write('Printing partial answers: '), nl, nl, 
   print_incremental_answers(Blocks),              % Print out partial answers.
   nextloop_incremental(Limit,Blocks).     % Get next command and proceed. 


loop_incremental([number,Ds],OldLimit,Blocks):- !,  % Command = numbers. 
                                                    % User's input just a digit string, 
						    % predicate get_command labels this case as
						    % "numbers". 
						    % Taken to signal number of segments to
						    % advance in incremental processing.  
   digits_to_number(Ds,Extra,_),           % Convert digit string to a decimal number. 
   nl, write('incrementing '),write(Extra),
   (Extra = 1 -> write(' segment') ; write(' segments')), nl, nl, 
   Limit is OldLimit + Extra,              % Increment limit by inputted number. 
   incremental_advance(Limit,Extra,Blocks,Newblocks),  % Incrementally advance each block in the 
                                                       % the block set, by the inputted amount,
						       % to give a new block set. 
   count_possible_words(Newblocks,N),             % Count up number of morphs in lexicon that 
   write('Possible words: '), write(N), nl, nl,   % are possible continuations from current configs. 
   nextloop_incremental(Limit,Newblocks).  % Get next command and proceed. 

loop_incremental(_,Limit,Blocks):-                      % Catch all - command not recognised. 
   write(' ** Input not recognised. Use a designated option ** '), 
   options(incremental), 
   nextloop_incremental(Limit,Blocks).     % Get next command and proceed. 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% incremental_advance/4: <number-limit><number-extrasegs><oldblocks><newblocks>
%
% advance each block in <oldblocks> by <number-extrasegs> up to <number-limit>
% and return results as <newblocks>. 

incremental_advance(_,_,[],[]).                        % Finished. 
incremental_advance(L,M,[Block|Blocks],Newblocks):-    
   incremental_advance_main(L,M,Block,Newblocks1),       % Advance this block. 
   incremental_advance(L,M,Blocks,Newblocks2),           % Advance rest blocks. 
   append(Newblocks1,Newblocks2,Newblocks).              % Sum up results. 

%%%%%%%%%%%%%%%%%%

% incremental_advance_main/4: <number-limit><number-extrasegs><block><newblocks>
%
% advance each block in <block> by <number-extrasegs> up to <number-limit>
% and return results as <newblocks>. 

% incremental_advance_main/4:

incremental_advance_main(Limit,Extra,[Surf1,Surf2,IN],Newblocks):- 
   unify_first_N(Extra,Surf1,Surf2,NewSurf1,NewSurf2), !, % unify the first `Extra' (a number) 
                                                          % elements of the real and incremental
							  % surface sequences. 
   xbagof([NewSurf1,NewSurf2,OUT],     % Parts of each new block.  
          incremental_apply_rules(IN,OUT,Limit),  % advance config upto `Limit' segs (a number)
	  Newblocks).                  % Collect all answers. 

incremental_advance_main(_,_,_,[]).    % If unify_first_N step of first case fails, return []. 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% unify_first_N/5: <N><list1-in><list2-in><list1-out><list2-out>

% Unifies the first N elements of two sets, i.e. succeeds if the first N elements 
% are the same or can unify. Returns remainders of the two lists. 

unify_first_N(N,As,Bs,As,Bs):- N =< 0, !. 
unify_first_N(_,[],[],[],[]):- !. 
unify_first_N(N,[A|As],[A|Bs],Cs,Ds):- 
   N > 0, 
   M is N - 1, 
   unify_first_N(M,As,Bs,Cs,Ds). 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% incremental_apply_rules/3: <config-in><config-out><Limit>
%
% Advance input configuration <config-in> up to limit <Limit>
% to give new config <config-out>. 

incremental_apply_rules(Out,Out,Limit):-     % Finished, so return config OUT, if: 
   Out = [N|_],                        %  - look up how many input segs current config
                                       % current config spans across, 
   N >= Limit,                         %  - that number >= limit for incremental processing. 
   obligatory_check_config(Out).       %  - partition of analysis does not violate oblig 
                                       % requirement of any two level rules.  

incremental_apply_rules(In,Out,Limit):-      
   In = [N|_],                         % Look up how many input segs current config
                                       % current config spans across, 
   N < Limit, 			       % Span is less than limit.
   apply_a_rule(In,New),               % Advance config by a single rule application. 
   incremental_apply_rules(New,Out,Limit).  % Recurse. 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% count_possible_words/2: 
%
% Counts up all the possible morphemes that can be reached from all the 
% pointers to lexicon of a set of blocks -- sets a limit on the number of possible
% morphs that could possibly be derived by continuing to elaborate all current 
% partial analyses. 

count_possible_words(Blocks,N):- 
   set_of(Ptr,
          A^B^C^D^member([A,B,[C,Ptr|D]],Blocks),    % Collect up the pointers of all the blocks. 
	  Ptrs), 
   delete_any(initial,Ptrs,Ptrs2),                   % Eliminate the initial state. 
   add_up_possible_words(Ptrs2,N).                   % Add up all the possible morphemes that
                                                     % can be reached from the pointer states. 

%%%%%%%%%%%%%%%

% Counts total of morphs that can reached from members of a list of pointers to 
% lexicon (i.e. states).  Makes use of the possible_words/2 facts asserted during lexicon
% compilation by index_lexicon/0 predicate, recording number of morphs that can be reached 
% individual state. 

add_up_possible_words([],0).            % finished. 
add_up_possible_words([P|Ps],N):- 
   add_up_possible_words(Ps,M), 
   possible_words(P,L),               
   N is M + L. 

%%%%%%%%%%%%%%%

% Print out all  morphs that can be reached from any ptr of a block in Blocks. 

enumerate_possible_words(Blocks):- 
   set_of(Ptr,                                     % Collect up the pointers of all the blocks. 
          A^B^C^D^member([A,B,[C,Ptr|D]],Blocks), 
	  Ptrs),
   delete_any(initial,Ptrs,Ptrs2),                 % Eliminate the initial state. 
   search_for_possible_words(Ptrs2).               % Print out the morphs that can be 
                                                   % reached from the pointer states. 


% Print out all  morphs that can be reached from any pointer in a list of pointers. 

search_for_possible_words([]).              % Finished. 
search_for_possible_words([P|Ptrs]):- 
   search_for_possible_words_main(P),           % Do it for this pointer.
   search_for_possible_words(Ptrs).         % Do it for the rest. 

search_for_possible_words_main(State):-         
   set_of(W,word(State,W),Ws),             % Find morphs for this state, 
   list_print(Ws),                         % and print them out. 
   set_of(Nextstate,S1^S2^link(State,Nextstate,S1,S2),Successors), % Find all the successor states. 
   search_for_possible_words(Successors).  % Print morphs that can be reached from them. 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Extract and print out the partitions from each of a list of blocks. 

print_incremental_answers([]).
print_incremental_answers([B|Bs]):- 
   B = [_,_,[_,_,_,_,_,_,Partition]], 
   departition(Partition,_Surf,Lex), 
   write('Lexical string: '), print_segment_list(Lex), 
   print_partition(Partition), nl, 
   print_incremental_answers(Bs).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

