2018-12-09 00:01:22 +00:00
%% - * - Mode: Prolog - * -
2018-11-21 15:23:35 +00:00
%% vim: set softtabstop = 4 shiftwidth = 4 tabstop = 4 expandtab:
2018-11-17 16:14:13 +00:00
2018-11-22 17:49:55 +00:00
/ **
*
* polimani . pl
*
* Assignment 1 - Polynomial Manipulator
* Programming in Logic - DCC - FCUP
*
* Diogo Peralta Cordeiro
* up201705417 @ fc . up . pt
*
* Hugo David Cordeiro Sales
* up201704178 @ fc . up . pt
2018-11-22 18:55:37 +00:00
*
** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** *
2018-11-22 17:49:55 +00:00
* Follows 'Coding guidelines for Prolog' *
* https: // doi . org /10.1017/ S1471068411000391 *
2018-11-23 00:09:07 +00:00
** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** * /
2018-11-22 17:49:55 +00:00
2018-11-23 18:18:15 +00:00
/ *
* Import the Constraint Logic Programming over Finite Domains library
2018-11-22 18:55:37 +00:00
* Essentially , this library improves the way Prolog deals with integers ,
* allowing more predicates to be reversible .
* For instance , number ( N ) is always false , which prevents the
* reversing of a predicate .
* /
2018-11-22 11:51:19 +00:00
: - use_module ( library ( clpfd ) ) .
2018-11-25 16:47:43 +00:00
/ *
* Import Constraint Logic Programming for Reals library , which is somewhat
* similar to clpfd , but for real numbers
* /
: - use_module ( library ( clpr ) ) .
2018-11-22 11:51:19 +00:00
2018-12-20 23:04:19 +00:00
/ *
* The porter_stem library implements the stemming algorithm described by
* Porter in Porter , 1980 , `` An algorithm for suffix stripping '' .
* The library also includes a functional tokenizer
* /
: - use_module ( library ( porter_stem ) ) .
2018-12-07 16:11:11 +00:00
/ ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** *
* NLP *
** ** ** ** ** ** ** ** ** ** ** ** ** ** ** * /
2018-12-10 17:37:34 +00:00
2018-12-17 04:22:12 +00:00
%% polyplay ( ) is det
%
% Interactive prompt for the NLP Interface
%
2018-12-07 16:11:11 +00:00
polyplay : -
2018-12-20 00:21:07 +00:00
%% Replace the prompt and save the old one
2018-12-17 16:31:10 +00:00
prompt ( OldPrompt , '> ' ) ,
2018-12-20 00:21:07 +00:00
%% Read a line as codes , from the 'user_input' stream
2018-12-19 19:11:54 +00:00
read_line_to_codes ( user_input , InCodes ) ,
2018-12-20 02:24:31 +00:00
%% Restore old prompt
2018-12-17 16:31:10 +00:00
prompt ( _ , OldPrompt ) ,
2018-12-20 23:04:19 +00:00
%% Use the porter_stem library to tokenize the input
%% This does more than splitting at the spaces , such as
%% splitting at operators . Aditionally , gives
%% atoms already and handles 'P1' well
tokenize_atom ( InCodes , LA ) ,
2018-12-07 16:11:11 +00:00
(
2018-12-20 02:24:31 +00:00
%% If we read a 'bye' , terminate
2018-12-17 16:31:10 +00:00
LA == [ bye ] ,
write ( "See ya" ) ,
2018-12-19 21:04:17 +00:00
nl ,
2018-12-17 16:31:10 +00:00
!
2018-12-07 16:11:11 +00:00
;
2018-12-20 02:24:31 +00:00
(
2018-12-20 04:03:38 +00:00
%% Parse the input into a tree
parse_input ( TIn , LA , NC ) ,
(
%% If the tree is empty , it means nothing was understood
TIn == void ,
writeln ( "I didn't understand what you want." ) ,
writeln ( NC )
;
(
%% If there is unconsumed input , it means there was a syntatic error
NC \= = [] ,
write ( "Syntax error in token: " ) ,
%% Take the head of the list
cons ( H , _ , NC ) ,
write ( H ) ,
nl
;
%% Otherwise , process the parse tree and execute the commands within
process_input ( TIn )
)
)
2018-12-20 02:24:31 +00:00
;
2018-12-20 21:52:17 +00:00
%% Parsing failed
writeln ( "Could not parse input, so I didn't understand what you want." )
2018-12-20 04:03:38 +00:00
) ,
2018-12-20 22:45:58 +00:00
%% Go back to the beginning
polyplay
2018-12-20 02:24:31 +00:00
) ,
2018-12-20 22:45:58 +00:00
! .
text2poly ( S , P ) : -
split_string ( S , " " , "\r\t" , LS ) ,
parse_polynomial ( T , LS , [] ) ,
polynomial_tree_to_polynomial ( T , P1 ) ,
simpoly ( P1 , P ) .
2018-12-07 16:11:11 +00:00
2018-12-20 04:03:38 +00:00
%% process_input ( + Tree ) is det
2018-12-20 02:24:31 +00:00
%
% Execute the commands from the parse tree
%
2018-12-20 04:03:38 +00:00
process_input ( command ( CL , void ) ) : -
%% Process only command left
do_process_input ( CL ) .
2018-12-19 19:11:54 +00:00
process_input ( command ( CL , TCR ) ) : -
%% Process first command
do_process_input ( CL ) ,
%% If there ' s a tree on the right
TCR \= = void ,
%% recurse
process_input ( TCR ) .
2018-12-20 04:03:38 +00:00
%% do_process_input ( + Tree ) is det
2018-12-20 02:24:31 +00:00
%
% Process a single command from the input
% Takes , as the only argument , the tree representing
% the work to be done
%
2018-12-20 00:38:50 +00:00
do_process_input ( help_menu ) : -
writeln ( "Please allow me to introduce myself" ) ,
writeln ( "I'm a man[ual] of wealth and taste" ) ,
writeln ( "I've been around for a long, long semester" ) ,
writeln ( "Saved many a man's soul and faith" ) ,
writeln ( "Pleased to meet you" ) ,
writeln ( "Hope you guess my name" ) ,
writeln ( "But what's puzzling you" ) ,
writeln ( "Is the nature of my game" ) ,
nl ,
writeln ( "I'm a Polynomial Manipulator and the following commands are available:" ) ,
writeln ( "=> Show - Allows to print a polynomial mathematically" ) ,
writeln ( "=> Multiply - Allows to make multiplications" ) ,
writeln ( "=> Simplify - Allows to simplify a given polynomial" ) ,
writeln ( "=> Add - Allows to make sums" ) ,
writeln ( "=> bye - Hello darkness, my old friend" ) ,
writeln ( "Use 'tell me about {command}' to learn more about a specific command" ) ,
nl ,
writeln ( "Furthermore, I'm capable of memorizing polynomials during runtime. To learn more on that, type: tell me about storage" ) .
do_process_input ( help ( show ) ) : -
writeln ( "It's almost an echo of what you said, but a mathy one." ) ,
2018-12-20 23:19:22 +00:00
writeln ( "Example query:" ) ,
writeln ( "> show two plus x squared" ) ,
writeln ( "2+x^2" ) .
2018-12-20 00:38:50 +00:00
do_process_input ( help ( multiply ) ) : -
writeln ( "Multiplies a polynomial represented as an expression by a scalar resulting in a second polynomial. The two first arguments are assumed to be ground. The polynomial resulting from the sum is in simplified form." ) ,
2018-12-20 23:19:22 +00:00
writeln ( "Example query:" ) ,
writeln ( "> multiply three by two plus x squared" ) ,
writeln ( "3*x^2+6" ) .
2018-12-20 00:38:50 +00:00
do_process_input ( help ( simplify ) ) : -
writeln ( "Simplifies a polynomial represented as an expression as another polynomial as an expression." ) ,
2018-12-20 23:19:22 +00:00
writeln ( "Example query:" ) ,
writeln ( "> simplify two plus two plus one times y" ) ,
writeln ( "y+4" ) .
2018-12-20 00:38:50 +00:00
do_process_input ( help ( add ) ) : -
writeln ( "Adds two polynomials as expressions resulting in a third one. The two first arguments are assumed to be ground. The polynomial resulting from the sum is in simplified form." ) ,
writeln ( "Some example queries:" ) ,
2018-12-20 23:19:22 +00:00
writeln ( "> add two times x to four times x" ) ,
writeln ( "6*x" ) .
2018-12-20 00:38:50 +00:00
do_process_input ( help ( storage ) ) : -
2018-12-20 00:48:57 +00:00
writeln ( "Polynomials, pressed between the entries of my storage" ) ,
writeln ( "Polynomials, simplified through the ages just like predicates" ) ,
2018-12-20 00:45:35 +00:00
writeln ( "Quiet goal come floating down" ) ,
2018-12-20 00:48:57 +00:00
writeln ( "And settle softly to the ground" ) ,
2018-12-20 00:45:35 +00:00
writeln ( "Like golden atom leaves around my root" ) ,
2018-12-20 00:48:57 +00:00
writeln ( "I touched them and they burst apart with sweet polynomials" ) ,
2018-12-20 00:45:35 +00:00
writeln ( "Sweet polynomials" ) ,
2018-12-20 00:38:50 +00:00
nl ,
writeln ( "Storage manipulation is better illustrated with examples. Some example queries:" ) ,
writeln ( "Asking me to memorize something:" ) ,
2018-12-20 23:19:22 +00:00
writeln ( "> show two plus x squared as P1" ) ,
writeln ( "P1 = 2+x^2" ) ,
writeln ( "> multiply three by P1 as P2" ) ,
writeln ( "P2 = 3*x^2+6" ) ,
2018-12-20 00:38:50 +00:00
nl ,
writeln ( "Asking me to forget something:" ) ,
2018-12-20 23:19:22 +00:00
writeln ( "> forget P1 and show stored polynomials" ) ,
writeln ( "P2 = 6+3*x^2" ) .
2018-12-20 00:38:50 +00:00
do_process_input ( help ( bye ) ) : -
writeln ( "There must be some kind of way outta here" ) ,
writeln ( "Said the joker to the thief" ) ,
writeln ( "There's too much confusion" ) ,
writeln ( "I can't get no relief" ) .
2018-12-19 19:11:54 +00:00
do_process_input ( show_stored_polynomials ) : -
2018-12-20 02:24:31 +00:00
%% If the command is 'show_stored_polynomials'
%% Store in D the list of all results of
%% polynomial_store , which is a dynamic predicate
2018-12-19 19:11:54 +00:00
findall ( nm ( X , Y ) , polynomial_store ( X , Y ) , D ) ,
2018-12-20 02:24:31 +00:00
%% Print the list of stored variables
2018-12-20 00:21:07 +00:00
print_all_stored_variables ( D ) .
2018-12-19 23:37:26 +00:00
do_process_input ( show ( store ( P ) , T ) ) : -
2018-12-20 02:24:31 +00:00
%% If the command was to store and show
%% Delegate the work of storing
do_process_input ( store ( P , T ) ) ,
%% Show the variable and the polynomial . Delegate
do_process_input ( show ( P , T ) ) .
2018-12-19 19:11:54 +00:00
do_process_input ( show ( load ( P ) , void ) ) : -
2018-12-20 02:24:31 +00:00
%% Make sure there ' s a variable
2018-12-19 19:11:54 +00:00
P \= = void ,
(
2018-12-20 02:24:31 +00:00
%% Check if the variable is stored
2018-12-19 19:11:54 +00:00
polynomial_store ( P , T ) ,
2018-12-20 02:24:31 +00:00
%% Show the variable and the polynomial . Delegate
do_process_input ( show ( P , T ) )
2018-12-19 19:11:54 +00:00
;
2018-12-20 02:24:31 +00:00
writeln ( "Variable not stored" )
2018-12-19 19:11:54 +00:00
) .
2018-12-20 02:24:31 +00:00
do_process_input ( show ( void , T ) ) : -
%% Make sure there ' s a tree
T \= = void ,
%% Convert it to a flat polynomial
polynomial_tree_to_polynomial ( T , Pl ) ,
writeln ( Pl ) .
2018-12-19 19:11:54 +00:00
do_process_input ( show ( P , T ) ) : -
2018-12-20 02:24:31 +00:00
%% Make sure the arguments are in the right format and not one
%% that should be handled by other clauses
2018-12-17 17:06:25 +00:00
P \= = void ,
2018-12-20 00:21:07 +00:00
P \= = store ( _ ) ,
2018-12-20 02:24:31 +00:00
P \= = load ( _ ) ,
2018-12-17 17:06:25 +00:00
T \= = void ,
2018-12-20 02:24:31 +00:00
%% Write out the variable and the normal
%% representation of the polynomial
2018-12-17 17:06:25 +00:00
write ( P ) ,
write ( " = " ) ,
2018-12-20 02:24:31 +00:00
%% Convert the input tree to a flat polynomial , to print
2018-12-20 00:21:07 +00:00
polynomial_tree_to_polynomial ( T , Pl ) ,
2018-12-20 02:24:31 +00:00
writeln ( Pl ) .
2018-12-20 02:22:38 +00:00
do_process_input ( store_simplified ( V , PTNS ) ) : -
polynomial_tree_to_polynomial ( PTNS , PNS ) ,
simpoly ( PNS , P ) ,
assertz ( polynomial_store ( V , P ) ) ,
write ( V ) ,
write ( " = " ) ,
write ( P ) ,
nl .
2018-12-19 19:11:54 +00:00
do_process_input ( store ( P , T ) ) : -
2018-12-20 02:24:31 +00:00
(
%% If there is a polynomial stored with the same name
polynomial_store ( P , _ ) ,
%% Delete all occurences of it
retractall ( polynomial_store ( P , _ ) )
;
%% Otherwise , move forward and don ' t do anything special
true
) ,
! ,
%% Dynamically add to the end of the predicate , effectively storing it
2018-12-19 21:04:17 +00:00
assertz ( polynomial_store ( P , T ) ) .
2018-12-19 19:11:54 +00:00
do_process_input ( forget ( P ) ) : -
2018-12-20 02:24:31 +00:00
%% Remove all stored predicates with this variable
retractall ( polynomial_store ( P , _ ) ) .
2018-12-19 21:04:17 +00:00
do_process_input ( simplify ( PT ) ) : -
2018-12-20 02:24:31 +00:00
%% Convert the polynomial to it ' s flat representation
2018-12-19 21:04:17 +00:00
polynomial_tree_to_polynomial ( PT , P ) ,
2018-12-20 02:24:31 +00:00
%% Use simpoly from the UI layer to simplify , so it
%% gives nice error messages
2018-12-19 21:04:17 +00:00
simpoly ( P , SP ) ,
2018-12-20 02:24:31 +00:00
writeln ( SP ) .
2018-12-20 02:22:38 +00:00
do_process_input ( store_multiplication ( TN , PT , V ) ) : -
polynomial_tree_to_polynomial ( TN , N ) ,
polynomial_tree_to_polynomial ( PT , P ) ,
2018-12-20 21:52:17 +00:00
%% Left is always number . Enforced by parser
scalepoly ( P , N , P2 ) ,
2018-12-20 02:22:38 +00:00
simpoly ( P2 , SP ) ,
assertz ( polynomial_store ( V , SP ) ) ,
write ( V ) ,
write ( " = " ) ,
write ( SP ) ,
nl .
2018-12-19 21:04:17 +00:00
do_process_input ( multiply ( TN , PT ) ) : -
2018-12-20 02:24:31 +00:00
%% Flatten both
2018-12-19 21:04:17 +00:00
polynomial_tree_to_polynomial ( TN , N ) ,
polynomial_tree_to_polynomial ( PT , P ) ,
2018-12-20 02:24:31 +00:00
%% Use function from UI layer
2018-12-20 21:52:17 +00:00
%% Left is always the number . Enforced by parser
2018-12-20 23:29:12 +00:00
scalepoly ( P , N , P2 ) ,
2018-12-19 21:04:17 +00:00
simpoly ( P2 , SP ) ,
2018-12-20 02:24:31 +00:00
writeln ( SP ) .
2018-12-20 03:26:17 +00:00
do_process_input ( op ( + , TN , PT ) ) : -
polynomial_tree_to_polynomial ( TN , N ) ,
polynomial_tree_to_polynomial ( PT , P ) ,
addpoly ( N , P , P2 ) ,
simpoly ( P2 , SP ) ,
writeln ( SP ) .
do_process_input ( store_addition ( TN , PT , V ) ) : -
polynomial_tree_to_polynomial ( TN , N ) ,
polynomial_tree_to_polynomial ( PT , P ) ,
addpoly ( N , P , P2 ) ,
simpoly ( P2 , SP ) ,
assertz ( polynomial_store ( V , SP ) ) ,
write ( V ) ,
write ( " = " ) ,
write ( SP ) ,
nl .
2018-12-20 00:21:07 +00:00
%% print_all_stored_variables
%
2018-12-20 02:24:31 +00:00
% Prints the stored variables , given the list
2018-12-20 00:21:07 +00:00
%
print_all_stored_variables ( [ nm ( X , T ) | TS ] ) : -
2018-12-20 02:24:31 +00:00
%% Print
2018-12-20 00:21:07 +00:00
write ( X ) ,
write ( " = " ) ,
polynomial_tree_to_polynomial ( T , P ) ,
2018-12-20 02:24:31 +00:00
writeln ( P ) ,
%% Recurse on the right
2018-12-20 00:21:07 +00:00
print_all_stored_variables ( TS ) .
print_all_stored_variables ( [] ) .
2018-12-17 16:35:41 +00:00
2018-12-20 02:24:31 +00:00
%% polynomial_tree_to_polynomial ( + tree , - polynomial ) is det
%
% Flatten a polynomail tree into a simple polynomial
%
2018-12-20 23:15:18 +00:00
polynomial_tree_to_polynomial ( op ( neg , T ) , P1 ) : -
%% If it matched on the version with a node , don ' t go back
! ,
%% Delegate
polynomial_tree_to_polynomial ( T , P ) ,
atom_concat ( '-' , P , P1 ) .
2018-12-19 21:04:17 +00:00
polynomial_tree_to_polynomial ( op ( Op , TL , TR ) , P ) : -
2018-12-20 02:24:31 +00:00
%% If it matched on the version with a node , don ' t go back
2018-12-19 21:04:17 +00:00
! ,
2018-12-20 02:24:31 +00:00
%% Recurse on the left and right
2018-12-19 21:04:17 +00:00
polynomial_tree_to_polynomial ( TL , PL ) ,
polynomial_tree_to_polynomial ( TR , PR ) ,
2018-12-20 02:24:31 +00:00
%% Convert the results of the recursion to atoms
2018-12-19 21:04:17 +00:00
term_to_atom ( PL , TermL ) ,
term_to_atom ( PR , TermR ) ,
2018-12-20 02:24:31 +00:00
%% Concat the parts
2018-12-19 21:04:17 +00:00
atom_concat ( TermL , Op , Temp ) ,
atom_concat ( Temp , TermR , PA ) ,
2018-12-20 02:24:31 +00:00
%% Convert back to terms
2018-12-19 21:04:17 +00:00
term_to_atom ( P , PA ) .
2018-12-20 00:21:07 +00:00
polynomial_tree_to_polynomial ( load ( P ) , Pl ) : -
2018-12-20 02:24:31 +00:00
%% If there 's a load tag, don' t go back
! ,
%% Retrieve the polynomial from the store
2018-12-20 00:21:07 +00:00
polynomial_store ( P , TP ) ,
2018-12-20 02:24:31 +00:00
%% Recurse as if there was a normal tree here
2018-12-20 00:21:07 +00:00
polynomial_tree_to_polynomial ( TP , Pl ) .
2018-12-20 02:24:31 +00:00
%% If we get here , it means we didn ' t match any of the previous
%% clauses , so the tree is already flat
2018-12-19 21:04:17 +00:00
polynomial_tree_to_polynomial ( T , T ) .
2018-12-17 20:19:41 +00:00
2018-12-20 02:24:31 +00:00
%% special_word_number ( ? W:Atom , ? D:Int ) is det
2018-12-17 15:39:11 +00:00
%
2018-12-17 04:22:12 +00:00
% Definition of a Alphabetical and Numerical relation
2018-12-20 02:24:31 +00:00
% The third argument refers to different types of precedence:
% - f means a single unit digit , which doesn ' t
% combine on the right , but can on the left
% - g means a number which doesn ' t combine left or right
% - fy means a number which can optionally combine on the right
% - xfy means a number which requires a number on the left and
% an optional one on the right
2018-12-17 04:22:12 +00:00
%
2018-12-10 17:33:35 +00:00
special_word_number ( zero , 0 , f ) .
special_word_number ( a , 1 , f ) .
special_word_number ( one , 1 , f ) .
special_word_number ( two , 2 , f ) .
special_word_number ( three , 3 , f ) .
special_word_number ( four , 4 , f ) .
special_word_number ( five , 5 , f ) .
special_word_number ( six , 6 , f ) .
special_word_number ( seven , 7 , f ) .
special_word_number ( eight , 8 , f ) .
special_word_number ( nine , 9 , f ) .
2018-12-14 22:46:14 +00:00
special_word_number ( ten , 10 , g ) .
special_word_number ( eleven , 11 , g ) .
special_word_number ( twelve , 12 , g ) .
special_word_number ( thirteen , 13 , g ) .
special_word_number ( fourteen , 14 , g ) .
special_word_number ( fifteen , 15 , g ) .
special_word_number ( sixteen , 16 , g ) .
special_word_number ( seventeen , 17 , g ) .
special_word_number ( eighteen , 18 , g ) .
special_word_number ( nineteen , 19 , g ) .
2018-12-10 17:33:35 +00:00
special_word_number ( twenty , 20 , fy ) .
special_word_number ( thirty , 30 , fy ) .
special_word_number ( forty , 40 , fy ) .
special_word_number ( fifty , 50 , fy ) .
special_word_number ( sixty , 60 , fy ) .
special_word_number ( seventy , 70 , fy ) .
special_word_number ( eighty , 80 , fy ) .
special_word_number ( ninety , 90 , fy ) .
special_word_number ( hundred , 100 , xfy ) .
special_word_number ( thousand , 1000 , xfy ) .
special_word_number ( million , 1000000 , xfy ) .
2018-12-19 23:27:12 +00:00
%% special_word_number ( half , 0.5 , xf ) .
%% special_word_number ( third , 0.33333 , xf ) .
%% special_word_number ( quarter , 0.25 , xf ) .
2018-12-20 02:24:31 +00:00
%% parse_number_explicit ( + precedence , + tree_left , - tree ,
%% + stream , - not_consumed ) is det
2018-12-17 15:39:11 +00:00
%
2018-12-20 02:24:31 +00:00
% Use the precedence of the last number and the tree
% on the left to create the tree on the right , parsing
% the input stream .
%
% You probably want to call this with void in the first
% two arguments . They are for internal use
2018-12-17 15:39:11 +00:00
%
2018-12-17 16:31:10 +00:00
parse_number_explicit ( void , void , T , [ WN | In ] , NC ) : -
2018-12-20 02:24:31 +00:00
%% Entry point
%% Convert a word to a number with precedence f , g , or fy
2018-12-10 01:13:58 +00:00
special_word_number ( WN , N , P ) ,
2018-12-14 22:46:14 +00:00
member ( P , [ f , g , fy ] ) ,
! ,
2018-12-20 02:24:31 +00:00
%% Recurse with the previous precedence
%% and tree as arguments . The same in the other clauses
2018-12-17 16:31:10 +00:00
parse_number_explicit ( P , N , T , In , NC ) .
parse_number_explicit ( fy , NL , T , [ WN | In ] , NC ) : -
2018-12-14 22:46:14 +00:00
special_word_number ( WN , N , f ) ,
! ,
2018-12-20 02:24:31 +00:00
%% Add them on the left tree and recurse
2018-12-17 16:31:10 +00:00
parse_number_explicit ( f , op ( + , NL , N ) , T , In , NC ) .
parse_number_explicit ( xfy , TL , T , [ WN | In ] , NC ) : -
2018-12-14 22:46:14 +00:00
TL \= void ,
2018-12-10 01:13:58 +00:00
special_word_number ( WN , N , P ) ,
2018-12-14 22:46:14 +00:00
member ( P , [ f , g , fy ] ) ,
! ,
2018-12-20 02:24:31 +00:00
%% Add the parts
2018-12-17 16:31:10 +00:00
parse_number_explicit ( P , op ( + , TL , N ) , T , In , NC ) .
parse_number_explicit ( _ , TL , T , [ WN | In ] , NC ) : -
2018-12-20 02:24:31 +00:00
%% Whatever the precedence on the left
2018-12-10 01:13:58 +00:00
special_word_number ( WN , N , xfy ) ,
2018-12-20 02:24:31 +00:00
%% Enforce there was a left argument
2018-12-10 01:13:58 +00:00
TL \= void ,
2018-12-14 22:46:14 +00:00
! ,
2018-12-20 02:24:31 +00:00
%% Multiply this and the left
2018-12-17 16:31:10 +00:00
parse_number_explicit ( xfy , op ( * , TL , N ) , T , In , NC ) .
parse_number_explicit ( P , TL , T , [ and , WN | In ] , NC ) : -
2018-12-20 02:24:31 +00:00
%% And is part of a valid number if there ' s a valid
%% number on the left and right
2018-12-10 17:33:35 +00:00
special_word_number ( WN , _ , _ ) ,
2018-12-20 02:24:31 +00:00
%% Passthrough
2018-12-17 16:31:10 +00:00
parse_number_explicit ( P , TL , T , [ WN | In ] , NC ) ,
2018-12-10 01:13:58 +00:00
! .
2018-12-17 16:31:10 +00:00
parse_number_explicit ( _ , T , T , [ WN | In ] , [ WN | In ] ) : -
2018-12-20 02:24:31 +00:00
%% If there ' s a tree
2018-12-10 17:33:35 +00:00
T \= void ,
2018-12-20 02:24:31 +00:00
%% And can ' t consume more words as
%% numbers ( fail on first ) , then we ' re done
2018-12-10 17:33:35 +00:00
not ( special_word_number ( WN , _ , _ ) ) ,
2018-12-10 01:13:58 +00:00
! .
2018-12-14 22:46:14 +00:00
parse_number_explicit ( _ , T , T , [] , [] ) : -
2018-12-20 02:24:31 +00:00
%% If consumed all innput and there ' s a
%% tree , we ' re done
2018-12-10 17:33:35 +00:00
T \= void ,
2018-12-10 01:13:58 +00:00
! .
2018-12-14 22:46:14 +00:00
2018-12-20 02:24:31 +00:00
%% parse_floating_number ( - tree , + stream , - not_consumed ) is det
%
% Parse a floating point number
%
2018-12-20 20:45:11 +00:00
parse_floating_number ( N ) - - >
[ N ] ,
2018-12-20 21:38:46 +00:00
{ number ( N ) } .
2018-12-20 02:24:31 +00:00
parse_floating_number ( op ( '.' , TL , TR ) ) - - >
%% A float is a node with a dot as the operator
%% If there ' s a number on the left
2018-12-20 21:38:46 +00:00
parse_integer_number ( TL ) ,
2018-12-20 02:24:31 +00:00
%% Followed by either point or dot
2018-12-20 21:38:46 +00:00
[ Sep ] ,
2018-12-20 20:45:11 +00:00
{
2018-12-20 21:38:46 +00:00
member ( Sep , [ point , dot ] ) ,
2018-12-20 20:45:11 +00:00
!
} ,
2018-12-20 02:24:31 +00:00
%% Followed by another number
2018-12-20 21:38:46 +00:00
parse_positive_integer_number ( TR ) .
parse_floating_number ( TN ) - - >
%% Or any integer
parse_integer_number ( TN ) .
%% Tests:
%% ? - parse_floating_number ( TN , [ two ] , _ ) .
%@ TN = 2 .
%% ? - parse_floating_number ( TN , [ two , dot , 4 ] , _ ) .
%@ TN = op ( '.' , 2 , 4 ) .
%% ? - parse_floating_number ( TN , [ negative , two , dot , 4 ] , _ ) .
%@ TN = op ( '.' , op ( neg , 2 ) , 4 ) .
2018-12-20 23:15:18 +00:00
%@ TN = op ( '.' , op ( neg , 2 ) , 4 ) .
2018-12-20 02:24:31 +00:00
2018-12-20 21:38:46 +00:00
%% parse_positive_integer_number ( - tree , + stream , - not_consumed ) is det
2018-12-20 02:24:31 +00:00
%
% Parse an positive integer number
%
2018-12-20 21:38:46 +00:00
parse_positive_integer_number ( N ) - - >
2018-12-20 02:24:31 +00:00
[ N ] ,
2018-12-20 20:45:11 +00:00
{
2018-12-20 21:38:46 +00:00
integer ( N ) ,
%% CLPFD , a number greater than 0
N #>= 1, !
2018-12-20 20:45:11 +00:00
} .
2018-12-20 21:38:46 +00:00
parse_positive_integer_number ( T ) - - >
2018-12-20 02:24:31 +00:00
parse_number_explicit ( void , void , T ) .
2018-12-20 21:38:46 +00:00
%% parse_integer_number ( - tree , + stream , - not_consumed ) is det
2018-12-20 02:24:31 +00:00
%
% Parse an integer number
%
2018-12-20 21:38:46 +00:00
parse_integer_number ( N ) - - >
2018-12-19 23:27:12 +00:00
[ N ] ,
2018-12-20 21:38:46 +00:00
{ integer ( N ) , ! } .
parse_integer_number ( op ( neg , T ) ) - - > % TODO
%% A number can start with "negative" , to negate it
2018-12-20 02:24:31 +00:00
[ negative ] ,
2018-12-20 23:15:18 +00:00
parse_integer_number ( T ) .
2018-12-20 21:38:46 +00:00
parse_integer_number ( T ) - - >
2018-12-19 23:27:12 +00:00
parse_number_explicit ( void , void , T ) .
2018-12-09 00:01:22 +00:00
%% Tests:
2018-12-20 21:38:46 +00:00
%% ? - parse_integer_number ( T , [ two ] , _ ) .
2018-12-09 00:01:22 +00:00
%@ T = 2 .
2018-12-20 21:38:46 +00:00
%% ? - parse_integer_number ( T , [ 43 ] , _ ) .
2018-12-19 19:11:54 +00:00
%@ T = 43 .
2018-12-20 21:38:46 +00:00
%% ? - parse_integer_number ( T , [ nineteen , two ] , _ ) .
2018-12-14 22:46:14 +00:00
%@ false .
2018-12-20 21:38:46 +00:00
%% ? - parse_integer_number ( T , [ twenty ] , _ ) .
2018-12-09 00:01:22 +00:00
%@ T = 20 .
2018-12-20 21:38:46 +00:00
%% ? - parse_integer_number ( T , [ twenty , point , two ] , NC ) .
2018-12-19 23:27:12 +00:00
%@ T = op ( '.' , 20 , 2 ) ,
%@ NC = [] .
2018-12-20 21:38:46 +00:00
%% ? - parse_integer_number ( T , [ twenty , twenty ] , _ ) .
2018-12-14 22:46:14 +00:00
%@ false .
2018-12-20 21:38:46 +00:00
%% ? - parse_integer_number ( T , [ twenty , one ] , _ ) .
2018-12-09 00:01:22 +00:00
%@ T = op ( + , 20 , 1 ) .
2018-12-20 21:38:46 +00:00
%% ? - parse_integer_number ( T , [ negative , one , hundred ] , _ ) .
2018-12-20 02:24:31 +00:00
%@ T = op ( neg , op ( * , 1 , 100 ) ) ;
2018-12-10 01:13:58 +00:00
%@ false .
2018-12-20 21:38:46 +00:00
%% ? - parse_integer_number ( T , [ three , hundred ] , _ ) .
2018-12-09 00:01:22 +00:00
%@ T = op ( * , 3 , 100 ) .
2018-12-20 21:38:46 +00:00
%% ? - parse_integer_number ( T , [ twenty , hundred ] , _ ) .
2018-12-09 00:01:22 +00:00
%@ T = op ( * , 20 , 100 ) .
2018-12-20 21:38:46 +00:00
%% ? - parse_integer_number ( T , [ twenty , one , hundred ] , _ ) .
2018-12-09 00:01:22 +00:00
%@ T = op ( * , op ( + , 20 , 1 ) , 100 ) .
2018-12-20 21:38:46 +00:00
%% ? - parse_integer_number ( T , [ two , hundred , and , one ] , _ ) .
2018-12-09 00:01:22 +00:00
%@ T = op ( + , op ( * , 2 , 100 ) , 1 ) .
2018-12-20 21:38:46 +00:00
%% ? - parse_integer_number ( T , [ twenty , one , hundred , and , twenty , one ] , _ ) .
2018-12-10 01:13:58 +00:00
%@ T = op ( + , op ( + , op ( * , op ( + , 20 , 1 ) , 100 ) , 20 ) , 1 ) .
2018-12-20 21:38:46 +00:00
%% ? - parse_integer_number ( T , [ twenty , one , hundred , and , twenty , one , foo , bar , blah ] , NC ) .
2018-12-10 17:33:35 +00:00
%@ T = op ( + , op ( + , op ( * , op ( + , 20 , 1 ) , 100 ) , 20 ) , 1 ) ,
%@ NC = [ foo , bar , blah ] .
2018-12-20 21:38:46 +00:00
%% ? - parse_integer_number ( T , [ twenty , one , hundred , and , bleg , twenty , quux , one , foo , bar ] , NC ) .
2018-12-10 17:33:35 +00:00
%@ T = op ( * , op ( + , 20 , 1 ) , 100 ) ,
%@ NC = [ and , bleg , twenty , quux , one , foo , bar ] .
2018-12-20 21:38:46 +00:00
%% ? - parse_integer_number ( T , [ two , hundred , thousand ] , _ ) .
2018-12-10 01:13:58 +00:00
%@ T = op ( * , op ( * , 2 , 100 ) , 1000 ) .
2018-12-20 21:38:46 +00:00
%% ? - parse_integer_number ( T , [ twenty , one , hundred , thousand ] , _ ) .
2018-12-10 17:33:35 +00:00
%@ T = op ( * , op ( * , op ( + , 20 , 1 ) , 100 ) , 1000 ) .
2018-12-20 21:38:46 +00:00
%% ? - parse_integer_number ( T , [ thirty , five , million , five , hundred , thirty , four ] , _ ) .
2018-12-14 22:46:14 +00:00
%@ T = op ( + , op ( + , op ( * , op ( + , op ( * , op ( + , 30 , 5 ) , 1000000 ) , 5 ) , 100 ) , 30 ) , 4 ) .
2018-12-20 21:38:46 +00:00
%% ? - parse_integer_number ( T , [ foo , five , million ] , NC ) .
2018-12-10 17:33:35 +00:00
%@ false .
2018-12-10 01:13:58 +00:00
2018-12-17 16:31:10 +00:00
%% nlp_parse_power ( ? List , ? List ) is det
2018-12-17 15:39:11 +00:00
%
2018-12-17 16:31:10 +00:00
% Parse powers
2018-12-17 15:39:11 +00:00
%
2018-12-17 16:31:10 +00:00
parse_power ( op ( ^ , TB , 2 ) ) - - >
parse_polynomial_variable ( TB ) ,
[ squared ] .
parse_power ( op ( ^ , TB , 3 ) ) - - >
parse_polynomial_variable ( TB ) ,
[ cubed ] .
parse_power ( op ( ^ , TB , TN ) ) - - >
parse_polynomial_variable ( TB ) ,
[ raised , to ] ,
2018-12-20 21:38:46 +00:00
parse_positive_integer_number ( TN ) .
2018-12-17 16:31:10 +00:00
parse_power ( TB ) - - >
parse_polynomial_variable ( TB ) .
2018-12-20 02:24:31 +00:00
%% parse_operation ( + Op , + stream , - not_consumed ) is det
%
% Associate an operator with a word
%
2018-12-20 22:45:58 +00:00
parse_operation ( - ) - - > [ minus ] | [ - ] .
parse_operation ( + ) - - > [ plus ] | [ + ] .
parse_operation ( * ) - - > [ times ] | [ * ] .
2018-12-10 17:33:35 +00:00
2018-12-20 02:24:31 +00:00
%% parse_polynomial_operand ( - tree ) is det
%
% Parse a valid operand for either side of an
% operation in a polynomial
%
parse_polynomial_operand ( T ) - - >
parse_floating_number ( T ) .
parse_polynomial_operand ( T ) - - >
parse_power ( T ) .
parse_polynomial_operand ( load ( T ) ) - - >
%% Tag the variable , to be loaded later
parse_stored_variable ( T ) ,
{ ! } .
2018-12-20 03:03:52 +00:00
%% Tests:
%% ? - parse_polynomial_operand ( T , [ two ] , NC ) .
%@ T = 2 ,
%@ NC = [] ;
%@ false .
2018-12-14 22:46:14 +00:00
2018-12-20 02:24:31 +00:00
%% Declare polynomial_store as a dynamic predicate with two arguments
%% Used to store and retrieve polynomials associated with a variable
2018-12-20 20:45:11 +00:00
%% First being the variable name and the second its content
2018-12-17 15:41:21 +00:00
: - dynamic polynomial_store / 2 .
2018-12-17 04:22:12 +00:00
2018-12-20 02:24:31 +00:00
%% parse_stored_variable ( - var ) is det
%
% Parse a valid variable name , for storage
% A valid varaible is one that would be valid in Prolog
%
2018-12-19 19:11:54 +00:00
parse_stored_variable ( P ) - - >
[ P ] ,
2018-12-20 02:24:31 +00:00
{ valid_store_variable ( P ) } .
2018-12-19 19:11:54 +00:00
%% Tests:
%% ? - parse_stored_variable ( P , [ 'P1' ] , _ ) .
%@ P = 'P1' .
%% ? - parse_stored_variable ( P , [ 'x1' ] , _ ) .
%@ false .
2018-12-20 02:24:31 +00:00
%% parse_stored_variable ( + var ) is det
%
% Check if var is a valid variable name , for storage
% A valid varaible is one that would be valid in Prolog
%
valid_store_variable ( P ) : -
%% Get the list of codes of the atom
atom_codes ( P , L ) ,
%% Extract the first element
cons ( F , R , L ) ,
%% Partially builtin facilities:
%% Check if it ' s a valid start to a Prolog variable
code_type ( F , prolog_var_start ) ,
%% Check that each of the following is a valid
%% continuation to a variable name
maplist ( code_type_swap ( prolog_identifier_continue ) , R ) .
%% code_type_swap - swap arguments of code_type , so
%% it can be used with maplist . No lambdas ...
2018-12-19 19:11:54 +00:00
code_type_swap ( X , Y ) : - code_type ( Y , X ) .
2018-12-14 22:46:14 +00:00
2018-12-20 02:24:31 +00:00
%% parse_polynomial_variable ( - base , + stream , - not_consumed ) is det
%
% Parse a polynomial variable
%
2018-12-14 22:46:14 +00:00
parse_polynomial_variable ( B ) - - >
[ B ] ,
{ polynomial_variable ( B ) } .
2018-12-20 02:24:31 +00:00
%% parse_polynomial ( - tree , + stream , - not_consumed ) is det
%
% Parse a polynomial . Delegates to explicit variant
%
2018-12-19 23:27:12 +00:00
parse_polynomial ( T ) - - >
2018-12-20 20:45:11 +00:00
%% Ignore "polynomial" , if followed by a valid polynomial
2018-12-19 23:27:12 +00:00
[ polynomial ] ,
{ ! } ,
2018-12-20 02:24:31 +00:00
%% Delegate
2018-12-20 22:05:37 +00:00
parse_polynomial ( T ) .
2018-12-17 16:31:10 +00:00
parse_polynomial ( T ) - - >
2018-12-20 02:24:31 +00:00
%% Delegate
2018-12-19 23:27:12 +00:00
parse_polynomial_explicit ( _ - _ , T ) ,
! .
%% Tests:
%% ? - parse_polynomial ( T , [] , _ ) .
%@ false .
%% ? - parse_polynomial ( T , [ two ] , _ ) .
2018-12-20 03:03:52 +00:00
%@ T = 2 ,
%@ NC = [] .
2018-12-19 23:27:12 +00:00
%% ? - parse_polynomial ( T , [ two , times , three ] , _ ) .
2018-12-20 03:03:52 +00:00
%@ T = op ( * , 2 , 3 ) ,
%@ NC = [] .
2018-12-19 23:27:12 +00:00
%% ? - parse_polynomial ( T , [ two , times , three , plus , four ] , _ ) .
%@ T = op ( + , op ( * , 2 , 3 ) , 4 ) .
%% ? - parse_polynomial ( T , [ two , plus , three , times , four ] , _ ) .
%@ T = op ( + , 2 , op ( * , 3 , 4 ) ) .
%% ? - parse_polynomial ( T , [ two , plus , three , times , four , plus , six , times , five ] , _ ) .
%@ T = op ( + , 2 , op ( + , op ( * , 3 , 4 ) , op ( * , 6 , 5 ) ) ) .
2018-12-20 02:24:31 +00:00
%% ? - parse_polynomial ( T , [ two , times , times , two ] , NC ) .
%@ T = void ,
2018-12-19 23:27:12 +00:00
%@ NC = [ two , times , times , two ] .
%% ? - parse_polynomial ( T , [ two , plus , x , times , four ] , _ ) .
%@ T = op ( + , 2 , op ( * , x , 4 ) ) .
%% ? - parse_polynomial ( T , [ two , plus , x , times , four , plus , y , raised , to , five ] , _ ) .
%@ T = op ( + , 2 , op ( + , op ( * , x , 4 ) , op ( ^ , y , 5 ) ) ) .
%% ? - parse_polynomial ( T , [ two , plus , two , plus , one , times , y ] , _ ) .
%@ T = op ( + , op ( + , 2 , 2 ) , op ( * , 1 , y ) ) .
2018-12-20 22:05:37 +00:00
%% ? - parse_polynomial ( T , [ polynomial , 2 , plus , 3 , plus , 4 , y ] , _ ) .
%@ T = op ( + , op ( + , 2 , 3 ) , op ( * , 4 , y ) ) .
%% ? - parse_polynomial ( T , [ 2 , x ] , _ ) .
%@ true .
2018-12-19 23:27:12 +00:00
2018-12-20 02:24:31 +00:00
%% parse_polynomial_explicit ( + tree - at , - tree ) is det
%
% Explicitly parse a polynomial . You probably don ' t want
% to call this directly . The first argument is a difference
% structure of the tree on the left ; the second of the pair
% represents where to put the rest of the tree , in
% subsequent passes
%
% Call with _ - _ on the first argument , outputs the
% tree on the right
%
2018-12-17 16:31:10 +00:00
parse_polynomial_explicit ( void - _ , T ) - - >
2018-12-20 02:24:31 +00:00
%% Entry point . If the three on the left is void
%% Parse an operand and an op
2018-12-14 22:46:14 +00:00
parse_polynomial_operand ( TL ) ,
parse_operation ( Op ) ,
2018-12-20 02:24:31 +00:00
%% If consumed an op , double down and don ' t go back
2018-12-14 22:46:14 +00:00
! ,
2018-12-20 02:24:31 +00:00
%% Recurse with the tree on the left populated with
%% what we found and a reference to the place to
%% place the next tree
2018-12-17 16:31:10 +00:00
parse_polynomial_explicit ( op ( Op , TL , TRP ) - TRP , T ) .
2018-12-20 22:05:37 +00:00
parse_polynomial_explicit ( void - _ , T ) - - >
%% Entry point . If the three on the left is void
parse_polynomial_operand ( TL ) ,
%% There was no op , assume a times
%% Recurse with the tree on the left populated with
%% what we found and a reference to the place to
%% place the next tree
parse_polynomial_explicit ( op ( * , TL , TRP ) - TRP , T ) .
2018-12-17 16:31:10 +00:00
parse_polynomial_explicit ( TLP - TL , T ) - - >
2018-12-20 02:24:31 +00:00
%% Parse an operand on the left and place it in the tree
%% on the left , through the difference structure ,
2018-12-14 22:46:14 +00:00
parse_polynomial_operand ( TL ) ,
2018-12-20 02:40:30 +00:00
%% parse either a minus or a plus
2018-12-20 03:03:52 +00:00
{ member ( COp , [ - , + ] ) } ,
2018-12-20 02:40:30 +00:00
parse_operation ( COp ) ,
2018-12-14 22:46:14 +00:00
! ,
2018-12-20 02:40:30 +00:00
%% Recurse on the right with add ; position the sub tree on the right
parse_polynomial_explicit ( op ( COp , TLP , TRP ) - TRP , T ) .
2018-12-17 16:31:10 +00:00
parse_polynomial_explicit ( TLP - T , TLP ) - - >
2018-12-20 02:24:31 +00:00
%% Parse an operand on the left , placing the result of the
%% recusion on the TLP , through the difference structure and return that
2018-12-14 22:46:14 +00:00
parse_polynomial_operand ( TL ) ,
2018-12-20 02:24:31 +00:00
%% If we find a times ,
2018-12-14 22:46:14 +00:00
parse_operation ( * ) ,
! ,
2018-12-20 02:24:31 +00:00
%% Place the operand on the left , the following on the
%% right and get a T to place in the tree on the left from above
2018-12-17 16:31:10 +00:00
parse_polynomial_explicit ( op ( * , TL , TRP ) - TRP , T ) .
2018-12-19 23:27:12 +00:00
parse_polynomial_explicit ( TLP - T , TLP ) - - >
2018-12-20 02:24:31 +00:00
%% Same as above , but without an operator ,
2018-12-19 23:27:12 +00:00
parse_polynomial_operand ( TL ) ,
2018-12-20 02:24:31 +00:00
%% Assume times
2018-12-19 23:27:12 +00:00
parse_polynomial_explicit ( op ( * , TL , TRP ) - TRP , T ) ,
! .
2018-12-17 16:31:10 +00:00
parse_polynomial_explicit ( TLP - TL , TLP ) - - >
2018-12-14 22:46:14 +00:00
{ TLP \= void } ,
2018-12-20 02:24:31 +00:00
%% Base case . Parse a last operand
2018-12-14 22:46:14 +00:00
parse_polynomial_operand ( TL ) ,
! ,
{ TL \= void } .
2018-12-17 16:31:10 +00:00
parse_polynomial_explicit ( void - _ , T ) - - >
2018-12-20 02:24:31 +00:00
%% Base case . Parse a single operand
2018-12-17 15:41:21 +00:00
parse_polynomial_operand ( T ) ,
! ,
{ T \= void } .
2018-12-14 22:46:14 +00:00
2018-12-20 02:24:31 +00:00
%% parse_command ( - tree , + stream , - not_consumed ) is semidet
%
% Parse each individual command
%
2018-12-20 00:38:50 +00:00
parse_command ( help_menu ) - - >
[ help ] .
parse_command ( help ( C ) ) - - >
2018-12-20 02:40:30 +00:00
[ tell , me , about , C ] .
2018-12-18 03:02:53 +00:00
parse_command ( show_stored_polynomials ) - - >
[ show , stored , polynomials ] .
2018-12-19 23:37:26 +00:00
parse_command ( forget ( P ) ) - - >
[ forget ] ,
parse_stored_variable ( P ) .
parse_command ( show ( store ( P ) , T ) ) - - >
2018-12-14 22:46:14 +00:00
[ show ] ,
2018-12-17 16:34:02 +00:00
parse_polynomial ( T ) ,
2018-12-14 22:46:14 +00:00
[ as ] ,
2018-12-19 19:11:54 +00:00
parse_stored_variable ( P ) .
2018-12-20 00:21:07 +00:00
parse_command ( show ( P , void ) ) - - >
2018-12-18 03:02:53 +00:00
[ show ] ,
2018-12-19 19:11:54 +00:00
parse_stored_variable ( P ) .
2018-12-19 23:33:49 +00:00
parse_command ( show ( void , T ) ) - - >
2018-12-17 17:06:25 +00:00
[ show ] ,
2018-12-19 19:11:54 +00:00
parse_polynomial ( T ) ,
{ nonvar ( T ) } .
2018-12-17 15:41:21 +00:00
parse_command ( store ( P , T ) ) - - >
2018-12-14 22:46:14 +00:00
[ let ] ,
2018-12-19 19:11:54 +00:00
parse_stored_variable ( P ) ,
2018-12-14 22:46:14 +00:00
[ be ] ,
2018-12-17 16:34:02 +00:00
parse_polynomial ( T ) .
2018-12-17 16:31:10 +00:00
parse_command ( store ( P , T ) ) - - >
[ store ] ,
2018-12-17 16:34:02 +00:00
parse_polynomial ( T ) ,
2018-12-17 16:31:10 +00:00
[ as ] ,
2018-12-19 19:11:54 +00:00
parse_stored_variable ( P ) .
2018-12-20 02:22:38 +00:00
parse_command ( store_simplified ( V , P ) ) - - >
[ simplify ] ,
parse_polynomial ( P ) ,
[ as ] ,
[ V ] .
2018-12-17 15:41:21 +00:00
parse_command ( simplify ( T ) ) - - >
2018-12-14 22:46:14 +00:00
[ simplify ] ,
2018-12-17 16:34:02 +00:00
parse_polynomial ( T ) .
2018-12-20 02:22:38 +00:00
parse_command ( store_multiplication ( TN , TP , V ) ) - - >
[ multiply ] ,
2018-12-20 21:52:17 +00:00
parse_floating_number ( TN ) ,
2018-12-20 02:22:38 +00:00
[ by ] ,
parse_polynomial ( TP ) ,
[ as ] ,
[ V ] .
2018-12-20 21:52:17 +00:00
parse_command ( store_multiplication ( TN , TP , V ) ) - - >
[ multiply ] ,
parse_polynomial ( TP ) ,
[ by ] ,
parse_floating_number ( TN ) ,
[ as ] ,
[ V ] .
2018-12-19 21:04:17 +00:00
parse_command ( multiply ( TN , TP ) ) - - >
2018-12-14 22:46:14 +00:00
[ multiply ] ,
2018-12-20 21:52:17 +00:00
parse_floating_number ( TN ) ,
2018-12-14 22:46:14 +00:00
[ by ] ,
2018-12-17 16:35:41 +00:00
parse_polynomial ( TP ) .
2018-12-20 21:52:17 +00:00
parse_command ( multiply ( TN , TP ) ) - - >
[ multiply ] ,
parse_polynomial ( TP ) ,
[ by ] ,
parse_floating_number ( TN ) .
2018-12-20 01:10:35 +00:00
parse_command ( op ( - , TN , TP ) ) - - >
[ sub ] ,
parse_polynomial ( TN ) ,
[ X ] ,
2018-12-20 03:03:52 +00:00
{ member ( X , [ to , from , with ] ) } ,
2018-12-20 01:10:35 +00:00
parse_polynomial ( TP ) .
2018-12-20 03:26:17 +00:00
parse_command ( store_addition ( TN , TP , V ) ) - - >
[ add ] ,
parse_polynomial ( TN ) ,
[ X ] ,
{ member ( X , [ to , with ] ) } ,
parse_polynomial ( TP ) ,
[ as ] ,
[ V ] .
2018-12-18 03:02:53 +00:00
parse_command ( op ( + , TN , TP ) ) - - >
[ add ] ,
parse_polynomial ( TN ) ,
2018-12-19 23:27:12 +00:00
[ X ] ,
{ member ( X , [ to , with ] ) } ,
2018-12-18 03:02:53 +00:00
parse_polynomial ( TP ) .
2018-12-19 19:11:54 +00:00
%% Tests:
%% ? - parse_command ( T , [ show , 3 ] , NC ) .
%@ T = show ( void , 3 ) ,
2018-12-19 23:27:12 +00:00
%@ NC = [] .
%% ? - parse_command ( T , [ add , 3 , plus , x , to , 4 , plus , x ] , NC ) .
2018-12-20 02:24:31 +00:00
%@ false .
2018-12-19 23:27:12 +00:00
%@ T = op ( + , op ( + , 3 , x ) , op ( + , 4 , x ) ) ,
%@ NC = [] ;
%@ false .
2018-12-18 03:02:53 +00:00
2018-12-20 02:24:31 +00:00
%% parse_input ( - tree ) is det
%
2018-12-20 20:45:11 +00:00
% Parse each command and string into a list
2018-12-20 02:24:31 +00:00
%
2018-12-17 16:31:10 +00:00
parse_input ( command ( TCL , TCR ) ) - - >
2018-12-20 02:24:31 +00:00
%% Result is a struct with a command on the left
%% and a struct of commands on the right
%% parse a single command
2018-12-17 16:31:10 +00:00
parse_command ( TCL ) ,
2018-12-20 02:24:31 +00:00
%% separator
2018-12-17 16:31:10 +00:00
[ and ] ,
! ,
2018-12-20 02:24:31 +00:00
%% Recurse
2018-12-17 16:31:10 +00:00
parse_input ( TCR ) .
2018-12-19 19:11:54 +00:00
parse_input ( command ( TC , void ) ) - - >
2018-12-20 02:24:31 +00:00
%% If there 's no separator, we' re done recursing
%% parse a single command
2018-12-17 16:31:10 +00:00
parse_command ( TC ) .
2018-12-19 19:11:54 +00:00
%% ? - parse_input ( CT , [ show , 3 ] , _ ) .
%@ CT = command ( show ( void , 3 ) , void ) .
2018-12-17 15:39:11 +00:00
2018-11-22 18:04:45 +00:00
/ ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** *
2018-12-17 16:31:10 +00:00
* UI *
2018-11-22 18:04:45 +00:00
** ** ** ** ** ** ** ** ** ** ** ** ** ** ** * /
2018-11-23 00:09:07 +00:00
2018-11-22 18:04:45 +00:00
/ *
poly2list / 2 transforms a list representing a polynomial ( second
2018-11-23 00:09:07 +00:00
argument ) into a polynomial represented as an expression ( first
argument ) and vice - versa .
2018-11-22 18:04:45 +00:00
* /
poly2list ( P , L ) : -
2018-11-24 20:34:55 +00:00
is_polynomial_valid_in_predicate ( P , "poly2list" ) ,
2018-11-23 15:32:15 +00:00
polynomial_to_list ( P , L ) ,
! .
2018-11-22 18:04:45 +00:00
/ *
simpolylist / 2 simplifies a polynomial represented as a list into
another polynomial as a list .
* /
simpoly_list ( L , S ) : -
2018-11-24 20:34:55 +00:00
is_polynomial_as_list_valid_in_predicate ( L , "simpoly_list" ) ,
2018-11-23 15:32:15 +00:00
simplify_polynomial_as_list ( L , S ) ,
! .
2018-11-22 18:04:45 +00:00
/ *
2018-11-22 18:34:23 +00:00
simpoly / 2 simplifies a polynomial represented as an expression
2018-11-22 18:04:45 +00:00
as another polynomial as an expression .
* /
simpoly ( P , S ) : -
2018-11-24 20:34:55 +00:00
is_polynomial_valid_in_predicate ( P , "simpoly" ) ,
2018-11-23 15:32:15 +00:00
simplify_polynomial ( P , S ) ,
! .
2018-12-19 19:11:54 +00:00
%% Tests:
%% ? - simpoly ( 2 + 2 + 1 * y , S ) .
%@ S = y + 4 .
2018-11-22 18:04:45 +00:00
/ *
2018-11-22 18:55:37 +00:00
scalepoly / 3 multiplies a polynomial represented as an expression by a scalar
2018-11-22 18:04:45 +00:00
resulting in a second polynomial . The two first arguments are assumed to
be ground . The polynomial resulting from the sum is in simplified form .
* /
2018-11-25 18:38:09 +00:00
scalepoly ( P1 , C , S ) : -
2018-11-24 20:34:55 +00:00
is_polynomial_valid_in_predicate ( P1 , "scalepoly" ) ,
2018-12-17 16:31:10 +00:00
is_number_valid_in_predicate ( C , "scalepoly" ) ,
2018-11-25 18:38:09 +00:00
scale_polynomial ( P1 , C , S ) ,
2018-11-23 15:32:15 +00:00
! .
2018-11-25 18:38:09 +00:00
%% Tests:
%% ? - scalepoly ( 3 * x * z + 2 * z , 4 , S ) .
%@ S = 12 * x * z + 8 * z .
%% ? - scalepoly ( 3 * x * z + 2 * z , 2 , S ) .
2018-11-25 19:28:46 +00:00
%@ S = 6 * x * z + 4 * z .
2018-11-22 18:04:45 +00:00
/ *
2018-11-22 18:34:23 +00:00
addpoly / 3 adds two polynomials as expressions resulting in a
2018-11-22 18:04:45 +00:00
third one . The two first arguments are assumed to be ground .
The polynomial resulting from the sum is in simplified form .
* /
addpoly ( P1 , P2 , S ) : -
2018-11-24 20:34:55 +00:00
is_polynomial_valid_in_predicate ( P1 , "addpoly" ) ,
is_polynomial_valid_in_predicate ( P2 , "addpoly" ) ,
2018-11-23 15:32:15 +00:00
add_polynomial ( P1 , P2 , S ) ,
! .
2018-11-25 16:47:43 +00:00
%% Tests:
%% ? - addpoly ( 3 + x , 3 - x , S ) .
2018-11-25 17:01:38 +00:00
%@ S = 6 .
2018-11-25 16:47:43 +00:00
%% is_polynomial_valid_in_predicate ( + T , + F ) is det
%
% Returns true if valid polynomial , fails with UI message otherwise .
% The failure message reports which polynomial is invalid and in which
% predicate the problem ocurred .
%
is_polynomial_valid_in_predicate ( P , _ ) : -
%% If P is a valid polynomial , return true
polynomial ( P ) ,
! .
is_polynomial_valid_in_predicate ( P , F ) : -
2018-11-25 18:38:09 +00:00
%% Otherwise , write the polynomial and fails
2018-11-25 16:47:43 +00:00
write ( "Invalid polynomial in " ) ,
write ( F ) ,
write ( ": " ) ,
2018-12-20 23:31:33 +00:00
writeln ( P ) ,
2018-11-25 16:47:43 +00:00
fail .
%% Tests:
2018-11-25 19:28:46 +00:00
%% ? - is_polynomial_valid_in_predicate ( 1 - x , "Test" ) .
2018-11-25 16:47:43 +00:00
%@ true .
%% ? - is_polynomial_valid_in_predicate ( a * 4 - 0 * x , "Test" ) .
%@ Invalid polynomial in Test: a * 4 - 0 * x
%@ false .
%% is_polynomial_as_list_valid_in_predicate ( + L , + F ) is det
%
% Returns true if the polynomial represented as list is valid ,
% fails with UI message otherwise .
% The failure message reports which polynomial is invalid and
% in which predicate the problem ocurred .
%
is_polynomial_as_list_valid_in_predicate ( L , F ) : -
%% If L is a valid polynomial , return true
list_to_polynomial ( L , P ) ,
is_polynomial_valid_in_predicate ( P , F ) .
%% Tests:
%% ? - is_polynomial_as_list_valid_in_predicate ( [ 1 ] , "Test" ) .
%@ true .
%% ? - is_polynomial_as_list_valid_in_predicate ( [ 0 * x , a * 4 ] , "Test" ) .
%@ Invalid polynomial in Test: a * 4 + 0 * x
%@ false .
2018-11-22 18:04:45 +00:00
2018-12-17 16:31:10 +00:00
%% is_number_valid_in_predicate ( + C:number , + F:string ) is det
2018-11-25 18:38:09 +00:00
%
% Validates that C is a number or prints F and it then it
%
2018-12-17 16:31:10 +00:00
is_number_valid_in_predicate ( C , _ ) : -
2018-11-25 18:38:09 +00:00
number ( C ) ,
! .
2018-12-17 16:31:10 +00:00
is_number_valid_in_predicate ( C , F ) : -
2018-11-25 18:38:09 +00:00
%% Writes the argument and fails
write ( "Invalid number in " ) ,
write ( F ) ,
write ( ": " ) ,
2018-12-20 23:31:33 +00:00
writeln ( C ) ,
2018-11-25 18:38:09 +00:00
fail .
2018-11-22 18:55:37 +00:00
2018-12-09 00:01:22 +00:00
2018-11-22 18:04:45 +00:00
/ ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** *
* BACKEND *
** ** ** ** ** ** ** ** ** ** ** ** ** ** ** * /
2018-11-22 12:52:37 +00:00
%% polynomial_variable_list ( - List ) is det
2018-11-18 16:33:09 +00:00
%
% List of possible polynomial variables
%
2018-11-19 16:59:53 +00:00
polynomial_variable_list ( [ x , y , z ] ) .
2018-11-17 16:14:13 +00:00
2018-11-23 18:18:15 +00:00
%% polynomial_variable ( ? X:atom ) is semidet
2018-11-18 16:33:09 +00:00
%
% Returns true if X is a polynomial variable , false otherwise .
%
polynomial_variable ( X ) : -
2018-11-19 16:59:53 +00:00
polynomial_variable_list ( V ) ,
2018-11-19 15:56:48 +00:00
member ( X , V ) .
2018-11-19 16:59:53 +00:00
%% Tests:
2018-11-20 16:14:53 +00:00
%% ? - polynomial_variable ( x ) .
%@ true .
2018-11-22 12:52:37 +00:00
%% ? - polynomial_variable ( a ) .
2018-11-22 11:51:19 +00:00
%@ false .
2018-11-17 16:14:13 +00:00
2018-11-22 11:51:19 +00:00
%% power ( + X:atom ) is semidet
2018-11-18 16:33:09 +00:00
%
2018-11-19 16:59:53 +00:00
% Returns true if X is a power term , false otherwise .
2018-11-18 16:33:09 +00:00
%
2018-11-22 12:34:42 +00:00
power ( P ^ N ) : -
2018-11-25 21:22:21 +00:00
%% CLPFD comparison . Reversible
2018-11-25 16:47:43 +00:00
N #>= 1,
polynomial_variable ( P ) .
2018-11-18 16:33:09 +00:00
power ( X ) : -
2018-11-19 16:59:53 +00:00
polynomial_variable ( X ) .
%% Tests:
2018-11-22 11:51:19 +00:00
%% ? - power ( x ) .
%@ true .
2018-11-22 13:57:46 +00:00
%% ? - power ( a ) .
%@ false .
2018-11-19 16:59:53 +00:00
%% ? - power ( x ^ 1 ) .
2018-11-19 16:07:13 +00:00
%@ true .
2018-11-22 11:51:19 +00:00
%% ? - power ( x ^ 3 ) .
%@ true .
2018-11-20 16:14:53 +00:00
%% ? - power ( x ^ ( - 3 ) ) .
2018-11-22 13:57:46 +00:00
%@ false .
2018-11-25 16:47:43 +00:00
%% ? - power ( - x ) .
%@ false .
2018-11-22 11:51:19 +00:00
%% ? - power ( X ) .
2018-11-25 16:47:43 +00:00
%@ X = x ^ _462546 ,
%@ _462546 in 1 .. sup ;
%@ X = y ^ _462546 ,
%@ _462546 in 1 .. sup ;
%@ X = z ^ _462546 ,
%@ _462546 in 1 .. sup ;
2018-11-22 11:51:19 +00:00
%@ X = x ;
%@ X = y ;
%@ X = z .
2018-11-18 16:33:09 +00:00
2018-11-23 18:18:15 +00:00
%% term ( + N:atom ) is semidet
2018-11-18 16:33:09 +00:00
%
2018-11-19 16:59:53 +00:00
% Returns true if N is a term , false otherwise .
2018-11-18 16:33:09 +00:00
%
term ( N ) : -
2018-11-25 19:28:46 +00:00
% If N is not a free variable
nonvar ( N ) ,
% Assert it as a number
number ( N ) .
term ( N ) : -
% If N is a free variable and not compound
not ( compound ( N ) ) ,
var ( N ) ,
% Assert it must be between negative and positive infinity
% This uses the CLPR library , which makes this reversible ,
% whereas `number(N)` is always false , since it only succeeds
% if the argument is bound ( to a integer or float )
{ N >= 0 ; N < 0 } .
2018-11-18 16:33:09 +00:00
term ( X ) : -
power ( X ) .
2018-11-25 16:47:43 +00:00
term ( - X ) : -
power ( X ) .
2018-12-17 16:31:10 +00:00
term ( L * In ) : -
2018-11-18 16:33:09 +00:00
term ( L ) ,
2018-12-17 16:31:10 +00:00
term ( In ) .
2018-11-19 16:59:53 +00:00
%% Tests:
2018-11-20 16:14:53 +00:00
%% ? - term ( 2 * x ^ 3 ) .
%@ true .
%% ? - term ( x ^ ( - 3 ) ) .
2018-11-22 11:51:19 +00:00
%@ false .
2018-11-22 13:57:46 +00:00
%% ? - term ( a ) .
%@ false .
2018-11-22 18:44:33 +00:00
%% ? - term ( - 1 * x ) .
%@ true .
2018-11-25 16:47:43 +00:00
%% ? - term ( - x ) .
%@ true .
2018-11-22 11:51:19 +00:00
%% ? - term ( ( - 3 ) * x ^ 2 ) .
2018-11-20 16:14:53 +00:00
%@ true .
2018-11-22 13:57:46 +00:00
%% ? - term ( 3.2 * x ) .
%@ true .
2018-11-25 16:47:43 +00:00
%% ? - term ( - x * ( - z ) ) .
%@ true .
2018-11-22 13:57:46 +00:00
%% ? - term ( X ) .
2018-11-25 16:47:43 +00:00
%@ { X >= 0.0 } ;
%@ { X < 0.0 } ;
%@ X = x ^ _111514 ,
%@ _111514 in 1 .. sup ;
%@ X = y ^ _111514 ,
%@ _111514 in 1 .. sup ;
%@ X = z ^ _111514 ,
%@ _111514 in 1 .. sup ;
2018-11-23 14:56:01 +00:00
%@ X = x ;
%@ X = y ;
%@ X = z ;
2018-11-25 16:47:43 +00:00
%@ X = - x ^ _111522 ,
%@ _111522 in 1 .. sup ;
%@ X = - y ^ _111522 ,
%@ _111522 in 1 .. sup ;
%@ X = - z ^ _111522 ,
%@ _111522 in 1 .. sup ;
%@ X = - x ;
%@ X = - y ;
%@ X = - z ;
2018-11-24 20:34:55 +00:00
2018-11-23 18:18:15 +00:00
%% polynomial ( + M:atom ) is semidet
2018-11-18 16:33:09 +00:00
%
% Returns true if polynomial , false otherwise .
%
polynomial ( M ) : -
2018-11-23 18:18:15 +00:00
%% A polynomial is either a term
2018-11-18 16:33:09 +00:00
term ( M ) .
2018-12-17 16:31:10 +00:00
polynomial ( L + In ) : -
2018-11-23 18:18:15 +00:00
%% Or a sum of terms
polynomial ( L ) ,
2018-12-17 16:31:10 +00:00
term ( In ) .
polynomial ( L - In ) : -
2018-11-23 18:18:15 +00:00
%% Or a subtraction of terms
2018-11-18 16:33:09 +00:00
polynomial ( L ) ,
2018-12-17 16:31:10 +00:00
term ( In ) .
2018-11-19 16:59:53 +00:00
%% Tests:
2018-11-22 11:51:19 +00:00
%% ? - polynomial ( x ) .
%@ true .
%% ? - polynomial ( x ^ 3 ) .
%@ true .
%% ? - polynomial ( 3 * x ^ 7 ) .
%@ true .
2018-12-19 21:04:17 +00:00
%% ? - polynomial ( 2 + 3 * x + 4 * x * y ^ 3 ) .
2018-11-22 11:51:19 +00:00
%@ true .
2018-11-23 18:18:15 +00:00
%% ? - polynomial ( 2 - 3 * x + 4 * x * y ^ 3 ) .
%@ true .
2018-11-22 13:57:46 +00:00
%% ? - polynomial ( a ) .
%@ false .
%% ? - polynomial ( x ^ ( - 3 ) ) .
%@ false .
2018-11-25 16:47:43 +00:00
%% ? - polynomial ( - x + 3 ) .
%@ true .
%% ? - polynomial ( - x - - z ) .
%@ true .
2018-11-18 16:33:09 +00:00
2018-11-23 18:18:15 +00:00
%% power_to_canon ( + T:atom , - T ^ N:atom ) is semidet
2018-11-18 16:33:09 +00:00
%
% Returns a canon power term .
%
2018-11-19 16:59:53 +00:00
power_to_canon ( T ^ N , T ^ N ) : -
2018-11-22 11:51:19 +00:00
polynomial_variable ( T ) ,
2018-11-23 18:18:15 +00:00
% CLP ( FD ) operator to ensure N is different from 1 ,
% in a reversible way
2018-11-22 13:57:46 +00:00
N #\= 1.
2018-11-19 16:59:53 +00:00
power_to_canon ( T , T ^ 1 ) : -
polynomial_variable ( T ) .
%% Tests:
%% ? - power_to_canon ( x , X ) .
2018-11-22 11:51:19 +00:00
%@ X = x ^ 1 .
2018-11-25 16:47:43 +00:00
%% ? - power_to_canon ( - x , X ) .
%@ false .
%@ X = - 1 * x ^ 1 .
2018-11-22 11:51:19 +00:00
%% ? - power_to_canon ( X , x ^ 1 ) .
2018-11-19 16:59:53 +00:00
%@ X = x .
2018-11-22 11:51:19 +00:00
%% ? - power_to_canon ( X , x ^ 4 ) .
%@ X = x ^ 4 .
2018-11-22 13:57:46 +00:00
%% ? - power_to_canon ( X , a ^ 1 ) .
%@ false .
%% ? - power_to_canon ( X , x ^ ( - 3 ) ) .
%@ X = x ^ - 3 .
2018-11-25 16:47:43 +00:00
%% ? - power_to_canon ( X , - 1 * x ^ 1 ) .
%@ X = - x .
2018-11-19 16:59:53 +00:00
2018-11-23 18:18:15 +00:00
%% term_to_list ( ? T , ? List ) is semidet
2018-11-18 16:33:09 +00:00
%
2018-11-25 22:00:25 +00:00
% Converts a term to a list of its monomials and vice versa .
% Can verify if term and monomials list are compatible .
2018-11-18 16:33:09 +00:00
%
term_to_list ( L * N , [ N | TS ] ) : -
number ( N ) ,
2018-11-19 16:59:53 +00:00
term_to_list ( L , TS ) .
term_to_list ( L * P , [ P2 | TS ] ) : -
power ( P ) ,
power_to_canon ( P , P2 ) ,
term_to_list ( L , TS ) .
2018-11-25 16:47:43 +00:00
term_to_list ( L * - P , [ - P2 | TS ] ) : -
power ( P ) ,
power_to_canon ( P , P2 ) ,
term_to_list ( L , TS ) .
2018-11-19 16:59:53 +00:00
term_to_list ( N , [ N ] ) : -
number ( N ) .
term_to_list ( P , [ P2 ] ) : -
power ( P ) ,
power_to_canon ( P , P2 ) .
2018-11-25 16:47:43 +00:00
term_to_list ( - P , [ - P2 ] ) : -
power ( P ) ,
power_to_canon ( P , P2 ) .
2018-11-19 16:59:53 +00:00
%% Tests:
2018-11-22 13:57:46 +00:00
%% ? - term_to_list ( 1 , X ) .
%@ X = [ 1 ] .
2018-11-22 18:44:33 +00:00
%% ? - term_to_list ( - 1 , X ) .
%@ X = [ - 1 ] .
2018-11-25 16:47:43 +00:00
%% ? - term_to_list ( x , X ) .
%@ X = [ x ^ 1 ] .
%% ? - term_to_list ( - x , X ) .
%@ X = [ - x ^ 1 ] .
2018-11-23 15:32:15 +00:00
%% ? - term_to_list ( 2 * 3 , X ) .
%@ X = [ 3 , 2 ] .
2018-11-20 16:14:53 +00:00
%% ? - term_to_list ( 1 * 2 * y * z * 23 * x * y * x ^ 3 * x , X ) .
%@ X = [ x ^ 1 , x ^ 3 , y ^ 1 , x ^ 1 , 23 , z ^ 1 , y ^ 1 , 2 , 1 ] .
2018-11-23 18:18:15 +00:00
%% ? - term_to_list ( 1 * 2 * y * z * 23 * x * y * ( - 1 ) , X ) .
%@ X = [ - 1 , y ^ 1 , x ^ 1 , 23 , z ^ 1 , y ^ 1 , 2 , 1 ] .
2018-11-22 18:44:33 +00:00
%% ? - term_to_list ( X , [ - 1 ] ) .
%@ X = - 1 .
%% ? - term_to_list ( X , [ x ^ 1 , - 1 ] ) .
%@ X = - 1 * x .
2018-11-25 16:47:43 +00:00
%% ? - term_to_list ( X , [ - x ^ 1 ] ) .
%@ X = - x .
2018-11-19 16:59:53 +00:00
%% ? - term_to_list ( X , [ y ^ 1 , x ^ 1 ] ) .
%@ X = x * y .
%% ? - term_to_list ( X , [ x ^ 4 ] ) .
2018-11-22 11:51:19 +00:00
%@ X = x ^ 4 .
2018-11-19 16:59:53 +00:00
%% ? - term_to_list ( X , [ y ^ 6 , z ^ 2 , x ^ 4 ] ) .
%@ X = x ^ 4 * z ^ 2 * y ^ 6 .
2018-11-23 18:18:15 +00:00
%% ? - term_to_list ( X , [ y ^ 6 , z ^ 2 , x ^ 4 , - 2 ] ) .
%@ X = - 2 * x ^ 4 * z ^ 2 * y ^ 6 .
2018-11-25 16:59:03 +00:00
%% ? - term_to_list ( X , [ x ^ 1 , 0 ] ) .
%@ X = 0 * x .
2018-11-25 19:28:46 +00:00
%% ? - term_to_list ( X , [ y ^ 1 , - 2 ] ) .
%@ X = - 2 * y .
2018-11-17 22:28:51 +00:00
2018-11-20 16:14:53 +00:00
%% simplify_term ( + Term_In:term , ? Term_Out:term ) is det
2018-11-18 16:33:09 +00:00
%
2018-11-24 16:10:44 +00:00
% Simplifies a given term .
% This function can also be be used to verify if
% a term is simplified .
2018-11-18 16:33:09 +00:00
%
2018-11-20 16:14:53 +00:00
simplify_term ( Term_In , Term_Out ) : -
term_to_list ( Term_In , L ) ,
2018-11-23 18:18:15 +00:00
%% Sort the list of numbers and power to group them ,
%% simplifying the job of `join_similar_parts_of_term`
2018-11-17 23:53:49 +00:00
sort ( 0 , @ = < , L , L2 ) ,
2018-11-23 00:09:07 +00:00
(
2018-11-24 15:06:39 +00:00
%% If there ' s a 0 in the list , then the whole term is 0
2018-11-23 00:09:07 +00:00
member ( 0 , L2 ) ,
Term_Out = 0
;
2018-11-23 18:18:15 +00:00
%% Otherwise
2018-11-23 00:09:07 +00:00
(
2018-11-24 15:06:39 +00:00
%% If there ' s only one element , then the term was already simplified
%% This is done so that the `exclude` following doesn ' t remove all ones
2018-11-23 00:09:07 +00:00
length ( L2 , 1 ) ,
Term_Out = Term_In
;
2018-11-24 15:06:39 +00:00
%% Remove all remaining ones
2018-11-23 00:09:07 +00:00
exclude ( == ( 1 ) , L2 , L3 ) ,
join_similar_parts_of_term ( L3 , L4 ) ,
2018-11-23 18:18:15 +00:00
%% Reverse the list , since the following call gives the result in the
2018-11-24 15:06:39 +00:00
%% reverse order otherwise
reverse ( L4 , L5 ) ,
2018-11-23 00:09:07 +00:00
term_to_list ( Term_Out , L5 )
)
) ,
2018-11-20 16:14:53 +00:00
% First result is always the most simplified form .
! .
2018-11-19 16:59:53 +00:00
%% Tests:
2018-11-22 13:57:46 +00:00
%% ? - simplify_term ( 1 , X ) .
%@ X = 1 .
%% ? - simplify_term ( x , X ) .
%@ X = x .
2018-11-17 22:28:51 +00:00
%% ? - simplify_term ( 2 * y * z * x ^ 3 * x , X ) .
2018-11-20 16:14:53 +00:00
%@ X = 2 * x ^ 4 * y * z .
%% ? - simplify_term ( 1 * y * z * x ^ 3 * x , X ) .
%@ X = x ^ 4 * y * z .
%% ? - simplify_term ( 0 * y * z * x ^ 3 * x , X ) .
%@ X = 0 .
%% ? - simplify_term ( 6 * y * z * 7 * x * y * x ^ 3 * x , X ) .
2018-11-23 18:18:15 +00:00
%@ X = 42 * x ^ 5 * y ^ 2 * z .
2018-11-25 16:47:43 +00:00
%% ? - simplify_term ( - x , X ) .
%@ X = - x .
%% ? - simplify_term ( - x * y * ( - z ) * 3 , X ) .
%@ X = 3 * - x * - z * y .
2018-11-22 13:57:46 +00:00
%% ? - simplify_term ( a , X ) .
%@ false .
%% ? - simplify_term ( x ^ ( - 3 ) , X ) .
%@ false .
2018-11-17 23:53:49 +00:00
2018-11-23 18:18:15 +00:00
%% join_similar_parts_of_term ( + List , - List ) is det
2018-11-19 16:59:53 +00:00
%
2018-11-24 16:10:44 +00:00
% Combine powers of the same variable in the given list .
2018-11-25 22:18:24 +00:00
% Requires that the list be sorted .
2018-11-19 16:59:53 +00:00
%
2018-11-22 15:59:00 +00:00
join_similar_parts_of_term ( [ P1 , P2 | L ] , L2 ) : -
2018-11-23 18:18:15 +00:00
%% If both symbols are powers
2018-11-19 16:59:53 +00:00
power ( P1 ) ,
power ( P2 ) ,
2018-11-23 18:18:15 +00:00
%% Decompose them into their parts
2018-11-19 15:56:48 +00:00
B ^ N1 = P1 ,
B ^ N2 = P2 ,
2018-11-23 18:18:15 +00:00
%% Sum the exponent
2018-11-17 22:28:51 +00:00
N is N1 + N2 ,
2018-11-23 18:18:15 +00:00
join_similar_parts_of_term ( [ B ^ N | L ] , L2 ) ,
% First result is always the most simplified form .
! .
2018-11-22 15:59:00 +00:00
join_similar_parts_of_term ( [ N1 , N2 | L ] , L2 ) : -
2018-11-23 18:18:15 +00:00
%% If they are both numbers
2018-11-17 23:53:49 +00:00
number ( N1 ) ,
number ( N2 ) ,
2018-11-23 18:18:15 +00:00
%% Multiply them
2018-11-17 22:28:51 +00:00
N is N1 * N2 ,
2018-11-23 18:18:15 +00:00
join_similar_parts_of_term ( [ N | L ] , L2 ) ,
% First result is always the most simplified form .
! .
2018-11-22 15:59:00 +00:00
join_similar_parts_of_term ( [ X | L ] , [ X | L2 ] ) : -
2018-11-25 19:28:46 +00:00
%% Otherwise consume one element and recurse
2018-11-23 18:18:15 +00:00
join_similar_parts_of_term ( L , L2 ) ,
% First result is always the most simplified form .
! .
2018-11-22 15:59:00 +00:00
join_similar_parts_of_term ( [] , [] ) .
2018-11-19 16:59:53 +00:00
%% Tests:
2018-11-22 15:59:00 +00:00
%% ? - join_similar_parts_of_term ( [ 3 ] , T ) .
%@ T = [ 3 ] .
%% ? - join_similar_parts_of_term ( [ x ^ 2 ] , T ) .
%@ T = [ x ^ 2 ] .
%% ? - join_similar_parts_of_term ( [ x ^ 1 , x ^ 1 , x ^ 1 , x ^ 1 ] , T ) .
2018-11-23 18:18:15 +00:00
%@ T = [ x ^ 4 ] .
2018-11-22 15:59:00 +00:00
%% ? - join_similar_parts_of_term ( [ 2 , 3 , x ^ 1 , x ^ 2 ] , T ) .
2018-11-23 18:18:15 +00:00
%@ T = [ 6 , x ^ 3 ] .
2018-11-22 15:59:00 +00:00
%% ? - join_similar_parts_of_term ( [ 2 , 3 , x ^ 1 , x ^ 2 , y ^ 1 , y ^ 6 ] , T ) .
2018-11-23 18:18:15 +00:00
%@ T = [ 6 , x ^ 3 , y ^ 7 ] .
2018-11-25 16:47:43 +00:00
%% ? - join_similar_parts_of_term ( [ 2 , 3 , - x ^ 1 , - x ^ 2 ] , T ) .
%@ T = [ 6 , - x ^ 1 , - x ^ 2 ] .
2018-11-17 22:28:51 +00:00
2018-11-19 16:59:53 +00:00
%% simplify_polynomial ( + P:atom , - P2:atom ) is det
2018-11-18 16:33:09 +00:00
%
2018-11-19 16:59:53 +00:00
% Simplifies a polynomial .
2018-11-18 16:33:09 +00:00
%
2018-11-22 16:32:21 +00:00
simplify_polynomial ( 0 , 0 ) : -
2018-11-25 19:28:46 +00:00
% 0 is already fully simplified . This is an
2018-11-23 18:18:15 +00:00
% exception to the following algorithm
2018-11-19 16:59:53 +00:00
! .
2018-11-22 15:59:00 +00:00
simplify_polynomial ( P , P2 ) : -
polynomial_to_list ( P , L ) ,
2018-11-23 14:56:01 +00:00
simplify_polynomial_as_list ( L , L2 ) ,
2018-11-23 16:21:16 +00:00
list_to_polynomial ( L2 , P2 ) ,
2018-11-23 18:18:15 +00:00
%% The first result is the most simplified one
2018-11-19 16:59:53 +00:00
! .
%% Tests:
2018-11-22 13:57:46 +00:00
%% ? - simplify_polynomial ( 1 , X ) .
2018-11-22 15:59:00 +00:00
%@ X = 1 .
2018-11-22 16:32:21 +00:00
%% ? - simplify_polynomial ( 0 , X ) .
%@ X = 0 .
2018-11-22 15:59:00 +00:00
%% ? - simplify_polynomial ( x , X ) .
%@ X = x .
%% ? - simplify_polynomial ( x * x , X ) .
%@ X = x ^ 2 .
2018-11-22 18:44:33 +00:00
%% ? - simplify_polynomial ( 2 + 2 , X ) .
%@ X = 2 * 2 .
%% ? - simplify_polynomial ( x + x , X ) .
%@ X = 2 * x .
2018-11-22 16:32:21 +00:00
%% ? - simplify_polynomial ( 0 + x * x , X ) .
%@ X = x ^ 2 .
2018-11-22 15:59:00 +00:00
%% ? - simplify_polynomial ( x ^ 2 * x + 3 * x ^ 3 , X ) .
%@ X = 4 * x ^ 3 .
%% ? - simplify_polynomial ( x ^ 2 * x + 3 * x ^ 3 + x ^ 3 + x * x * x , X ) .
%@ X = 6 * x ^ 3 .
2018-11-22 18:44:33 +00:00
%% ? - simplify_polynomial ( x ^ 2 * x + 3 * x ^ 3 + x ^ 3 + x * x * 4 + z , X ) .
%@ X = 5 * x ^ 3 + 4 * x ^ 2 + z .
2018-11-23 18:18:15 +00:00
%% ? - simplify_polynomial ( x ^ 2 * x + 3 * x ^ 3 - x ^ 3 - x * x * 4 + z , X ) .
%@ X = 3 * x ^ 3 - 4 * x ^ 2 + z .
2018-11-22 18:44:33 +00:00
%% ? - simplify_polynomial ( x + 1 + x , X ) .
%@ X = 2 * x + 1 .
%% ? - simplify_polynomial ( x + 1 + x + 1 + x + 1 + x , X ) .
2018-11-23 16:21:16 +00:00
%@ X = 4 * x + 3 .
2018-11-22 15:59:00 +00:00
2018-11-23 18:18:15 +00:00
%% simplify_polynomial_as_list ( + L1:List , - L3:List ) is det
%
2018-11-24 16:10:44 +00:00
% Simplifies a polynomial represented as a list .
2018-11-23 18:18:15 +00:00
%
2018-12-19 19:11:54 +00:00
simplify_polynomial_as_list ( L , L14 ) : -
2018-11-23 18:18:15 +00:00
%% Convert each term to a list
maplist ( term_to_list , L , L2 ) ,
2018-11-25 22:23:38 +00:00
%% Sort each sublist so that the next
2018-11-23 18:18:15 +00:00
%% sort gives the correct results
maplist ( sort ( 0 , @ > = ) , L2 , L3 ) ,
%% Sort the outer list
sort ( 0 , @ > = , L3 , L4 ) ,
%% For each of the parts of the terms , join them
maplist ( join_similar_parts_of_term , L4 , L5 ) ,
%% Sort each of the sublists
%% Done so the next call simplifies has less work
maplist ( sort ( 0 , @ = < ) , L5 , L6 ) ,
join_similar_terms ( L6 , L7 ) ,
2018-11-25 16:59:03 +00:00
%% Exclude any sublist that includes a 0 ( such as the
%% equivalent to the term 0 * x )
exclude ( member ( 0 ) , L7 , L8 ) ,
2018-11-23 18:18:15 +00:00
%% Reverse each sublist , because the next call
%% reverses the result
2018-11-25 16:59:03 +00:00
maplist ( reverse , L8 , L9 ) ,
maplist ( term_to_list , L10 , L9 ) ,
2018-11-23 18:18:15 +00:00
%% Delete any 0 from the list
2018-11-25 16:59:03 +00:00
delete ( L10 , 0 , L11 ) ,
2018-11-23 18:18:15 +00:00
%% Sort list converting back gives the result in the correct order
2018-11-25 16:59:03 +00:00
sort ( 0 , @ = < , L11 , L12 ) ,
(
2018-12-17 04:22:12 +00:00
%% If the list is empty , the result is a list with 0
L12 = [] , L13 = [ 0 ]
2018-11-25 16:59:03 +00:00
;
%% Otherwise , this is the result
L13 = L12
2018-12-19 19:11:54 +00:00
) ,
%% Further make sure all terms are simplified
maplist ( simplify_term , L13 , L14 ) .
2018-11-23 18:18:15 +00:00
%% Tests:
%% ? - simplify_polynomial_as_list ( [ x , 1 , x ^ 2 , x * y , 3 * x ^ 2 , 4 * x ] , L ) .
%@ L = [ 1 , 4 * x ^ 2 , 5 * x , x * y ] .
%% ? - simplify_polynomial_as_list ( [ 1 , x ^ 2 , x * y , 3 * x ^ 2 , - 4 , - 1 * x ] , L ) .
%@ L = [ - 3 , - 1 * x , 4 * x ^ 2 , x * y ] .
2018-12-19 19:11:54 +00:00
%% ? - simplify_polynomial_as_list ( [ 1 , 1 * x ] , L ) .
%@ L = [ 1 , x ] .
2018-11-25 16:59:03 +00:00
%% ? - simplify_polynomial_as_list ( [ 0 * x , 0 ] , L ) .
%@ L = [ 0 ] .
2018-11-23 18:18:15 +00:00
2018-11-25 22:31:46 +00:00
%% join_similar_terms ( + P:List , - P2:List ) is det
2018-11-22 18:44:33 +00:00
%
% Joins similar sublists representing terms by using
% ` add_terms ` to check if they can be merged and perform
% the addition . Requires the list of list be sorted with
% ` maplist ( sort ( 0 , @ > = ) , L , L2 ) ,
% sort ( 0 , @ > = , L2 , L3 ) `
% and that the sublists to be sorted with
2018-11-24 16:10:44 +00:00
% ` sort ( 0 , @ = < ) ` since that is inherited from ` add_terms ` .
2018-11-22 18:44:33 +00:00
%
2018-11-22 15:59:00 +00:00
join_similar_terms ( [ TL , TR | L ] , L2 ) : -
2018-11-22 18:44:33 +00:00
%% Check if terms can be added and add them
2018-11-22 15:59:00 +00:00
add_terms ( TL , TR , T2 ) ,
2018-11-22 18:44:33 +00:00
%% Recurse , accumulation on the first element
2018-11-22 15:59:00 +00:00
join_similar_terms ( [ T2 | L ] , L2 ) ,
%% Give only first result . Red cut
! .
join_similar_terms ( [ X | L ] , [ X | L2 ] ) : -
2018-11-22 18:44:33 +00:00
%% If a pair of elements can ' t be added , skip one
%% and recurse
2018-11-22 15:59:00 +00:00
join_similar_terms ( L , L2 ) ,
%% Give only first result . Red cut
! .
join_similar_terms ( [] , [] ) .
%% Tests:
%% ? - join_similar_terms ( [ [ 2 , x ^ 3 ] , [ 3 , x ^ 3 ] , [ x ^ 3 ] ] , L ) .
%@ L = [ [ 6 , x ^ 3 ] ] .
2018-11-20 16:14:53 +00:00
2018-11-22 18:44:33 +00:00
%% term_to_canon ( + T:List , - T2:List ) is det
%
2018-11-25 16:47:43 +00:00
% Adds the coefficient of the term as the first element of the list
2018-11-22 18:44:33 +00:00
%
2018-11-25 19:28:46 +00:00
%% Special cases to make this predicate reversible
2018-11-25 16:47:43 +00:00
term_to_canon ( [ 1 ] , [ 1 ] ) : -
2018-11-22 15:59:00 +00:00
! .
2018-11-25 16:47:43 +00:00
term_to_canon ( L2 , [ 1 | L ] ) : -
nonvar ( L ) ,
L2 = L ,
! .
term_to_canon ( [ - 1 ] , [ - 1 ] ) : -
! .
term_to_canon ( [ - P | L2 ] , [ - 1 , P | L ] ) : -
nonvar ( L ) ,
L2 = L ,
! .
term_to_canon ( [ N2 | L ] , [ N | L ] ) : -
number ( N ) ,
N2 = N ,
! .
2018-11-25 19:28:46 +00:00
%% Normal case
2018-11-25 16:47:43 +00:00
term_to_canon ( L , [ N | L2 ] ) : -
term_to_canon_with_coefficient ( N , L , L2 ) ,
2018-11-23 18:18:15 +00:00
! .
2018-11-22 15:59:00 +00:00
%% Tests:
2018-11-22 18:44:33 +00:00
%% ? - term_to_canon ( [ 2 ] , T ) .
%@ T = [ 2 ] .
2018-11-25 16:47:43 +00:00
%% ? - term_to_canon ( [ - x ] , T ) .
%@ T = [ - 1 , x ] .
%% ? - term_to_canon ( [ - x ^ 3 ] , T ) .
%@ T = [ - 1 , x ^ 3 ] .
%% ? - term_to_canon ( [ x ^ 1 ] , T ) .
%@ T = [ 1 , x ^ 1 ] .
2018-11-22 15:59:00 +00:00
%% ? - term_to_canon ( [ x ^ 3 ] , T ) .
%@ T = [ 1 , x ^ 3 ] .
2018-11-22 18:44:33 +00:00
%% ? - term_to_canon ( [ x ^ 3 , z ] , T ) .
%@ T = [ 1 , x ^ 3 , z ] .
2018-11-22 15:59:00 +00:00
%% ? - term_to_canon ( [ 2 , x ^ 3 ] , T ) .
%@ T = [ 2 , x ^ 3 ] .
2018-11-25 16:47:43 +00:00
%% ? - term_to_canon ( [ 2 , - x ^ 3 ] , T ) .
%@ T = [ - 2 , x ^ 3 ] .
%% ? - term_to_canon ( [ 2 , - x ^ 3 , - z ] , T ) .
%@ T = [ 2 , x ^ 3 , z ] .
%% ? - term_to_canon ( L , [ - 1 ] ) .
%@ L = [ - 1 ] .
%% ? - term_to_canon ( L , [ 1 ] ) .
%@ L = [ 1 ] .
%% ? - term_to_canon ( L , [ - 2 ] ) .
%@ L = [ - 2 ] .
%% ? - term_to_canon ( L , [ - 2 , x ] ) .
%@ L = [ - 2 , x ] .
%% ? - term_to_canon ( L , [ 1 , x ] ) .
%@ L = [ x ] .
%% ? - term_to_canon ( L , [ - 1 , x ] ) .
%@ L = [ - x ] .
%% ? - term_to_canon ( L , [ 1 , x , z , y ] ) .
%@ L = [ x , z , y ] .
%% ? - term_to_canon ( L , [ - 1 , x , z , y ] ) .
%@ L = [ - x , z , y ] .
%% term_to_canon_with_coefficient ( - N:number , + L:List , - L2:List ) is semidet
%
% Calculates the coefficient of the term and removes negations of powers ,
% accumulating the results in N
%
term_to_canon_with_coefficient ( N , [ N2 | TS ] , TS2 ) : -
number ( N2 ) ,
term_to_canon_with_coefficient ( N3 , TS , TS2 ) ,
N is N2 * N3 ,
! .
term_to_canon_with_coefficient ( N , [ P | TS ] , [ P2 | TS2 ] ) : -
sign_of_power ( P , N2 * P2 ) ,
term_to_canon_with_coefficient ( N3 , TS , TS2 ) ,
N is N2 * N3 ,
! .
term_to_canon_with_coefficient ( N , [] , [] ) : -
nonvar ( N ) ;
N = 1 .
%% Tests:
%% ? - term_to_canon_with_coefficient ( N , [ x ] , L ) .
%@ N = 1 ,
%@ L = [ x ] .
%% ? - term_to_canon_with_coefficient ( N , [ x , x ^ 2 , 2 ] , L ) .
%@ N = 2 ,
%@ L = [ x ^ 1 , x ^ 2 ] .
%% ? - term_to_canon_with_coefficient ( N , [ x , x ^ 2 , 2 , 4 , z ] , L ) .
%@ N = 8 ,
%@ L = [ x , x ^ 2 , z ] .
%% ? - term_to_canon_with_coefficient ( N , [ x , x ^ 2 , 2 , 4 , - z ] , L ) .
%@ N = - 8 ,
%@ L = [ x , x ^ 2 , z ] .
%% ? - term_to_canon_with_coefficient ( N , [ x , - x ^ 2 , 2 , 4 , - z ] , L ) .
%@ N = 8 ,
%@ L = [ x , x ^ 2 , z ] .
%% ? - term_to_canon_with_coefficient ( N , L , [ x ] ) .
%@ N = 1 ,
%@ L = [ x ] .
%% ? - term_to_canon_with_coefficient ( N , L , [ 1 ] ) .
%@ N = 1 ,
%@ L = [ 1 ] .
%% ? - term_to_canon_with_coefficient ( N , L , [ 2 ] ) .
%@ N = 1 ,
%@ L = [ 2 ] .
%% sign_of_power ( P:power , P:term ) is det
%
% If there isn ' t a leading minus , multiplies the power by 1 ,
% otherwise by a - 1 . This way it prefers the positive version .
% Not idempotent
%
sign_of_power ( P , 1 * P ) : -
%% If P can ' t unify with a minus followed by an unnamed variable
P \= - _ ,
! .
sign_of_power ( - P , - 1 * P ) .
%% Tests:
%% ? - sign_of_power ( x , X ) .
%@ X = 1 * x .
%% ? - sign_of_power ( - x , X ) .
%@ X = - 1 * x .
%% ? - sign_of_power ( X , 1 * x ) .
%@ X = x .
%% ? - sign_of_power ( X , - 1 * x ) .
%@ X = - x .
2018-11-20 16:14:53 +00:00
2018-12-17 16:31:10 +00:00
%% add_terms ( + L:List , + In:List , - Result:List ) is det
2018-11-22 18:44:33 +00:00
%
% Adds two terms represented as list by adding
% the coeficients if the power is the same .
2018-11-25 19:28:46 +00:00
% Returns false if they can ' t be added
2018-11-22 18:44:33 +00:00
% Requires the list of terms to be simplified .
%
2018-11-22 15:59:00 +00:00
add_terms ( [ NL | TL ] , [ NR | TR ] , [ N2 | TL2 ] ) : -
2018-11-23 18:18:15 +00:00
%% Convert each term to a canon form . This ensures they
%% have a number in front , so it can be added
2018-11-22 15:59:00 +00:00
term_to_canon ( [ NL | TL ] , [ NL2 | TL2 ] ) ,
term_to_canon ( [ NR | TR ] , [ NR2 | TR2 ] ) ,
2018-11-25 17:50:49 +00:00
%% If the rest of the term is the same
2018-11-22 15:59:00 +00:00
TL2 == TR2 ,
2018-11-23 18:18:15 +00:00
%% Add the coeficients
2018-11-22 15:59:00 +00:00
N2 is NL2 + NR2 .
%% Tests
2018-12-17 16:31:10 +00:00
%% ? - add_terms ( [ 1 ] , [ 1 ] , In ) .
%@ In = [ 2 ] .
%% ? - add_terms ( [ x ] , [ x ] , In ) .
%@ In = [ 2 , x ] .
%% ? - add_terms ( [ 2 , x ^ 3 ] , [ x ^ 3 ] , In ) .
%@ In = [ 3 , x ^ 3 ] .
%% ? - add_terms ( [ 2 , x ^ 3 ] , [ 3 , x ^ 3 ] , In ) .
%@ In = [ 5 , x ^ 3 ] .
%% ? - add_terms ( [ 2 , x ^ 3 ] , [ 3 , x ^ 2 ] , In ) .
2018-11-25 19:28:46 +00:00
%@ false .
2018-11-17 22:28:51 +00:00
2018-11-23 15:32:15 +00:00
%% polynomial_to_list ( + P:polynomial , - L:List ) is det
2018-11-20 01:48:23 +00:00
%
% Converts a polynomial in a list .
%
2018-11-22 18:44:33 +00:00
polynomial_to_list ( L - T , [ T2 | LS ] ) : -
term ( T ) ,
negate_term ( T , T2 ) ,
2018-11-23 15:32:15 +00:00
polynomial_to_list ( L , LS ) ,
! .
2018-11-22 15:59:00 +00:00
polynomial_to_list ( L + T , [ T | LS ] ) : -
term ( T ) ,
2018-11-23 15:32:15 +00:00
polynomial_to_list ( L , LS ) ,
! .
2018-11-22 15:59:00 +00:00
polynomial_to_list ( T , [ T ] ) : -
2018-11-23 15:32:15 +00:00
term ( T ) ,
! .
2018-11-20 01:48:23 +00:00
%% Tests:
2018-11-22 18:44:33 +00:00
%% ? - polynomial_to_list ( 2 , S ) .
2018-11-23 15:32:15 +00:00
%@ S = [ 2 ] .
2018-11-22 18:44:33 +00:00
%% ? - polynomial_to_list ( x ^ 2 , S ) .
2018-11-23 15:32:15 +00:00
%@ S = [ x ^ 2 ] .
2018-11-22 18:44:33 +00:00
%% ? - polynomial_to_list ( x ^ 2 + x ^ 2 , S ) .
2018-11-23 15:32:15 +00:00
%@ S = [ x ^ 2 , x ^ 2 ] .
2018-11-22 18:44:33 +00:00
%% ? - polynomial_to_list ( 2 * x ^ 2 + 5 + y * 2 , S ) .
2018-11-23 15:32:15 +00:00
%@ S = [ y * 2 , 5 , 2 * x ^ 2 ] .
2018-11-22 18:44:33 +00:00
%% ? - polynomial_to_list ( 2 * x ^ 2 + 5 - y * 2 , S ) .
2018-11-23 15:32:15 +00:00
%@ S = [ - 2 * y , 5 , 2 * x ^ 2 ] .
2018-11-22 18:44:33 +00:00
%% ? - polynomial_to_list ( 2 * x ^ 2 - 5 - y * 2 , S ) .
2018-11-23 15:32:15 +00:00
%@ S = [ - 2 * y , - 5 , 2 * x ^ 2 ] .
2018-11-20 01:48:23 +00:00
2018-11-24 16:10:44 +00:00
%% list_to_polynomial ( + L:List , - P:Polynomial ) is det
2018-11-20 01:48:23 +00:00
%
% Converts a list in a polynomial .
2018-11-24 16:10:44 +00:00
% An empty list will return false .
2018-11-20 01:48:23 +00:00
%
list_to_polynomial ( [ T1 | T2 ] , P ) : -
2018-11-24 16:10:44 +00:00
% Start recursive calls until we are in the
% end of the list . We know that the `-` will
% always be at the left of a term .
2018-11-20 01:48:23 +00:00
list_to_polynomial ( T2 , L1 ) ,
(
2018-11-24 16:10:44 +00:00
% If this is a negative term
term_string ( T1 , S1 ) ,
string_chars ( S1 , [ First | _ ] ) ,
First = - ,
% Concat them
term_string ( L1 , S2 ) ,
string_concat ( S2 , S1 , S3 ) ,
term_string ( P , S3 )
2018-11-20 01:48:23 +00:00
;
2018-11-24 16:10:44 +00:00
% Otherwise sum them
P = L1 + T1
2018-11-20 01:48:23 +00:00
) ,
% The others computations are semantically meaningless
! .
2018-11-24 16:10:44 +00:00
list_to_polynomial ( [ T ] , T ) .
2018-11-20 01:48:23 +00:00
%% Tests:
2018-11-23 18:18:15 +00:00
%% ? - list_to_polynomial ( [ 1 , x , x ^ 2 ] , P ) .
%@ P = x ^ 2 + x + 1 .
2018-11-24 16:24:42 +00:00
%% ? - list_to_polynomial ( [ - 1 , - x , - x ^ 2 ] , P ) .
%@ P = - x ^ 2 - x - 1 .
%% ? - list_to_polynomial ( [ 1 , - x , x ^ 2 ] , P ) .
%@ P = x ^ 2 - x + 1 .
%% ? - list_to_polynomial ( [ x ^ 2 , x , 1 ] , P ) .
%@ P = 1 + x + x ^ 2 .
%% ? - list_to_polynomial ( [ a , - e ] , P ) .
%@ P = - e + a .
%% ? - list_to_polynomial ( [] , P ) .
%@ false .
%% ? - list_to_polynomial ( [ a ] , P ) .
%@ P = a .
2018-11-20 01:48:23 +00:00
2018-11-22 18:44:33 +00:00
%% negate_term ( T , T2 ) is det
%
2018-11-24 16:10:44 +00:00
% Negate the coeficient of a term and return the negated term .
2018-11-22 18:44:33 +00:00
%
negate_term ( T , T2 ) : -
term_to_list ( T , L ) ,
2018-11-23 18:18:15 +00:00
%% Ensure there is a coeficient
2018-11-25 16:47:43 +00:00
term_to_canon ( L , L2 ) ,
2018-12-17 16:31:10 +00:00
[ N | In ] = L2 ,
2018-11-22 18:44:33 +00:00
%% ( - ) / 1 is an operator , needs to be evaluated , otherwise
%% it gives a symbolic result , which messes with further processing
N2 is - N ,
2018-11-25 19:28:46 +00:00
%% Convert the term back from canonic form
2018-12-17 16:31:10 +00:00
term_to_canon ( L3 , [ N2 | In ] ) ,
2018-11-23 18:18:15 +00:00
%% Reverse the order of the list , because converting
%% implicitly reverses it
2018-11-25 16:47:43 +00:00
reverse ( L3 , L4 ) ,
2018-11-22 18:44:33 +00:00
term_to_list ( T2 , L4 ) ,
! .
%% Tests:
2018-12-17 16:31:10 +00:00
%% ? - negate_term ( 1 , In ) .
%@ In = - 1 .
%% ? - negate_term ( x , In ) .
%@ In = - x .
%% ? - negate_term ( - x , In ) .
%@ In = x .
%% ? - negate_term ( x ^ 2 , In ) .
%@ In = - x ^ 2 .
%% ? - negate_term ( 3 * x * y ^ 2 , In ) .
%@ In = - 3 * y ^ 2 * x .
2018-11-20 01:48:23 +00:00
2018-11-24 16:10:44 +00:00
%% scale_polynomial ( + P:Polynomial , + C:Constant , - S:Polynomial ) is det
2018-11-20 01:48:23 +00:00
%
2018-11-24 16:10:44 +00:00
% Multiplies a polynomial by a scalar .
2018-11-20 01:48:23 +00:00
%
scale_polynomial ( P , C , S ) : -
polynomial_to_list ( P , L ) ,
2018-11-23 18:18:15 +00:00
%% Convert each term to a list
2018-11-23 14:56:01 +00:00
maplist ( term_to_list , L , L2 ) ,
2018-11-25 17:50:49 +00:00
%% Canonize terms
maplist ( term_to_canon , L2 , L3 ) ,
2018-11-23 18:18:15 +00:00
%% Append C to the start of each sublist
2018-11-25 17:50:49 +00:00
maplist ( cons ( C ) , L3 , L4 ) ,
%% Convert to a list of terms
maplist ( term_to_list , L5 , L4 ) ,
2018-11-23 18:18:15 +00:00
%% Simplify the resulting polynomial
2018-11-25 17:50:49 +00:00
simplify_polynomial_as_list ( L5 , L6 ) ,
%% Return as a simplified polynomial
list_to_polynomial ( L6 , S ) ,
2018-11-22 18:55:37 +00:00
! .
2018-11-21 15:23:35 +00:00
%% Tests:
%% ? - scale_polynomial ( 3 * x ^ 2 , 2 , S ) .
2018-11-23 15:32:15 +00:00
%@ S = 6 * x ^ 2 .
2018-11-23 16:21:16 +00:00
%% cons ( + C:atom , + L:List , - L2:List ) is det
%
2018-11-24 16:10:44 +00:00
% Add an atom C to the head of a list L .
2018-11-23 16:21:16 +00:00
%
2018-11-23 15:32:15 +00:00
cons ( C , L , [ C | L ] ) .
2018-11-24 16:24:42 +00:00
%% Tests:
2018-11-25 19:28:46 +00:00
%% ? - cons ( C , L , L2 ) .
%@ L2 = [ C | L ] .
2018-11-20 01:48:23 +00:00
2018-11-22 15:41:11 +00:00
%% add_polynomial ( + P1:polynomial , + P2:polynomial , - S:polynomial ) is det
%
2018-11-24 16:10:44 +00:00
% S = P1 + P2 .
2018-11-22 15:41:11 +00:00
%
add_polynomial ( P1 , P2 , S ) : -
2018-11-23 18:18:15 +00:00
%% Convert both polynomials to lists
2018-11-22 15:41:11 +00:00
polynomial_to_list ( P1 , L1 ) ,
polynomial_to_list ( P2 , L2 ) ,
2018-11-23 18:18:15 +00:00
%% Join them
2018-11-23 16:21:16 +00:00
append ( L1 , L2 , L3 ) ,
2018-11-23 18:18:15 +00:00
%% Simplify the resulting polynomial
2018-11-23 16:21:16 +00:00
simplify_polynomial_as_list ( L3 , L4 ) ,
2018-11-23 18:18:15 +00:00
%% Convert back
2018-11-23 16:21:16 +00:00
list_to_polynomial ( L4 , S ) ,
! .
2018-11-22 15:41:11 +00:00
%% Tests:
2018-11-23 16:21:16 +00:00
%% ? - add_polynomial ( 2 , 2 , S ) .
%@ S = 4 .
%% ? - add_polynomial ( x , x , S ) .
%@ S = 2 * x .
%% ? - add_polynomial ( 2 * x + 5 * z , 2 * z + 6 * x , S ) .
%@ S = 8 * x + 7 * z .