%======================================================================
%----The tptp2X  utility is used  to make transformations on the 
%----clauses in TPTP problem, and to output the clauses in formats 
%----accepted  by existing ATP systems. See the associated ReadMe
%----file for details.
%----
%----Written by Geoff Sutcliffe, July 1992.
%----Updated by Geoff Sutcliffe, November 1992.
%----Updated by Geoff Sutcliffe, March 1993.
%----Revised by Geoff Sutcliffe, January, 1994.
%----Updated by Geoff Sutcliffe, April, 1994.
%----Revised by Geoff Sutcliffe, May 1994, with ideas from
%----    Gerd Neugebauer
%======================================================================
%----------------------------------------------------------------------
%----Here's how files get loaded into Prolog. Fix this if your dialect
%----does not use compile/1 (quite possible, as compile/1 is only a
%----de facto standard). 
tptp2X_load(FileName):-
    compile(FileName).
%----------------------------------------------------------------------
%----Load the configuration file
:-tptp2X_load('tptp2X.config').
%----------------------------------------------------------------------
%----Simple append, required in tptpread
append([],List,List).

append([Head|Tail],List,[Head|TailList]):-
    append(Tail,List,TailList).
%----------------------------------------------------------------------
%----Simple select
select(Element,[Element|Tail],Tail).

select(Element,[Head|Tail],[Head|SelectedTail]):-
    select(Element,Tail,SelectedTail).
%----------------------------------------------------------------------
%----Simple member
member(Element,[Element|_]).

member(Element,[_|Tail]):-
    member(Element,Tail).
%----------------------------------------------------------------------
%----Remove all elements upto the last delimiter
list_tail([],_,[],not_found):-
    !.
    
%----Check if the delimiter is further down the list
list_tail([_|ListTail],Delimiter,TailTail,found):-
    list_tail(ListTail,Delimiter,TailTail,found),
    !.

%----Check if this is the delimiter
list_tail([Delimiter|ListTail],Delimiter,ListTail,found):-
    !.

%----Otherwise pass back this list
list_tail(List,_,List,not_found).
%----------------------------------------------------------------------
%----Clauses to the same as the UNIX basename command
basename(FullName,Suffix,Basename):-
    name(FullName,FullNameList),
    name(Suffix,SuffixList),
%----Delete upto last / (ASCII 47)
    list_tail(FullNameList,47,FullNameTailList,_),
%----Try to delete suffix from list
    (append(BasenameList,SuffixList,FullNameTailList) ->
        name(Basename,BasenameList);
%----If not possible, then ignore the suffix
        name(Basename,FullNameTailList)).
%----------------------------------------------------------------------
%----Clauses the same as the UNIX dirname command
dirname(FullName,Dirname):-
    name(FullName,FullNameList),
%----Remove the basename
    basename(FullName,'',Basename),
    name(Basename,BasenameList),
%----Find what is before the basename, if anything
    (append(DirnameList,[47|BasenameList],FullNameList) ->
        name(Dirname,DirnameList);
%----If no directory then it's the current one
        Dirname = '.').
%----------------------------------------------------------------------
%-----Convert from an integer to a list of characters
integer_name(Integer,FinalString):-
    integer_name(Integer,[],FinalString).

integer_name(Integer,StringSoFar,[Character|StringSoFar]):-
    Integer < 10,
    !,
    Character is Integer + 48.

integer_name(Integer,StringSoFar,FinalString):-
    TopHalf is Integer // 10,
    BottomHalf is Integer mod 10,
    Character is BottomHalf + 48,
    integer_name(TopHalf,[Character|StringSoFar],FinalString).
%----------------------------------------------------------------------
%----Do name for atoms and integers
any_name(Atom,AtomList):-
    atom(Atom),
    !,
    name(Atom,AtomList).

any_name(Integer,IntegerList):-
    integer(Integer),
    integer_name(Integer,IntegerList).
%----------------------------------------------------------------------
%----Concatenate a list of atoms into a list of the ASCII
concatenate_atoms_to_list([],[]):-
    !.

concatenate_atoms_to_list([FirstTerm|RestOfTerms],TermsList):-
    any_name(FirstTerm,FirstList),
    concatenate_atoms_to_list(RestOfTerms,RestList),
    append(FirstList,RestList,TermsList).
