From a64a765f32af532a3d3211a6d832a08c6d9dd9cf Mon Sep 17 00:00:00 2001 From: bakaq Date: Wed, 20 Sep 2023 20:56:04 -0300 Subject: [PATCH 1/4] Improved dif/2 --- src/lib/dif.pl | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/lib/dif.pl b/src/lib/dif.pl index 73d65518..4fe35b80 100644 --- a/src/lib/dif.pl +++ b/src/lib/dif.pl @@ -7,7 +7,7 @@ arguments are different terms. :- use_module(library(atts)). :- use_module(library(dcgs)). -:- use_module(library(lists), [append/3]). +:- use_module(library(lists), [append/3, maplist/3]). :- attribute dif/1. @@ -23,6 +23,29 @@ dif_set_variables([Var|Vars], X, Y) :- put_dif_att(Var, X, Y), dif_set_variables(Vars, X, Y). +remove_goal([], _, []). +remove_goal([G0|G0s], Goal0, Goals) :- + ( G0 == Goal0 -> + remove_goal(G0s, Goal0, Goals) + ; Goals = [G0|Goals1], + remove_goal(G0s, Goal0, Goals1) + ). + +vars_remove_goal([], _). +vars_remove_goal([Var|Vars], Goal0) :- + get_atts(Var, +dif(Goals0)), + remove_goal(Goals0, Goal0, Goals), + put_atts(Var, +dif(Goals)), + vars_remove_goal(Vars, Goal0). + +reinforce_goal(Goal0, Goal) :- + Goal = ( + term_variables(Goal0, Vars), + dif:vars_remove_goal(Vars, Goal0), + Goal0 = (L \== R), + dif(L, R) + ). + append_goals([], _). append_goals([Var|Vars], Goals) :- ( get_atts(Var, +dif(VarGoals)) -> @@ -34,9 +57,10 @@ append_goals([Var|Vars], Goals) :- append_goals(Vars, Goals). verify_attributes(Var, Value, Goals) :- - ( get_atts(Var, +dif(Goals)) -> + ( get_atts(Var, +dif(Goals0)) -> term_variables(Value, ValueVars), - append_goals(ValueVars, Goals) + append_goals(ValueVars, Goals0), + maplist(reinforce_goal, Goals0, Goals) ; Goals = [] ). From f5c23fbb16bcbd1cc25f699c31317f3f4a6e62ce Mon Sep 17 00:00:00 2001 From: bakaq Date: Wed, 20 Sep 2023 20:56:25 -0300 Subject: [PATCH 2/4] Tests for dif/2 --- tests-pl/dif_tests.pl | 235 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 tests-pl/dif_tests.pl diff --git a/tests-pl/dif_tests.pl b/tests-pl/dif_tests.pl new file mode 100644 index 00000000..01ece5fa --- /dev/null +++ b/tests-pl/dif_tests.pl @@ -0,0 +1,235 @@ +/**/ + +:- use_module(library(format)). +:- use_module(library(dcgs)). +:- use_module(library(lists)). +:- use_module(library(debug)). +:- use_module(library(atts)). +:- use_module(library(dif)). + +% Tests from https://www.complang.tuwien.ac.at/ulrich/iso-prolog/dif + +test("dif#1",( + call_residual_goals(dif(1,2), Res), + Res = [] +)). + +test("dif#2",( + \+ (dif(1,Y), Y = 1) +)). + +test("dif#3",( + call_residual_goals((dif(1,Y), Y=2), Res), + Y == 2, + Res = [] +)). + +test("dif#4",( + \+ (dif(X,-Y), X= -Y) +)). + +test("dif#5",( + \+ (dif(X,Y), X=Y) +)). + +test("dif#6",( + \+ (dif(X,Y), X=Y, X=1) +)). + +test("dif#7",( + \+ (dif(-X,-Y), X=Y) +)). + +test("dif#8",( + \+ (dif(-X,-Y), X=Y, X=1) +)). + +% I don't understand exactly what is expected for dif#9 and dif#10 + +test("dif#11",( + call_residual_goals((X=Y, dif(X-Y,1-2)), Res), + X == Y, + Res = [] +)). + +test("dif#12",( + call_residual_goals((dif(X-Y,1-2), X=Y), Res), + X == Y, + Res = [] +)). + +test("dif#13",( + call_residual_goals((X=Y, Y=1, dif(X-Y,1-2)), Res), + X == 1, + Y == 1, + Res = [] +)). + +test("dif#14",( + call_residual_goals((dif(X-Y,1-2), X=Y, Y=1), Res), + X == 1, + Y == 1, + Res = [] +)). + +test("dif#15",( + call_residual_goals((dif(X-Y,1-2), X=Y, X=2), Res), + X == 2, + Y == 2, + Res = [] +)). + +test("dif#16",( + call_residual_goals((dif(A-C,B-D), C-D=z-z, A-B=1-2), Res), + A == 1, + B == 2, + C == z, + D == z, + Res = [] +)). + +test("dif#17",( + call_residual_goals((A-B=1-2, C-D=z-z, dif(A-C,B-D)), Res), + A == 1, + B == 2, + C == z, + D == z, + Res = [] +)). + +test("dif#18",( + call_residual_goals((dif(A,[C|B]), A=[[]|_], A=[B]), Res), + A == [[]], + B == [], + Res = [dif:dif([[]], [C])] +)). + +test("dif#19",( + call_residual_goals((dif([E],[/]), E=1), Res), + E == 1, + Res = [] +)). + +test("dif#20",( + call_residual_goals((dif([a],B), B=[_|_], B=[b]), Res), + B == [b], + Res = [] +)). + +test("dif#21",( + call_residual_goals((dif([],A), A = [_]), Res), + A = [_], + Res = [] +)). + +test("dif#22",( + call_residual_goals((A = [_], dif([],A)), Res), + A = [_], + Res = [] +)). + +test("dif#t1",( + set_prolog_flag(occurs_check, false), + \+ \+ -X=X +)). + +test("dif#t2",( + set_prolog_flag(occurs_check, false), + \+ (-X=X, -Y=Y, X\=Y) +)). + +test("dif#t3",( + set_prolog_flag(occurs_check, false), + call_residual_goals((-X=X, dif(X,1)), Res), + X == -X, + Res = [] +)). + +test("dif#t4",( + set_prolog_flag(occurs_check, false), + \+ (-X=X, -Y=Y, dif(X,Y)) +)). + +test("dif#t5",( + set_prolog_flag(occurs_check, false), + \+ (dif(X,Y), -X=X, -Y=Y) +)). + +test("dif#t6",( + set_prolog_flag(occurs_check, false), + \+ (A=[[]|A],dif(A,B),B=[[]|A]) +)). + +test("dif#t7",( + set_prolog_flag(occurs_check, false), + \+ (dif(-X,X),-Y=Y,X=Y) +)). + +test("dif#o1",( + set_prolog_flag(occurs_check, true), + \+ (-X = X) +)). + +test("dif#o2",( + set_prolog_flag(occurs_check, true), + call_residual_goals((dif(-X,X)), Res), + Res = [] +)). + +test("dif#o3",( + set_prolog_flag(occurs_check, true), + call_residual_goals((dif(-X,Y), X=Y), Res), + X == Y, + Res = [] +)). + +test("dif#12 but with multiple variables in the residuals",( + call_residual_goals((dif(X-Y-_, 1-2-3), X = Y), Res), + X == Y, + Res = [] +)). + +main :- + findall(test(Name, Goal), test(Name, Goal), Tests), + run_tests(Tests, Failed), + show_failed(Failed), + halt. + +portray_failed_([]) --> []. +portray_failed_([F|Fs]) --> + "\"", F, "\"", "\n", portray_failed_(Fs). + +portray_failed([]) --> []. +portray_failed([F|Fs]) --> + "\n", "Failed tests:", "\n", portray_failed_([F|Fs]). + +show_failed(Failed) :- + phrase(portray_failed(Failed), F), + format("~s", [F]). + +run_tests([], []). +run_tests([test(Name, Goal)|Tests], Failed) :- + format("Running test \"~s\"~n", [Name]), + ( call(Goal) -> + Failed = Failed1 + ; format("Failed test \"~s\"~n", [Name]), + Failed = [Name|Failed1] + ), + run_tests(Tests, Failed1). + +assert_p(A, B) :- + phrase(portray_clause_(A), Portrayed), + phrase((B, ".\n"), Portrayed). + +call_residual_goals(Goal, ResidualGoals) :- + call_residue_vars(Goal, Vars), + variables_residual_goals(Vars, ResidualGoals). + +variables_residual_goals(Vars, Goals) :- + phrase(variables_residual_goals(Vars), Goals). + +variables_residual_goals([]) --> []. +variables_residual_goals([Var|Vars]) --> + dif:attribute_goals(Var), + variables_residual_goals(Vars). + From cac52c05376b8d1701c81cc5f631913ed2b412c5 Mon Sep 17 00:00:00 2001 From: bakaq Date: Thu, 21 Sep 2023 12:14:27 -0300 Subject: [PATCH 3/4] Run dif tests on cargo test --- tests-pl/dif_tests.pl => src/tests/dif.pl | 17 +++++++++++++++++ tests/scryer/src_tests.rs | 9 +++++++++ 2 files changed, 26 insertions(+) rename tests-pl/dif_tests.pl => src/tests/dif.pl (91%) diff --git a/tests-pl/dif_tests.pl b/src/tests/dif.pl similarity index 91% rename from tests-pl/dif_tests.pl rename to src/tests/dif.pl index 01ece5fa..752458b5 100644 --- a/tests-pl/dif_tests.pl +++ b/src/tests/dif.pl @@ -195,6 +195,15 @@ main :- show_failed(Failed), halt. +main_quiet :- + findall(test(Name, Goal), test(Name, Goal), Tests), + run_tests_quiet(Tests, Failed), + ( Failed = [] -> + format("All tests passed", []) + ; format("Some tests failed", []) + ), + halt. + portray_failed_([]) --> []. portray_failed_([F|Fs]) --> "\"", F, "\"", "\n", portray_failed_(Fs). @@ -217,6 +226,14 @@ run_tests([test(Name, Goal)|Tests], Failed) :- ), run_tests(Tests, Failed1). +run_tests_quiet([], []). +run_tests_quiet([test(Name, Goal)|Tests], Failed) :- + ( call(Goal) -> + Failed = Failed1 + ; Failed = [Name|Failed1] + ), + run_tests_quiet(Tests, Failed1). + assert_p(A, B) :- phrase(portray_clause_(A), Portrayed), phrase((B, ".\n"), Portrayed). diff --git a/tests/scryer/src_tests.rs b/tests/scryer/src_tests.rs index f913788e..5572b75f 100644 --- a/tests/scryer/src_tests.rs +++ b/tests/scryer/src_tests.rs @@ -75,3 +75,12 @@ fn clpz_load() { fn iso_conformity_tests() { load_module_test("tests-pl/iso-conformity-tests.pl", "All tests passed"); } + +#[test] +fn dif_tests() { + run_top_level_test_with_args( + &["src/tests/dif.pl", "-f", "-g", "main_quiet"], + "", + "All tests passed", + ); +} From cb79e83510066c2ef14d96ff441d844869222f1e Mon Sep 17 00:00:00 2001 From: bakaq Date: Thu, 21 Sep 2023 14:00:37 -0300 Subject: [PATCH 4/4] Avoid dif/1 attribute with empty list Closes #1956 --- src/lib/dif.pl | 5 ++++- src/tests/dif.pl | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/lib/dif.pl b/src/lib/dif.pl index 4fe35b80..fedb320c 100644 --- a/src/lib/dif.pl +++ b/src/lib/dif.pl @@ -35,7 +35,10 @@ vars_remove_goal([], _). vars_remove_goal([Var|Vars], Goal0) :- get_atts(Var, +dif(Goals0)), remove_goal(Goals0, Goal0, Goals), - put_atts(Var, +dif(Goals)), + ( Goals = [] -> + put_atts(Var, -dif(_)) + ; put_atts(Var, +dif(Goals)) + ), vars_remove_goal(Vars, Goal0). reinforce_goal(Goal0, Goal) :- diff --git a/src/tests/dif.pl b/src/tests/dif.pl index 752458b5..bb1c76d6 100644 --- a/src/tests/dif.pl +++ b/src/tests/dif.pl @@ -189,6 +189,13 @@ test("dif#12 but with multiple variables in the residuals",( Res = [] )). +% https://github.com/mthom/scryer-prolog/issues/1956 +test("scryer-prolog#1956",( + call_residue_vars((dif(a-a,X-_),X=b), Res), + X == b, + Res = [] +)). + main :- findall(test(Name, Goal), test(Name, Goal), Tests), run_tests(Tests, Failed),