GotAI.NET

Форум: Проблемы искусственного интеллекта

 

Регистрация | Вход

 Все темы | Новая тема Стр.1 (1)   Поиск:  
 Автор Тема: Продукционная система
og http://openai.narod.ru
Сообщений: 19
Продукционная система
Добавлено: 16 янв 09 11:06
Здравствуйте уважаемые товарищи форумчане.

Представляю вашему вниманию разработанную мной продукционную систему, исполненную в виде компонента с дуальными интерфейсами. Компонента целиком написана на С++, без использования каких либо других компонент и библиотек(кроме STL и ATL естественно)

Как возникла сия компонента:
В настоящий момент пишу анализатор текста, получалось громоздко и путано. Выделил из программы продукционную систему и оформил в виде компонента.

Функциональность системы бедная. Добавляется она следующим образом: в моей программе-анализаторе возникает необходимость в дополнительной функциональности, и сразу в компоненте эта функциональность добавляется.

Система обладает хорошей скоростью. Она практически вся логарифмическая, хотя есть темные квадратные места...
К явным недостаткам можно отнести:
1)бедный функционал, например в правилах очень не хватает квантора всеобщности.
2)невозможность добавлять правила после старта системы, но это не принципиальная невозможность, её можно устранить.
К явным достоинствам можно отнести скорость, легкость использования и интеграции в свои программы, особенно на COM совместимых языках, открытость.

Пример использования программы (на си-шарпе): pr1.zip

В примере создается квадратный массив ячеек, для каждой ячейки задается левый и верхний сосед.
Массив ячеек выводится на экран в виде массива кнопок, при клике на кнопку ячесйка "активируется".
"Активированная" ячейка обозначается нулем.
В программе задаются два простых правила:
1) Если узел1 - это ячейка и сверху узел2 - это активированная тячейка, и слева тоже активированная ячейка - то активировать ячейку узел1.
2) Если соседу снизу и справа активированны - то активироватся.

Правила могут быть произвольного размера. Единственно что, если они цикличные (в примере если есть связь cell1-cell2, cell2-cell3 и cell3-cell1), то они будут выдавать лишние ребра, но это я исправлю когда мне понадобятся цикличные правила.

Жду вопросов, предложений и комментариев.
[Ответ][Цитата]
og http://openai.narod.ru
Сообщений: 19
На: Продукционная система
Добавлено: 19 янв 09 12:17
Правила представляют собой паттерны, множество "фактов" - граф.
Как только в графе появляется структура подходящяя под IF-часть паттерна правила,
в граф добавляются ребра из THEN-части паттерна правила.


Принцип работы в общем:

У PMInstance есть "база знаний" в виде трехместного орграфа, и набор правил.

"База знаний" хранится массивом ребер вида "S R O"
S - субъект
R - реляция
O - объект
S, R и O просто числа.

Правило также представляют собой наборы подобных ребер, только с тем отличием
что S или O или оба сразу могут быть неконстантными.
Правило состоит двух наборов - IF часть и THEN часть.

Например Rule1 (x1, x2 и x3 - переменные, остальные константы),
IF-часть:

X1 rel1 M
X1 rel1 N

X2 rel1 M
X2 rel1 N

X1 rel2 X3
X2 rel2 X3

X3 rel1 M

THEN-часть
X3 rel1 N

Теперь если накидать в граф такие ребра

A rel1 M
A rel1 N
B rel1 M
B rel1 N
C rel1 M
A rel2 C
B rel2 C
->

то когда вы закинете последнее ребро "B rel2 C"
сработает правило и добавит в граф ребро "C rel1 N"
вызовится событие с идентификатором сработавшего правила и набором добавленных ребер.

а вот пример программы, использующую данный компонент
(скачать бинарник и саму библиотеку можно по ссылке выше):


