| Index: nacl/deltablue.c
|
| diff --git a/nacl/deltablue.c b/nacl/deltablue.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..2821f2914b3254d5090e220d543e3dddcd13d9e5
|
| --- /dev/null
|
| +++ b/nacl/deltablue.c
|
| @@ -0,0 +1,1116 @@
|
| +/* This is an implementation of the DeltaBlue incremental dataflow
|
| + constraint solver written in portable C.
|
| +
|
| + The original version was by John Maloney.
|
| + This version was modified for portability and benchmarking
|
| + by Mario Wolczko, Sun Microsystems Labs, 2 Oct 96.
|
| + */
|
| +
|
| +#include <stdio.h>
|
| +#include <stdlib.h>
|
| +#include <string.h>
|
| +#include <time.h>
|
| +
|
| +typedef enum {false, true} Boolean;
|
| +typedef void (*Proc)();
|
| +typedef void * Element;
|
| +
|
| +/*
|
| + List: Supports variable sized, ordered lists of elements. */
|
| +
|
| +typedef struct {
|
| + Element *slots; /* variable-sized array of element slots */
|
| + int slotCount; /* number of slots currently allocated */
|
| + int first; /* index of first element */
|
| + int last; /* index of last element (first-1, if empty) */
|
| +} *List, ListStruct;
|
| +
|
| +/*
|
| + Constraint, variable, and strength data definitions for DeltaBlue.
|
| + */
|
| +
|
| +/* Strength Constants */
|
| +typedef enum {
|
| + S_required= 0,
|
| + S_strongPreferred= 1,
|
| + S_preferred= 2,
|
| + S_strongDefault= 3,
|
| + S_default= 4,
|
| + S_weakDefault= 5,
|
| + S_weakest= 6
|
| +} Strength;
|
| +
|
| +struct constraint;
|
| +
|
| +typedef struct {
|
| + long value;
|
| + List constraints;
|
| + struct constraint* determinedBy;
|
| + long mark;
|
| + Strength walkStrength;
|
| + Boolean stay;
|
| + char name[10];
|
| +} *Variable, VariableStruct;
|
| +
|
| +typedef struct constraint {
|
| + Proc execute;
|
| + Boolean inputFlag;
|
| + Strength strength;
|
| + char whichMethod;
|
| + char methodCount;
|
| + char varCount;
|
| + char methodOuts[7];
|
| + Variable variables[1];
|
| +} *Constraint, ConstraintStruct;
|
| +
|
| +/* Other Constants and Macros */
|
| +#define NO_METHOD (-1)
|
| +#define SATISFIED(c) ((c)->whichMethod != NO_METHOD)
|
| +#define Weaker(a,b) (a > b)
|
| +
|
| +/*
|
| + Implementation of List
|
| + Invariants and relationships:
|
| + slots != NULL
|
| + slotCount > 0
|
| + sizeof(*slots) == slotCount * sizeof(Element)
|
| + 0 <= first < slotCount
|
| + -1 <= last < slotCount
|
| + last >= first (if not empty)
|
| + last == first - 1 (if empty)
|
| + NumberOfItems == (last - first) + 1
|
| + */
|
| +
|
| +/* Private Prototypes */
|
| +void Error(char*);
|
| +void Grow(List);
|
| +void MakeRoom(List);
|
| +char* StrengthString(Strength strength);
|
| +
|
| +/* Variables */
|
| +Variable Variable_Create(char *, long);
|
| +Variable Variable_CreateConstant(char *, long);
|
| +void Variable_Destroy(Variable);
|
| +void Variable_Print(Variable);
|
| +
|
| +/* Constraints */
|
| +Constraint Constraint_Create(int, Strength);
|
| +void Constraint_Destroy(Constraint);
|
| +void Constraint_Print(Constraint);
|
| +
|
| +/* Miscellaneous */
|
| +void ExecutePlan(List);
|
| +
|
| +Constraint StayC(Variable v, Strength); /* keep v constant */
|
| +Constraint EditC(Variable v, Strength); /* change v */
|
| +Constraint EqualsC(Variable a, Variable b, Strength); /* a = b */
|
| +/* (src * scale) + offset = dest*/
|
| +Constraint ScaleOffsetC(Variable src, Variable scale, Variable offset,
|
| + Variable dest, Strength);
|
| +
|
| +void InitDeltaBlue(void);
|
| +void AddVariable(Variable);
|
| +void DestroyVariable(Variable);
|
| +void AddConstraint(Constraint);
|
| +void DestroyConstraint(Constraint);
|
| +List ExtractPlan(void);
|
| +List ExtractPlanFromConstraint(Constraint);
|
| +List ExtractPlanFromConstraints(List);
|
| +
|
| +
|
| +
|
| +/****** Create and Destruction ******/
|
| +
|
| +List List_Create(int initialCount)
|
| +{
|
| + List newList;
|
| +
|
| + newList = (List) malloc(sizeof(ListStruct));
|
| + if (newList == NULL) Error("out of memory");
|
| + newList->slots = (Element *) malloc(initialCount * sizeof(Element));
|
| + if (newList->slots == NULL) Error("out of memory");
|
| + newList->slotCount = initialCount;
|
| + newList->first = 0;
|
| + newList->last = -1;
|
| + return newList;
|
| +}
|
| +
|
| +void List_Destroy(List list)
|
| +{
|
| + if (list->slots == NULL) Error("bad ListStruct; already freed?");
|
| + free(list->slots);
|
| + list->slots = NULL;
|
| + list->slotCount = 0;
|
| + list->first = 0;
|
| + list->last = -1;
|
| + free(list);
|
| +}
|
| +
|
| +/****** Enumeration and Queries ******/
|
| +
|
| +void List_Do(List list, Proc proc)
|
| +{
|
| + Element *nextPtr = &(list->slots[list->first]);
|
| + Element *lastPtr = &(list->slots[list->last]);
|
| +
|
| + while (nextPtr <= lastPtr) {
|
| + (*proc)(*nextPtr++);
|
| + }
|
| +}
|
| +
|
| +int List_Size(List list)
|
| +{
|
| + return (list->last - list->first) + 1;
|
| +}
|
| +
|
| +void* List_At(List list, int index)
|
| +{
|
| + if (index < 0 || index > list->last - list->first + 1)
|
| + Error("List access out of bounds");
|
| + return list->slots[index + list->first];
|
| +}
|
| +
|
| +/****** Adding ******/
|
| +
|
| +void List_Add(List list, Element element)
|
| +{
|
| + if (list->last >= (list->slotCount - 1)) MakeRoom(list);
|
| + list->slots[++list->last] = element;
|
| +}
|
| +
|
| +void List_Append(List list1, List list2)
|
| +{
|
| + Element *nextPtr = &(list2->slots[list2->first]);
|
| + Element *lastPtr = &(list2->slots[list2->last]);
|
| +
|
| + while (nextPtr <= lastPtr) {
|
| + List_Add(list1, *nextPtr++);
|
| + }
|
| +}
|
| +
|
| +/****** Removing ******/
|
| +
|
| +void List_Remove(List list, Element element)
|
| +{
|
| + Element *srcPtr = &list->slots[list->first];
|
| + Element *destPtr = &list->slots[0];
|
| + Element *lastPtr = &list->slots[list->last];
|
| +
|
| + list->last = list->last - list->first;
|
| + list->first = 0;
|
| + while (srcPtr <= lastPtr) {
|
| + if (*srcPtr == element) {
|
| + list->last--;
|
| + } else {
|
| + *destPtr++ = *srcPtr;
|
| + }
|
| + srcPtr++;
|
| + }
|
| +}
|
| +
|
| +Element List_RemoveFirst(List list)
|
| +{
|
| + Element element;
|
| +
|
| + if (list->last < list->first) return NULL;
|
| + element = list->slots[list->first++];
|
| + return element;
|
| +}
|
| +
|
| +void List_RemoveAll(List list)
|
| +{
|
| + list->first = 0;
|
| + list->last = -1;
|
| +}
|
| +
|
| +/****** Private ******/
|
| +
|
| +#define max(x, y) ((x) > (y) ? (x) : (y))
|
| +#define min(x, y) ((x) < (y) ? (x) : (y))
|
| +
|
| +void Error(char *errorString)
|
| +{
|
| + printf("error: %s.\n", errorString);
|
| + exit(-1);
|
| +}
|
| +
|
| +void Grow(List list)
|
| +{
|
| + list->slotCount += min(max(list->slotCount, 2), 512);
|
| + list->slots = realloc(list->slots, (list->slotCount * sizeof(Element)));
|
| + if (list->slots == NULL) Error("out of memory");
|
| +}
|
| +
|
| +void MakeRoom(List list)
|
| +{
|
| + Element *srcPtr = &list->slots[list->first];
|
| + Element *destPtr = &list->slots[0];
|
| + Element *lastPtr = &list->slots[list->last];
|
| +
|
| + if (((list->last - list->first) + 1) >= list->slotCount) Grow(list);
|
| + if (list->first == 0) return;
|
| + while (srcPtr <= lastPtr) {
|
| + *destPtr++ = *srcPtr++;
|
| + }
|
| + list->last = list->last - list->first;
|
| + list->first = 0;
|
| +}
|
| +
|
| +/*
|
| + Constraint, variable, and other operations for DeltaBlue.
|
| + */
|
| +
|
| +/******* Private *******/
|
| +
|
| +void Execute(Constraint c)
|
| +{
|
| + c->execute(c);
|
| +}
|
| +
|
| +void Noop(Constraint c)
|
| +{
|
| + /* default execute procedure; does nothing */
|
| +};
|
| +
|
| +/******* Variables *******/
|
| +
|
| +Variable Variable_Create(char *name, long initialValue)
|
| +{
|
| + Variable new;
|
| +
|
| + new = (Variable) malloc(sizeof(VariableStruct));
|
| + if (new == NULL) Error("out of memory");
|
| + new->value = initialValue;
|
| + new->constraints = List_Create(2);
|
| + new->determinedBy = NULL;
|
| + new->mark = 0;
|
| + new->walkStrength = S_weakest;
|
| + new->stay = true;
|
| + strncpy(new->name, name, 10);
|
| + new->name[9] = 0;
|
| + AddVariable(new);
|
| + return new;
|
| +}
|
| +
|
| +Variable Variable_CreateConstant(char *name, long value)
|
| +{
|
| + Variable new;
|
| +
|
| + new = (Variable) malloc(sizeof(VariableStruct));
|
| + if (new == NULL) Error("out of memory");
|
| + new->value = value;
|
| + new->constraints = List_Create(0);
|
| + new->determinedBy = NULL;
|
| + new->mark = 0;
|
| + new->walkStrength = S_required;
|
| + new->stay = true;
|
| + strncpy(new->name, name, 10);
|
| + new->name[9] = 0;
|
| + AddVariable(new);
|
| + return new;
|
| +}
|
| +
|
| +void Variable_Destroy(Variable v)
|
| +{
|
| + if (v->constraints == NULL) {
|
| + Error("bad VariableStruct; already freed?");
|
| + }
|
| + List_Destroy(v->constraints);
|
| + v->constraints = NULL;
|
| + free(v);
|
| +}
|
| +
|
| +void Variable_Print(Variable v)
|
| +{
|
| + printf(
|
| + "%s(%s,%ld)",
|
| + v->name, StrengthString(v->walkStrength), v->value);
|
| +}
|
| +
|
| +/******* Constraints *******/
|
| +
|
| +Constraint Constraint_Create(int variableCount, Strength strength)
|
| +{
|
| + Constraint new;
|
| + int i;
|
| +
|
| + new = (Constraint) malloc(sizeof(ConstraintStruct)
|
| + + ((variableCount - 1) * sizeof(Variable)));
|
| + if (new == NULL) Error("out of memory");
|
| + new->execute = Noop;
|
| + new->inputFlag = false;
|
| + new->strength = strength;
|
| + new->whichMethod = NO_METHOD;
|
| + new->methodCount = 0;
|
| + for (i = 0; i < 7; i++) {
|
| + new->methodOuts[i] = 0;
|
| + }
|
| + new->varCount = variableCount;
|
| + for (i = 0; i < new->varCount; i++) {
|
| + new->variables[i] = NULL;
|
| + }
|
| + return new;
|
| +}
|
| +
|
| +void Constraint_Destroy(Constraint c)
|
| +{
|
| + if (c->execute == NULL) {
|
| + Error("bad ConstraintStruct; already freed?");
|
| + }
|
| + c->execute = NULL;
|
| + free(c);
|
| +}
|
| +
|
| +void Constraint_Print(Constraint c)
|
| +{
|
| + int i, outIndex;
|
| +
|
| + if (!SATISFIED(c)) {
|
| + printf("Unsatisfied(");
|
| + for (i = 0; i < c->varCount; i++) {
|
| + Variable_Print(c->variables[i]);
|
| + printf(" ");
|
| + }
|
| + printf(")");
|
| + } else {
|
| + outIndex = c->methodOuts[c->whichMethod];
|
| + printf("Satisfied(");
|
| + for (i = 0; i < c->varCount; i++) {
|
| + if (i != outIndex) {
|
| + Variable_Print(c->variables[i]);
|
| + printf(" ");
|
| + }
|
| + }
|
| + printf("-> ");
|
| + Variable_Print(c->variables[outIndex]);
|
| + printf(")");
|
| + }
|
| + printf("\n");
|
| +}
|
| +
|
| +/******* Miscellaneous Functions *******/
|
| +
|
| +char* StrengthString(Strength strength)
|
| +{
|
| + static char temp[20];
|
| +
|
| + switch (strength) {
|
| + case S_required: return "required";
|
| + case S_strongPreferred: return "strongPreferred";
|
| + case S_preferred: return "preferred";
|
| + case S_strongDefault: return "strongDefault";
|
| + case S_default: return "default";
|
| + case S_weakDefault: return "weakDefault";
|
| + case S_weakest: return "weakest";
|
| + default:
|
| + sprintf(temp, "strength[%d]", strength);
|
| + return temp;
|
| + }
|
| +}
|
| +
|
| +void ExecutePlan(List list)
|
| +{
|
| + List_Do(list, Execute);
|
| +}
|
| +
|
| +
|
| +/*
|
| +
|
| + DeltaBlue, an incremental dataflow constraint solver.
|
| +
|
| + */
|
| +
|
| +/******* Private Macros and Prototypes *******/
|
| +
|
| +#define OUT_VAR(c) (c->variables[c->methodOuts[c->whichMethod]])
|
| +
|
| +void FreeVariable(Variable);
|
| +void AddIfSatisfiedInput(Constraint);
|
| +void CollectSatisfiedInputs(Variable);
|
| +List MakePlan(void);
|
| +void IncrementalAdd(Constraint);
|
| +void AddAtStrength(Constraint);
|
| +void IncrementalRemove(Constraint);
|
| +Boolean AddPropagate(Constraint);
|
| +void CollectUnsatisfied(Constraint);
|
| +void RemovePropagateFrom(Variable);
|
| +Constraint Satisfy(Constraint);
|
| +int ChooseMethod(Constraint);
|
| +void Recalculate(Constraint);
|
| +int OutputWalkStrength(Constraint);
|
| +Boolean ConstantOutput(Constraint);
|
| +Boolean InputsKnown(Constraint);
|
| +void NewMark(void);
|
| +void Error(char *);
|
| +Constraint NextDownstreamConstraint(List, Variable);
|
| +
|
| +/******* DeltaBlue Globals *******/
|
| +
|
| +List allVariables = NULL;
|
| +long currentMark = 0;
|
| +
|
| +/******** Public: Initialization *******/
|
| +
|
| +void InitDeltaBlue(void)
|
| +{
|
| + Variable v;
|
| +
|
| + if (allVariables == NULL) allVariables = List_Create(128);
|
| + v = (Variable) List_RemoveFirst(allVariables);
|
| + while (v != NULL) {
|
| + FreeVariable(v);
|
| + v = (Variable) List_RemoveFirst(allVariables);
|
| + }
|
| + List_RemoveAll(allVariables);
|
| + currentMark = 0;
|
| +}
|
| +
|
| +/* this is used when we know we are going to throw away all variables */
|
| +void FreeVariable(Variable v)
|
| +{
|
| + Constraint c;
|
| + int i;
|
| +
|
| + c = (Constraint) List_RemoveFirst(v->constraints);
|
| + while (c != NULL) {
|
| + for (i = c->varCount - 1; i >= 0; i--) {
|
| + List_Remove((c->variables[i])->constraints, (Element) c);
|
| + }
|
| + Constraint_Destroy(c);
|
| + c = (Constraint) List_RemoveFirst(v->constraints);
|
| + }
|
| + Variable_Destroy(v);
|
| +}
|
| +
|
| +/******** Public: Variables and Constraints *******/
|
| +
|
| +void AddVariable(Variable v)
|
| +{
|
| + List_Add(allVariables, v);
|
| +}
|
| +
|
| +void DestroyConstraint(Constraint c);
|
| +
|
| +void DestroyVariable(Variable v)
|
| +{
|
| + Constraint c;
|
| +
|
| + c = (Constraint) List_RemoveFirst(v->constraints);
|
| + while (c != NULL) {
|
| + DestroyConstraint(c);
|
| + c = (Constraint) List_RemoveFirst(v->constraints);
|
| + }
|
| + List_Remove(allVariables, v);
|
| + Variable_Destroy(v);
|
| +}
|
| +
|
| +void AddConstraint(Constraint c)
|
| +{
|
| + int i;
|
| +
|
| + for (i = c->varCount - 1; i >= 0; i--) {
|
| + List_Add((c->variables[i])->constraints, (Element) c);
|
| + }
|
| + c->whichMethod = NO_METHOD;
|
| + IncrementalAdd(c);
|
| +}
|
| +
|
| +void DestroyConstraint(Constraint c)
|
| +{
|
| + int i;
|
| +
|
| + if (SATISFIED(c)) IncrementalRemove(c);
|
| + for (i = c->varCount - 1; i >= 0; i--) {
|
| + List_Remove((c->variables[i])->constraints, (Element) c);
|
| + }
|
| + Constraint_Destroy(c);
|
| +}
|
| +
|
| +/******** Public: Plan Extraction *******/
|
| +
|
| +List hot = NULL; /* used to collect "hot" constraints */
|
| +
|
| +void AddIfSatisfiedInput(Constraint c)
|
| +{
|
| + if (c->inputFlag && SATISFIED(c)) {
|
| + List_Add(hot, c);
|
| + }
|
| +}
|
| +
|
| +void CollectSatisfiedInputs(Variable v)
|
| +{
|
| + List_Do(v->constraints, AddIfSatisfiedInput);
|
| +}
|
| +
|
| +List ExtractPlan(void)
|
| +{
|
| + if (hot == NULL) hot = List_Create(128);
|
| + List_RemoveAll(hot);
|
| + List_Do(allVariables, CollectSatisfiedInputs);
|
| + return MakePlan();
|
| +}
|
| +
|
| +List ExtractPlanFromConstraint(Constraint c)
|
| +{
|
| + if (hot == NULL) hot = List_Create(128);
|
| + List_RemoveAll(hot);
|
| + AddIfSatisfiedInput(c);
|
| + return MakePlan();
|
| +}
|
| +
|
| +List ExtractPlanFromConstraints(List constraints)
|
| +{
|
| + if (hot == NULL) hot = List_Create(128);
|
| + List_RemoveAll(hot);
|
| + List_Do(constraints, AddIfSatisfiedInput);
|
| + return MakePlan();
|
| +}
|
| +
|
| +/******* Private: Plan Extraction *******/
|
| +
|
| +List MakePlan()
|
| +{
|
| + List plan;
|
| + Constraint nextC;
|
| + Variable out;
|
| +
|
| + NewMark();
|
| + plan = List_Create(128);
|
| + nextC = (Constraint) List_RemoveFirst(hot);
|
| + while (nextC != NULL) {
|
| + out = OUT_VAR(nextC);
|
| + if ((out->mark != currentMark) && InputsKnown(nextC)) {
|
| + List_Add(plan, nextC);
|
| + out->mark = currentMark;
|
| + nextC = NextDownstreamConstraint(hot, out);
|
| + } else {
|
| + nextC = (Constraint) List_RemoveFirst(hot);
|
| + }
|
| + }
|
| + return plan;
|
| +}
|
| +
|
| +Boolean InputsKnown(Constraint c)
|
| +{
|
| + int outIndex, i;
|
| + Variable in;
|
| +
|
| + outIndex = c->methodOuts[c->whichMethod];
|
| + for (i = c->varCount - 1; i >= 0; i--) {
|
| + if (i != outIndex) {
|
| + in = c->variables[i];
|
| + if ((in->mark != currentMark) &&
|
| + (!in->stay) &&
|
| + (in->determinedBy != NULL)) {
|
| + return false;
|
| + }
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +/******* Private: Adding *******/
|
| +
|
| +void IncrementalAdd(Constraint c)
|
| +{
|
| + Constraint overridden;
|
| +
|
| + NewMark();
|
| + overridden = Satisfy(c);
|
| + while (overridden != NULL) {
|
| + overridden = Satisfy(overridden);
|
| + }
|
| +}
|
| +
|
| +Constraint Satisfy(Constraint c)
|
| +{
|
| + int outIndex, i;
|
| + Constraint overridden;
|
| + Variable out;
|
| +
|
| + c->whichMethod = ChooseMethod(c);
|
| + if (SATISFIED(c)) {
|
| + /* mark inputs to allow cycle detection in AddPropagate */
|
| + outIndex = c->methodOuts[c->whichMethod];
|
| + for (i = c->varCount - 1; i >= 0; i--) {
|
| + if (i != outIndex) {
|
| + c->variables[i]->mark = currentMark;
|
| + }
|
| + }
|
| + out = c->variables[outIndex];
|
| + overridden = (Constraint) out->determinedBy;
|
| + if (overridden != NULL) overridden->whichMethod = NO_METHOD;
|
| + out->determinedBy = c;
|
| + if (!AddPropagate(c)) {
|
| + Error("Cycle encountered");
|
| + return NULL;
|
| + }
|
| + out->mark = currentMark;
|
| + return overridden;
|
| + } else {
|
| + if (c->strength == S_required) {
|
| + Error("Could not satisfy a required constraint");
|
| + }
|
| + return NULL;
|
| + }
|
| +}
|
| +
|
| +int ChooseMethod(Constraint c)
|
| +{
|
| + int best, m;
|
| + Strength bestOutStrength;
|
| + Variable mOut;
|
| +
|
| + best = NO_METHOD;
|
| + bestOutStrength = c->strength;
|
| + for (m = c->methodCount - 1; m >= 0; m--) {
|
| + mOut = c->variables[c->methodOuts[m]];
|
| + if ((mOut->mark != currentMark) &&
|
| + (Weaker(mOut->walkStrength, bestOutStrength))) {
|
| + best = m;
|
| + bestOutStrength = mOut->walkStrength;
|
| + }
|
| + }
|
| + return best;
|
| +}
|
| +
|
| +Boolean AddPropagate(Constraint c)
|
| +{
|
| + List todo;
|
| + Constraint nextC;
|
| + Variable out;
|
| +
|
| + todo = List_Create(8); /* unprocessed constraints */
|
| + nextC = c;
|
| + while (nextC != NULL) {
|
| + out = OUT_VAR(nextC);
|
| + if (out->mark == currentMark) {
|
| + /* remove the cycle-causing constraint */
|
| + IncrementalRemove(c);
|
| + return false;
|
| + }
|
| + Recalculate(nextC);
|
| + nextC = NextDownstreamConstraint(todo, out);
|
| + }
|
| + List_Destroy(todo);
|
| + return true;
|
| +}
|
| +
|
| +/******* Private: Removing *******/
|
| +
|
| +List unsatisfied; /* used to collect unsatisfied downstream constraints */
|
| +Strength strength; /* used to add unsatisfied constraints in strength order */
|
| +
|
| +void AddAtStrength(Constraint c)
|
| +{
|
| + if (c->strength == strength) IncrementalAdd(c);
|
| +}
|
| +
|
| +void CollectUnsatisfied(Constraint c)
|
| +{
|
| + if (!SATISFIED(c)) List_Add(unsatisfied, c);
|
| +}
|
| +
|
| +void IncrementalRemove(Constraint c)
|
| +{
|
| + Variable out;
|
| + int i;
|
| +
|
| + out = OUT_VAR(c);
|
| + c->whichMethod = NO_METHOD;
|
| + for (i = c->varCount - 1; i >= 0; i--) {
|
| + List_Remove((c->variables[i])->constraints, (Element) c);
|
| + }
|
| + unsatisfied = List_Create(8);
|
| + RemovePropagateFrom(out);
|
| + for (strength = S_required; strength <= S_weakest; strength++) {
|
| + List_Do(unsatisfied, AddAtStrength);
|
| + }
|
| + List_Destroy(unsatisfied);
|
| +}
|
| +
|
| +void RemovePropagateFrom(Variable v)
|
| +{
|
| + Constraint nextC;
|
| + List todo;
|
| +
|
| + v->determinedBy = NULL;
|
| + v->walkStrength = S_weakest;
|
| + v->stay = true;
|
| + todo = List_Create(8);
|
| + while (true) {
|
| + List_Do(v->constraints, CollectUnsatisfied);
|
| + nextC = NextDownstreamConstraint(todo, v);
|
| + if (nextC == NULL) {
|
| + break;
|
| + } else {
|
| + Recalculate(nextC);
|
| + v = OUT_VAR(nextC);
|
| + }
|
| + }
|
| + List_Destroy(todo);
|
| +}
|
| +
|
| +/******* Private: Recalculation *******/
|
| +
|
| +void Recalculate(Constraint c)
|
| +{
|
| + Variable out;
|
| +
|
| + out = OUT_VAR(c);
|
| + out->walkStrength = OutputWalkStrength(c);
|
| + out->stay = ConstantOutput(c);
|
| + if (out->stay) c->execute(c);
|
| +}
|
| +
|
| +int OutputWalkStrength(Constraint c)
|
| +{
|
| + int outIndex, m, mOutIndex;
|
| + Strength minStrength;
|
| +
|
| + minStrength = c->strength;
|
| + outIndex = c->methodOuts[c->whichMethod];
|
| + for (m = c->methodCount - 1; m >= 0; m--) {
|
| + mOutIndex = c->methodOuts[m];
|
| + if ((mOutIndex != outIndex) &&
|
| + (Weaker(c->variables[mOutIndex]->walkStrength, minStrength))) {
|
| + minStrength = c->variables[mOutIndex]->walkStrength;
|
| + }
|
| + }
|
| + return minStrength;
|
| +}
|
| +
|
| +Boolean ConstantOutput(Constraint c)
|
| +{
|
| + int outIndex, i;
|
| +
|
| + if (c->inputFlag) return false;
|
| + outIndex = c->methodOuts[c->whichMethod];
|
| + for (i = c->varCount - 1; i >= 0; i--) {
|
| + if (i != outIndex) {
|
| + if (!c->variables[i]->stay) return false;
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +/******* Private: Miscellaneous *******/
|
| +
|
| +void NewMark(void)
|
| +{
|
| + currentMark++;
|
| +}
|
| +
|
| +Constraint NextDownstreamConstraint(List todo, Variable variable)
|
| +{
|
| + List allC = variable->constraints;
|
| + Constraint *nextPtr = (Constraint *) &(allC->slots[allC->first]);
|
| + Constraint *lastPtr = (Constraint *) &(allC->slots[allC->last]);
|
| + Constraint determiningC = variable->determinedBy;
|
| + Constraint first = NULL;
|
| +
|
| + for ( ; nextPtr <= lastPtr; nextPtr++) {
|
| + if ((*nextPtr != determiningC) && SATISFIED(*nextPtr)) {
|
| + if (first == NULL) {
|
| + first = *nextPtr;
|
| + } else {
|
| + List_Add(todo, *nextPtr);
|
| + }
|
| + }
|
| + }
|
| + if (first == NULL) {
|
| + first = (Constraint) List_RemoveFirst(todo);
|
| + }
|
| + return first;
|
| +}
|
| +
|
| +
|
| +/*
|
| + Some useful constraints. Each function instantiates and installs
|
| + a constraint on the argument variables.
|
| + */
|
| +
|
| +
|
| +/* macro to reference a constraint variable value */
|
| +#define var(i) ((c->variables[i])->value)
|
| +
|
| +/******* Stay Constraint *******/
|
| +
|
| +Constraint StayC(Variable v, Strength strength)
|
| +{
|
| + Constraint new = Constraint_Create(1, strength);
|
| + new->variables[0] = v;
|
| + new->methodCount = 1;
|
| + new->methodOuts[0] = 0;
|
| + AddConstraint(new);
|
| + return new;
|
| +};
|
| +
|
| +/******* Edit Constraint *******/
|
| +
|
| +Constraint EditC(Variable v, Strength strength)
|
| +{
|
| + Constraint new = Constraint_Create(1, strength);
|
| + new->inputFlag = true;
|
| + new->variables[0] = v;
|
| + new->methodCount = 1;
|
| + new->methodOuts[0] = 0;
|
| + AddConstraint(new);
|
| + return new;
|
| +};
|
| +
|
| +/****** Equals Constraint ******/
|
| +
|
| +void EqualsC_Execute(Constraint c)
|
| +{
|
| + /* a = b */
|
| + switch (c->whichMethod) {
|
| + case 0:
|
| + var(0) = var(1);
|
| + break;
|
| + case 1:
|
| + var(1) = var(0);
|
| + break;
|
| + }
|
| +}
|
| +
|
| +Constraint EqualsC(Variable a, Variable b, Strength strength)
|
| +{
|
| + Constraint new = Constraint_Create(2, strength);
|
| + new->execute = EqualsC_Execute;
|
| + new->variables[0] = a;
|
| + new->variables[1] = b;
|
| + new->methodCount = 2;
|
| + new->methodOuts[0] = 0;
|
| + new->methodOuts[1] = 1;
|
| + AddConstraint(new);
|
| + return new;
|
| +};
|
| +
|
| +/******** Add Constraint *******/
|
| +
|
| +void AddC_Execute(Constraint c)
|
| +{
|
| + /* a + b = sum */
|
| + switch (c->whichMethod) {
|
| + case 0:
|
| + var(2) = var(0) + var(1);
|
| + break;
|
| + case 1:
|
| + var(1) = var(2) - var(0);
|
| + break;
|
| + case 2:
|
| + var(0) = var(2) - var(1);
|
| + break;
|
| + }
|
| +}
|
| +
|
| +Constraint AddC(Variable a, Variable b, Variable sum, Strength strength)
|
| +{
|
| + Constraint new = Constraint_Create(3, strength);
|
| + new->execute = AddC_Execute;
|
| + new->variables[0] = a;
|
| + new->variables[1] = b;
|
| + new->variables[2] = sum;
|
| + new->methodCount = 3;
|
| + new->methodOuts[0] = 2;
|
| + new->methodOuts[1] = 1;
|
| + new->methodOuts[2] = 0;
|
| + AddConstraint(new);
|
| + return new;
|
| +};
|
| +
|
| +/******** ScaleOffset Constraint *******/
|
| +
|
| +void ScaleOffsetC_Execute(Constraint c)
|
| +{
|
| + /* (src * scale) + offset = dest */
|
| + switch (c->whichMethod) {
|
| + case 0:
|
| + var(3) = (var(0) * var(1)) + var(2);
|
| + break;
|
| + case 1:
|
| + var(0) = (var(3) - var(2)) / var(1);
|
| + break;
|
| + }
|
| +}
|
| +
|
| +Constraint ScaleOffsetC(Variable src, Variable scale, Variable offset,
|
| + Variable dest, Strength strength)
|
| +{
|
| + Constraint new = Constraint_Create(4, strength);
|
| + new->execute = ScaleOffsetC_Execute;
|
| + new->variables[0] = src;
|
| + new->variables[1] = scale;
|
| + new->variables[2] = offset;
|
| + new->variables[3] = dest;
|
| + new->methodCount = 2;
|
| + new->methodOuts[0] = 3;
|
| + new->methodOuts[1] = 0;
|
| + AddConstraint(new);
|
| + return new;
|
| +};
|
| +
|
| +/***************************************************************************
|
| +
|
| + Timing Functions
|
| +
|
| +****************************************************************************/
|
| +
|
| +long startTime;
|
| +
|
| +long Milliseconds()
|
| +{
|
| + int millisecondsPerClock = CLOCKS_PER_SEC / 1000;
|
| + return (clock() / millisecondsPerClock);
|
| +}
|
| +
|
| +void Start()
|
| +{
|
| + startTime = Milliseconds();
|
| +}
|
| +
|
| +void Finish(long *milliseconds)
|
| +{
|
| + *milliseconds = Milliseconds() - startTime;
|
| +}
|
| +
|
| +/***************************************************************************
|
| +*
|
| +* This is the standard DeltaBlue benchmark. A long chain of equality
|
| +* constraints is constructed with a stay constraint on one end. An edit
|
| +* constraint is then added to the opposite end and the time is measured for
|
| +* adding and removing this constraint, and extracting and executing a
|
| +* constraint satisfaction plan. There are two cases. In case 1, the added
|
| +* constraint is stronger than the stay constraint and values must propagate
|
| +* down the entire length of the chain. In case 2, the added constraint is
|
| +* weaker than the stay constraint so it cannot be accomodated. The cost in
|
| +* this case is, of course, very low. Typical situations lie somewhere between
|
| +* these two extremes.
|
| +*
|
| +****************************************************************************/
|
| +
|
| +void ChainTest(int n)
|
| +{
|
| + long msecs, i;
|
| + char name[20];
|
| + Variable prev, v, first, last;
|
| + Constraint editC;
|
| + List plan;
|
| +
|
| + InitDeltaBlue();
|
| + prev = first = last = NULL;
|
| +
|
| + for (i = 0; i < n; i++) {
|
| + sprintf(name, "v%ld", i);
|
| + v = Variable_Create(name, 0);
|
| + if (prev != NULL) {
|
| + EqualsC(prev, v, S_required);
|
| + }
|
| + if (i == 0) first = v;
|
| + if (i == (n-1)) last = v;
|
| + prev = v;
|
| + }
|
| + StayC(last, S_default);
|
| + editC = EditC(first, S_strongDefault);
|
| + plan = ExtractPlanFromConstraint(editC);
|
| + for (i = 0; i < 100; i++) {
|
| + first->value = i;
|
| + ExecutePlan(plan);
|
| + if (last->value != i)
|
| + Error("ChainTest failed!");
|
| + }
|
| + List_Destroy(plan);
|
| + DestroyConstraint(editC);
|
| +}
|
| +
|
| +/***************************************************************************
|
| + *
|
| + * This test constructs a two sets of variables related to each other by a
|
| + * simple linear transformation (scale and offset). The time is measured to
|
| + * change a variable on either side of the mapping and to change the scale or
|
| + * offset factors. It has been tested for up to 2000 variable pairs.
|
| + *
|
| + ****************************************************************************/
|
| +
|
| +void Change(Variable v, long newValue)
|
| +{
|
| + Constraint editC;
|
| + long i, msecs;
|
| + List plan;
|
| +
|
| + editC = EditC(v, S_strongDefault);
|
| + plan = ExtractPlanFromConstraint(editC);
|
| + v->value = newValue;
|
| + for (i = 0; i < 10; i++) {
|
| + ExecutePlan(plan);
|
| + }
|
| + List_Destroy(plan);
|
| + DestroyConstraint(editC);
|
| +}
|
| +
|
| +void ProjectionTest(int n)
|
| +{
|
| + Variable src, scale, offset, dest;
|
| + long msecs, i;
|
| + char name[20];
|
| + List dests;
|
| +
|
| + InitDeltaBlue();
|
| +
|
| + scale = Variable_Create("scale", 10);
|
| + offset = Variable_Create("offset", 1000);
|
| + dests = List_Create(n);
|
| +
|
| + for (i = 1; i <= n; i++) {
|
| + /* make src and dest variables */
|
| + sprintf(name, "src%ld", i);
|
| + src = Variable_Create(name, i);
|
| + sprintf(name, "dest%ld", i);
|
| + dest = Variable_Create(name, i);
|
| + List_Add(dests, dest);
|
| +
|
| + /* add stay on src */
|
| + StayC(src, S_default);
|
| +
|
| + /* add scale/offset constraint */
|
| + ScaleOffsetC(src, scale, offset, dest, S_required);
|
| + }
|
| + Change(src, 17);
|
| + if (dest->value != 1170)
|
| + Error("Projection Test 1 failed!");
|
| +
|
| + Change(dest, 1050);
|
| + if (src->value != 5)
|
| + Error("Projection Test 2 failed!");
|
| +
|
| + Change(scale, 5);
|
| + for (i = 1; i < List_Size(dests); ++i)
|
| + if (((Variable)List_At(dests, i - 1))->value != i * 5 + 1000)
|
| + Error("Projection Test 3 failed!");
|
| +
|
| + Change(offset, 2000);
|
| + for (i = 1; i < List_Size(dests); ++i)
|
| + if (((Variable)List_At(dests, i - 1))->value != i * 5 + 2000)
|
| + Error("Projection Test 4 failed!");
|
| +
|
| + List_Destroy(dests);
|
| +}
|
| +
|
| +int run_deltablue(int n)
|
| +{
|
| + const int iterations= 1;
|
| + int j;
|
| + long msecs;
|
| +
|
| + Start();
|
| + for (j= 0; j < iterations; ++j) {
|
| + ChainTest(n);
|
| + ProjectionTest(n);
|
| + }
|
| + Finish(&msecs);
|
| + /*printf("Total time for %d iterations of chain and projection tests: %ld ms\n",
|
| + iterations, msecs);
|
| + printf("Average time per iteration: %g ms\n", (double)msecs / iterations);*/
|
| + return 0;
|
| +}
|
|
|