Now that I have Associated Nodes working, I'd like to take the results and schedule meetings between the two parties represented by the node types, in order of preference according to the score generated by Assocated Nodes. Any suggestions? The algorithm I'm thinking of is something like this:

Create two arrays:

1 - matches[type1][type2] with type2 sorted by score, use this as a stack
2 - meetings[type2][slot], to be populated

Each node of type 1 is supposed to get 6 meetings with a matching type2 out of 12 slots

for meeting = 1 to 6
for each type1
for each session
if meetings[matches[type1][0]][session] is empty, meetings[matches[type1][0]] == array_pop(matches[type1])
exit to next type1
else next session
end session loop
end type loop
end meeting loop

Any suggestions of modules that might offer some of this functionality? It seems to me that it could be generally useful for scheduling classes to rooms, students to classes, patrons to tables, etc.

Comments

jfberroyer’s picture

I'm not sure to understand everything, but I think your needs (scheduling classes to rooms, students to classes, patrons to tables, etc.) suppose to associate nodes of a type with nodes of an other type, but with Associated Nodes you can only associate nodes of type A or B with nodes of type A or B (and not associate node of type A only with nodes of type B only). This should be a feature in a next release because the applications you describe sound really interesting.

emdalton’s picture

I figured out how to only associate type A with type B, not A and B, by creating an invisible field containing the content type, and creating a negative association for that field. The part I still haven't figured out is the scheduling. I have the algorithm, and I've been tinkering around with trying to figure out how to implement it in PHP, but I haven't got it working yet. I'm by no means a PHP expert, let alone fluent in Drupal API. Here's what I was working on, in case you find it at all helpful:

Script to schedule best matches between two data types
To force ordering of criteria, use exponential progression for score points, e.g. 1, 2, 4, 8, 16

Get data type 1 - Available resource
Get data type 2 - needs minimum of resource 1
Get type 2 minimum match score $minmatchscore e.g. if top 2 (of 5) must match, min is 24, as all others added up will not suffice
Get type 2 maximim number of matches needed: $maxmatchnum

Get number of slots $timeslots (e.g. 12)
Get length of slots in minutes as $slotlength (e.g. 15)

Get name (or id) of association algorithm to use

Get list of matches


/* construct array from database list: need database access functions */
/* final associative array will be $matchindex[type2][type1] = matchscore */
/* $matchindex[type2] is an associative array of type1 values and match scores */

$db = DB::connect('<removed>');
$q = $db->query('SELECT company, investor, matchscore FROM association_cache'); (or whatever table is)
while ($row = $q->fetchRow()) {
  $matchindex[$row[0]][$row[1]] = $row[2];
} /* end loading array */

/* Or do it this way:
$db->SetFetchMode(DB_FETCHMODE_ASSOC);
$matchindex = $db->getAll('SELECT company, investor, matchscore FROM association_cache');
*/

/* drupal style

$result = db_query_range('SELECT n.nid, n.title, n.created
FROM {node} n WHERE n.uid = %d', $uid, 0, 10);
while ($node = db_fetch_object($result)) {
// Perform operations on $node->body, etc. here.
  }


*/

/* within the $matchindex array we just created, sort each collection of $matchindex[type2] by type1. */
/* also, construct parallel array of counts as $matches[type2] = count. */

foreach ($matchindex as $thisType2 => $theseScores) /* $theseScores is an array of scores by investor */
{
	$companyScores = $matchindex[$thisType2]; /* an array of scores (values) by investor (key) for $thisType2 */
	asort($companyScores); /* within each company, sort investor keys by score value */
	$matchcount[$thisType2] = count($companyScores);
} /* end sort $matchindex */

/* now need to sort $matches by value, which is the count of type1 per type2 */
/* this needs parallel arrays, we set $matches earlier */

asort($matchcount); /* this orders the list of key values (company names) by the number of matches they each have */

$type1count = $db->query(SELECT COUNT (DISTINCT type1) FROM associations WHERE 'aid' = 1);

$totalslots = $type1count * $timeslots;

while ($slotsUsed <= $totalslots) {


	/* build array $appointment[type1][slot] = [type2] -- type2 is the value */

	foreach ($matchcount as $thisType2 => $thisCount) {
		$thisType1 = $matchindex[$thisType2][0]; /* take the first type1 from the presorted matching list */
		if count($appointment_reverse[$thisType2]) < $maxmatch {
			foreach ($appointment[$thisType1] as $slotindex => $thisSlotType2) {
			/* check to make sure this type2 isn't already scheduled in this time slot */
				if (!appointment[$thisType1][$thisSlot] && !in_array($thisSlot, $appointment_reverse[$thisType2])) 	{
					$appointment[$thisType1][$thisSlot] = $thisType2;
					$appointment_reverse[$thisType2][$thisSlot] = $thisType1;
					unset($matchindex[$thisType2][$thisType1]);
					$success = 1;
					$slotsUsed++;
				} /* end check for sched conflict */
			} /* end foreach slot for that type1 */
		} /* end check to see if this type2 has plenty of appointments already */
		if (!$success) {
			print "Unable to schedule " . $thisType2 . "with " . $thisType1 . ", no remaining slots, score was " . $matchindex[$thisType2][$thisType1];
			unset($matchindex[$thisType2][$thisType1]);
			$success = 0;
		} /* end unsuccessful schedule handling */

 	} /*end foreach type2 - go to the next type2*/

	/* This will only go through once. Need a "while" loop to stop when all the slots are full or the array is empty. */
	/* will it automatically reset foreach? Should.... */

} /* end while -- out of slots */