332 lines
10 KiB
TeX
332 lines
10 KiB
TeX
%==========================================================================
|
|
\chapter{Language Interoperability}
|
|
\label{Language Interoperability}
|
|
|
|
%==========================================================================
|
|
\section{Zero-based vs. One-based Indexing in Matrices}
|
|
\label{Zero-based vs. One-based Indexing in Matrices}
|
|
|
|
Some definitions:
|
|
\begin{description}
|
|
\item[0-based indexing] Row and column indices are numbered starting at 0.
|
|
\item[1-based indexing] Row and column indices are numbered starting at 1.
|
|
\item[0-based storage] Natural for C, possible in Fortran.
|
|
\item[1-based storage] Natural for Fortran, sometimes used in C.
|
|
\end{description}
|
|
|
|
%==========================================================================
|
|
\subsection{The issues and a suggested decision}
|
|
\label{The issues and a suggested decision}
|
|
|
|
The issues are as follows:
|
|
\begin{enumerate}
|
|
\item We want the code to be natural to write.
|
|
\item We want to interoperate with other codes as much as possible.
|
|
\item We want the code to be as efficient as possible.
|
|
\end{enumerate}
|
|
|
|
In a later section, we describe four different ways to write one
|
|
sample code in C. The sample code does a simple matvec, allocates an
|
|
int array that will mark the coarse grid variables in a multigrid
|
|
scheme, directly calls a Fortran subroutine to fill in the coarse grid
|
|
array (we might typically have a C wrapper around the Fortran
|
|
subroutine, but the intention here is to explicitely demonstrate the
|
|
parameter translation required to interface with the routine), then
|
|
de-allocates the coarse grid array.
|
|
|
|
The \code{A} and \code{B} examples use 0-based and 1-based indexing
|
|
with no pointer tricks. Example \code{C} uses 1-based indexing with a
|
|
pointer trick that is left fully exposed for illustrative purposes.
|
|
Example \code{D} supports both 0 and 1-based indexing and uses a
|
|
\code{hypre_BaseArray} class (see the following section for details on
|
|
this class) to hide the tricks illustrated in example C. In these
|
|
examples, it is assumed that the Fortran subroutine provides the same
|
|
indexing support as the calling C-routines.
|
|
|
|
{\bf Issue 1:} Example \code{A} is the most straightforward and least
|
|
confusing of all the examples. That is, 0-based indexing is the most
|
|
natural for C programming. However, examples \code{C} and \code{D}
|
|
are not all that bad either. Example \code{B} is horribly confusing.
|
|
The most natural style for Fortran is 1-based, but a Fortran variant
|
|
of examples \code{C} and \code{D} for 0-based indexing would also be
|
|
fairly natural. Arrays would be declared like this:
|
|
\begin{verbatim}
|
|
integer Ai(base:An+base)
|
|
\end{verbatim}
|
|
and the \code{iiA} loop would look like this:
|
|
\begin{verbatim}
|
|
do iiA = base, An-1+base
|
|
\end{verbatim}
|
|
|
|
{\bf Issue 2:} We cannot dictate what other code groups support regarding
|
|
indexing. So, if we want to interoperate with other codes, we need to
|
|
support both 0-based and 1-based indexing as in example \code{D} below.
|
|
|
|
{\bf Issue 3:} To keep efficiency high, we do NOT want to have to modify the
|
|
data in the \code{A_i} and \code{A_j} arrays. That is, we want to use the
|
|
pointer tricks below to interoperate with other codes. However, this
|
|
means that the whole code does EITHER 0-based OR 1-based indexing
|
|
during any single run, and NOT both.
|
|
|
|
Suggested decision: Support both 0-based and 1-based indexing.
|
|
|
|
%==========================================================================
|
|
\subsection{Hiding the details}
|
|
\label{Hiding the details}
|
|
|
|
Although code for supporting both 0-based and 1-based indexing is not
|
|
too ugly even when the tricks are exposed, it is easier to make
|
|
mistakes and/or get confused during code development and debugging.
|
|
In an attempt to minimize this, we introduce below a
|
|
\code{hypre_BaseArray} class and a set of coding rules and guidelines.
|
|
|
|
{\noindent\bf The BaseArray class:}
|
|
\begin{verbatim}
|
|
Types:
|
|
hypre_IntBaseArray, hypre_DoubleBaseArray, ...
|
|
|
|
Note: These types are just typedefs for `int' and `double', so
|
|
compilers will not treat them at distinct types (strong typing).
|
|
It would be nice to have compilers do strong typing on them
|
|
to help reduce mistakes, but it is apparantly not possible to
|
|
do this in C *and* retain the ability to use the `[]' operators
|
|
and do casting.
|
|
|
|
Constructor/destructor macros:
|
|
base_array = hypre_AllocBaseArray(type, size, base)
|
|
hypre_FreeBaseArray(base_array, base)
|
|
|
|
Macro that returns a pointer to the real data:
|
|
base_array_data = hypre_BaseArrayData(base_array, base)
|
|
|
|
Macro that converts from 1 base index to another
|
|
new_index = hypre_ConvertBaseIndex(index, base, new_base)
|
|
|
|
Function that converts from 1 base to another (This function actually
|
|
modifies the data in the array, so it should be used only when necessary):
|
|
hypre_ConvertBaseArray(&base_array, base, new_base)
|
|
\end{verbatim}
|
|
|
|
{\noindent\bf Coding Rules and Guidelines:}
|
|
\begin{itemize}
|
|
|
|
\item All arrays with array indices that refer to either rows/columns
|
|
of matrices or elements of vectors must be \code{hypre_BaseArray} types.
|
|
This reduces the possibility of making coding errors.
|
|
|
|
\item All \code{hypre_BaseArray} types in the same routine should use the
|
|
same base. It is recommended that only one `base' variable be defined
|
|
for each routine in an attempt to enforce this.
|
|
|
|
\item Care must be taken when calling other codes that depend on the
|
|
matrix and vector base to convert (if necessary) to a base that the
|
|
called code supports.
|
|
|
|
\end{itemize}
|
|
|
|
%==========================================================================
|
|
\subsection{Sample code}
|
|
\label{Sample code}
|
|
|
|
\begin{verbatim}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
* Indexing example code:
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
/*-----------------------------------------------
|
|
* A) 0-based indexing
|
|
*-----------------------------------------------*/
|
|
|
|
int
|
|
hypre_SampleA( hypre_Matrix *A,
|
|
hypre_Vector *x,
|
|
hypre_Vector *y )
|
|
{
|
|
double *A_data = hypre_MatrixData(A);
|
|
int *A_i = hypre_MatrixI(A);
|
|
int *A_j = hypre_MatrixJ(A);
|
|
int *A_n = hypre_MatrixN(A);
|
|
|
|
double *x_data = hypre_VectorData(x);
|
|
double *y_data = hypre_VectorData(y);
|
|
|
|
int iiA, jjA;
|
|
|
|
int *coarse_grid;
|
|
|
|
/* ... *
|
|
|
|
/* matvec *
|
|
for (iiA = 0; iiA < A_n; iiA++ )
|
|
{
|
|
for (jjA = A_i[iiA]; jjA < A_i[iiA+1]; jjA++)
|
|
{
|
|
y_data[iiA] += A_data[jjA] * x_data[A_j[jjA]];
|
|
}
|
|
}
|
|
|
|
/* coarse-grid allocation *
|
|
coarse_grid = hypre_TAlloc(int, A_n);
|
|
|
|
/* coarse-grid selection function call *
|
|
hypre_coarsen_( ..., coarse_grid);
|
|
|
|
/* coarse-grid de-allocation *
|
|
hypre_TFree(coarse_grid);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*-----------------------------------------------
|
|
* B) 1-based indexing (no tricks)
|
|
*-----------------------------------------------*/
|
|
|
|
int
|
|
hypre_SampleB( hypre_Matrix *A,
|
|
hypre_Vector *x,
|
|
hypre_Vector *y )
|
|
{
|
|
double *A_data = hypre_MatrixData(A);
|
|
int *A_i = hypre_MatrixI(A);
|
|
int *A_j = hypre_MatrixJ(A);
|
|
int *A_n = hypre_MatrixN(A);
|
|
|
|
double *x_data = hypre_VectorData(x);
|
|
double *y_data = hypre_VectorData(y);
|
|
|
|
int iiA, jjA;
|
|
|
|
int *coarse_grid;
|
|
|
|
/* ... *
|
|
|
|
/* matvec *
|
|
for (iiA = 1; iiA <= A_n; iiA++ )
|
|
{
|
|
for (jjA = A_i[iiA-1]; jjA < A_i[iiA]; jjA++)
|
|
{
|
|
y_data[iiA-1] += A_data[jjA-1] * x_data[A_j[jjA-1]-1];
|
|
}
|
|
}
|
|
|
|
/* coarse-grid allocation *
|
|
coarse_grid = hypre_TAlloc(int, A_n);
|
|
|
|
/* coarse-grid selection function call *
|
|
hypre_coarsen_( ..., coarse_grid);
|
|
|
|
/* coarse-grid de-allocation *
|
|
hypre_TFree(coarse_grid);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*-----------------------------------------------
|
|
* C) 1-based indexing (with tricks):
|
|
*-----------------------------------------------*/
|
|
|
|
int
|
|
hypre_SampleC( hypre_Matrix *A,
|
|
hypre_Vector *x,
|
|
hypre_Vector *y )
|
|
{
|
|
double *A_data = hypre_MatrixData(A) - 1;
|
|
int *A_i = hypre_MatrixI(A) - 1;
|
|
int *A_j = hypre_MatrixJ(A) - 1;
|
|
int *A_n = hypre_MatrixN(A);
|
|
|
|
double *x_data = hypre_VectorData(x) - 1;
|
|
double *y_data = hypre_VectorData(y) - 1;
|
|
|
|
int iiA, jjA;
|
|
|
|
int *coarse_grid;
|
|
|
|
/* ... *
|
|
|
|
/* matvec *
|
|
for (iiA = 1; iiA < A_n+1; iiA++ )
|
|
{
|
|
for (jjA = A_i[iiA]; jjA < A_i[iiA+1]; jjA++)
|
|
{
|
|
y_data[iiA] += A_data[jjA] * x_data[A_j[jjA]];
|
|
}
|
|
}
|
|
|
|
/* coarse-grid allocation *
|
|
coarse_grid = hypre_TAlloc(int, A_n) - 1;
|
|
|
|
/* coarse-grid selection function call *
|
|
hypre_coarsen_( ..., coarse_grid + 1);
|
|
|
|
/* coarse-grid de-allocation *
|
|
hypre_TFree(coarse_grid + 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*-----------------------------------------------
|
|
* D) 0 & 1-based indexing:
|
|
*
|
|
* We use the same tricks as in example C, except
|
|
* that we "hide" most of them in the following
|
|
* macros and functions:
|
|
*
|
|
* hypre_MatrixData, hypre_MatrixI, hypre_MatrixJ
|
|
* hypre_VectorData
|
|
* hypre_AllocBaseArray
|
|
* hypre_FreeBaseArray
|
|
* hypre_BaseArrayData
|
|
*
|
|
* The integer `base' is either a 0 or a 1 depending
|
|
* on whether the storage is 0 or 1-based.
|
|
*
|
|
* We also use the following types so that the
|
|
* code is more explicit about which variables
|
|
* we are applying "tricks" to.
|
|
*-----------------------------------------------*/
|
|
|
|
int
|
|
hypre_SampleD( hypre_Matrix *A,
|
|
hypre_Vector *x,
|
|
hypre_Vector *y )
|
|
{
|
|
hypre_DoubleBaseArray *A_data = hypre_MatrixData(A);
|
|
hypre_IntBaseArray *A_i = hypre_MatrixI(A);
|
|
hypre_IntBaseArray *A_j = hypre_MatrixJ(A);
|
|
hypre_IntBaseArray *A_n = hypre_MatrixN(A);
|
|
|
|
hypre_DoubleBaseArray *x_data = hypre_VectorData(x);
|
|
hypre_DoubleBaseArray *y_data = hypre_VectorData(y);
|
|
|
|
hypre_IntBaseArray *coarse_grid;
|
|
|
|
int iiA, jjA;
|
|
|
|
/* ... */
|
|
|
|
/* matvec */
|
|
for (iiA = base; iiA < A_n+base; iiA++ )
|
|
{
|
|
for (jjA = A_i[iiA]; jjA < A_i[iiA+1]; jjA++)
|
|
{
|
|
y_data[iiA] += A_data[jjA] * x_data[A_j[jjA]];
|
|
}
|
|
}
|
|
|
|
/* coarse-grid allocation ( = hypre_TAlloc(int, A_n) - base ) */
|
|
coarse_grid = hypre_AllocBaseArray(int, A_n, base);
|
|
|
|
/* coarse-grid selection function call */
|
|
hypre_coarsen_( ..., &base,
|
|
hypre_BaseArrayData(coarse_grid, base);
|
|
|
|
/* coarse-grid de-allocation ( = hypre_TFree(coarse_grid + base) ) */
|
|
hypre_FreeBaseArray(coarse_grid, base);
|
|
return 0;
|
|
}
|
|
|
|
\end{verbatim}
|
|
|