|
kusano |
7d535a |
/*! @file sp_coletree.c
|
|
kusano |
7d535a |
* \brief Tree layout and computation routines
|
|
kusano |
7d535a |
*
|
|
kusano |
7d535a |
*
|
|
kusano |
7d535a |
* -- SuperLU routine (version 3.1) --
|
|
kusano |
7d535a |
* Univ. of California Berkeley, Xerox Palo Alto Research Center,
|
|
kusano |
7d535a |
* and Lawrence Berkeley National Lab.
|
|
kusano |
7d535a |
* August 1, 2008
|
|
kusano |
7d535a |
*
|
|
kusano |
7d535a |
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
|
kusano |
7d535a |
*
|
|
kusano |
7d535a |
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
|
|
kusano |
7d535a |
* EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
|
kusano |
7d535a |
*
|
|
kusano |
7d535a |
* Permission is hereby granted to use or copy this program for any
|
|
kusano |
7d535a |
* purpose, provided the above notices are retained on all copies.
|
|
kusano |
7d535a |
* Permission to modify the code and to distribute modified code is
|
|
kusano |
7d535a |
* granted, provided the above notices are retained, and a notice that
|
|
kusano |
7d535a |
* the code was modified is included with the above copyright notice.
|
|
kusano |
7d535a |
*
|
|
kusano |
7d535a |
*/
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* Elimination tree computation and layout routines */
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
#include <stdio.h></stdio.h>
|
|
kusano |
7d535a |
#include <stdlib.h></stdlib.h>
|
|
kusano |
7d535a |
#include "slu_ddefs.h"
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/*
|
|
kusano |
7d535a |
* Implementation of disjoint set union routines.
|
|
kusano |
7d535a |
* Elements are integers in 0..n-1, and the
|
|
kusano |
7d535a |
* names of the sets themselves are of type int.
|
|
kusano |
7d535a |
*
|
|
kusano |
7d535a |
* Calls are:
|
|
kusano |
7d535a |
* initialize_disjoint_sets (n) initial call.
|
|
kusano |
7d535a |
* s = make_set (i) returns a set containing only i.
|
|
kusano |
7d535a |
* s = link (t, u) returns s = t union u, destroying t and u.
|
|
kusano |
7d535a |
* s = find (i) return name of set containing i.
|
|
kusano |
7d535a |
* finalize_disjoint_sets final call.
|
|
kusano |
7d535a |
*
|
|
kusano |
7d535a |
* This implementation uses path compression but not weighted union.
|
|
kusano |
7d535a |
* See Tarjan's book for details.
|
|
kusano |
7d535a |
* John Gilbert, CMI, 1987.
|
|
kusano |
7d535a |
*
|
|
kusano |
7d535a |
* Implemented path-halving by XSL 07/05/95.
|
|
kusano |
7d535a |
*/
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
static
|
|
kusano |
7d535a |
int *mxCallocInt(int n)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
register int i;
|
|
kusano |
7d535a |
int *buf;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
buf = (int *) SUPERLU_MALLOC( n * sizeof(int) );
|
|
kusano |
7d535a |
if ( !buf ) {
|
|
kusano |
7d535a |
ABORT("SUPERLU_MALLOC fails for buf in mxCallocInt()");
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
for (i = 0; i < n; i++) buf[i] = 0;
|
|
kusano |
7d535a |
return (buf);
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
static
|
|
kusano |
7d535a |
void initialize_disjoint_sets (
|
|
kusano |
7d535a |
int n,
|
|
kusano |
7d535a |
int **pp
|
|
kusano |
7d535a |
)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
(*pp) = mxCallocInt(n);
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
static
|
|
kusano |
7d535a |
int make_set (
|
|
kusano |
7d535a |
int i,
|
|
kusano |
7d535a |
int *pp
|
|
kusano |
7d535a |
)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
pp[i] = i;
|
|
kusano |
7d535a |
return i;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
static
|
|
kusano |
7d535a |
int link (
|
|
kusano |
7d535a |
int s,
|
|
kusano |
7d535a |
int t,
|
|
kusano |
7d535a |
int *pp
|
|
kusano |
7d535a |
)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
pp[s] = t;
|
|
kusano |
7d535a |
return t;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* PATH HALVING */
|
|
kusano |
7d535a |
static
|
|
kusano |
7d535a |
int find (
|
|
kusano |
7d535a |
int i,
|
|
kusano |
7d535a |
int *pp
|
|
kusano |
7d535a |
)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
register int p, gp;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
p = pp[i];
|
|
kusano |
7d535a |
gp = pp[p];
|
|
kusano |
7d535a |
while (gp != p) {
|
|
kusano |
7d535a |
pp[i] = gp;
|
|
kusano |
7d535a |
i = gp;
|
|
kusano |
7d535a |
p = pp[i];
|
|
kusano |
7d535a |
gp = pp[p];
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
return (p);
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
#if 0
|
|
kusano |
7d535a |
/* PATH COMPRESSION */
|
|
kusano |
7d535a |
static
|
|
kusano |
7d535a |
int find (
|
|
kusano |
7d535a |
int i
|
|
kusano |
7d535a |
)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
if (pp[i] != i)
|
|
kusano |
7d535a |
pp[i] = find (pp[i]);
|
|
kusano |
7d535a |
return pp[i];
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
static
|
|
kusano |
7d535a |
void finalize_disjoint_sets (
|
|
kusano |
7d535a |
int *pp
|
|
kusano |
7d535a |
)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
SUPERLU_FREE(pp);
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/*
|
|
kusano |
7d535a |
* Find the elimination tree for A'*A.
|
|
kusano |
7d535a |
* This uses something similar to Liu's algorithm.
|
|
kusano |
7d535a |
* It runs in time O(nz(A)*log n) and does not form A'*A.
|
|
kusano |
7d535a |
*
|
|
kusano |
7d535a |
* Input:
|
|
kusano |
7d535a |
* Sparse matrix A. Numeric values are ignored, so any
|
|
kusano |
7d535a |
* explicit zeros are treated as nonzero.
|
|
kusano |
7d535a |
* Output:
|
|
kusano |
7d535a |
* Integer array of parents representing the elimination
|
|
kusano |
7d535a |
* tree of the symbolic product A'*A. Each vertex is a
|
|
kusano |
7d535a |
* column of A, and nc means a root of the elimination forest.
|
|
kusano |
7d535a |
*
|
|
kusano |
7d535a |
* John R. Gilbert, Xerox, 10 Dec 1990
|
|
kusano |
7d535a |
* Based on code by JRG dated 1987, 1988, and 1990.
|
|
kusano |
7d535a |
*/
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/*
|
|
kusano |
7d535a |
* Nonsymmetric elimination tree
|
|
kusano |
7d535a |
*/
|
|
kusano |
7d535a |
int
|
|
kusano |
7d535a |
sp_coletree(
|
|
kusano |
7d535a |
int *acolst, int *acolend, /* column start and end past 1 */
|
|
kusano |
7d535a |
int *arow, /* row indices of A */
|
|
kusano |
7d535a |
int nr, int nc, /* dimension of A */
|
|
kusano |
7d535a |
int *parent /* parent in elim tree */
|
|
kusano |
7d535a |
)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
int *root; /* root of subtee of etree */
|
|
kusano |
7d535a |
int *firstcol; /* first nonzero col in each row*/
|
|
kusano |
7d535a |
int rset, cset;
|
|
kusano |
7d535a |
int row, col;
|
|
kusano |
7d535a |
int rroot;
|
|
kusano |
7d535a |
int p;
|
|
kusano |
7d535a |
int *pp;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
root = mxCallocInt (nc);
|
|
kusano |
7d535a |
initialize_disjoint_sets (nc, &pp);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* Compute firstcol[row] = first nonzero column in row */
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
firstcol = mxCallocInt (nr);
|
|
kusano |
7d535a |
for (row = 0; row < nr; firstcol[row++] = nc);
|
|
kusano |
7d535a |
for (col = 0; col < nc; col++)
|
|
kusano |
7d535a |
for (p = acolst[col]; p < acolend[col]; p++) {
|
|
kusano |
7d535a |
row = arow[p];
|
|
kusano |
7d535a |
firstcol[row] = SUPERLU_MIN(firstcol[row], col);
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* Compute etree by Liu's algorithm for symmetric matrices,
|
|
kusano |
7d535a |
except use (firstcol[r],c) in place of an edge (r,c) of A.
|
|
kusano |
7d535a |
Thus each row clique in A'*A is replaced by a star
|
|
kusano |
7d535a |
centered at its first vertex, which has the same fill. */
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
for (col = 0; col < nc; col++) {
|
|
kusano |
7d535a |
cset = make_set (col, pp);
|
|
kusano |
7d535a |
root[cset] = col;
|
|
kusano |
7d535a |
parent[col] = nc; /* Matlab */
|
|
kusano |
7d535a |
for (p = acolst[col]; p < acolend[col]; p++) {
|
|
kusano |
7d535a |
row = firstcol[arow[p]];
|
|
kusano |
7d535a |
if (row >= col) continue;
|
|
kusano |
7d535a |
rset = find (row, pp);
|
|
kusano |
7d535a |
rroot = root[rset];
|
|
kusano |
7d535a |
if (rroot != col) {
|
|
kusano |
7d535a |
parent[rroot] = col;
|
|
kusano |
7d535a |
cset = link (cset, rset, pp);
|
|
kusano |
7d535a |
root[cset] = col;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
SUPERLU_FREE (root);
|
|
kusano |
7d535a |
SUPERLU_FREE (firstcol);
|
|
kusano |
7d535a |
finalize_disjoint_sets (pp);
|
|
kusano |
7d535a |
return 0;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/*
|
|
kusano |
7d535a |
* q = TreePostorder (n, p);
|
|
kusano |
7d535a |
*
|
|
kusano |
7d535a |
* Postorder a tree.
|
|
kusano |
7d535a |
* Input:
|
|
kusano |
7d535a |
* p is a vector of parent pointers for a forest whose
|
|
kusano |
7d535a |
* vertices are the integers 0 to n-1; p[root]==n.
|
|
kusano |
7d535a |
* Output:
|
|
kusano |
7d535a |
* q is a vector indexed by 0..n-1 such that q[i] is the
|
|
kusano |
7d535a |
* i-th vertex in a postorder numbering of the tree.
|
|
kusano |
7d535a |
*
|
|
kusano |
7d535a |
* ( 2/7/95 modified by X.Li:
|
|
kusano |
7d535a |
* q is a vector indexed by 0:n-1 such that vertex i is the
|
|
kusano |
7d535a |
* q[i]-th vertex in a postorder numbering of the tree.
|
|
kusano |
7d535a |
* That is, this is the inverse of the previous q. )
|
|
kusano |
7d535a |
*
|
|
kusano |
7d535a |
* In the child structure, lower-numbered children are represented
|
|
kusano |
7d535a |
* first, so that a tree which is already numbered in postorder
|
|
kusano |
7d535a |
* will not have its order changed.
|
|
kusano |
7d535a |
*
|
|
kusano |
7d535a |
* Written by John Gilbert, Xerox, 10 Dec 1990.
|
|
kusano |
7d535a |
* Based on code written by John Gilbert at CMI in 1987.
|
|
kusano |
7d535a |
*/
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
static
|
|
kusano |
7d535a |
/*
|
|
kusano |
7d535a |
* Depth-first search from vertex v.
|
|
kusano |
7d535a |
*/
|
|
kusano |
7d535a |
void etdfs (
|
|
kusano |
7d535a |
int v,
|
|
kusano |
7d535a |
int first_kid[],
|
|
kusano |
7d535a |
int next_kid[],
|
|
kusano |
7d535a |
int post[],
|
|
kusano |
7d535a |
int *postnum
|
|
kusano |
7d535a |
)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
int w;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
for (w = first_kid[v]; w != -1; w = next_kid[w]) {
|
|
kusano |
7d535a |
etdfs (w, first_kid, next_kid, post, postnum);
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
/* post[postnum++] = v; in Matlab */
|
|
kusano |
7d535a |
post[v] = (*postnum)++; /* Modified by X. Li on 08/10/07 */
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
static
|
|
kusano |
7d535a |
/*
|
|
kusano |
7d535a |
* Depth-first search from vertex n. No recursion.
|
|
kusano |
7d535a |
* This routine was contributed by CĂŠdric Doucet, CEDRAT Group, Meylan, France.
|
|
kusano |
7d535a |
*/
|
|
kusano |
7d535a |
void nr_etdfs (int n, int *parent,
|
|
kusano |
7d535a |
int *first_kid, int *next_kid,
|
|
kusano |
7d535a |
int *post, int postnum)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
int current = n, first, next;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
while (postnum != n){
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* no kid for the current node */
|
|
kusano |
7d535a |
first = first_kid[current];
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* no first kid for the current node */
|
|
kusano |
7d535a |
if (first == -1){
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* numbering this node because it has no kid */
|
|
kusano |
7d535a |
post[current] = postnum++;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* looking for the next kid */
|
|
kusano |
7d535a |
next = next_kid[current];
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
while (next == -1){
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* no more kids : back to the parent node */
|
|
kusano |
7d535a |
current = parent[current];
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* numbering the parent node */
|
|
kusano |
7d535a |
post[current] = postnum++;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* get the next kid */
|
|
kusano |
7d535a |
next = next_kid[current];
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* stopping criterion */
|
|
kusano |
7d535a |
if (postnum==n+1) return;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* updating current node */
|
|
kusano |
7d535a |
current = next;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
/* updating current node */
|
|
kusano |
7d535a |
else {
|
|
kusano |
7d535a |
current = first;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/*
|
|
kusano |
7d535a |
* Post order a tree
|
|
kusano |
7d535a |
*/
|
|
kusano |
7d535a |
int *TreePostorder(
|
|
kusano |
7d535a |
int n,
|
|
kusano |
7d535a |
int *parent
|
|
kusano |
7d535a |
)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
int *first_kid, *next_kid; /* Linked list of children. */
|
|
kusano |
7d535a |
int *post, postnum;
|
|
kusano |
7d535a |
int v, dad;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* Allocate storage for working arrays and results */
|
|
kusano |
7d535a |
first_kid = mxCallocInt (n+1);
|
|
kusano |
7d535a |
next_kid = mxCallocInt (n+1);
|
|
kusano |
7d535a |
post = mxCallocInt (n+1);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* Set up structure describing children */
|
|
kusano |
7d535a |
for (v = 0; v <= n; first_kid[v++] = -1);
|
|
kusano |
7d535a |
for (v = n-1; v >= 0; v--) {
|
|
kusano |
7d535a |
dad = parent[v];
|
|
kusano |
7d535a |
next_kid[v] = first_kid[dad];
|
|
kusano |
7d535a |
first_kid[dad] = v;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/* Depth-first search from dummy root vertex #n */
|
|
kusano |
7d535a |
postnum = 0;
|
|
kusano |
7d535a |
#if 0
|
|
kusano |
7d535a |
/* recursion */
|
|
kusano |
7d535a |
etdfs (n, first_kid, next_kid, post, &postnum);
|
|
kusano |
7d535a |
#else
|
|
kusano |
7d535a |
/* no recursion */
|
|
kusano |
7d535a |
nr_etdfs(n, parent, first_kid, next_kid, post, postnum);
|
|
kusano |
7d535a |
#endif
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
SUPERLU_FREE (first_kid);
|
|
kusano |
7d535a |
SUPERLU_FREE (next_kid);
|
|
kusano |
7d535a |
return post;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/*
|
|
kusano |
7d535a |
* p = spsymetree (A);
|
|
kusano |
7d535a |
*
|
|
kusano |
7d535a |
* Find the elimination tree for symmetric matrix A.
|
|
kusano |
7d535a |
* This uses Liu's algorithm, and runs in time O(nz*log n).
|
|
kusano |
7d535a |
*
|
|
kusano |
7d535a |
* Input:
|
|
kusano |
7d535a |
* Square sparse matrix A. No check is made for symmetry;
|
|
kusano |
7d535a |
* elements below and on the diagonal are ignored.
|
|
kusano |
7d535a |
* Numeric values are ignored, so any explicit zeros are
|
|
kusano |
7d535a |
* treated as nonzero.
|
|
kusano |
7d535a |
* Output:
|
|
kusano |
7d535a |
* Integer array of parents representing the etree, with n
|
|
kusano |
7d535a |
* meaning a root of the elimination forest.
|
|
kusano |
7d535a |
* Note:
|
|
kusano |
7d535a |
* This routine uses only the upper triangle, while sparse
|
|
kusano |
7d535a |
* Cholesky (as in spchol.c) uses only the lower. Matlab's
|
|
kusano |
7d535a |
* dense Cholesky uses only the upper. This routine could
|
|
kusano |
7d535a |
* be modified to use the lower triangle either by transposing
|
|
kusano |
7d535a |
* the matrix or by traversing it by rows with auxiliary
|
|
kusano |
7d535a |
* pointer and link arrays.
|
|
kusano |
7d535a |
*
|
|
kusano |
7d535a |
* John R. Gilbert, Xerox, 10 Dec 1990
|
|
kusano |
7d535a |
* Based on code by JRG dated 1987, 1988, and 1990.
|
|
kusano |
7d535a |
* Modified by X.S. Li, November 1999.
|
|
kusano |
7d535a |
*/
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
/*
|
|
kusano |
7d535a |
* Symmetric elimination tree
|
|
kusano |
7d535a |
*/
|
|
kusano |
7d535a |
int
|
|
kusano |
7d535a |
sp_symetree(
|
|
kusano |
7d535a |
int *acolst, int *acolend, /* column starts and ends past 1 */
|
|
kusano |
7d535a |
int *arow, /* row indices of A */
|
|
kusano |
7d535a |
int n, /* dimension of A */
|
|
kusano |
7d535a |
int *parent /* parent in elim tree */
|
|
kusano |
7d535a |
)
|
|
kusano |
7d535a |
{
|
|
kusano |
7d535a |
int *root; /* root of subtree of etree */
|
|
kusano |
7d535a |
int rset, cset;
|
|
kusano |
7d535a |
int row, col;
|
|
kusano |
7d535a |
int rroot;
|
|
kusano |
7d535a |
int p;
|
|
kusano |
7d535a |
int *pp;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
root = mxCallocInt (n);
|
|
kusano |
7d535a |
initialize_disjoint_sets (n, &pp);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
for (col = 0; col < n; col++) {
|
|
kusano |
7d535a |
cset = make_set (col, pp);
|
|
kusano |
7d535a |
root[cset] = col;
|
|
kusano |
7d535a |
parent[col] = n; /* Matlab */
|
|
kusano |
7d535a |
for (p = acolst[col]; p < acolend[col]; p++) {
|
|
kusano |
7d535a |
row = arow[p];
|
|
kusano |
7d535a |
if (row >= col) continue;
|
|
kusano |
7d535a |
rset = find (row, pp);
|
|
kusano |
7d535a |
rroot = root[rset];
|
|
kusano |
7d535a |
if (rroot != col) {
|
|
kusano |
7d535a |
parent[rroot] = col;
|
|
kusano |
7d535a |
cset = link (cset, rset, pp);
|
|
kusano |
7d535a |
root[cset] = col;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
SUPERLU_FREE (root);
|
|
kusano |
7d535a |
finalize_disjoint_sets (pp);
|
|
kusano |
7d535a |
return 0;
|
|
kusano |
7d535a |
} /* SP_SYMETREE */
|