| /**************************************************************/ |
| /* ********************************************************** */ |
| /* * * */ |
| /* * PARTITION * */ |
| /* * * */ |
| /* * $Module: PARTITION * */ |
| /* * * */ |
| /* * Copyright (C) 1999, 2001 MPI fuer Informatik * */ |
| /* * * */ |
| /* * 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 * */ |
| /* * * */ |
| /* * * */ |
| /* $Revision$ * */ |
| /* $State$ * */ |
| /* $Date$ * */ |
| /* $Author$ * */ |
| /* * * */ |
| /* * Contact: * */ |
| /* * Christoph Weidenbach * */ |
| /* * MPI fuer Informatik * */ |
| /* * Stuhlsatzenhausweg 85 * */ |
| /* * 66123 Saarbruecken * */ |
| /* * Email: weidenb@mpi-sb.mpg.de * */ |
| /* * Germany * */ |
| /* * * */ |
| /* ********************************************************** */ |
| /**************************************************************/ |
| |
| |
| /**************************************************************/ |
| /* Include */ |
| /**************************************************************/ |
| |
| #include "partition.h" |
| |
| |
| /**************************************************************/ |
| /* Inline functions */ |
| /**************************************************************/ |
| |
| static __inline__ ECLASS part_GetClass(PARTITION p, ELEMENT e) |
| { |
| return p[e]; |
| } |
| |
| |
| static __inline__ PARTITION part_SetClass(PARTITION p, ELEMENT e, ECLASS c) |
| { |
| p[e] = c; |
| return p; |
| } |
| |
| |
| static __inline__ int part_GetClassSize(PARTITION p, ELEMENT e) |
| { |
| return p[p[part_CARD] + e]; |
| } |
| |
| |
| static __inline__ PARTITION part_SetClassSize(PARTITION p, ELEMENT e, int |
| classsize) |
| { |
| p[p[part_CARD] + e] = classsize; |
| return p; |
| } |
| |
| |
| static __inline__ int part_GetStamp(PARTITION p, ELEMENT e) |
| { |
| return p[-part_HEAD - 1 - e]; |
| } |
| |
| |
| static __inline__ PARTITION part_SetStamp(PARTITION p, ELEMENT e, int stamp) |
| { |
| p[-part_HEAD - 1 - e] = stamp; |
| return p; |
| } |
| |
| |
| static __inline__ BOOL part_Stamped(PARTITION p, ELEMENT e) |
| { |
| return part_GetStamp(p, e) == p[part_STAMPCOUNTER]; |
| } |
| |
| |
| static __inline__ ELEMENT part_DelayedInit(PARTITION p, ELEMENT e) |
| /*************************************************************** |
| RETURNS: the (now stamped) element |
| EFFECT: establishes the equivalence class {e} in p, thus |
| partially initializing p |
| ***************************************************************/ |
| { |
| if (!part_Stamped(p, e)) { |
| part_SetClass(p, e, -e - 1); /* representative e (>= 0) of {e} is coded */ |
| /* as -e - 1 (< 0) */ |
| part_SetClassSize(p, e, 1); |
| part_SetStamp(p, e, p[part_STAMPCOUNTER]); |
| } |
| return e; |
| } |
| |
| |
| /**************************************************************/ |
| /* Functions */ |
| /**************************************************************/ |
| |
| PARTITION part_Create(int size) |
| /**************************************************************** |
| RETURNS: the initial partition {{0}, {1}, {2}, ..., {size - 1}} |
| of the set {0, 1, 2, ..., size - 1} |
| ****************************************************************/ |
| { |
| PARTITION result; |
| |
| #ifdef CHECK |
| if (size < 0) { |
| misc_StartErrorReport(); |
| misc_ErrorReport("\n In part_Create: negative size %d.", size); |
| misc_FinishErrorReport(); |
| } |
| #endif |
| |
| result = (PARTITION) memory_Calloc(size * 3 + part_HEAD, sizeof(int)) |
| + size + part_HEAD; /* move pointer to the middle of the array */ |
| /* to allow negative indices */ |
| result[part_CARD] = size; |
| result[part_ALLOC] = size * 3 + part_HEAD; |
| result[part_STAMPCOUNTER] = 1; |
| return result; |
| } |
| |
| |
| PARTITION part_Init(PARTITION p, int size) |
| /**************************************************************** |
| RETURNS: the initial partition {{0}, {1}, {2}, ..., {size - 1}} |
| of the set {0, 1, 2, ..., size - 1} |
| EFFECT: stores the initial partition to p if it's big enough, |
| otherwise creates a new partition, therefore |
| CAUTION: must be called inside an assignment like: |
| p = part_Init(p, ...) |
| ****************************************************************/ |
| { |
| int alloc, i; |
| |
| #ifdef CHECK |
| if (size < 0) { |
| misc_StartErrorReport(); |
| misc_ErrorReport("\n In part_Init: negative size %d.", size); |
| misc_FinishErrorReport(); |
| } |
| #endif |
| |
| alloc = (p[part_ALLOC] - part_HEAD) / 3; |
| if (size > alloc) { |
| part_Free(p); |
| p = part_Create(size); |
| } |
| else { |
| p[part_CARD] = size; |
| p[part_STAMPCOUNTER]++; |
| |
| /* if a stamp overflow occurs, reinit stamps: */ |
| if (p[part_STAMPCOUNTER] <= 0) { |
| for (i = 0; i < alloc; i++) |
| part_SetStamp(p, i, 0); |
| p[part_STAMPCOUNTER] = 1; |
| } |
| |
| } |
| return p; |
| } |
| |
| |
| static ELEMENT part_NF(PARTITION p, ELEMENT e) |
| /*************************************************************** |
| RETURNS: the normal form element of the class [e]; this is an |
| element of [e] that sometimes differ from the |
| representative |
| EFFECT: makes the normal form to the direct parent of all |
| elements visited on the search path from e to this |
| normal form ("path compression") |
| ***************************************************************/ |
| { |
| ELEMENT nf, aux; |
| |
| #ifdef CHECK |
| if (!part_Element(p, e)) { |
| misc_StartErrorReport(); |
| misc_ErrorReport("\n In part_NF: %d not in partitioned set.", e); |
| misc_FinishErrorReport(); |
| } |
| #endif |
| |
| nf = e; |
| while (part_GetClass(p, part_DelayedInit(p, nf)) >= 0) |
| nf = part_GetClass(p, nf); |
| |
| /* path compression: */ |
| while (e != nf) { |
| aux = part_GetClass(p, e); |
| part_SetClass(p, e, nf); |
| e = aux; |
| } |
| |
| return nf; |
| } |
| |
| |
| ECLASS part_Find(PARTITION p, ELEMENT e) |
| /*************************************************************** |
| RETURNS: (the representative of) class [e] |
| ***************************************************************/ |
| { |
| |
| #ifdef CHECK |
| if (!part_Element(p, e)) { |
| misc_StartErrorReport(); |
| misc_ErrorReport("\n In part_Find: %d not in partitioned set.", e); |
| misc_FinishErrorReport(); |
| } |
| #endif |
| |
| return -part_GetClass(p, part_NF(p, e)) - 1; |
| /* representative e is coded as -e - 1 (cf. part_DelayedInit) */ |
| } |
| |
| |
| PARTITION part_Union(PARTITION p, ECLASS c1, ECLASS c2) |
| /*************************************************************** |
| RETURNS: the union of the classes |
| EFFECT: the representative of c1 is the representative of the |
| union |
| ***************************************************************/ |
| { |
| ELEMENT nf1, nf2, aux; |
| |
| #ifdef CHECK |
| if (!part_Element(p, c1)) { |
| misc_StartErrorReport(); |
| misc_ErrorReport("\n In part_Union: first class %d not in partitioned set.", |
| c1); |
| misc_FinishErrorReport(); |
| } |
| if (!part_Element(p, c2)) { |
| misc_StartErrorReport(); |
| misc_ErrorReport |
| ("\n In part_Union: second class %d not in partitioned set.", c2); |
| misc_FinishErrorReport(); |
| } |
| #endif |
| |
| nf1 = part_NF(p, c1); |
| nf2 = part_NF(p, c2); |
| if (nf1 != nf2) { |
| |
| /* make [nf1] the bigger (or at least not smaller) class: */ |
| if (part_GetClassSize(p, nf1) < part_GetClassSize(p, nf2)) { |
| aux = nf1; |
| nf1 = nf2; |
| nf2 = aux; |
| part_SetClass(p, nf1, part_GetClass(p, nf2)); |
| part_SetClass(p, -part_GetClass(p, nf2) - 1, nf1); |
| } |
| |
| part_SetClass(p, nf2, nf1); |
| part_SetClassSize(p, nf1, |
| part_GetClassSize(p, nf1) + part_GetClassSize(p, nf2)); |
| } |
| return p; |
| } |
| |