--PAGE_BREAK--
Будем рассматривать как множество объектов, отображенных из функцией . Эти объекты называются значениями переменной , а множество – областью [1].
– конечное (возможно пустое) множество ограничений на произвольном подмножестве переменных из .
Решением численной ЗУО называется множество значений переменных , такое что и все ограничения из удовлетворяются.
2 МЕТОДЫ РАСПРОСТРАНЕНИЯ ОГРАНИЧЕНИЙ
2.1 Алгоритм Indigo
Входными данными для алгоритма Indigoявляется множество ограничений, включая равенства и неравенства, и набор переменных. Алгоритм определяет оптимальный интервал для всей системы.
Выполнение алгоритма происходит от самого сильного ограничения к самому слабому, в ходе которого мы пытаемся удовлетворить каждое ограничение путем сжимания границ переменных, входящих в него. Сжимание границ одних переменных ограничения может стать причиной сжимания границ других переменных. Для реализации этого алгоритм содержит очередь ограничений, которые необходимо проверить. Изначально очередь содержит только исходные ограничения . Если мы можем сжать границы любой переменной ограничения , мы добавляем в очередь другие ограничения, содержащие эту переменную. Продолжаем обрабатывать ограничения из очереди до тех пор, пока она не станет пустой. После того, как все ограничения были обработаны, мы получаем значения всех переменных [3].
Псевдокод алгоритм выглядит следующим образом:
all constraints := list of all constraints, strongest first;
all variables := set of all variables;
active_constraints := new set;
for v in all variables do
initialize v.bounds to unbounded;
end for;
for current constraint in all constraints do
tight_variables := new set;
queue := new queue;
queue.add(current_constraint);
while queue not empty do
cn := queue.front;
tighten_bounds(cn, queue, tight_variables,
active_constraints);
check_constraint(cn, active_constraints);
queue.dequeue;
end while;
end for;
Переменная active_constraints содержит множество ограничений, которые уже были рассмотрены, но которые могут быть рассмотрены опять, если мы сожмем границы одной из переменной ограничений. Во время обработки каждого ограничения очередь (queue) содержит множество ограничений, границы чьих переменных может потребоваться сжать, и tight_variables – это множество переменных, чьи границы были сжаты во время обработки текущего ограничения. Во время обработки текущего ограничения мы никогда не сжимаем границы одной переменной дважды.
Процедура tighten_bounds сжимает границы переменных ограничения , и добавляет в очередь другие затронутые ограничения. Процедура check
_
constraintпроверяет на неудовлетворенность требуемые ограничения и также определяет, когда ограничения должны быть добавлены или удалены из множества active
_
constraints.
Procedure tighten_bounds(cn, queue, tight variables, active constraints)
for v in cn.variables and v not in tight_variables do
tighten_flag := cn.tighten_bounds_for(v);
tight_variables.add(v);
if tighten_flag then
for c in v.constraints do
if c in active_constraints and c not in queue then
queue.add(c);
end if;
end for;
end if;
end for;
endproceduretighten_bounds;
В процедуре tighten
_
boundsпроцедура tighten
_
bounds
_
forсжимает границы переданной переменной, на сколько это возможно, и возвращает истину, если границы изменились.
Procedure check_constraint(cn, active constraints)
If cn is unary then
If cn is required and cn is not satisfiable then
exception(required_constraint_not_satisfied);
end if;
return;
end if;
if not all of c’s variables have unique values then
active_constraints.add(cn);
return;
end if;
if cn is satisfied then
active_constraints.delete(cn);
else if cn is required then
exception(required_constraint_not_satisfied);
else exception(constraints_too_difficult);
end if;
end procedure check_constraint;
В процедуре check
_
constraintмы в первую очередь смотрим, унарное ли ограничение . Унарным является то ограничение, которое содержат только одну переменную. Унарное ограничение должно быть обработано только один раз, т.к. нет больше причин рассматривать его, потому что его влияние полностью представлено в текущих границах переменной, которую оно содержит. Иначе ограничение является -арным. Если не все переменные имеют уникальные значения, то нам необходимо добавить в active
_
constraints, т.к. нам будет необходимо рассмотреть опять, когда границы одной из его переменных будут сжаты. Однако, если все переменные имеют уникальные значения, больше никогда не нужно будет рассматривать, и ограничение нужно удалить из active
_
constraints, если оно там находится.
Рассмотрим применение алгоритма Indigo на следующем примере. Пусть нам дана система уравнений
(2.1)
В данной системе первых четыре уравнения являются самыми сильными, т.е. они будут удовлетворятся в первую очередь. Пятое уравнение – строгое, шестое – среднее, а последних четыре являются слабыми.
Ограничения начинают обрабатываться от самого сильного к слабому. Так после обработки неравенства мы сжимаем границы до . Затем обрабатываем следующее сильное ограничение , сжимая границы к . Оба из этих ограничений одноместны, так что они не добавляются к активным ограничениям. Затем, мы обрабатываем , сжимая границы до . С этого момента переменные этого ограничения имеют уникальную ценность, поэтому мы записываем это ограничение в активные ограничения. Последнее требуемое ограничение– . Мы обрабатываем его и сжимаем границы до , и также добавляем его в активные ограничения.
Теперь переходим к строгому ограничению . Благодаря этому неравенству границы сжимаются до . Сжатие границ приводит к тому, что нам необходимо пересмотреть через неравенство , которое находится в активных ограничениях, т.е. новые границы будут . А так как границы изменились, пересматриваем еще одно активное ограничение , получаем, что границы равны , а границы равны .
Затем мы обрабатываем среднее ограничение . С этих пор границы переменной устанавливаем и сжимаем границы до , до , и до .
Наконец мы обрабатываем самое слабое ограничение . Оно не имеет ни какого значения, в то время как сжимает границы до . Возвращаясь к активным ограничениям, получаем и границы и соответственно. Остающиеся слабые ограничения не имеет никакого значения. Таким образом, мы нашли решение , , , .
2.2 Реализация на ЭВМ алгоритма Indigo
На основе материала данной курсовой работы была разработана программа «Метод Индиго» на языке программирования Delphi, реализующая применение алгоритма Indigo для решения системы ограничений (2.1).
После запуска программы перед пользователем появляется диалоговое окно, наглядный вид которого представлен на рис.2.1.
Рисунок 2.1 – Диалоговое окно метода Indigo
Основная часть данного окна разделена на две составляющие:
– текстовое поле «Условие», предназначенное для ввода исходной системы ограничений;
– текстовое поле «Шаги решения», отображающее этапы решения алгоритма.
При вводе ограничений в текстовое поле «Условие» пользователю необходимо указать статус каждого уравнения: сильное – r, строгое – s, среднее – mили слабое – w(рис. 2.2)
Рисунок 2.2 – Исходные данные
В нижней части диалогового окна расположена кнопка «Решить». При нажатии на данную кнопку в правой части диалогового окна появляются пошаговые изменения переменных системы (рис 2.3), благодаря этому можно проследить на каком этапе и границы какой переменной были сжаты, а также можно увидеть решение системы в диалоговом окне «Решение» (рис. 2.4).
Рисунок 2.3 – Этапы решения
Рисунок 2.4 – Результат реализации алгоритма
Текс программной реализации алгоритма находится в приложении А.
2.3 АлгоритмIncremental Hierarchical Constraint Solver (IHCS)
Incremental Hierarchical Constraint Solver (IHCS) –алгоритмпошаговогоиерархическогорешениясистемыограничений. В алгоритме IHCS, как и в Indigo, система ограничений может содержать как равенства, так и неравенства. Алгоритм базируется на идее преобразования начальной конфигурации , соответствующей иерархии ограничений, в конфигурацию решения. При этом алгоритм обрабатывает ограничения от сильного к слабому. Конфигурация иерархии представляет собой тройку , таких, что их объединение равно , где – хранилище активных ограничений, т.е. тех, которые уже были обработаны и удовлетворены; – хранилище смягченных ограничений, т.е. обработанных, но неудовлетворенных неравенств; – хранилище неисследованных уравнений, которые в дальнейшем будут обработаны.
Псевдокод данного алгоритма выглядит следующим образом:
procedure IHCS(H: constraint hierarchy)
AS•RS•US
while US not empty do
apply forward rule to AS•RS•US, i.e., move c from US to AS
if conflict in AS then
apply backward rule to AS•RS•US;
endif
endwhile
endIHCS
Алгоритм начинается с конфигурации . Затем, поочередно от сильного ограничения к слабому, неравенства перемещают из хранилища неисследованных (изначально ) в хранилище активных (изначально пустого). IHCSразделен на 2 фазы: прямой ход, в ходе которого используется «прямое правило», и обратный ход, соответствующий «обратному правилу», которое вызывается для разрешения любых конфликтов, возникающих во время прямого хода.
Прямой алгоритм – это адаптация алгоритма совместимости по дугам (arc consistency), основанного на распространении ограничений, обобщенного на случай ограничений с произвольным числом переменных. ПрямойходреализуетсяспомощьюфункцииForward.
Function Forward()
while US = cjUS’ do
US¬US’
AS ¬ASÈ{cj}
AO ¬AO+1
AOcj¬AO
Enqueue(cj,Q) ‘Q initially epty
while Dequeue(Q,ck) do
if not Revise(ck,Tcj,Q) then
if not Backward(ck) then return false
returntrue
Счетчик всякий раз увеличивается на единицу, когда новое ограничение попадает в хранилище активных ограничений, чтобы обновить порядок активации этого ограничения.
Функция Revise осуществляет удаление несовместимых ограничений из области переменных и обновляет информацию о зависимости между ограничениями. Все эти преобразования запоминаются в стеке , а активные ограничения, содержащие затронутые ограничения, ставятся в очередь (очередь распространения). Если там нет значений, удовлетворяющих продолжение
--PAGE_BREAK--, тогда Revise возвращает false, иначе true.
Во время работы обратного алгоритма должны выполняться следующие условия:
1. Только ограничения, имеющие отношение к конфликту могут изменить статус (смягчены или деактивированы) для того, чтобы избежать бесполезного поиска.
2. Повторно должна быть достигнута потенциально лучшая конфигурация, чтобы добиться значимого результата.
3. Никакая перспективная конфигурация не должна использоваться повторно, чтобы избежать циклов.
4. Для полноты алгоритма никакая перспективная конфигурация не должна быть пропущена.
5. Должна быть достигнута глобальная совместимость нового хранилища активных ограничений, повторно выполняя при этом как можно меньше работы.
Обратное правило является правилом, которое перемещает ограничения в хранилище неисследованных ограничений. Если текущий конфликт возник не первым, то во время решения предыдущего конфликта обратное правило генерирует перспективную конфигурацию с неисследованными ограничениями.
Ограничения, смягченные в предыдущих конфликтах, следует пересмотреть на предмет реактивации, если некоторые ограничения, вовлеченные в те конфликты, сейчас смягчены. Это даст шанс, что новое смягчение также разрешит эти ранние конфликты, следовательно, позволяет ранее смягченным ограничениям стать активными. За осуществление обратного правила отвечает функция Backward.
И наконец, алгоритм IHCSостанавливается, как только конфигурация становится .
Рассмотрим следующий пример:
при этом начальные значения и равны .
В данной системе ограничений первых два неравенства являются строгими, а вторые два – слабыми. На первом шаге первое сильное ограничение помещается в хранилище . Затем оно попадает в , где проверяются значения параметров и . , тогда по правилу разности интервалов получим , далее находим пересечение . Таким образом, получили новые границы : . Аналогично для получаем .
На втором шаге из в попадает второе ограничение . Попробуем удовлетворить его. По правилу умножения и разности интервалов: . Как видно это неравенство не удовлетворяется, поэтому оно перемещается в хранилище .
Учитывая третье ограничение , мы пересчитываем границы и , откуда получаем и соответственно. Рассматривая последнее ограничение, можно сделать вывод, что это ограничение у нас, также как и второе, не удовлетворяется.
ЗАКЛЮЧЕНИЕ
В данной курсовой работе были рассмотрены основные понятия интервальной арифметики и задачи распространения ограничений.
Задачи распространения ограничений над непрерывными областями обычно называются численными задачами удовлетворения ограничений. Задачи этого класса могут быть использованы для представления большого количества описывающих физические или химические явления моделей, в частности моделей с неточными данными или частично определенными параметрами.
Для решения задач распространения ограничений существует различное множество алгоритмов. В курсовой работе были рассмотрены два из них: алгоритм распространения ограничений Indigo и IHCS (IncrementalHierarchicalConstraintSolver). Алгоритм Indigo заключается в том, что при обработке ограничений от самого сильного к самому слабому мы пытаемся удовлетворить каждое ограничение путем сжимания границ переменных, входящих в него, при этом сжимание границ одних переменных ограничения может стать причиной сжиманияграниц других переменных. Для выполнения этих действий в алгоритме используется очередь ограничений, которые необходимо проверить. Изначально очередь содержит только исходные ограничения . Если мы можем сжать границы любой переменной ограничения , мы добавляем в очередь другие ограничения, содержащие эту переменную. Алгоритм останавливается, когда очередь становится пустой.
Алгоритм IHCSбазируется на идее преобразования начальной конфигурации , соответствующей иерархии ограничений, в конфигурацию решения. Конфигурация иерархии представляет собой тройку , таких, что их объединение равно . Алгоритм начинается с конфигурации
. Затем, поочередно от сильного ограничения к слабому, неравенства перемещают из хранилища неисследованных (изначально ) в хранилище активных (изначально пустого). IHCSостанавливается, как только конфигурация становится .
Рассматривая эти два алгоритма можно сказать, что Indigo достаточно легок в понимании и прост в реализации, по сравнению с IHCS. В данной курсовой работе был реализован алгоритм Indigo на языке программирования Delphi (см. Приложение А). В дальнейшем планируется реализовать IHCS и сравнить результаты, получаемые с помощью двух алгоритмов.
СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ
1. Семенов, А.Л. Методы распространения ограничений: основные концепции / А.Л. Семенов // Международное совещание по интервальной математике и методам распространения ограничений: труды совещания. – Новосибирск. – 2003. – С. 6–20.
2. Лоенко, М. Решение систем нелинейных уравнений методами интервального распространения ограничений / М. Лоенко // Новосибирский филиал Российского научно-исследовательского института искусственного интеллекта. – Россия. – Том 7. – №2. – 2002.– С.84–93.
3. Borning, A. The Indigo Algorithm / A. Borning, R. Anderson, B. Freeman-Benson // TR 96-05-01, Department of Computer Science and Engineering, University of Washington. – 1996.
4. Menezes, F. Incremental Hierarchical Constraint Solver (IHCS) / F. Menezes, P. Barahoma, P. Codognet // An Incremental Hierarchical Constraint Solver, in: Proceedings of PPCP93, – Newport, 1993. – pp. 190-199.
5. Barták, R. Constraint Guide – Constraint Hierarchy Solvers/ R. Barták// Guide to Constraint Programming [Электронныйресурс]. – 1998. – Режимдоступа : kti.mff.cuni.cz/~bartak/constraints/ch_solvers.html. – Датадоступа: 25.04.2010.
ПРОЛОЖЕНИЕА
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, UMathParser, MyFunctions;
type
TForm1 = class(TForm)
Button1: TButton;
GroupBox1: TGroupBox;
ListBox1: TListBox;
GroupBox3: TGroupBox;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private { Private declarations }
public { Public declarations }
end;
TConstraint = class
constructor Create(Constraint: string);
destructor Free;
function TightenBoundsForEqual(V: string): boolean;
function TightenBoundsForNoEqual(V: string): boolean;
function TightenBoundsForWeakEqual(V: string): boolean;
function TightenBoundsFor(V: string): boolean;
function IsElemInVars(Elem: string): boolean;
public
Prior: char; // приоритет ограничения
CType: char; // тип ограничения = 'l' 'e' 'm'
Variables: TSArray; // переменные
VarCount: integer; // число переменных
LPart, RPart: TMathParser;
end;
TVariable = class
VarName: string;
LBound, RBound: extended; // границы интервала
constructor Create(pName: string; pLBound, pRBound: extended);
destructor Free;
procedure SetBounds(pLBound,pRBound: extended);
end;
TConstraintList = record
Count: integer;
List: array of TConstraint;
end;
TVariableList = record
Count: integer;
List: array of TVariable;
end;
const
LInfinity = -1e50; // минус бесконечность
RInfinity = 1e50; // плюс бесконечность
var Form1: TForm1;
implementation
uses CQueue, CSet, Math, VSet, Unit2;
{$R *.dfm}
var ConstraintList: TConstraintList; // список ограничений
VariableList: TVariableList; // список переменных
constructor TConstraint.Create(Constraint: string);
var SLPart, SRPart: string;
SVar: string;
begin
GetLeftAndRightParts(Constraint,SLPart,SRPart,Prior,CType);
GetVarList(Constraint,Variables,VarCount,SVar);
LPart:=TMathParser.create;
RPart:=TMathParser.create;
LPart.Translate(SLPart,SVar);
RPart.Translate(SRPart,SVar);
end;
destructor TConstraint.Free;
begin
VarCount:=0;
Variables:=nil;
LPart.Free;
RPart.Free;
end;
// возвращает указатель на переменную с именем Name
Function GetPVariable(Name: string): TVariable;
var i: integer;
begin
i:=0;
while VariableList.List[i].VarName Name do
inc(i);
Result:=VariableList.List[i];
end;
Function Svertka(var OldL, OldR: extended; NewL, NewR: extended): boolean;
var tempL, tempR: extended;
begin
tempL:=OldL;
tempR:=OldR;
if NewL
begin
if NewR
OldR:=OldL
else
if OldR
OldL:=OldR // свертка
else
begin
OldL:=max(OldL,NewL);
OldR:=min(OldR,NewR);
end;
end;
if (tempL OldL) or (tempR OldR) then
Result:=true
else
Result:=false;
end;
// СЖАТИЕ ПЕРЕМЕННЫХ ДЛЯ РАВЕНСТВА
Function TConstraint.TightenBoundsForEqual(V: string): boolean;
type ArrayOfE = array of extended;
var Number: integer; // номер переменной v в списке переменных
i: integer;
NumberArray: ArrayOfE;
IndexMassiv: ArrayOfE;
Svob: extended; // свободный член
PVar,tempP: TVariable;
tempLBound, tempRBound, Coef: extended;
Function FillArray(Place: integer; Chislo: integer): ArrayOfE;
var i: integer;
begin
for i:=0 to VarCount-1 do
NumberArray[i]:=0;
NumberArray[Place]:=Chislo;
Result:=NumberArray;
end;
begin
Number:=0;
while Variables[Number] V do
inc(Number);
SetLength(NumberArray,VarCount);
SetLength(IndexMassiv,VarCount); // получаем коэффициенты
for i:=0 to VarCount-1 do
IndexMassiv[i]:=LPart.Get(FillArray(i,1)) — LPart.Get(FillArray(i,0)) —
RPart.Get(FillArray(i,1)) + RPart.Get(FillArray(i,0));
Svob:=LPart.Get(FillArray(0,0)) — RPart.Get(FillArray(0,0));
if IndexMassiv[Number]
begin
for i:=0 to VarCount-1 do
IndexMassiv[i]:=-IndexMassiv[i];
Svob:=-Svob;
end;
Coef:=IndexMassiv[Number];
PVar:=GetPVariable(V);
tempLBound:=-Svob/Coef;
tempRBound:=-Svob/Coef;
for i:=0 to VarCount-1 do
if i Number then
begin
tempP:=GetPVariable(Variables[i]);
if IndexMassiv[i] > 0 then
begin
tempLBound:=tempLBound — IndexMassiv[i]*tempP.RBound/coef;
tempRBound:=tempRBound — IndexMassiv[i]*tempP.LBound/coef;
end
else
begin
tempLBound:=tempLBound — IndexMassiv[i]*tempP.LBound/coef;
tempRBound:=tempRBound — IndexMassiv[i]*tempP.RBound/coef;
end;
end;
Result:=Svertka(PVar.LBound,PVar.RBound,tempLBound,tempRBound);
end;
// СЖАТИЕ ПЕРЕМЕННЫХ ДЛЯ НЕРАВЕНСТВА
Function TConstraint.TightenBoundsForNoEqual(V: string): boolean;
var PVar: TVariable;
begin
PVar:=GetPVariable(V);
if CType = 'l' then
PVar.RBound:=RPart.Get([1])
else
PVar.LBound:=RPart.Get([1]);
Result:=True;
end;
// СЖАТИЕ ПЕРЕМЕННЫХ ДЛЯ СЛАБЫХ РАВЕНСТВ
Function TConstraint.TightenBoundsForWeakEqual(V: string): boolean;
var PVar: TVariable;
begin
PVar:=GetPVariable(V);
Result:=Svertka(PVar.LBound,PVar.RBound,RPart.Get([1]),
RPart.Get([1]));
end;
// СЖАТИЕ ПЕРЕМЕННЫХ
Function TConstraint.TightenBoundsFor(V: string): boolean;
var t: TVariable;
Procedure ShowSteps;
var NewString: string; продолжение
--PAGE_BREAK--