[gecode-users] Set constraints working for sequential data, but not non-sequential data. Ideas?

Holger Winnemoeller holger.winnemoeller at gmail.com
Wed Dec 16 05:21:13 CET 2009


*QUESTION: How can I solve the following problem for anything but toy
examples?*

Say, I have the following sets:

All : {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}
subA: {0,1,2,3,4}
subB: {5,6,7,8,9}

If I ask for a subset of "All" which contains 4 elements, of which 2
elements are from "subA" and 2 elements are from "subB", I get a variety of
results, such as
{0,1,5,6}
{0,1,5,7}
...
{3,4,8,9}
...

etc.

This works perfectly fine.

Now, for cases where subA, and  subB are not strictly sequential (i.e.
sorted but non-consecutive numbers)

subA: {4,8,14,16,17}
subB: {0,3,5,10,12}

The system quickly runs out of steam (maybe not for the toy example here,
but for |All| = 100, |subA| = |subB| = 20, asking for 10 items -- see
attached code). Gecode just keeps computing and never seems to find a
solution.

Given that the sub-sets are disjoint a solution should really be trivial in
any case (take 50% of one subset and 50% of the other). However, I don't
want to make the assumption that they are disjoint.

I have attached some demo code for what I am talking about, so you can
experiment with it.

Thanks for your help!

Holger.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.gecode.org/pipermail/users/attachments/20091215/0f54715c/attachment.htm>
-------------- next part --------------
#include <gecode/set.hh>
#include <gecode/support.hh>
#include <gecode/kernel.hh>
#include <gecode/search.hh>
#include <vector>
#include <algorithm>

using namespace std;
using namespace Gecode;

#define BROKEN_PROBLEM 1 // will not finish
//#define BROKEN_PROBLEM 0 // works just fine

// A "Minimal" space definition for the problem
class MiniSpace: public Space
{
	SetVarArray mSetStore;
	void CreateAndRequestCategory(int numItemsInCategories, int requestFromEachCategory, vector<int>& allItems)
	{
		vector<int> data (numItemsInCategories); // space to hold items
		for(int i=0; i<numItemsInCategories; ++i) // fill data from allItems
		{
			data[i] = allItems.back();
			allItems.pop_back();
		}

		// sort the items before loading them into Gecode -- not sure if this is necessary
		sort(data.begin(), data.end());

		// 1.) Create a new set domain that holds the "special" items
		IntSet specialSet(&data[0], (int)data.size());
		// 2.) Create a set variable that we'll associate with that set later on
		SetVar specialSelected(*this);
		// 3.) Set "specialSelected" to the intersection of whatever a possible solution is, and
		//     the "specialSet". This ensures that we can talk about items that are included
		//     in the solution, but also belong to the special set
		rel(*this, mSetStore[0], SOT_INTER, specialSet, SRT_EQ, specialSelected);
		// 4.) Now ensure that we only have "requestFromEachCategory" of these overlapping items
		cardinality(*this, specialSelected, requestFromEachCategory, requestFromEachCategory);
	}

public:
	MiniSpace(int problemSize, int numItemsInCategories, int numRequestedSize)
	{
		puts("Setting up problem...");
		// Create a SetVariable array (only need one element really, but this allows me to define the domain in one step)
		mSetStore = SetVarArray(*this, 1, IntSet::empty, 0, problemSize);
		SetVar resultSet = mSetStore[0]; // get the one variable that was defined in the above line

		// impose the constraint that we only want "numRequestedSize" items in the result set
		cardinality(*this, resultSet, numRequestedSize, numRequestedSize);

		// Create two sets of random non-overlapping items from inventory
		vector<int> allItems (problemSize);
		for(int i=0; i<problemSize; ++i) allItems[i] = problemSize-1-i; // init items
#if BROKEN_PROBLEM
		random_shuffle(allItems.begin(), allItems.end()); // shuffle items
#endif
		int requestFromEachCategory = numRequestedSize * 4 / 10;
		CreateAndRequestCategory(numItemsInCategories, requestFromEachCategory, allItems); // one category

		// Create another set of items and request elements from it
		CreateAndRequestCategory(numItemsInCategories, requestFromEachCategory, allItems); // another category

		// Given these constraints, branch
		branch(*this, mSetStore, SET_VAR_NONE, SET_VAL_MIN_INC);
	}
	MiniSpace(bool share, MiniSpace& s) : Space(share, s) {mSetStore.update(*this, share, s.mSetStore);}
	virtual Space* copy(bool share) {return new MiniSpace(share, *this);}
	void print() const
	{
		for(SetVarGlbValues d(mSetStore[0]);d();++d)
			std::cout << d.val() << " ";
	}
};

int main(int argc, char* argv[])
{
	// Run the problem
	//MiniSpace problem (
	//	3000,	// total number of items in inventory
	//	200,	// several sub-inventories (non-overlapping) with X elements each
	//	20		// requesting X items
	//); // space instance

	MiniSpace problem (
		100,	// total number of items in inventory
		20,		// several sub-inventories (non-overlapping) with X elements each
		10		// requesting X items
	); // space instance

	DFS<MiniSpace> solver (&problem);
	int count=0;
	puts("Looking for solutions...");
	while(true){
		MiniSpace* solution = solver.next();
		if(!solution) break;
		std::cout << "Solution Nr." << count++ << std::endl;
		solution->print();
		std::cout << std::endl;
		delete solution;
	}
	std::cout << "Done..." << std::endl;
	system("pause");
	return 0;
}



More information about the users mailing list