namespace PMClient
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
try
{
//создаем пул продукционных систем
pmPool = new PMPoolClass();

//задаем параметры пр.системы
//(строго говоря, сейчас не используется, -зарезервировано на будущее)
PMICreateParams param = new PMICreateParams();
param.name = "First";

//получаем пр.систему из пула
pmFirst = pmPool.CreatePMInstance(param);
//привязываем обработчик события
//событие возникает при срабатывании правила
pmFirst.ruleEvent += new _IPMInstanceEvents_ruleEventEventHandler(pmFirst_ruleEvent);

//создаем таблицу лейблов. Для каждой пр.системы можно создать
//произвольное количество таких таблиц.
//и для каждого узла графа пр.системы можно задать соответсвенный элемент в
//каждой такой таблице
OuterTable ot = pmFirst.CreateOuterTable("ot");

//создаем новые узлы графа и запоминаем их идентификаторы -
// строго говоря в графе хранятся только ребра и сколько бы мы
// не получили идентификаторов - на граф это не влияет
Ideas ids = new Ideas();
ids.been = pmFirst.GetNewID();
ids.cell = pmFirst.GetNewID();
ids.leftfrom = pmFirst.GetNewID();
ids.ris = pmFirst.GetNewID();
ids.setted = pmFirst.GetNewID();
ids.upfrom = pmFirst.GetNewID();

string cell1 = "cell1";
string cell2 = "cell2";
string cell3 = "cell3";

/*simple 1*/
ruleClass ruleS1 = new ruleClass(); //создаем правило

ruleS1.AndXC(cell1, ids.ris, ids.cell); //заполняем его
ruleS1.AndXC(cell1, ids.been, ids.setted);

ruleS1.AndXC(cell2, ids.ris, ids.cell);
ruleS1.AndXC(cell2, ids.been, ids.setted);

ruleS1.AndXC(cell3, ids.ris, ids.cell);

ruleS1.AndXX(cell1, ids.leftfrom, cell3);
ruleS1.AndXX(cell2, ids.upfrom, cell3);

ruleS1.ThenXC(cell3, ids.been, ids.setted);
ruleS1.EndRule(); //это обязательно

int ruleS1ID = 0;

//добавляем правило в пр.систему и запоминаем его идентификатор
//последний параметр говорит поднимать ли события при срабатывании правила
pmFirst.AddRule(ruleS1, out ruleS1ID, true);
/*simple 1*/

/*simple 2*/ //аналогично создаем и второе правило
ruleClass ruleS2 = new ruleClass();

ruleS2.AndXC(cell1, ids.ris, ids.cell);
ruleS2.AndXC(cell1, ids.been, ids.setted);

ruleS2.AndXC(cell2, ids.ris, ids.cell);
ruleS2.AndXC(cell2, ids.been, ids.setted);

ruleS2.AndXC(cell3, ids.ris, ids.cell);

ruleS2.AndXX(cell3, ids.leftfrom, cell1);
ruleS2.AndXX(cell3, ids.upfrom, cell2);

ruleS2.ThenXC(cell3, ids.been, ids.setted);
ruleS2.EndRule();

int ruleS2ID = 0;
pmFirst.AddRule(ruleS2, out ruleS2ID, true);
/*simple 2*/

pmFirst.StartInstance(); //запускам систему
//теперь мы можем накидывать ребра

matr = new Matr(20, this, ref pmFirst, ref ot, ids);
matr.Draw();

}
catch (Exception exp)
{
MessageBox.Show("Error: " + exp.Message);
}
}

void pmFirst_ruleEvent(int ruleId, int taId)
{
//ruleId у нас не используется т.к. then-часть обоих правил одинакова
// - следовательно обрабатываться они могут одинаково
//taId - зарезервирован для будущего использования
matr.ActivateCells();
}

PMPoolClass pmPool;
PMInstance pmFirst;
Matr matr;
}

public struct Ideas
{
public int cell;
public int ris;
public int setted;
public int been;
public int leftfrom;
public int upfrom;
};

public class Matr
{
public Matr(int size, Form frm, ref PMInstance pm, ref OuterTable ot, Ideas ids)
{
this.size = size;
this.ids = ids;
this.pm = pm;
this.ot = ot;
this.frm = frm;
matr = new int[size, size];
for (int i = 0; i < size; ++i)
{
for (int j = 0; j < size; ++j)
{
//метод OuterTable во-первых возвращает идентификатор нового узла графа
//во вторых ставит ему в соответствие элемент (лейбл)
//в качестве такового мы используем номер строки и столбца через запятую
matr[i, j] = ot.AddElem(i.ToString() + "," + j.ToString());
//вот здесь мы наполняем пр.систему ребрами
pm.PutLink(matr[i, j], ids.ris, ids.cell, true);
if (j > 0) pm.PutLink(matr[i, j - 1], ids.upfrom, matr[i, j], true);
if (i > 0) pm.PutLink(matr[i - 1, j], ids.leftfrom, matr[i, j], true);
}
}
}

public void Draw()
{
for (int i = 0; i < size; ++i)
{
for (int j = 0; j < size; ++j)
{
Button cb = new Button();
cb.Text = "";
cb.Width = 20;
cb.Height = 30;
cb.Left = 25 * i + 20;
cb.Top = 35 * j + 50;
cb.Click += new EventHandler(cb_Click);
cb.Tag = (i * size + j).ToString();
frm.Controls.Add(cb);
}
}
}

//метод запускается при срабатывании правила
public void ActivateCells()
{
Array sub, rel, ob, positive;
//получаем массив всех полученных при срабатывании правила ребер
pm.GetActuatedTriplets(out sub, out rel, out ob, out positive);
for (int tr = 0; tr < sub.Length; ++tr)
{
string tmp;

//получаем из таблицы лейбл, соответвующий для этого узла
//узнаем из него номер строки и столбца
if (!ot.GetElemString(((int[])sub)[tr], out tmp)) continue;

string[] tmp2 = tmp.Split('','');
if (tmp2.Length != 2) continue;

int y = Convert.ToInt32(tmp2[0]);
int x = Convert.ToInt32(tmp2[1]);

frm.Controls[y * size + x].Text = "0";
}
}

void cb_Click(object sender, EventArgs e)
{
Button me = (Button)sender;
me.Text = "0";
int index1 = (int)(Convert.ToInt32((string)me.Tag) / size);
int index2 = (Convert.ToInt32((string)me.Tag) - size * index1);

//при клике на кнопку добавляем в систему ребро
pm.PutLink(matr[index1, index2], ids.been, ids.setted, true);
}

public int size;
int[,] matr;
PMInstance pm;
OuterTable ot;
Form frm;
Ideas ids;
}
}
[Ответ][Цитата]
MadGod
Сообщений: 413
На: Продукционная система
Добавлено: 19 янв 09 13:07
Это здорово.


[Ответ][Цитата]
 Стр.1 (1)