コード例 #1
0
ファイル: BiDirScheduler.cpp プロジェクト: DrSobik/IPPS
bool BiDirScheduler::schedule(ProcessModel &pm, Resources &rc, Schedule &schedule) {
	Debugger::info << "Building schedule using simple bidirectional approach." << ENDL;

	/** Algorithm:
	 * 
	 * Lv - set of head scheduled operations;
	 * Lr - set of tail scheduled operations;
	 * Av - set of additionally head-schedulable operations;
	 * Ar - set of additianally tail-schedulable operations;
	 *  
	 *  1. Lv = Lr = 0; 
	 *	   Av = first available operations of the graph;
	 *     Ar = first available operations in the reverse graph.
	 * 
	 *  2. While  Av + Ar != 0
	 * 
	 *  2.a) select operation from Av according to some priority rule;
	 *  2.b) schedule the selected operation as soon as possible;
	 *  2.c) include the operation into Lv and exclude it from Av
	 *  2.d) select next available operation(s) which are not in Ar + Lr and insert them into Av
	 * 
	 *  2.e) select operation from Ar according to some priority rule;
	 *  2.f) schedule the selected operation as late as possible before all of the operations from Lr;
	 *  2.g) include the operation into Lr and exclude it from Ar;
	 *  2.h) select next available operation(s) (in inverse graph) which are not in Av + Lv and insert them into Ar.
	 *  
	 *	3. Shift left the start times of the operations from Lr so that they start immediately after latest from Lv finishes.
	 *  
	 * */

	QTextStream out(stdout);

	QList<ListDigraph::Node> Lv;
	QList<ListDigraph::Node> Lr;
	QList<ListDigraph::Node> Av;
	QList<ListDigraph::Node> Ar;
	QList<ListDigraph::Node> Avnext;
	QList<ListDigraph::Node> Lravail; // Currently available nodes from Lr

	QMap<ListDigraph::Node, Machine*> nodemachLr; // Assignments of the operations from Lr to the machines
	QHash<int, double> backmach; // Machines for backward operation scheduling <machine ID, time for operation finish>

	for (int i = 0; i < rc.machines().size(); i++) {
		backmach[rc.machines()[i]->ID] = 10000000;
	}

	ListDigraph::NodeMap<bool> nodesscheduled(pm.graph, false); // Scheduled nodes
	bool nodeavail; // Used for checking whether some node is available fro scheduling
	ListDigraph::Node curnode;

	Lv.clear();
	Lr.clear();
	Av.clear();
	Ar.clear();

	// Initialize the sets of operations Av
	for (ListDigraph::OutArcIt gait(pm.graph, pm.head); gait != INVALID; ++gait) {
		for (ListDigraph::OutArcIt lait(pm.graph, pm.graph.target(gait)); lait != INVALID; ++lait) {
			Av.append(pm.graph.target(lait));
		}
	}

	//out << "Operations of Av:" << endl;
	//for (int i = 0; i < Av.size(); i++) {
	//	out << Av[i] << endl;
	//}

	// Initialize the sets of operations Ar
	for (ListDigraph::InArcIt gait(pm.graph, pm.tail); gait != INVALID; ++gait) {
		for (ListDigraph::InArcIt lait(pm.graph, pm.graph.source(gait)); lait != INVALID; ++lait) {
			Ar.append(pm.graph.source(lait));
			//Ar.append(pm.graph.source(gait));
		}
	}



	//out << "Operations of Ar:" << endl;
	//for (int i = 0; i < Ar.size(); i++) {
	//	out << *pm.ops[Ar[i]] << endl;
	//}

	//getchar();

	NodeWeightComparatorGreater nwcg(&pm);

	// Run the loop
	while (Av.size() + Ar.size() > 0) {

		// Scheduling one operation from Av
		Avnext.clear();

		//out << "Scheduling operations" << endl;
		//for (int i = 0; i < Av.size(); i++) {
		//	out << pm.ops[Av[i]]->ID <<" ";
		//}
		//out<<endl;
		if (Av.size() > 0) {
			// Sort the nodes of Av
			qSort(Av.begin(), Av.end(), nwcg);

			curnode = Av[0];

			// Schedule the first operation (as soon as possible)
			//Machine &m = rc(pm.ops[Av[0]]->toolID).nextAvailable();

			// Select the fastest available machine from the corresponding tool group
			//Machine &m = rc(pm.ops[Av[0]]->toolID).fastestAvailable(pm.ops[Av[0]]->r(), pm.ops[Av[0]]->type);

			// Select the machine from the corresponding tool group to finish the operation the earliest
			Machine &m = rc(pm.ops[curnode]->toolID).earliestToFinish(pm.ops[curnode]);

			m << pm.ops[curnode];
			nodesscheduled[curnode] = true;

			// Include the operation into Lv
			Lv.append(curnode);

			// Iterate through all child nodes of the current node
			for (ListDigraph::OutArcIt oait(pm.graph, curnode); oait != INVALID; ++oait) {
				if (!Lr.contains(pm.graph.target(oait)) && !Ar.contains(pm.graph.target(oait))) {
					// Check availability
					nodeavail = true;
					for (ListDigraph::InArcIt iait(pm.graph, pm.graph.target(oait)); iait != INVALID; ++iait) {
						nodeavail = nodeavail && nodesscheduled[pm.graph.source(iait)];
					}
					if (nodeavail) {
						//out << "Now available : " << pm.graph.id(cursucc) << endl;
						// Update ready time of the newly enabled node
						pm.ops[pm.graph.target(oait)]->r(0.0);
						for (ListDigraph::InArcIt init(pm.graph, pm.graph.target(oait)); init != INVALID; ++init) {
							pm.ops[pm.graph.target(oait)]->r(Math::max(pm.ops[pm.graph.target(oait)]->r(), pm.ops[pm.graph.source(init)]->c()));
						}

						//if (!nodesscheduled[pm.graph.target(oait)]) {
						Av/*next*/.append(pm.graph.target(oait));
						//}
					}
				}
			}

			// Exclude the operation from Av
			Av.removeAt(0);
		}
		//getchar();

		//Av = Avnext;

		// Scheduling one operation from Ar
		if (Ar.size() > 0) {
			// Sort the nodes of Ar
			qSort(Ar.begin(), Ar.end(), nwcg);

			curnode = Ar.last();

			// Schedule the operation with as late as possible before all operations from Lr
			// The operation with the smallest priority is selected

			//Machine &m = rc(pm.ops[curnode]->toolID).nextAvailable();

			// Select the fastest available machine from the corresponding tool group
			//Machine &m = rc(pm.ops[curnode]->toolID).fastestAvailable(10000000, pm.ops[curnode]->type);

			// Select the random machine from the corresponding tool group
			//Machine &m = rc(pm.ops[curnode]->toolID).randomMachine();

			// Find machine which could start this operation the latest
			Machine *m = NULL;
			double lateststarttime = 0.0;
			double curstarttime;

			// Iterate over all machines able to process the operation
			QList<Machine*> machines = rc(pm.ops[curnode]->toolID).machines();
			for (int i = 0; i < machines.size(); i++) {
				curstarttime = backmach[machines[i]->ID] - machines[i]->procTime(pm.ops[curnode]);

				if (lateststarttime <= curstarttime) {
					lateststarttime = curstarttime;
					m = machines[i];
				}
			}
			
			backmach[m->ID] = lateststarttime;

			// Select the machine from the corresponding tool group to finish the operation the earliest
			//Machine &m = rc(pm.ops[curnode]->toolID).earliestToFinish(pm.ops[curnode]);

			//m << pm.ops[curnode];
			nodemachLr[curnode] = m;
			//nodesscheduled[curnode] = true;


			// Include the operation into Lr
			Lr.prepend(curnode);

			// Iterate through all parent nodes of the current node
			for (ListDigraph::InArcIt iait(pm.graph, curnode); iait != INVALID; ++iait) {
				if (!Lv.contains(pm.graph.source(iait)) && !Av.contains(pm.graph.source(iait))) {
					Ar.prepend(pm.graph.source(iait));
				}
			}

			// Exclude the operation from Av
			Ar.removeLast();
		}

		//out << "Av size = " << Av.size() << endl;

	}

	// Shift left all of the operations from Lr so that the earliest from them is started as soon as possible

	//out << "Operations in nodemachLr: " << endl;
	//for (int i = 0; i < nodemachLr.size(); i++) {
	//	out << *pm.ops[nodemachLr[i].first] << endl;
	//}

	//getchar();


	QList<ListDigraph::Node> keys;
	while (nodemachLr.size() > 0) {

		keys = nodemachLr.keys();

		// Collect currently available (immediately schedulable) nodes from Lr
		Lravail.clear();
		for (int i = 0; i < nodemachLr.size(); i++) {
			for (ListDigraph::InArcIt iait(pm.graph, keys[i]); iait != INVALID; ++iait) {
				if (Lv.contains(pm.graph.source(iait)) && nodesscheduled[pm.graph.source(iait)]) {
					Lravail.append(keys[i]);
					Lv.append(keys[i]);
					//Lr.removeOne(nodemachLr.keys()[i]);
					break;
				}
			}
		}

		//
		//Sort the nodes in Lravail
		qSort(Lravail.begin(), Lravail.end(), nwcg);

		//out << "Lravail operations before ready times update:" << endl;
		//for (int i = 0; i < Lravail.size(); i++) {
		//	out << *pm.ops[Lravail[i]] << endl;
		//}
		//getchar();

		// Update the ready time of the operations in Lravail and schedule them
		for (int i = 0; i < Lravail.size(); i++) {
			pm.ops[Lravail[i]]->r(0.0);
			for (ListDigraph::InArcIt iait(pm.graph, Lravail[i]); iait != INVALID; ++iait) {
				pm.ops[Lravail[i]]->r(Math::max(pm.ops[Lravail[i]]->r(), pm.ops[pm.graph.source(iait)]->c()));
			}

			// Schedule the available nodes
			*(nodemachLr.value(Lravail[i])) << pm.ops[Lravail[i]];
			nodesscheduled[Lravail[i]] = true;
			nodemachLr.remove(Lravail[i]);
		}

		//out << "Lravail operations after ready times update:" << endl;
		//for (int i = 0; i < Lravail.size(); i++) {
		//	out << *pm.ops[Lravail[i]] << endl;
		//}
		//getchar();
	}

	//out << "Resources after scheduling" << endl;
	//out << rc << endl;

	// Iterate over all nodes directly preceding the tail and
	//Debugger::info << "Collecting schedule data ..." << ENDL;
	schedule.objective = 0.0;
	for (ListDigraph::ArcIt ait(pm.graph); ait != INVALID; ++ait) {
		if (pm.graph.target(ait) == pm.tail) {
			if (pm.ops[pm.graph.source(ait)]->ID < 0) {
				for (ListDigraph::InArcIt iait(pm.graph, pm.graph.source(ait)); iait != INVALID; ++iait) {
					schedule.objective += pm.ops[pm.graph.source(iait)]->wT();
				}
			} else {
				schedule.objective += pm.ops[pm.graph.source(ait)]->wT();
			}
		}
	}

	//Debugger::info << "Done collecting schedule data." << ENDL;

	return true;


	// Run BFS on the reverse graph to set due date for the operations

	Operation *so;
	Operation *to;
	ReverseDigraph<ListDigraph> rg(pm.graph);
	Bfs<ReverseDigraph<ListDigraph> > bfsr(rg);
	bfsr.init();
	bfsr.addSource(pm.tail);

	//out << "Running BFS algorithm on the reverse graph ..." << endl;
	while (!bfsr.emptyQueue()) {
		curnode = bfsr.processNextNode();
		if (pm.ops[curnode]->ID < 0) continue;

		//out << "Processing node with id= " << rg.id(curnode) << " " << *(pm.ops[curnode]) << endl;

		//out << "Next available nodes:" << endl;
		for (ReverseDigraph<ListDigraph>::OutArcIt it(rg, curnode); it != INVALID; ++it) {
			// Update the due dates of the reverse target nodes
			// Rev. target d == rev. source d. - rev. source longest processing time
			so = pm.ops[rg.source(it)];
			to = pm.ops[rg.target(it)];
			to->d(so->d() - rc(so->toolID).slowestMachine(so->type).procTime(so));

			//out << "Node with id= " << rg.id(rg.target(it)) << " " << *(pm.ops[rg.target(it)]) << endl;
		}

	}
	so = to = NULL;
	//out << "Done running BFS algorithm on the reverse graph." << endl;




	return true;
}