Это моя первая программа CHR, поэтому я надеюсь, что кто-нибудь придет и даст мне несколько советов, как ее улучшить.
Я думаю, что вам нужно расширить все списки в факты.Оттуда, если вы знаете, что у проекта есть только один родитель и один ребенок, вы можете установить родительские отношения из этого.Кроме того, если у вас есть отношения родитель-ребенок, вы можете удалить этот набор из других фактов в других проектах и уменьшить количество проблем на единицу.В конце концов вы поймете все, что можете.Единственная разница между полностью определенным набором данных и не полностью определенным состоит в том, насколько далеко может пойти это сокращение.Если это не совсем так, это оставит некоторые факты, чтобы вы могли видеть, какие проекты / родители / дети все еще создают неоднозначность.
:- use_module(library(chr)).
:- chr_constraint project/3, project_parent/2, project_child/2,
project_parents/2, project_children/2, project_size/2, parent/2.
%% turn a project into a fact about its size plus
%% facts for each parent and child in this project
project(N, Parents, Children) <=>
length(Parents, Len),
project_size(N, Len),
project_parents(N, Parents),
project_children(N, Children).
%% expand the list of parents for this project into a fact per parent per project
project_parents(_, []) <=> true.
project_parents(N, [Parent|Parents]) <=>
project_parent(N, Parent),
project_parents(N, Parents).
%% same for the children
project_children(_, []) <=> true.
project_children(N, [Child|Children]) <=>
project_child(N, Child),
project_children(N, Children).
%% a single parent-child combo on a project is exactly what we need
one_parent @ project_size(Project, 1),
project_parent(Project, Parent),
project_child(Project, Child) <=>
parent(Parent, Child).
%% if I have a parent relationship for project of size N,
%% remove this parent and child from the project and decrease
%% the number of parents and children by one
parent_det @ parent(Parent, Child) \ project_size(Project, N),
project_parent(Project, Parent),
project_child(Project, Child) <=>
succ(N0, N),
project_size(Project, N0).
Я запустил это на вашем примере, набрав main/0
предикат для этого:
main :-
project(1, [jane, claire], [brian, stephen]),
project(2, [claire, jane], [emma, william]),
project(3, [jane, claire], [william, james]),
project(4, [jane, sophia, claire], [brian, james, isabella]),
project(5, [claire], [brian]),
project(6, [jane], [emma]).
Это выводит:
parent(sophia, isabella),
parent(jane, james),
parent(claire, william),
parent(jane, emma),
parent(jane, stephen),
parent(claire, brian).
Чтобы продемонстрировать неполное определение, я добавил седьмой проект:
project(7, [sally,sandy], [grace,miriam]).
Затем программавыводит это:
project_parent(7, sandy),
project_parent(7, sally),
project_child(7, miriam),
project_child(7, grace),
project_size(7, 2),
parent(sophia, isabella),
parent(jane, james),
parent(claire, william),
parent(jane, emma),
parent(jane, stephen),
parent(claire, brian).
Как видите, любой оставшийся project_size/2
говорит о количестве элементов, которые предстоит решить (в седьмом проекте еще предстоит определить два родителя / потомка), а вывернуть точно родителей / детей, которые еще предстоит обработать, а также все parent/2
отношения, которые можно определить.
Я очень доволен этим результатом, но, надеюсь, другие могут прийти и улучшить мойcode!
Edit : у моего кода есть недостаток, который был обнаружен в списке рассылки, что некоторые входные данные не будут сходиться, даже если решениеможет быть вычислено, например:
project(1,[jane,claire],[brian, stephan]),
project(2,[jane,emma],[stephan, jones]).
Для получения дополнительной информации см. Решение Иана , которое использует пересечение множества для определения отображения.