%----------------------------------------------------------------------
%----Concatenate a list of terms into a big atom
concatenate_atoms(Atoms,Atom):-
    concatenate_atoms_to_list(Atoms,AtomsList),
    name(Atom,AtomsList).
%----------------------------------------------------------------------
%-----Fast reverse a list
fast_reverse_list([],ReverseList,ReverseList):-
    !.

fast_reverse_list([Head|Tail],ReverseSoFar,ReverseList):-
    fast_reverse_list(Tail,[Head|ReverseSoFar],ReverseList).
%----------------------------------------------------------------------
read_line_as_list(10,[]):-
    !.

read_line_as_list(LastCharacter,[LastCharacter|RestOfLine]):-
    get0(NextCharacter),
    read_line_as_list(NextCharacter,RestOfLine).

read_line(Line):-
    get0(FirstCharacter),
    read_line_as_list(FirstCharacter,LineAsList),
    name(Line,LineAsList).
%----------------------------------------------------------------------
%----Check if this is a comment line
comment_line(Line):-
    name(Line,[37,45,45,45,45,45,45,45,45|_]).
%----------------------------------------------------------------------
%----Keep reading until
read_until_comment_line(HeaderLine,[]):-
    comment_line(HeaderLine),
    !.

read_until_comment_line(TPTPLine,[Line|RestOfHeaderLines]):-
%----Remove TPTP comment character, if any
    (name(TPTPLine,[37|RestOfAscii]) ->
        name(Line,RestOfAscii);
        Line = TPTPLine),
%----Read next line
    read_line(NextLine),
    read_until_comment_line(NextLine,RestOfHeaderLines).
%----------------------------------------------------------------------
%----Read lines between two comment lines
read_header_lines(FileHeader):-
%----Get the first line and check it is a comment line
    read_line(FirstHeaderLine),
    comment_line(FirstHeaderLine),
    !,
    read_line(Line),
    read_until_comment_line(Line,FileHeader).
    
%----If the first line is not a comment then return nothing
read_header_lines([]).
%----------------------------------------------------------------------
%----Read the header from a TPTP file, one line at a time
read_input_file_header(TPTPFileName,FileHeader):-
    tptp_path_name(TPTPFileName,TPTPPathName),
%----Redirect input
    seeing(CurrentInput),
    see(TPTPPathName),
    read_header_lines(FileHeader),
%----Reset input to old input
    seen,
    see(CurrentInput).
%---------------------------------------------------------------------
%----Write a comment line
output_comment_line(CommentAtom):-
    write(CommentAtom),
    write('-------------------------------------'),
    write('-------------------------------------'),
    nl.
%----------------------------------------------------------------------
%----Output the file header using the given comment atom
output_file_header([],_):-
    !.

output_file_header([FirstHeaderLine|RestOfHeaderLines],CommentAtom):-
    write(CommentAtom),
    write(FirstHeaderLine),
    nl,
    output_file_header(RestOfHeaderLines,CommentAtom).
%----------------------------------------------------------------------
%----Make the output file name
%----If the output directory is user, then output to stdout
make_output_file_name(user,_,_,user):-
    !.

make_output_file_name(OutputDirectory,OutputName,FileNameExtension,
OutputFileName):-
    concatenate_atoms([OutputDirectory,'/',OutputName,FileNameExtension],
OutputFileName).
%----------------------------------------------------------------------
%----Allow mulitple output formats (useful for the competition)
output_clauses_in_format(_,_,[],_,_):-
    !.

output_clauses_in_format(FileHEader,OutputClauses,[FirstFormat|
RestOfFormats],OutputName,OutputDirectory):-
    !,
    output_clauses_in_format(FileHEader,OutputClauses,FirstFormat,
OutputName,OutputDirectory),
    output_clauses_in_format(FileHEader,OutputClauses,RestOfFormats,
OutputName,OutputDirectory).

%----Format the clauses and write to file
output_clauses_in_format(FileHeader,OutputClauses,OutputFormat,
OutputName,OutputDirectory):-
%----Extract the main name of the output format
    OutputFormat =.. [FormatName|_],
