Цього року в мене є курсова з дисципліни “Штучний інтелект”. Нічого особливо складного, окрім того, що навчитися користуватися бібіотекою SWI-Prolog, в моєму випадку вона не представляла, тому розробка ПЗ загалом зайняла два дні.
Оскільки серце програми написано на Prolog, а від нас вимагають прикрутити його до якогось нормального інтерфейсу (щоб не викликати команди з консолі), потрібно було розібратись з використанням бібліотеки SWI-Prolog у Qt, котрий я обрав для створення інтерфейсу. А обрав я його, бо був з ним знайомий і він написаний на С++, а на С++ якраз і є написаний інтерфейс для бібліотеки. Далі опишу процес, бо знайти потрібну інформацію в інтернеті було непросто, тому нехай десь буде ще одна копія.
На всяк випадок — я користувався реалізацією прологу SWI-Prolog, писав усе під віндовс і папка, куди встановлено пролог називається pl.
1. Найперше, що ми маємо знайти це заголовочні файли, dll-ка пролога (swipl.dll) та ще одна dll-ка, яку використовує пролог – pthreadVC.dll. Заголовочні файли знаходяться тут: pl/include, dll-ки тут – pl/bin.
2. Як підключати dll в Qt всім, мабуть, відомо. Просто прописуєте у pro-файлі проекту таку штуку:
LIBS += "G:\Documents\workspace\ai\ai-diff-build-desktop\debug\swipl.dll"
Дивіться, щоб dll були у папці з debug-версією вашої програми, бо коли ви запустите її, вона почне шукати їх там само, де лежить її ехе. А за замовчуванням він буде лежати у папці <назва проекту>-build-desktop/debug.
Детальніше про підключення сторонніх бібліотек до Qt тут.
3. Заголовочні файли мабуть можна і не копіювати в папку проекту — в принципі нічого не зміниться, якщо ви вкажете, де їх шукати, в pro-файлі такою строкою
INCLUDEPATH += "pl-include"
Я їх скопіював, тому вказав відносний шлях.
В нашій програмі ми підключимо лише два: SWI-Prolog.h та SWI-cpp.h. В першому знаходиться С-інтерфейс, в другому С++-інтерфейс. З першого використовуються ф-її ініціалізації. З другого все інше, бо з об’єктами працювати простіше.
4. Ініціалізація прологу виконується таким кодом:
#define PROLOG_PROGRAM "G:/Documents/My Dropbox/Personal/Univ/ai/diff.pl"
static char * av[] = {PROLOG_PROGRAM};
if(!PL_initialise(1,av))
{
PL_halt(1);
return;
}
В PROLOG_PROGRAM зберігається шлях до програми на пролозі, що буде завантажена відразу після ініціалізації. Власне, в ній знаходиться вся логіка. Ще може виникнути така помилка: “FATAL ERROR: Could not find system resources”. Вирішується просто – http://www.swi-prolog.org/FAQ/FindResources.html
5. Виклик наших предикатів робиться таким чином:
PlTermv terms(3);
terms[0] = PlCompound(function.toStdString().c_str());
terms[1] = PlCompound(variable.toStdString().c_str());
PlQuery q("d", terms);
Про те, що таке клас PlCompound, можна прочитати тут, а про інші класи для створення термів тут. Взагалі у пролога гарна документація, правда мені в ній мало що зрозуміло, і прикладів використання майже нема.
Моя курсова вміє рахувати похідні складних функцій, тому параметри мого предиката (d) такі:
1. функція, похідну якої треба знайти
2. аргумент, по якому шукається
3. відповідь
Відповідь знаходитиметься в terms[2] і виводиться через приведення до char*.
ui->derivEdit->setText(QString(terms[2]));
Ну а перед тим, як звертатись за відповіддю варто перевірити, чи знайшлись взагалі якісь рішення. Це робиться через метод next_solution(). Через нього ж можна перевірити всі рішення.
if(q.next_solution())
ui->derivEdit->setText(QString(terms[2]));
else
ui->derivEdit->setText("no solution");
5. Обробка помилок у пролозі нескладна. Якщо щось трапилось, вам кинеться PlException. Після приведення його до char* зможете побачити текст помилки. Так це зроблено у мене:
try
{
PlTermv terms(3);
terms[0] = PlCompound(function.toStdString().c_str());
terms[1] = PlCompound(variable.toStdString().c_str());
PlQuery q("d", terms);
if(q.next_solution())
ui->derivEdit->setText(QString(terms[2]));
else
ui->derivEdit->setText("no solution");
}
catch(PlException &ex)
{
QMessageBox::warning(this,
"Prolog Exception",
QString("Prolog has thrown an exception: ")+QString((char*) ex));
}
6. На останок кілька посилань, з яких я черпав інформацію.
http://www.swi-prolog.org/pldoc/doc_for?object=section(1,’9′,swi(‘/doc/Manual/foreign.html’)) - документація по використанню пролога в інших мовах програмування.
http://www.swi-prolog.org/FAQ/ - faq по прологу, мені знадобився.
http://www.swi-prolog.org/pldoc/package/pl2cpp.html - документація по С++ інтерфейсу, описання класів та іншого.
http://electricbacon.wordpress.com/2010/09/08/calc-example-using-swi-prolog-and-c/ - звідси я взяв ініціалізацію пролога, гарний приклад програми на С++.
http://stackoverflow.com/questions/2690296/class-problem-c-and-prolog - ще один приклад роботи з прологом на С++
Це все. Сподіваюсь, комусь допоможе.