algorithm - semi-random set of subsets -
i'm trying generate semi-random subsets restrictions.
here variable descriptions example values:
- objcount - number of objects (12)
- visiblecount (aka setsize) - number of objects per set (6)
- setcount - number of sets (12)
- objappearances - number of set in object appears =
setcount * visiblecount / objcount
i need produce given number of sets (setcount) follow these rules:
- each set collection of objects, no object can in single set more once.
- furthermore, each object should in same number of sets. if doesn't devide evenly, number sets in object appears can off 1 (some objects in 4 sets, , others in 5). i'll try avoid situation, it's not critical.
it's turning out far less trivial thought. me code/psuedocode? solution generalized version helpful too.
thanks in advance.
edit: visiblecount set size. number of times object appears (objappearances) setcount * visiblecount / objcount
edit2: should add want sets random. if sets have sequential objects (e.g. set1:5,6,7 set2:3,4,5 set3:10,11,0), solution isn't useful. sorry not making clear.
edit3: here solution not work. (in c#)
static void main(string[] args) { var objectcount = 12; var setsize = 6; var setcount = 12; var sets = enumerable.range(0, setcount).select(i => new list<int>()).toarray(); // setcount-sized array of lists var objectappearances = setsize * setcount / objectcount; var rand = new random(); // fill sets (int obj = 0; obj < objectcount; obj++) { (int = 0; < objectappearances; a++) { // collection of sets not full var nonfullsets = sets.where(s => s.count < setsize); // collection of non-full sets without obj var setswithoutobj = nonfullsets.where(s => !s.contains(obj)); /////////////////////// // here problem. of non-full sets may // have copy of obj /////////////////////// // choose set @ random var currentsetindex = rand.next(setswithoutobj.count()); var currentset = setswithoutobj.elementat(currentsetindex); // add object currentset.add(obj); } } // randomize order within each set , output each (int = 0; < setcount; i++) { var randomlyorderedset = sets[i].orderby(obj => rand.next()); sets[i] = new list<int>(randomlyorderedset); // output foreach (var obj in sets[i]) console.write(string.format("{0}, ", obj)); console.writeline(); } console.readline(); }
here's solution - implementation of mizardx's answer
static void main(string[] args) { var objectcount = 12; var setsize = 6; var setcount = 10; var rand = new random(); // make matrix [setcount][objectcount] var matrix = new int[setcount][]; (int s = 0; s < setcount; s++) matrix[s] = enumerable.repeat(0, objectcount).toarray(); // put approximately same number of objects in each set // adding sequential objects sequential sets (not random) (int s = 0; s < setcount; s++) { var firstobject = (int)math.ceiling((double)s * objectcount / setcount); (int = 0; < setsize; i++) { var o = (firstobject + i) % objectcount; matrix[s][o] = 1; } } // output result (int s = 0; s < setcount; s++) { (int o = 0; o < objectcount; o++) { console.write(string.format("{0}, ", matrix[s][o])); } console.writeline(); } console.writeline(); // shuffle sets matrix = matrix.orderby(s => rand.next()).toarray(); // make new matrix shuffle objects var objorder = enumerable.range(0, objectcount).orderby(o => rand.next()).toarray(); var matrixsuffled = new int[setcount][]; (int s = 0; s < setcount; s++) matrixsuffled[s] = enumerable.repeat(0, objectcount).toarray(); (int o = 0; o < objectcount; o++) { var oldobj = o; var newobj = objorder[o]; (int s = 0; s < setcount; s++) { matrixsuffled[s][newobj] = matrix[s][oldobj]; } } // check , output result var objectcounters = enumerable.repeat(0, objectcount).toarray(); (int s = 0; s < setcount; s++) { var objectsinthisset = 0; (int o = 0; o < objectcount; o++) { objectsinthisset += matrixsuffled[s][o]; objectcounters[o] += matrixsuffled[s][o]; console.write(string.format("{0}, ", matrixsuffled[s][o])); } console.write(string.format(" {0}", objectsinthisset)); console.writeline(); } // output object count console.writeline(); (int o = 0; o < objectcount; o++) console.write(string.format("{0} ", objectcounters[o])); console.readline(); }
- create objcount × setcount matrix, , fill ones , zeros each column contains visiblecount ones, , each row contains (almost) equal number of ones. order irrelevant @ point.
- shuffle columns (and rows, if objcount not divide setcount × visiblecount evenly).
- for each column i, if cell @ row j equals 1, add object j set i.
for 12 objects, 6 sets , 3 visible, initial matrix might this:
1 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0 1
and after shuffle:
1 0 1 0 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 1 0 0 0 1 0 0 0 0 0 1
resulting in sets:
{1,3,8} {3,5,11} {1,7,8} {4,6,9} {2,4,10} {10,11,12}
Comments
Post a Comment