Данная статья описывает nuget-package AabSemantics, который можно загрузить с NuGet.org (например, с помощью команды dotnet add package AabSemantics --version 1.1.0
или любым другим удобным способом).
Исходный код пакета (там можно найти дополнительные модули, примеры кода и юнит-тесты): https://github.com/CourageAndrey/AabSemantics
Документация: https://github.com/CourageAndrey/AabSemantics/wiki
0. Что это вообще такое и зачем
Семантическая сеть - это граф, в узлах которого находятся понятия (concepts), а рёбрами служат утверждения об отношениях между ними (statements). То есть, это граф хорошо структурированных знаний, подходящий для использования в экспертных системах. Зачем ещё может понадобиться:
системы принятия решений
моделирование знаний
построение игрового ИИ
чат-боты
образовательные проекты
изучение графовых моделей знаний
1. Как начать с этим работать
Итак, нам потребуются понятия и связывающие их утверждения. Кроме того, чтобы всё завелось, понадобится ещё немного вступительной магии:
ILanguage language = Language.Default; // язык: по умолчанию английский, но есть и русский
var modules = new IExtensionModule[] // модули расширения, хоть и не обязательно
{
new BooleanModule(),
new ClassificationModule(),
// new SetModule(),
// new MathematicsModule(),
// new ProcessesModule(),
};
foreach (var module in modules)
{
module.RegisterMetadata();
}
ISemanticNetwork semanticNetwork = new SemanticNetwork(language) // сама семантическая сеть
.WithModules(modules);
// понятия
IConcept animal = "Kingdom: Animalia".CreateConceptById("Animal");
IConcept chordate = "Phylum: Chordata".CreateConceptById("Chordate");
IConcept mammal = "Class: Mammalia".CreateConceptById("Mammal");
IConcept carnivor = "Order: Carnivora".CreateConceptById("Carnivor");
// Just skip Ursidae, Ursinae and Ursini for short.
IConcept bear = "Genus: Ursus".CreateConceptById("Bear");
semanticNetwork.Concepts.Add(animal);
semanticNetwork.Concepts.Add(chordate);
semanticNetwork.Concepts.Add(mammal);
semanticNetwork.Concepts.Add(carnivor);
semanticNetwork.Concepts.Add(bear);
// утверждения
semanticNetwork.DeclareThat(chordate).IsDescendantOf(animal);
semanticNetwork.DeclareThat(mammal).IsDescendantOf(chordate);
semanticNetwork.DeclareThat(carnivor).IsDescendantOf(mammal);
semanticNetwork.DeclareThat(bear).IsDescendantOf(carnivor);
И уже у данной семантической сети можно спрашивать, что она знает:
IAnswer answer = semanticNetwork.Ask().IfIs(bear, animal);
Приведённый ответ можно преобразовать в текстовый вид с помощью какого-либо из TextRender-ов и Describe-расширений. Например, ответ выше будет выглядеть вот так (все предложения ниже генерируются автоматически):
Yes, "Bear" is "Animal".
Explanation:
"Chordate" is "Animal". ("Classification")
"Mammal" is "Chordate". ("Classification")
"Carnivor" is "Mammal". ("Classification")
"Bear" is "Carnivor". ("Classification")
Как можно видеть выше, нигде напрямую не утверждалось, что медведь является животным - но благодаря цепочке утверждений и набору заданных для отношения "Является" правил семантическая сеть сама делает об этом вывод.
Пример выше - это сокращённый первый тестовый пример работы с AabSemantics.
Сила этого пакета - в его расширяемости. Пока классы понятий соответствуют контракту интерфейса IConcept, а классы утверждений - IStatement, движок будет с ними работать, как с родными.
2. Вопросы
Вопросы - это способ получить структурированный ответ из знаний, хранящшихся в базе знаний. Абсолютное большинство вопросов (IQuestion) просто оборачивают класс-строитель StatementQuestionProcessor. Например, отношения классификации (работа с которыми показана выше) делают это так:
public override IAnswer Process(IQuestionProcessingContext context)
{
return context
.From<IsQuestion, IsStatement>() // 1. начинаем обработку для определённого типа вопроса и утверждения
.WithTransitives( // 2. включаем обработку транзитивных утверждений
statements => statements.Count == 0, // ... если без этого ничего не было найдено
question => question.Child, // ... используя дочернее понятие вопроса как новый субъект вопрошания
newSubject => new IsQuestion(newSubject, Parent)) // ... и задавая новый вопрос с другим субъектом
.Where(s => s.Parent == Parent && s.Child == Child) // 3. проверяем, нет ли в выборке утверждения с искомыми параметрами
.SelectBooleanIncludingChildren( // 4. формируем ответ типа да/нет из всего найденного
statements => statements.Count > 0, // ... да при таких условиях
language => language.GetQuestionsExtension<ILanguageClassificationModule, Localization.ILanguageQuestions>().Answers.IsTrue, // ... формат положительного ответа
language => language.GetQuestionsExtension<ILanguageClassificationModule, Localization.ILanguageQuestions>().Answers.IsFalse, // ... формат отрицательного ответа
new Dictionary<String, IKnowledge> // ... параметры для ответа
{
{ Strings.ParamParent, Parent },
{ Strings.ParamChild, Child },
});
}
Хотя встречаются и гораздо более сложные экземпляры (например, в дополнительных модулях Mathematics и Processes).
3. Что ещё
Всякие специальные понятия, типы отношений и вопросы к ним сгруппированы в модули расширений (extension module). В NuGet-пакет входят только два из них - Boolean и Classification. В репозитории можно найти ещё Mathematics, Processes и Set. Создавая собственные расширения, группировать их по модулям необязательно - но если это сделать, можно будет воспользоваться всеми плюшками базового десктопного приложения (WPF-клиент) для редактирования утверждений и задавания вопросов.
Понятия можно маркировать атрибутами.
Утверждения лучше реализовывать в виде новых классов, реализующих интерфейс IStatement или расширяющих его базовую реализацию Statement<StatementT>. Для ленивых есть CustomStatement, в котором есть только строка типа и словарь строковых пар ключ-значение для перечисления заданных свойств.
Реализовывать можно не только свои виды утверждений, но также понятий, атрибутов, и вопросов. Но главное всё же утверждения и вопросы, они крепко взаимосвязаны.
Есть структуры для изоморфного поиска сруктур из связанных знаний - это класс IsomorphicSearchPattern и его производные.
На этом же механизме работают мутации и продукции - способы (полу)автоматической модификации графа знаний в зависимости от того, что в нём сейчас находится.
До тех пор, пока пользовательские классы понятий, утверждений и вопросов корректно реализуют контракты соответствующих интерфейсов, они будут так же корректно обрабатываться движком.
Когда задаётся вопрос к семантической сети, для него создаётся отдельный контекст, позволяющий задавать дочерние вопросы и генерировать промежуточные результаты с сохранением базе знаний.
По умолчанию используется семантическая сеть, целиком расположенная в оперативной памяти, с возможностью сериализации в XML- или JSON-файл. Однако, в репозитории есть и другие примеры работы - с базой данных или через REST. Собственно, реализация новых механизмов сериалилизации / хранения / маппинга знаний - наверное, самое востребованный тип доработки.
Надеюсь, эта библиотека окажется для кого-нибудь полезной. Автор открыт для вопросов и предложений - здесь на хабре или на GitHub-странице проекта.
Kotrecon
Хорошая штука, на первый взгляд, а русскоязычная документация есть или только на английском?
courage_andrey Автор
Документация только на английском. Пакет локализации самой библиотеки для русского есть.
https://github.com/CourageAndrey/AabSemantics/blob/master/Code/Clients/AabSemantics.SimpleWpfClient/Localization/Русский.xml