#region License Information
/* HeuristicLab
* Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using HeuristicLab.Data;
using HeuristicLab.Core;
namespace HeuristicLab.Scheduling.JSSP {
public class ScheduleTreeNode {
private TimeSlot data;
private ScheduleTreeNode left;
private ScheduleTreeNode right;
private ScheduleTreeNode parent;
public ScheduleTreeNode(TimeSlot t) {
data = t;
}
public ScheduleTreeNode Left {
get { return left; }
set { left = value; }
}
public ScheduleTreeNode Right {
get { return right; }
set { right = value; }
}
public ScheduleTreeNode Parent {
get { return parent; }
set { parent = value; }
}
public void SetLeft(ScheduleTreeNode child) {
this.Left = child;
child.Parent = this;
}
public void SetRight(ScheduleTreeNode child) {
this.Right = child;
child.Parent = this;
}
public TimeSlot Data {
get { return data; }
set { data = value; }
}
}
public class ScheduleTree : StorableBase {
private ScheduleTreeNode root;
public ScheduleTreeNode Root {
get { return root; }
}
private int timespan;
public int Timespan {
get { return timespan; }
}
public ScheduleTree(int timespan) {
root = new ScheduleTreeNode(new TimeSlot(0, timespan));
this.timespan = timespan;
}
public ScheduleTree() : this(10000) { }
private int InsertOperation(Operation op) {
return Insert(this.Root, op);
}
private int InsertOperation(TimeSlot t) {
return Insert(this.Root, t.operation);
}
// ToDo: Rewrite code! (not efficient)
public int Insert(Operation op) {
foreach(ScheduleTreeNode node in this.InOrder) {
int start = Math.Max(node.Data.start, op.Start);
if((IsLeaf(node)) && (FitsIntoEmptySlot(node.Data, start, op.Duration))) {
op.Start = start;
return Insert(node, op);
}
}
return -1;
}
private bool FitsIntoEmptySlot(TimeSlot slot, int start, int duration) {
// beware of operations with processing time zero --> check operation != null
return ((slot.free >= duration) && (slot.start <= start) && (slot.end >= start + duration) && (slot.operation == null));
}
private void UpdateMaxFreeSlot(ScheduleTreeNode slot) {
while(slot != null) {
if(!IsLeaf(slot)) {
int newMax = Math.Max(slot.Left.Data.maxFreeSlot, slot.Right.Data.maxFreeSlot);
slot.Data.free = slot.Left.Data.free + slot.Right.Data.free;
slot.Data.maxFreeSlot = newMax;
}
slot = slot.Parent;
}
}
public int Insert(ScheduleTreeNode slot, Operation op) {
if (op == null) {
return -1;
}
int end = op.Start + op.Duration;;
if(slot.Data.maxFreeSlot < op.Duration) {
return -1;
}
if(IsLeaf(slot)) {
// fits exactly into slot; beware of operations with processing time 0 --> check operation != null
if((slot.Data.start == op.Start) && (slot.Data.end == end) && (slot.Data.operation == null)) {
slot.Data = new TimeSlot(op);
UpdateMaxFreeSlot(slot);
return op.Start;
}
// empty slot before op.
if(slot.Data.start < op.Start) {
ScheduleTreeNode empty1 = new ScheduleTreeNode(new TimeSlot(slot.Data.start, op.Start));
slot.SetLeft(empty1);
if(slot.Data.end > end) {
ScheduleTreeNode empty2 = new ScheduleTreeNode(new TimeSlot(op.Start, slot.Data.end));
slot.SetRight(empty2);
return Insert(empty2, op);
} else {
slot.SetRight(new ScheduleTreeNode(new TimeSlot(op)));
UpdateMaxFreeSlot(slot);
return op.Start;
}
}
// empty after op.
if(slot.Data.end > end) {
ScheduleTreeNode occupied = new ScheduleTreeNode(new TimeSlot(op));
ScheduleTreeNode empty2 = new ScheduleTreeNode(new TimeSlot(end, slot.Data.end));
slot.SetRight(empty2);
slot.SetLeft(occupied);
UpdateMaxFreeSlot(slot);
return op.Start;
}
} else {
if(slot.Left.Data.end < end) {
return Insert(slot.Right, op);
} else {
return Insert(slot.Left, op);
}
}
return -1;
}
public bool IsLeaf(ScheduleTreeNode slot) {
return ((slot.Right == null) && (slot.Left == null));
}
public ScheduleTreeNode GetFirstNode() { // left-most slot
ScheduleTreeNode node = root;
while (node.Left != null) {
node = node.Left;
}
return node;
}
public ScheduleTreeNode GetLastNode() { // right-most slot
ScheduleTreeNode node = root;
while (node.Right != null) {
node = node.Right;
}
return node;
}
public override string ToString() {
StringBuilder builder = new StringBuilder();
foreach(ScheduleTreeNode node in this.InOrder) {
if(IsLeaf(node)) {
builder.Append(node.Data.ToString());
builder.Append(";");
}
}
return builder.ToString();
}
#region IEnumerable Members
public IEnumerable InOrder {
get { return ScanInOrder(root); }
}
IEnumerable ScanInOrder(ScheduleTreeNode root) {
if(root.Left != null) {
foreach(ScheduleTreeNode node in ScanInOrder(root.Left)) {
yield return node;
}
}
yield return root;
if(root.Right != null) {
foreach(ScheduleTreeNode node in ScanInOrder(root.Right)) {
yield return node;
}
}
}
#endregion
#region IStorable Members
public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary persistedObjects) {
XmlNode node = base.GetXmlNode(name, document, persistedObjects);
node.InnerText = this.ToString();
return node;
}
public override void Populate(XmlNode node, IDictionary restoredObjects) {
base.Populate(node, restoredObjects);
string[] tokens = node.InnerText.Split(';');
for(int i = 0; i < tokens.Length - 1; i++) {
TimeSlot t = new TimeSlot(tokens[i]);
if(t.job > -1) {
this.InsertOperation(t);
}
}
}
public override object Clone(IDictionary clonedObjects) {
ScheduleTree clone = new ScheduleTree(timespan);
clonedObjects.Add(Guid, clone);
foreach (ScheduleTreeNode node in this.InOrder) {
if (IsLeaf(node) && (node.Data.job > -1)) {
clone.InsertOperation(node.Data);
}
}
return clone;
}
#endregion
}
}