Правила представляют собой паттерны, множество "фактов" - граф.
Как только в графе появляется структура подходящяя под 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;
}
}