Logo Search packages:      
Sourcecode: tablix2 version File versions  Download package

sameday.c

/* TABLIX, PGA general timetable solver                              */
/* Copyright (C) 2002-2004 Tomaz Solc                                      */

/* This program 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 2 of the License, or       */
/* (at your option) any later version.                                     */

/* This program 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 this program; if not, write to the Free Software             */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */

/* $Id: sameday.c,v 1.1.2.3 2005/09/02 19:30:38 avian Exp $ */

/** @module
 *
 * @author Tomaz Solc 
 * @author-email tomaz.solc@siol.net
 *
 * @credits
 * Ideas taken from a patch for Tablix 0.0.3 by 
 * Jaume Obrador <obrador@espaiweb.net>
 *
 * @brief 
 * Adds a weight if a class has the same subject twice (i.e. two events
 * with the same name) in a day. Adds two weights if three times in a day, etc.
 *
 * @ingroup School scheduling
 */

/** @resource-restriction ignore-sameday
 *
 * <resourcetype type="class">
 *    <resource name="example-class">
 *          <restriction type="ignore-sameday"/>
 *    </resource>
 * </resourcetype>
 *
 * Set this restriction to a class that you don't want to be checked for 
 * multiple occurrences of the same subject in a day. This module ignores 
 * classes that have this restriction.
 */

/** @tuple-restriction ignore-sameday
 *
 * Set this restriction to all events that you do not want to be checked for
 * multiple occurences per day.
 */

/** @tuple-restriction consecutive 
 *
 * This is an alias for "ignore-sameday" restriction. It makes this module 
 * compatible with "consecutive.so".
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "module.h"

static int *ignore;
static int *ignore_event;

static int classid;
static int classnum;

static int periods, days;

static struct namemap_t {
      char *name;
      int num;
} *namemap;

static int namemapnum;

static int *tuplenamemap;

static int *su;

int getignoresameday(char *restriction, char *content, resource *res)
{
      ignore[res->resid]=1;

      return 0;
}

int getevent(char *restriction, char *cont, tupleinfo *tuple)
{
      int tupleid;

      if(*cont) {
            error(_("restriction '%s' does not take an argument"), 
                                                restriction);
            return(-1);
      }

      tupleid=tuple->tupleid;

      ignore_event[tupleid]=1;

      return 0;
}


int module_fitness(chromo **c, ext **e, slist **s)
{
      int a,b,d;
      int resid;
      int flag;
      int sum;

      int nsu;

      int nameid;

      int tupleid;

      int time;

      ext *cext=e[0];

      assert(cext->connum==classnum);

      sum=0;
      for(resid=0;resid<classnum;resid++) if(ignore[resid]==0) {
            time=0;
            for(d=0;d<days;d++) {
                  nsu=0;
                  for(b=0;b<periods;b++) {
                        tupleid=cext->tupleid[time][resid];
                        if(tupleid!=-1&&!ignore_event[tupleid]) {
                              flag=1;
                              nameid=tuplenamemap[tupleid];

                              for(a=0;a<nsu;a++) {
                                    if(nameid==su[a]) {
                                          sum++;
                                          flag=0;
                                          break;
                                    }
                              }
                              if(flag) {
                                    su[nsu]=nameid;
                                    nsu++;
                              }
                        }
                        time++;
                  }
            }
      }
      return(sum);
}

static int init_namemap()
{
      int n,m;

      int nameid;

      /* We have at most dat_tuplenum different tuple names. */
      namemap=malloc(sizeof(*namemap)*dat_tuplenum);
      namemapnum=0;

      tuplenamemap=malloc(sizeof(*tuplenamemap)*dat_tuplenum);

      if(namemap==NULL||tuplenamemap==NULL) return -1;
      
      for(n=0;n<dat_tuplenum;n++) {

            /* Search if we already know this tuple name */
            nameid=-1;
            for(m=0;m<namemapnum;m++) {
                  if(!strcmp(dat_tuplemap[n].name, namemap[m].name)) {
                        nameid=m;
                        break;
                  }
            }
            if(nameid==-1) {
                  /* This tuple name is new */
                  nameid=namemapnum;
                  namemap[nameid].name=strdup(dat_tuplemap[n].name);
                  namemapnum++;
            }

            tuplenamemap[n]=nameid;
      }

      return 0;
}

int module_precalc(moduleoption *opt)
{
      int resid,d;
      int result;

      if(init_namemap()) {
            error(_("Can't allocate memory"));
            return -1;
      }

      result=0;

      for(d=0;d<namemapnum;d++) {
            namemap[d].num=0;
      }

      for(resid=0;resid<classnum;resid++) if(ignore[resid]==0) {
            for(d=0;d<dat_tuplenum;d++) {
                  if(res_get_conflict(&dat_restype[classid],
                                    resid, 
                                    dat_tuplemap[d].resid[classid]
                                    )) {
                        namemap[tuplenamemap[d]].num++;
                  }
            }

            for(d=0;d<namemapnum;d++) {
                  if(namemap[d].num>days) {
                        error(_("Class '%s' has %d events "
                              "with name '%s', however only "
                              "%d days are defined"), 
                              dat_restype[classid].res[resid].name,
                              namemap[d].num,
                              namemap[d].name,
                              days);
                        result=-1;
                  }
                  namemap[d].num=0;
            }
      }

      return(result);
}


int module_init(moduleoption *opt)
{
      int c;
      fitnessfunc *fitness;

      c=res_get_matrix(restype_find("time"), &days, &periods);
      if(c) {
            error(_("Resource type 'time' is not a matrix"));
            return -1;
      }

      classid=restype_findid("class");
      if(classid<0) {
            error(_("Resource type '%s' not found"), "class");
            return -1;
      }

      classnum=dat_restype[classid].resnum;

      su=malloc(sizeof(*su)*periods);
      ignore=malloc(sizeof(*ignore)*classnum);
      ignore_event=malloc(sizeof(*ignore_event)*dat_tuplenum);
      if(ignore==NULL||su==NULL) {
            error(_("Can't allocate memory"));
            return -1;
      }

      for(c=0;c<classnum;c++) {
            ignore[c]=0;
      }

      for(c=0;c<dat_tuplenum;c++) {
            ignore_event[c]=0;
      }

      precalc_new(module_precalc);

      handler_res_new("class", "ignore-sameday", getignoresameday);
      handler_tup_new("ignore-sameday", getevent);
      handler_tup_new("consecutive", getevent);

      fitness=fitness_new("sameday",
                  option_int(opt, "weight"),
                  option_int(opt, "mandatory"),
                  module_fitness);

      if(fitness_request_ext(fitness, "class", "time")) return -1;

      return 0;
}


Generated by  Doxygen 1.6.0   Back to index