correction to mrp-assignment.c patch
- From: Lee Baylis <lee leebaylis co uk>
- To: planner-dev-list gnome org
- Subject: correction to mrp-assignment.c patch
- Date: Mon, 01 Dec 2008 01:07:25 +0000
Hi all,
apologies - the recent patch I submitted for mrp-assignment.c doesn't
take account of the asymmetrical nature of 'units_in_use' (i.e.,
units_in_use stores units to the right of an edge). As a result, whilst
the code for mrp_assignment_edges_remove_from_first_after does exactly
what it says, it is not a useful routine to deploy in resource
overallocation calculations.
I have replaced the function with the simpler
mrp_assignment_edges_remove_after, which is more useful. Hopefully this
will get through before those patches make it to commit!
Also attached are the updated call to the function in mrp-resource.c, as
well as the header and changelog.
Sorry about that!
lee
Index: ChangeLog
===================================================================
--- ChangeLog (revision 940)
+++ ChangeLog (working copy)
@@ -1,3 +1,40 @@
+2008-11-28 Lee Baylis <lee leebaylis co uk>
+
+ * libplanner/mrp-assignment.c (assignment_edge_compare),
+ (mrp_assignment_edges_insert_sorted_from_assignment),
+ (mrp_assignment_edges_insert_sorted_from_assignment_list),
+ (mrp_assignment_edges_plot_units_in_use),
+ (mrp_assignment_edges_calculate_max_units_in_use),
+ (mrp_assignment_edges_remove_to_last_before),
+ (mrp_assignment_edges_remove_after),
+ (mrp_assignment_edge_get_delta_units):
+ Moved and changed Date struct from planner-usage-row to become
+ MrpAssignmentEdge struct;
+ Introduced functions for creating and manipulating lists of
+ MrpAssignmentEdge objects.
+ * libplanner/mrp-assignment.h:
+ * libplanner/mrp-resource.c (mrp_resource_get_assignment_edges),
+ (mrp_resource_allocation_status),
+ (mrp_resource_test_if_overallocated),
+ (resource_get_edges_with_units_in_use),
+ (mrp_resource_get_max_units_used_between),
+ (mrp_resource_get_available_units_between),
+ (mrp_resource_get_available_units_during):
+ Moved logic for calculating overallocation from planner-usage-row;
+ Introduced functions for listing and analysing a resource's
+ MrpAssignmentEdge objects;
+ Introduced resource overallocation test function.
+ * libplanner/mrp-resource.h:
+ * src/planner-usage-row.c (usage_row_realize),
+ (usage_row_draw_resource_ival), (usage_row_draw_resource),
+ (usage_row_draw_assignment):
+ Moved Date & date_type structs and the date_compare
+ function to mrp-assignment;
+ Moved code which initialised Dates to mrp-assignment;
+ Replaced 12 color variables with 4 color_scheme structs
+ and matched them to overallocation scenarios;
+ Moved logic for calculating overallocation to mrp-resource.
+
2008-11-05 Maurice van der Pot <griffon26 kfk4ever com>
* libplanner/mrp-parser.c: Removed unused function.
Index: libplanner/mrp-assignment.c
===================================================================
--- libplanner/mrp-assignment.c (revision 940)
+++ libplanner/mrp-assignment.c (working copy)
@@ -3,6 +3,7 @@
* Copyright (C) 2001-2003 CodeFactory AB
* Copyright (C) 2001-2003 Richard Hult <richard imendio com>
* Copyright (C) 2001-2002 Mikael Hallendal <micke imendio com>
+ * Copyright (C) 2008 Lee Baylis <lee leebaylis co uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -43,19 +44,20 @@
PROP_UNITS
};
+static void assignment_class_init (MrpAssignmentClass *klass);
+static void assignment_init (MrpAssignment *assignment);
+static void assignment_finalize (GObject *object);
+static void assignment_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void assignment_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static gint assignment_edge_compare (gconstpointer edge1,
+ gconstpointer edge2);
-static void assignment_class_init (MrpAssignmentClass *klass);
-static void assignment_init (MrpAssignment *assignment);
-static void assignment_finalize (GObject *object);
-static void assignment_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec);
-static void assignment_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec);
-
static MrpObjectClass *parent_class;
GType
@@ -226,6 +228,33 @@
}
}
+static gint
+assignment_edge_compare (gconstpointer edge1,
+ gconstpointer edge2)
+{
+ const MrpAssignmentEdge *a, *b;
+
+ a = edge1;
+ b = edge2;
+
+ if (a->time < b->time) {
+ return -1;
+ }
+ else if (a->time == b->time) {
+ /* if times are equal, overallocation calculations require that end_edges are sorted before start_edges */
+ if (a->type < b->type) {
+ return 1;
+ }
+ else if (a->type == b->type) {
+ return 0;
+ } else {
+ return -1;
+ }
+ } else {
+ return 1;
+ }
+}
+
/**
* mrp_assignment_new:
*
@@ -267,8 +296,8 @@
*
* Retrieves the #MrpResource associated with @assignment.
*
- * Return value: the resource associated with the assignment object. The reference
- * count of the resource is not increased.
+ * Return value: the resource associated with the assignment object.
+ * The reference count of the resource is not increased.
**/
MrpResource *
mrp_assignment_get_resource (MrpAssignment *assignment)
@@ -294,3 +323,210 @@
return assignment->priv->units;
}
+
+/**
+ * mrp_assignment_edges_insert_sorted_from_assignment:
+ * @edges: a #GList optionally containing #MrpAssignmentEdge objects
+ * @assignment: an #MrpAssignment
+ *
+ * Determines the start and end edges (essentially times + assignment units)
+ * from an assignment's associated task, and inserts them into the list of
+ * edges sorted by mrptime. Mostly useful for tracking a MrpResource's
+ * total assignment units whilst scanning across a project.
+ *
+ * Return Value: pointer to the updated edges GList.
+ **/
+GList *
+mrp_assignment_edges_insert_sorted_from_assignment (GList *edges,
+ MrpAssignment *assignment)
+{
+ MrpTask *task;
+ gint units;
+ MrpAssignmentEdge *start_edge, *end_edge;
+
+ g_return_val_if_fail (MRP_IS_ASSIGNMENT (assignment), edges);
+
+ task = mrp_assignment_get_task (assignment);
+ units = mrp_assignment_get_units (assignment);
+
+ start_edge = g_new0 (MrpAssignmentEdge, 1);
+ start_edge->type = START_EDGE;
+ start_edge->time = mrp_task_get_work_start(task);
+ start_edge->units = units;
+ start_edge->assignment = assignment;
+ start_edge->task = task;
+
+ edges = g_list_insert_sorted (edges, start_edge, assignment_edge_compare);
+
+ end_edge = g_new0 (MrpAssignmentEdge, 1);
+ end_edge->type = END_EDGE;
+ end_edge->time = mrp_task_get_finish(task);
+ end_edge->units = units;
+ end_edge->assignment = assignment;
+ end_edge->task = task;
+
+ edges = g_list_insert_sorted (edges, end_edge, assignment_edge_compare);
+
+ return edges;
+}
+
+/**
+ * mrp_assignment_edges_insert_sorted_from_assignment_list:
+ * @edges: a #GList containing #MrpAssignmentEdge objects
+ * @assignments: a #GList contianing #MrpAssignment objects
+ *
+ * Determines the sorted start and end edges for all passed assignments.
+ * Mostly useful for scanning a #MrpResource object's total assignment
+ * units across a project.
+ *
+ * Return Value: pointer to the updated edges #GList.
+ **/
+GList *
+mrp_assignment_edges_insert_sorted_from_assignment_list (GList *edges,
+ GList *assignments)
+{
+ GList *a;
+ MrpAssignment *assignment;
+
+ for (a = assignments; a; a = a->next) {
+ assignment = a->data;
+ edges = mrp_assignment_edges_insert_sorted_from_assignment(edges, assignment);
+ }
+ return edges;
+}
+
+/**
+ * mrp_assignment_edges_plot_units_in_use:
+ * @edges: a #GList containing #MrpAssignmentEdge objects
+ *
+ * Iterates the #GList of #MrpAssignmentEdge objects calculating a
+ * running total for each #MrpAssignmentEdge by adding units for
+ * start edges and subtracting them for end edges. Mostly useful for
+ * calculating a #MrpResource object's allocation within a period.
+ *
+ * Return Value: pointer to the updated edges #GList.
+ **/
+GList *
+mrp_assignment_edges_plot_units_in_use (GList *edges)
+{
+ GList *e;
+ MrpAssignmentEdge *edge;
+ gint units = 0;
+
+ for (e = edges; e; e = e->next) {
+ edge = e->data;
+ units += mrp_assignment_edge_get_delta_units(edge);
+ edge->units_in_use = units;
+ }
+ return edges;
+}
+
+/**
+ * mrp_assignment_edges_calculate_max_units_in_use:
+ * @edges: a #GList containing #MrpAssignmentEdge objects
+ *
+ * Iterates the #GList of #MrpAssignmentEdge objects consulting the
+ * running total for each #MrpAssignmentEdge and storing the maximum.
+ *
+ * Return Value: #gint containing the maximum units in use.
+ **/
+gint
+mrp_assignment_edges_calculate_max_units_in_use (GList *edges)
+{
+ GList *e;
+ MrpAssignmentEdge *edge;
+ gint units = 0;
+
+ for (e = edges; e; e = e->next){
+ edge = e->data;
+ if (edge->units_in_use > units) {
+ units = edge->units_in_use;
+ }
+ }
+ return units;
+}
+
+/**
+ * mrp_assignment_edges_remove_to_last_before:
+ * @edges: a #GList containing #MrpAssignmentEdge objects
+ * @time: a #mrptime
+ *
+ * Removes all but the last #MrpAssignmentEdge object before @time from @edges.
+ * Mostly useful for isolating time periods for later calculation.
+ *
+ * Return Value: pointer to the updated edges #GList.
+ **/
+GList *
+mrp_assignment_edges_remove_to_last_before(GList *edges,
+ mrptime time)
+{
+ GList *e;
+ MrpAssignmentEdge *edge;
+
+ if (edges){
+ e = edges->next;
+ if (e){
+ edge = e->data;
+ while (edge->time <= time){
+ edges = g_list_delete_link(edges, edges);
+ e = edges->next;
+ if (!e) {break;}
+ edge = e->data;
+ }
+ }
+ }
+ return edges;
+}
+
+/**
+ * mrp_assignment_edges_remove_after:
+ * @edges: a #GList containing #MrpAssignmentEdge objects
+ * @time: a #mrptime
+ *
+ * Removes all #MrpAssignmentEdge objects after @time from @edges.
+ * Mostly useful for isolating time periods for later calculation.
+ *
+ * Return Value: pointer to the updated edges #GList.
+ **/
+GList *
+mrp_assignment_edges_remove_after(GList *edges,
+ mrptime time)
+{
+ GList *last;
+ MrpAssignmentEdge *edge;
+
+ if (edges){
+ last = g_list_last(edges);
+ if (last){
+ edge = last->data;
+ while (time <= edge->time){
+ edges = g_list_delete_link(edges, last);
+ last = g_list_last(edges);
+ if (!last) {break;}
+ edge = last->data;
+ }
+ }
+ }
+
+ return edges;
+}
+
+/**
+ * mrp_assignment_edge_get_delta_units:
+ * @edge: a #MrpAssignmentEdge
+ *
+ * Edge-sensing function: returns the change in units associated with
+ * an assignment, either signed positive for a start edge, or negative
+ * for an end edge.
+ *
+ * Return Value: gint representing the change in assignment units at the edge.
+ **/
+gint
+mrp_assignment_edge_get_delta_units (MrpAssignmentEdge *edge)
+{
+ if (edge->type == START_EDGE) {
+ return edge->units;
+ } else {
+ return 0 - edge->units;
+ }
+}
Index: libplanner/mrp-assignment.h
===================================================================
--- libplanner/mrp-assignment.h (revision 940)
+++ libplanner/mrp-assignment.h (working copy)
@@ -3,6 +3,7 @@
* Copyright (C) 2001-2002 CodeFactory AB
* Copyright (C) 2001-2002 Richard Hult <richard imendio com>
* Copyright (C) 2001-2002 Mikael Hallendal <micke imendio com>
+ * Copyright (C) 2008 Lee Baylis <lee leebaylis co uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -36,6 +37,8 @@
typedef struct _MrpAssignmentClass MrpAssignmentClass;
typedef struct _MrpAssignmentPriv MrpAssignmentPriv;
+typedef enum _MrpAssignmentEdgeType MrpAssignmentEdgeType;
+typedef struct _MrpAssignmentEdge MrpAssignmentEdge;
struct _MrpAssignment {
MrpObject parent;
@@ -47,12 +50,36 @@
MrpObjectClass parent_class;
};
-GType mrp_assignment_get_type (void) G_GNUC_CONST;
+enum _MrpAssignmentEdgeType{
+ START_EDGE,
+ END_EDGE
+};
-MrpAssignment *mrp_assignment_new (void);
+struct _MrpAssignmentEdge {
+ MrpAssignmentEdgeType type;
+ mrptime time;
+ gint units;
+ gint units_in_use;
+ MrpAssignment *assignment;
+ MrpTask *task;
+};
-MrpTask *mrp_assignment_get_task (MrpAssignment *assignment);
-MrpResource *mrp_assignment_get_resource (MrpAssignment *assignment);
-gint mrp_assignment_get_units (MrpAssignment *assignment);
+GType mrp_assignment_get_type (void) G_GNUC_CONST;
+MrpAssignment *mrp_assignment_new (void);
+
+MrpTask *mrp_assignment_get_task (MrpAssignment *assignment);
+MrpResource *mrp_assignment_get_resource (MrpAssignment *assignment);
+gint mrp_assignment_get_units (MrpAssignment *assignment);
+GList * mrp_assignment_edges_insert_sorted_from_assignment (GList *edges,
+ MrpAssignment *assignment);
+GList * mrp_assignment_edges_insert_sorted_from_assignment_list (GList *edges,
+ GList *assignments);
+GList * mrp_assignment_edges_plot_units_in_use (GList *edges);
+gint mrp_assignment_edges_calculate_max_units_in_use (GList *edges);
+GList * mrp_assignment_edges_remove_to_last_before (GList *edges,
+ mrptime time);
+GList * mrp_assignment_edges_remove_after (GList *edges,
+ mrptime time);
+gint mrp_assignment_edge_get_delta_units (MrpAssignmentEdge *edge);
#endif /* __MRP_ASSIGNMENT_H__ */
Index: libplanner/mrp-resource.c
===================================================================
--- libplanner/mrp-resource.c (revision 940)
+++ libplanner/mrp-resource.c (working copy)
@@ -5,6 +5,7 @@
* Copyright (C) 2002-2003 Richard Hult <richard imendio com>
* Copyright (C) 2002 Mikael Hallendal <micke imendio com>
* Copyright (C) 2004 Alvaro del Castillo <acs barrapunto com>
+ * Copyright (C) 2008 Lee Baylis <lee leebaylis co uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -32,6 +33,9 @@
#include "mrp-task.h"
#include "mrp-resource.h"
+/* Constant for usage calculations
+FIXME: need to alter the UI so that users can set the priv->units value per resource, then can remove this constant */
+#define USAGE_MAX_UNITS 100
struct _MrpResourcePriv {
gchar *name;
@@ -69,25 +73,27 @@
};
-static void resource_class_init (MrpResourceClass *klass);
-static void resource_init (MrpResource *resource);
-static void resource_finalize (GObject *object);
-static void resource_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec);
-static void resource_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec);
-static void resource_calendar_changed (MrpCalendar *calendar,
- MrpResource *resource);
-static void resource_removed (MrpObject *object);
-static void resource_invalidate_task_costs (MrpResource *resource);
-static void resource_assignment_removed_cb (MrpAssignment *assignment,
- MrpResource *resource);
-static void resource_group_removed_cb (MrpGroup *group,
- MrpResource *resource);
+static void resource_class_init (MrpResourceClass *klass);
+static void resource_init (MrpResource *resource);
+static void resource_finalize (GObject *object);
+static void resource_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void resource_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void resource_calendar_changed (MrpCalendar *calendar,
+ MrpResource *resource);
+static void resource_removed (MrpObject *object);
+static void resource_invalidate_task_costs (MrpResource *resource);
+static void resource_assignment_removed_cb (MrpAssignment *assignment,
+ MrpResource *resource);
+static void resource_group_removed_cb (MrpGroup *group,
+ MrpResource *resource);
+static GList *resource_get_edges_with_units_in_use (MrpResource *resource,
+ GList *edges);
static MrpObjectClass *parent_class;
@@ -826,3 +832,206 @@
g_object_set (resource, "calendar", calendar, NULL);
}
+
+/* There are two ways to look for overallocation:
+
+ - the first is to chart a running total of a resource's allocation
+ across the whole project, and scan through it looking for total values
+ of allocation at either a time or some condition.
+
+ This is the technique previously adopted in planner-usage-row,
+ now moved here and embellished upon.
+
+ - The second is to scan a resource's allocations for those which are
+ active at a given time, and add up the usage. Whilst this is likely a
+ more efficient method for larger projects, we are rarely interested in
+ an individual time, more usually a period between two times, and so it
+ is not clear right now whether implementing this second will be of any use.
+*/
+
+/**
+ * mrp_resource_get_assignment_edges:
+ * @resource: a #MrpResource
+ * @edges: a #GList optionally containing #MrpAssignmentEdge objects
+ *
+ * Adds all the assignment edges for the resource to the edges glist,
+ * sorted by mrptime. Usually you want this list to be empty before
+ * calling this function. Free the edges list when done. Mostly useful
+ * for calculating total resource allocation over the project.
+ *
+ * Return Value: the updated edges GList
+ **/
+GList *
+mrp_resource_get_assignment_edges (MrpResource *resource,
+ GList *edges)
+{
+ GList *assignments;
+ g_return_val_if_fail (MRP_IS_RESOURCE (resource), edges);
+
+ assignments = mrp_resource_get_assignments (resource);
+ edges = mrp_assignment_edges_insert_sorted_from_assignment_list(edges, assignments);
+
+ return edges;
+}
+
+/**
+ * mrp_resource_allocation_status:
+ * @resource: a #MrpResource
+ * @units: a #gint
+ *
+ * Lookup table for allocation status based on the number of units of a
+ * resource which are allocated
+ *
+ * Return Value: an entry from the MrpResourceAllocation enum
+ **/
+MrpResourceAllocation
+mrp_resource_allocation_status (MrpResource *resource, gint units)
+{
+ g_return_val_if_fail (MRP_IS_RESOURCE (resource), MRP_RESOURCE_OVERALLOCATED);
+/* FIXME: replace USAGE_MAX_UNITS on a per-resource basis rather than a defined constant */
+ if (units == 0) {
+ return MRP_RESOURCE_FREE;
+ }
+ else if (units < USAGE_MAX_UNITS) {
+ return MRP_RESOURCE_UNDERALLOCATED;
+ }
+ else if (units == USAGE_MAX_UNITS) {
+ return MRP_RESOURCE_ALLOCATED;
+ } else {
+ return MRP_RESOURCE_OVERALLOCATED;
+ }
+}
+
+/**
+ * mrp_resource_test_if_overallocated:
+ * @resource: a #MrpResource
+ *
+ * Scans the project duration for the resource and determines if it is
+ * ever overallocated.
+ *
+ * Return Value: gboolean inidcating whether resource is ever overallocated
+ **/
+gboolean
+mrp_resource_test_if_overallocated (MrpResource *resource)
+{
+ gint units;
+
+ g_return_val_if_fail (MRP_IS_RESOURCE (resource), TRUE);
+
+ units = mrp_resource_get_max_units_used_between(resource, NULL, NULL);
+
+ if (mrp_resource_allocation_status(resource, units) == MRP_RESOURCE_OVERALLOCATED){
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * resource_get_edges_with_units_in_use:
+ * @resource: a #MrpResource
+ *
+ * Return Value: a GList of MrpAssignmentEdge objects with the running total
+ * of units in use calculated.
+ *
+ **/
+GList *
+resource_get_edges_with_units_in_use (MrpResource *resource,
+ GList *edges)
+{
+ g_return_val_if_fail (MRP_IS_RESOURCE (resource), edges);
+
+ edges = mrp_resource_get_assignment_edges(resource, edges);
+ edges = mrp_assignment_edges_plot_units_in_use(edges);
+
+ return edges;
+}
+
+
+/**
+ * mrp_resource_get_max_units_used_between:
+ * @resource: a #MrpResource
+ * @start: a #mrptime marking the start of a period, or project start if #NULL
+ * @end: a #mrptime marking the end of a period, or project end if #NULL
+ *
+ * Plots cumulative allocation for the resource across the project,
+ * then scans between the start and end times given, and calculates
+ * the maximum allocation in this period.
+ *
+ * Return Value: gint indicating the maximum units which have been allocated
+ * to the resource in this period.
+ **/
+
+gint
+mrp_resource_get_max_units_used_between (MrpResource *resource,
+ mrptime start,
+ mrptime end)
+{
+ GList *edges = NULL;
+ gint units;
+
+ /* FIXME: replace USAGE_MAX_UNITS on a per-resource basis rather than a defined constant */
+ g_return_val_if_fail (MRP_IS_RESOURCE (resource), USAGE_MAX_UNITS + 1);
+
+ edges = resource_get_edges_with_units_in_use(resource, edges);
+
+ if (start){
+ edges = mrp_assignment_edges_remove_to_last_before(edges, start);
+ }
+ if (end){
+ edges = mrp_assignment_edges_remove_after(edges, end);
+ }
+
+ units = mrp_assignment_edges_calculate_max_units_in_use(edges);
+
+ g_list_free(edges);
+
+ return units;
+}
+
+/**
+ * mrp_resource_get_available_units_between:
+ * @resource: a #MrpResource
+ * @start: a #mrptime
+ * @end: a #mrptime
+ *
+ * Return Value: gint indicating the maximum units which are available
+ * for the resource in this period without causing overallocation.
+ **/
+gint
+mrp_resource_get_available_units_between (MrpResource *resource,
+ mrptime start,
+ mrptime end)
+{
+/* FIXME: replace USAGE_MAX_UNITS on a per-resource basis rather than a defined constant */
+ g_return_val_if_fail (MRP_IS_RESOURCE (resource), -1);
+ /* gint available;
+
+ available =*/
+ return USAGE_MAX_UNITS - mrp_resource_get_max_units_used_between(resource, start, end);
+
+ /* if (available < 0){
+ available = 0;
+ }
+ return available;*/
+}
+
+/**
+ * mrp_resource_get_available_units_during:
+ * @resource: a #MrpResource
+ * @task: a #MrpTask
+ *
+ * Return Value: gint indicating the maximum units which are available
+ * for the resource between the times the task is running, without
+ * causing overallocation.
+ **/
+gint
+mrp_resource_get_available_units_during (MrpResource *resource,
+ MrpTask *task)
+{
+ g_return_val_if_fail (MRP_IS_RESOURCE (resource), -1);
+ g_return_val_if_fail (MRP_IS_TASK (task), -1);
+
+ return mrp_resource_get_available_units_between(resource,
+ mrp_task_get_work_start(task),
+ mrp_task_get_finish(task));
+}
[Date Prev][
Date Next] [Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]