%----Get the file name extension (don't like this yet)
    concatenate_atoms([FormatName,'_format_information'],
ExtensionQueryPredicate),
    ExtensionQuery =.. [ExtensionQueryPredicate,FileNameExtension,
CommentAtom],
    ExtensionQuery,
%----Make the output file name
    make_output_file_name(OutputDirectory,OutputName,FileNameExtension,
OutputFileName),
%----Make the output query
    Query =.. [FormatName,OutputClauses,OutputFormat],
%----Redirect the output
    telling(CurrentOutput),
    tell(OutputFileName),
%----Output the file header
    output_comment_line(CommentAtom),
    output_file_header(FileHeader,CommentAtom),
    output_comment_line(CommentAtom),
%----Output the clauses in the required format
    Query,
%----Put a comment line
    output_comment_line(CommentAtom),
%----Restore output direction
    told,
    tell(CurrentOutput).
%---------------------------------------------------------------------
%----Control of a single transformation, including output.
do_transformation(InputClauses,InputName,Dictionary,Transformation,
OutputClauses,OutputName,NewDictionary):-
%----Extract the main name of the transformation
    Transformation =.. [TransformationName|_],
    Query =.. [TransformationName,InputClauses,Dictionary,
Transformation,OutputClauses,NewDictionary,TransformationSuffix],
    Query,
    !,
    concatenate_atoms([InputName,TransformationSuffix],OutputName).

do_transformation(_,_,_,Transformation,_,_,_):-
    write('The tranformation '),
    write(Transformation),
    write(' failed'),
    nl,
    fail.
%---------------------------------------------------------------------
%----Do one transformation that is a sequence in the transformations
%----list.
%----When no more transformation to do, then copy to output
transform_clauses(Clauses,Name,Dictionary,[],Clauses,Name,
Dictionary):-
    !.
    
%----If a list of transformations, then do each one. Use member due
%----to backtracking approach
transform_clauses(InputClauses,InputName,Dictionary,
[[OneTransformation|OtherTransformations]|RestOfTransformations],
OutputClauses,OutputName,NewDictionary):-
    !,
    member(Transformation,[OneTransformation|OtherTransformations]),
    do_transformation(InputClauses,InputName,Dictionary,
Transformation,IntermediateClauses,IntermediateName,
IntermediateDictionary),
    transform_clauses(IntermediateClauses,IntermediateName,
IntermediateDictionary,RestOfTransformations,OutputClauses,
OutputName,NewDictionary).

%----If a definite transformation, then do it
transform_clauses(InputClauses,InputName,Dictionary,[Transformation|
RestOfTransformations],OutputClauses,OutputName,NewDictionary):-
    !,
    do_transformation(InputClauses,InputName,Dictionary,
Transformation,IntermediateClauses,IntermediateName,
IntermediateDictionary),
    transform_clauses(IntermediateClauses,IntermediateName,
IntermediateDictionary,RestOfTransformations,OutputClauses,OutputName,
NewDictionary).

%----If a single transformation, then do it
transform_clauses(InputClauses,InputName,Dictionary,Transformation,
OutputClauses,OutputName,NewDictionary):-
    do_transformation(InputClauses,InputName,Dictionary,
Transformation,OutputClauses,OutputName,NewDictionary).
%---------------------------------------------------------------------
%----Do a transformation by combination from the transformation list.
%----Done by backtracking over the transformations.
do_all_transformations_and_output(InputClauses,BaseInputName,
Transformations,FileHeader,OutputFormat,OutputDirectory,Dictionary):-
    transform_clauses(InputClauses,BaseInputName,Dictionary,
Transformations,OutputClauses,BaseOutputName,NewDictionary),
    instantiate_variables_from_dictionary(NewDictionary),
    output_clauses_in_format(FileHeader,OutputClauses,OutputFormat,
BaseOutputName,OutputDirectory),
    fail.

%----Succeed when all transformation have been backtracked over
do_all_transformations_and_output(_,_,_,_,_,_,_).
%---------------------------------------------------------------------
%----The entry point to convert a TPTP file to other formats
tptp2X(TPTPFileName,Transformations,OutputFormat,OutputDirectory):-
%----These operators are used in the TPTP. They must be declared here
%----so that they are declared at run, rather than compile time. If 
%----they are only done as :-op(100,fx,++)., then compiled versions of 
%----this code will not work
    op(100,fx,++),
    op(100,fx,--),
%----Read in the file header
    read_input_file_header(TPTPFileName,FileHeader),
%----Read in the clauses
    read_input_clauses_from_file(TPTPFileName,InputClauses,_,
Dictionary),
%----Extract the base file name
    basename(TPTPFileName,'.p',BaseInputName),
%----Do each transformation and output the clauses in the required
%----format. 
    do_all_transformations_and_output(InputClauses,BaseInputName,
Transformations,FileHeader,OutputFormat,OutputDirectory,Dictionary).

tptp2X:-
    write('
Using tptp2X
------------
The main entry point to the tptp2X utility is tptp2X/4, in the form :

?-tptp2X(<TPTP file>,<Transformations>,<Output format>,<Output directory>).

where:'),
    write('
+ <TPTP file> is  the file name of  the TPTP problem file.  If the file name is
  not absolute, then it considered to be relative to the directory specified in
  the tptp_directory/1 fact.  If the  file name  is specified  as "user",  then
  input is taken from standard input.'),
    nl,
    write('Enter TPTP file name         : '),
    read(TPTPFileName),
    write('
+ <Transformation>  is a  transformation  or  list of  (possibly  sublists  of) 
  transformations.  A  transformation  is applied  directly.  For  a list,  the
  transformations  are applied  sequentially in  the order  they appear  in the 
  list.  If a  sublist  of  transformations  appears  in the  list,  then  each 
  transformation  in  the  sublist  is  used  as part  of  a different  overall 
  transformation sequence.  The total number of transformation sequences is the 
  product of the  sizes of the sublists,  or 1 if  there are  no sublists.  The 
  available transformations are :
      none,               to do  nothing (same  as omitting it,  but useful  in
                             sublists).
      lr,                 to reverse the literals in the clauses.
      cr,                 to reverse the clauses in the problem.
      clr,                to do both  reversals.  The rearrangment  of  clauses
                             and/or literals in  a problem facilitates  testing
                             the sensitivity  of an ATP system  to the order in
                             which the clauses and literals are presented.
      equality(<Remove>), to remove  equality axioms  and substitution  axioms.
      <Remove> is a Prolog list that indicates which equality axioms to remove.
      The list elements can be :
          reflexivity,    to remove reflexivity,
          symmetry,       to remove symmetry,
          transitivity,   to remove transitivity,
          function_sub,   to remove function substitution,
          predicate_sub,  to remove predicate substitution.
      These may be abbreviated to their first letters, i.e., r, s, t, f, and p.
      magic,              to do Mark Stickel`s magic set transformation.
      shorten,            to replace  all the symbols in the  problem by short,
                             meaningless  symbols.  This is  useful if  you are
                             only interested  in the syntax of the problem, and
                             do not  want to read through the long,  meaningful
                             symbols that are often used in TPTP problems.'),
    nl,
    write('Enter transformations list   : '),
    read(Transformations),
    write('
+ <Format> is an output format  or a list of output formats.  An output file is
  written for each output format specified. The available output formats are :
      meteor,             to convert to the METEOR format.       
      mgtp,               to convert to the MGTP format.
      otter(<SoS>,<Otter options>), to convert to the Otter .in format.
      <SoS> specifies the Set of Support to use. It can be one of :
          theorem,        to use the clauses whose status is theorem;
          hypothesis,     to use the clauses whose status is hypothesis or
                             theorem;
          positive,       to use the positive clauses;
          negative,       to use the negative clauses;
          unit,           to use the unit clauses;
          none,           to use no clauses.
      <Otter options> is  a Prolog list of  Otter options which will  be output
      before the clause lists.
      pttp,               to convert to the PTTP format.
      setheo,             to convert to the SETHEO .lop format.
      sprfn,              to convert to the SPRFN format.
      tptp,               to convert to the TPTP format.'),
    nl,
    write('Enter output format          : '),
    read(OutputFormat),
    write('
+ <Output directory> is  where the output files  are placed.  If the  directory
  is specified as "user", then output is sent to standard output.'),
    nl,
    write('Enter output directory       : '),
    read(OutputDirectory),
    tptp2X(TPTPFileName,Transformations,OutputFormat,OutputDirectory).
%---------------------------------------------------------------------
%----Execute the tptp2X/0 entry point, then quite
execute_tptp2X:-
    tptp2X,
    halt.
%---------------------------------------------------------------------
%----Make an interactive executable
%----There is no generic version, but the SICStus version is common
make_tptp2X_interactive_for_dialect(generic):-
    write('Interactive tptp2X cannot be made for generic Prolog'),
    nl.

%----BinProlog version
make_tptp2X_interactive_for_dialect(binprolog):-
    write('Interactive tptp2X cannot be made for BinProlog'),
    nl.
%----Still some problems with this
%    binprolog(BinPrologExecutable),
%    make_executable_unix_appl(BinPrologExecutable,tptp2X,tptp2X_interactive).

%----SICStus 0.7 version
make_tptp2X_interactive_for_dialect(sicstus07):-
    write('Interactive tptp2X cannot be made for SICStus 0.7 Prolog'),
    nl.

%----SICStus 2.1 version.
make_tptp2X_interactive_for_dialect(sicstus21):-
    nofileerrors,
    save(tptp2X_interactive),
    execute_tptp2X.

%----Sepia version
make_tptp2X_interactive_for_dialect(sepia):-
    nofileerrors,
    save(tptp2X_interactive),
    execute_tptp2X.

%----Quintus version
make_tptp2X_interactive_for_dialect(quintus):-
    save_program(tptp2X_interactive,execute_tptp2X).

%----Redirect the interactive making according to dialect
make_tptp2X_interactive:-
    prolog_dialect(Dialect),
    !,
    make_tptp2X_interactive_for_dialect(Dialect).

make_tptp2X_interactive:-
    write('No Prolog dialect installed, interactive not made'),
    nl,
    fail.
%---------------------------------------------------------------------
%----Get the Transformations and output format from tptp2Xrc file
%----First look locally
get_transformation_and_output_directory(Transformations,OutputFormat):-
    see(tptp2Xrc),
    read(Transformations),
    read(OutputFormat),
    seen,
    !.
    
%----Second look in tptp2X directory
get_transformation_and_output_directory(Transformations,OutputFormat):-
    tptp_path_name('TPTP2X/tptp2Xrc',PathName),
    see(PathName),
    read(Transformations),
    read(OutputFormat),
    seen,
    !.

%----Default is TPTP format with no transformation
get_transformation_and_output_directory([],tptp).
%---------------------------------------------------------------------
%----This executes tptp2X as a filter, with the tptp2Xrc file
execute_filter:-
    get_transformation_and_output_directory(Transformations,
OutputFormat),
    tptp2X(user,Transformations,OutputFormat,user),
    halt.
%---------------------------------------------------------------------
%----Make a saved state filter.
%----There is no generic version, but the SICStus version is common
make_tptp2X_filter_for_dialect(generic):-
    write('The filter cannot be made for generic Prolog'),
    nl.

%----BinProlog version
make_tptp2X_filter_for_dialect(binprolog):-
    write('The filter cannot be made for BinProlog'),
    nl.
%----Still some problems with this
%    binprolog(BinPrologExecutable),
%    make_executable_unix_appl(BinPrologExecutable,tptp2X,tptp2X_filter).

%----SICStus 0.7 version
make_tptp2X_filter_for_dialect(sicstus07):-
    write('The filter cannot be made for SICStus 0.7 Prolog'),
    nl.

%----SICStus 2.1 version.
make_tptp2X_filter_for_dialect(sicstus21):-
    nofileerrors,
    save(tptp2X_filter),
    execute_filter.

%----Sepia version
make_tptp2X_filter_for_dialect(sepia):-
    nofileerrors,
    save(tptp2X_filter),
    execute_filter.

%----Quintus version
make_tptp2X_filter_for_dialect(quintus):-
    save_program(tptp2X_filter,execute_filter).

%----Redirect the filter making according to dialect
make_tptp2X_filter:-
    prolog_dialect(Dialect),
    !,
    make_tptp2X_filter_for_dialect(Dialect).

make_tptp2X_filter:-
    write('No Prolog dialect installed, filter not made'),
    nl,
    fail.
%---------------------------------------------------------------------
