Merge branch 'nlp-ph' into nlp

This commit is contained in:
Hugo Sales 2018-12-17 16:31:10 +00:00
commit 74d9e9cc5b
1 changed files with 323 additions and 271 deletions

View File

@ -34,7 +34,301 @@
:- use_module(library(clpr)).
/*******************************
* USER INTERFACE *
* NLP *
*******************************/
%% polyplay() is det
%
% Interactive prompt for the NLP Interface
%
polyplay :-
prompt(OldPrompt, '> '),
read_string(user_input, "\n", "\r\t ", _, In),
prompt(_, OldPrompt),
split_string(In, " ", "", LS),
maplist(string_to_atom, LS, LA),
(
LA == [bye],
write("See ya"),
!
;
(
parse_input(TIn, LA, NC),
(
TIn == void,
writeln("I didn't understand what you want."),
writeln(NC)
;
process_input(TIn)
)
;
writeln("I didn't understand what you want.")
),
polyplay
),
!.
%% Tests:
%% ?- polyplay.
%% nlp_number(?W:Atom, ?D:Int) is det
%
% Definition of a Alphabetical and Numerical relation
%
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).
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).
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).
%% nlp_number(?W:Atom, ?D:Int) is det
%
% Definition of a Alphabetical and Numerical relation
%
%% Entry point
parse_number_explicit(void, void, T, [WN | In], NC) :-
special_word_number(WN, N, P),
member(P, [f, g, fy]),
!,
parse_number_explicit(P, N, T, In, NC).
parse_number_explicit(fy, NL, T, [WN | In], NC) :-
special_word_number(WN, N, f),
!,
parse_number_explicit(f, op(+, NL, N), T, In, NC).
parse_number_explicit(xfy, TL, T, [WN | In], NC) :-
TL \= void,
special_word_number(WN, N, P),
member(P, [f, g, fy]),
!,
parse_number_explicit(P, op(+, TL, N), T, In, NC).
parse_number_explicit(_, TL, T, [WN | In], NC) :-
special_word_number(WN, N, xfy),
TL \= void,
!,
parse_number_explicit(xfy, op(*, TL, N), T, In, NC).
parse_number_explicit(P, TL, T, [and, WN | In], NC) :-
special_word_number(WN, _, _),
parse_number_explicit(P, TL, T, [WN | In], NC),
!.
parse_number_explicit(_, T, T, [WN | In], [WN | In]) :-
T \= void,
not(special_word_number(WN, _, _)),
!.
parse_number_explicit(_, T, T, [], []) :-
T \= void,
!.
parse_number(T, SL, NC) :-
parse_number_explicit(void, void, T, SL, NC).
%% Tests:
%% ?- parse_number(T, [two], _).
%@ T = 2.
%% ?- parse_number(T, [nineteen, two], _).
%@ false.
%% ?- parse_number(T, [twenty], _).
%@ T = 20.
%% ?- parse_number(T, [twenty, twenty], _).
%@ false.
%% ?- parse_number(T, [twenty, one], _).
%@ T = op(+, 20, 1).
%% ?- parse_number(T, [hundred], _).
%@ false.
%% ?- parse_number(T, [three, hundred], _).
%@ T = op(*, 3, 100).
%% ?- parse_number(T, [twenty, hundred], _).
%@ T = op(*, 20, 100).
%% ?- parse_number(T, [twenty, one, hundred], _).
%@ T = op(*, op(+, 20, 1), 100).
%% ?- parse_number(T, [two, hundred, and, one], _).
%@ T = op(+, op(*, 2, 100), 1).
%% ?- parse_number(T, [twenty, one, hundred, and, twenty, one], _).
%@ T = op(+, op(+, op(*, op(+, 20, 1), 100), 20), 1).
%% ?- parse_number(T, [twenty, one, hundred, and, twenty, one, foo, bar, blah], NC).
%@ T = op(+, op(+, op(*, op(+, 20, 1), 100), 20), 1),
%@ NC = [foo, bar, blah].
%% ?- parse_number(T, [twenty, one, hundred, and, bleg, twenty, quux, one, foo, bar], NC).
%@ T = op(*, op(+, 20, 1), 100),
%@ NC = [and, bleg, twenty, quux, one, foo, bar].
%% ?- parse_number(T, [two, hundred, thousand], _).
%@ T = op(*, op(*, 2, 100), 1000).
%% ?- parse_number(T, [twenty, one, hundred, thousand], _).
%@ T = op(*, op(*, op(+, 20, 1), 100), 1000).
%% ?- parse_number(T, [thirty, five, million, five, hundred, thirty, four], _).
%@ T = op(+, op(+, op(*, op(+, op(*, op(+, 30, 5), 1000000), 5), 100), 30), 4).
%% ?- parse_number(T, [foo, five, million], NC).
%@ false.
%% nlp_parse_power(?List, ?List) is det
%
% Parse powers
%
%% Order matters
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],
parse_number(TN).
parse_power(TB) -->
parse_polynomial_variable(TB).
parse_operation(+) --> [plus].
parse_operation(*) --> [times].
parse_polynomial_operand(T) --> parse_number(T).
parse_polynomial_operand(T) --> parse_power(T).
parse_polynomial_operand(T) --> parse_stored_variable(T).
:- dynamic polynomial_store/2.
parse_stored_variable(load(P)) --> %% NOTE Not sure if it's better to load now or later
[P],
{ polynomial_store(P, _) }.
parse_polynomial_variable(B) -->
[B],
{ polynomial_variable(B) }.
parse_polynomial(T, NC, NC) :-
not(parse_polynomial_explicit(_-_, T, NC, _)),
!.
parse_polynomial(T) -->
parse_polynomial_explicit(_-_, T).
parse_polynomial_explicit(void-_, T) -->
parse_polynomial_operand(TL),
parse_operation(Op),
!,
parse_polynomial_explicit(op(Op, TL, TRP)-TRP, T).
parse_polynomial_explicit(TLP-TL, T) -->
parse_polynomial_operand(TL),
parse_operation(+),
!,
parse_polynomial_explicit(op(+, TLP, TRP)-TRP, T).
parse_polynomial_explicit(TLP-T, TLP) -->
parse_polynomial_operand(TL),
parse_operation(*),
!,
parse_polynomial_explicit(op(*, TL, TRP)-TRP, T).
parse_polynomial_explicit(TLP-TL, TLP) -->
{ TLP \= void },
parse_polynomial_operand(TL),
!,
{ TL \= void }.
parse_polynomial_explicit(void-_, T) -->
parse_polynomial_operand(T),
!,
{ T \= void }.
%% Tests:
%% ?- parse_polynomial(T, [], _).
%@ false.
%% ?- parse_polynomial(T, [two], _).
%@ T = 2.
%% ?- parse_polynomial(T, [two, times, three], _).
%@ T = op(*, 2, 3).
%% ?- 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))).
%% ?- parse_polynomial(T, [two, times, times, two], NC); write(NC).
%@ NC = [two, times, times, two] ;
%@ _2006
%@ true. %% NOTE Potential problem. It seems NC isn't unified with the list, if it fails
%% ?- 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)).
parse_command(show(void, T)) --> %% NOTE Probably easier if the tree is always binary
[show],
parse_polynomial_explicit(T).
parse_command(show(P, T)) -->
[show],
parse_polynomial_explicit(T),
[as],
[P].
parse_command(show_all) -->
[show, stored, polynomials].
parse_command(store(P, T)) -->
[let],
[P],
[be],
parse_polynomial_explicit(T).
parse_command(store(P, T)) -->
[store],
parse_polynomial_explicit(T),
[as],
[P].
parse_command(simplify(T)) -->
[simplify],
parse_polynomial_explicit(T).
parse_command(op(*, TN, TP)) -->
[multiply],
parse_number(TN),
[by],
parse_polynomial_explicit(_-_, TP).
parse_input(command(TCL, TCR)) -->
parse_command(TCL),
[and],
!,
parse_input(TCR).
parse_input(TC) -->
parse_command(TC).
parse_input(void, [], _).
%% nlp_print_memory
%
% Prints the NLP memory
%
nlp_print_memory([nm(X,Y)|T]) :-
write(X),
write(" = "),
writeln(Y),
nlp_print_memory(T).
nlp_print_memory([]).
/*******************************
* UI *
*******************************/
/*
@ -153,248 +447,6 @@ is_number_valid_in_predicate(C, F) :-
fail.
/*******************************
* NLP *
*******************************/
%% polyplay() is det
%
% Interactive prompt for the NLP Interface
%
polyplay :-
prompt(Old, '> '),
read_string(user_input, "\n", "\r\t ", _, Stdin),
prompt(_, Old),
string_lower(Stdin, Stdin_lower),
split_string(Stdin_lower, " ", "", LS),
maplist(string_to_atom, LS, R),
(
R == [bye],
write("See ya"),
!
;
(
nlp_handler(R, Z),
writeln(Z)
;
writeln("I didn't understand what you want.")
),
polyplay
),
!.
%% nlp_number(?W:Atom, ?D:Int) is det
%
% Definition of a Alphabetical and Numerical relation
%
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).
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).
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).
%% Entry point
parse_number_explicit(void, void, T, [WN | R], NC) :-
special_word_number(WN, N, P),
member(P, [f, g, fy]),
!,
parse_number_explicit(P, N, T, R, NC).
parse_number_explicit(fy, NL, T, [WN | R], NC) :-
special_word_number(WN, N, f),
!,
parse_number_explicit(f, op(+, NL, N), T, R, NC).
parse_number_explicit(xfy, TL, T, [WN | R], NC) :-
TL \= void,
special_word_number(WN, N, P),
member(P, [f, g, fy]),
!,
parse_number_explicit(P, op(+, TL, N), T, R, NC).
parse_number_explicit(_, TL, T, [WN | R], NC) :-
special_word_number(WN, N, xfy),
TL \= void,
!,
parse_number_explicit(xfy, op(*, TL, N), T, R, NC).
parse_number_explicit(P, TL, T, [and, WN | R], NC) :-
special_word_number(WN, _, _),
parse_number_explicit(P, TL, T, [WN | R], NC),
!.
parse_number_explicit(_, T, T, [WN | R], [WN | R]) :-
T \= void,
not(special_word_number(WN, _, _)),
!.
parse_number_explicit(_, T, T, [], []) :-
T \= void,
!.
parse_number(T, SL, NC) :-
parse_number_explicit(void, void, T, SL, NC).
%% Tests:
%% ?- parse_number(T, [two], _).
%@ T = 2.
%% ?- parse_number(T, [nineteen, two], _).
%@ false.
%% ?- parse_number(T, [twenty], _).
%@ T = 20.
%% ?- parse_number(T, [twenty, twenty], _).
%@ false.
%% ?- parse_number(T, [twenty, one], _).
%@ T = op(+, 20, 1).
%% ?- parse_number(T, [hundred], _).
%@ false.
%% ?- parse_number(T, [three, hundred], _).
%@ T = op(*, 3, 100).
%% ?- parse_number(T, [twenty, hundred], _).
%@ T = op(*, 20, 100).
%% ?- parse_number(T, [twenty, one, hundred], _).
%@ T = op(*, op(+, 20, 1), 100).
%% ?- parse_number(T, [two, hundred, and, one], _).
%@ T = op(+, op(*, 2, 100), 1).
%% ?- parse_number(T, [twenty, one, hundred, and, twenty, one], _).
%@ T = op(+, op(+, op(*, op(+, 20, 1), 100), 20), 1).
%% ?- parse_number(T, [twenty, one, hundred, and, twenty, one, foo, bar, blah], NC).
%@ T = op(+, op(+, op(*, op(+, 20, 1), 100), 20), 1),
%@ NC = [foo, bar, blah].
%% ?- parse_number(T, [twenty, one, hundred, and, bleg, twenty, quux, one, foo, bar], NC).
%@ T = op(*, op(+, 20, 1), 100),
%@ NC = [and, bleg, twenty, quux, one, foo, bar].
%% ?- parse_number(T, [two, hundred, thousand], _).
%@ T = op(*, op(*, 2, 100), 1000).
%% ?- parse_number(T, [twenty, one, hundred, thousand], _).
%@ T = op(*, op(*, op(+, 20, 1), 100), 1000).
%% ?- parse_number(T, [thirty, five, million, five, hundred, thirty, four], _).
%@ T = op(+, op(+, op(*, op(+, op(*, op(+, 30, 5), 1000000), 5), 100), 30), 4).
%% ?- parse_number(T, [foo, five, million], NC).
%@ false.
parse_operation(+) --> [plus].
parse_operation(*) --> [times].
parse_polynomial_operand(T) --> parse_number(T).
parse_polynomial_operand(T) --> parse_power(T).
parse_polynomial_operand(T) --> parse_stored_variable(T).
:- dynamic polynomial_store/2.
parse_stored_variable(T) --> %% NOTE Not sure if it's better to load now or later
[P],
{ polynomial_store(P, T) }.
parse_polynomial_variable(B) -->
[B],
{ polynomial_variable(B) }.
%% Order matters
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],
parse_number(TN).
parse_power(TB) -->
parse_polynomial_variable(TB).
parse_polynomial(void-_, T) -->
parse_polynomial_operand(TL),
parse_operation(Op),
!,
parse_polynomial(op(Op, TL, TRP)-TRP, T).
parse_polynomial(TLP-TL, T) -->
parse_polynomial_operand(TL),
parse_operation(+),
!,
parse_polynomial(op(+, TLP, TRP)-TRP, T).
parse_polynomial(TLP-T, TLP) -->
parse_polynomial_operand(TL),
parse_operation(*),
!,
parse_polynomial(op(*, TL, TRP)-TRP, T).
parse_polynomial(TLP-TL, TLP) -->
{ TLP \= void },
parse_polynomial_operand(TL),
!,
{ TL \= void }.
parse_polynomial(void-_, T) -->
parse_polynomial_operand(T),
!,
{ T \= void }.
%% Tests:
%% ?- parse_polynomial(_-_, T, [], _).
%@ false.
%% ?- parse_polynomial(_-_, T, [two], _).
%@ T = 2.
%% ?- parse_polynomial(_-_, T, [two, times, three], _).
%@ T = op(*, 2, 3).
%% ?- 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))).
%% ?- parse_polynomial(_-_, T, [two, times, times, two], NC); write(NC).
%@ _3164
%@ true. %% NOTE Potential problem. It seems NC isn't unified with the list, if it fails
%% ?- 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)).
parse_command(show(T)) --> %% NOTE Probably easier if the tree is always binary
[show],
parse_polynomial(T).
parse_command(show(store(P, T))) -->
[show],
parse_polynomial(T),
[as],
[P].
parse_command(store(P, T)) -->
[let],
[P],
[be],
parse_polynomial(T).
parse_command(simplify(T)) -->
[simplify],
parse_polynomial(T).
parse_command(op(*, TN, TP)) -->
[multiply],
parse_number(TN),
[by],
parse_polynomial(TP).
/*******************************
* BACKEND *
*******************************/
@ -474,9 +526,9 @@ term(X) :-
power(X).
term(-X) :-
power(X).
term(L * R) :-
term(L * In) :-
term(L),
term(R).
term(In).
%% Tests:
%% ?- term(2*x^3).
%@ true .
@ -523,14 +575,14 @@ term(L * R) :-
polynomial(M) :-
%% A polynomial is either a term
term(M).
polynomial(L + R) :-
polynomial(L + In) :-
%% Or a sum of terms
polynomial(L),
term(R).
polynomial(L - R) :-
term(In).
polynomial(L - In) :-
%% Or a subtraction of terms
polynomial(L),
term(R).
term(In).
%% Tests:
%% ?- polynomial(x).
%@ true .
@ -979,7 +1031,7 @@ sign_of_power(-P, -1*P).
%% ?- sign_of_power(X, -1*x).
%@ X = -x.
%% add_terms(+L:List, +R:List, -Result:List) is det
%% add_terms(+L:List, +In:List, -Result:List) is det
%
% Adds two terms represented as list by adding
% the coeficients if the power is the same.
@ -996,15 +1048,15 @@ add_terms([NL | TL], [NR | TR], [N2 | TL2]) :-
%% Add the coeficients
N2 is NL2 + NR2.
%% Tests
%% ?- add_terms([1], [1], R).
%@ R = [2].
%% ?- add_terms([x], [x], R).
%@ R = [2, x].
%% ?- add_terms([2, x^3], [x^3], R).
%@ R = [3, x^3].
%% ?- add_terms([2, x^3], [3, x^3], R).
%@ R = [5, x^3].
%% ?- add_terms([2, x^3], [3, x^2], R).
%% ?- 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).
%@ false.
%% polynomial_to_list(+P:polynomial, -L:List) is det
@ -1087,28 +1139,28 @@ negate_term(T, T2) :-
term_to_list(T, L),
%% Ensure there is a coeficient
term_to_canon(L, L2),
[N | R] = L2,
[N | In] = L2,
%% (-)/1 is an operator, needs to be evaluated, otherwise
%% it gives a symbolic result, which messes with further processing
N2 is -N,
%% Convert the term back from canonic form
term_to_canon(L3, [N2 | R]),
term_to_canon(L3, [N2 | In]),
%% Reverse the order of the list, because converting
%% implicitly reverses it
reverse(L3, L4),
term_to_list(T2, L4),
!.
%% Tests:
%% ?- negate_term(1, R).
%@ R = -1.
%% ?- negate_term(x, R).
%@ R = -x.
%% ?- negate_term(-x, R).
%@ R = x.
%% ?- negate_term(x^2, R).
%@ R = -x^2.
%% ?- negate_term(3*x*y^2, R).
%@ R = -3*y^2*x.
%% ?- 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.
%% scale_polynomial(+P:Polynomial,+C:Constant,-S:Polynomial) is det
%