Examples of usage of librsb
.
More...
Examples of usage of librsb
.
The following fully working example programs illustrate correct ways of using the library. The script displayed here should be sufficient to build them.
#!/bin/bash
# Script to build the librsb example programs.
LIBRSB_CONFIG=${LIBRSB_CONFIG:-librsb-config}
for s in *.c
do
p=${s/.c/}
rm -f $p
CFLAGS=`${LIBRSB_CONFIG} --I_opts`
LDFLAGS=`${LIBRSB_CONFIG} --ldflags --extra_libs`
CC=`${LIBRSB_CONFIG} --cc`
cmd="$CC $CFLAGS $s $LDFLAGS -o $p"
echo $cmd
$cmd
done
if test x"yes" = x"yes" ; then
# activated if you have built the Fortran modules and installed them in the right path.
for s in *.F90
do
p=${s/.F90/}
rm -f $p
CFLAGS=`${LIBRSB_CONFIG} --I_opts`
LDFLAGS=`${LIBRSB_CONFIG} --ldflags --extra_libs`
FC=`${LIBRSB_CONFIG} --fc`
cmd="$FC $CFLAGS $s $LDFLAGS -o $p"
echo $cmd
$cmd
done
fi
#include <stdio.h>
#include <stdlib.h>
int main(const int argc, char * const argv[])
{
struct rsb_mtx_t *mtxAp = NULL;
const int brA = bs, bcA = bs;
char ib[200];
printf("Hello, RSB!\n");
printf("Initializing the library...\n");
{
printf("Error initializing the library!\n");
goto err;
}
printf("Correctly initialized the library.\n");
printf("Attempting to set the"
" RSB_IO_WANT_EXTRA_VERBOSE_INTERFACE library option.\n");
{
{
char errbuf[256];
printf("Failed setting the"
" RSB_IO_WANT_EXTRA_VERBOSE_INTERFACE"
" library option (reason string:\n%s).\n",errbuf);
{
printf("This error may be safely ignored.\n");
}
else
{
printf("Some unexpected error occurred!\n");
goto err;
}
}
else
{
printf("Setting back the "
"RSB_IO_WANT_EXTRA_VERBOSE_INTERFACE"
" library option.\n");
evi = 0;
&evi);
}
}
VA,IA,JA,nnzA,typecode,nrA,ncA,brA,bcA,
,&errval);
{
printf("Error while allocating the matrix!\n");
goto err;
}
printf("Correctly allocated a matrix.\n");
printf("Summary information of the matrix:\n");
ib,sizeof(ib));
printf("%s",ib);
printf("\n");
if((errval =
{
printf("Error performing a multiplication!\n");
goto err;
}
printf("Correctly performed a SPMV.\n");
printf("Correctly freed the matrix.\n");
{
printf("Error finalizing the library!\n");
goto err;
}
printf("Correctly finalized the library.\n");
printf("Program terminating with no error.\n");
return EXIT_SUCCESS;
err:
printf("Program terminating with error.\n");
return EXIT_FAILURE;
}
#include <stdio.h>
#include <stdlib.h>
int main(const int argc, char * const argv[])
{
#ifndef RSB_NUMERICAL_TYPE_DOUBLE
printf("'double' type configured out."
" Please reconfigure the library with it and recompile.\n");
return EXIT_SUCCESS;
#else
const int nnz = 4;
const int nr = 3;
const int nc = 3;
int IA[] = { 0, 1, 2, 2 };
int JA[] = { 0, 1, 0, 2 };
double VA[] = { 11.0, 22.0, 13.0, 33.0 };
double X[] = { 0.0, 0.0, 0.0 };
double B[] = { -1.0, -2.0, -2.0 };
double AB[] = { 11.0+26.0, 44.0, 66.0+13.0 };
int i;
printf("Hello, RSB!\n");
{
goto err;
}
printf("Correctly initialized the library.\n");
{
goto err;
}
{
goto err;
}
{
printf("Symmetry property non set ?!\n");
goto err;
}
{
goto err;
}
{
goto err;
}
printf("Correctly allocated a matrix.\n");
VA[0] = 0.0;
{
goto err;
}
if( VA[0] != 11.0 )
{
goto err;
}
{
goto err;
}
for( i = 0 ; i < nc; ++i )
if( X[i] != AB[i] )
{
printf("Computed SPMV result seems wrong. Terminating.\n");
goto err;
}
printf("Correctly performed a SPMV.\n");
{
goto err;
}
printf("Correctly freed the matrix.\n");
{
goto err;
}
printf("Correctly finalized the library.\n");
printf("Program terminating with no error.\n");
return EXIT_SUCCESS;
err:
printf("Program terminating with error.\n");
return EXIT_FAILURE;
#endif
}
#include <stdio.h>
#include <stdlib.h>
int main(const int argc, char * const argv[])
{
#ifndef RSB_NUMERICAL_TYPE_DOUBLE
printf("'double' type configured out."
" Please reconfigure the library with it and recompile.\n");
return EXIT_SUCCESS;
#else
const int nnz = 4;
const int nr = 3;
const int nc = 3;
int IA[] = { 0, 1, 2, 2 };
int JA[] = { 0, 1, 0, 2 };
double VA[] = { 11.0, 22.0, 13.0, 33.0 };
double X[] = { 0.0, 0.0, 0.0 };
double B[] = { -1.0, -2.0, -2.0 };
double AB[] = { 11.0+26.0, 44.0, 66.0+13.0 };
int i;
printf("Hello, RSB!\n");
{
goto err;
}
printf("Correctly initialized the library.\n");
{
goto err;
}
{
goto err;
}
{
printf("Symmetry property non set ?!\n");
goto err;
}
{
goto err;
}
{
goto err;
}
printf("Correctly allocated a matrix.\n");
VA[0] = 0.0;
{
goto err;
}
if( VA[0] != 11.0 )
{
goto err;
}
{
goto err;
}
for( i = 0 ; i < nc; ++i )
if( X[i] != AB[i] )
{
printf("Computed SPMV result seems wrong. Terminating.\n");
goto err;
}
printf("Correctly performed a SPMV.\n");
{
goto err;
}
printf("Correctly freed the matrix.\n");
{
goto err;
}
printf("Correctly finalized the library.\n");
printf("Program terminating with no error.\n");
return EXIT_SUCCESS;
err:
printf("Program terminating with error.\n");
return EXIT_FAILURE;
#endif
}
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
int tune_from_file(
char *
const filename,
rsb_int_t wvat)
{
struct rsb_mtx_t *mtxMp = NULL;
const void * alphap = NULL;
const void * betap = NULL;
char ib[200];
const char*const is = "RSB_MIF_MATRIX_INFO__TO__CHAR_P";
const int ione = 1;
const rsb_type_t typecodea [] = RSB_MATRIX_SPBLAS_TYPE_CODES_ARRAY;
int typecodei;
goto err;
goto err;
printf("Loading matrix from file \"%s\".\n",filename);
goto err;
for( typecodei = 0 ; typecodei < RSB_IMPLEMENTED_TYPES; ++typecodei )
{
struct rsb_mtx_t *mtxAp = NULL;
struct rsb_mtx_t *mtxOp = NULL;
sf = 0.0;
tn = 0;
printf("Considering %c clone.\n",typecode);
flagsA);
goto err;
printf("Base matrix:\n");
printf("%s\n\n",ib);
alphap, mtxAp, nrhs, order, NULL, ldB, betap, NULL, ldC);
if(tn == 0)
printf("After %lfs, autotuning routine did not find a better"
" threads count configuration.\n",dt);
else
printf("After %lfs, thread autotuning declared speedup of %lg x,"
" when using threads count of %d.\n",dt,sf,tn);
printf("\n");
mtxOp = mtxAp;
alphap, NULL, nrhs, order, NULL, ldB, betap, NULL, ldC);
goto err;
if( mtxOp == mtxAp )
{
printf("After %lfs, global autotuning found old matrix optimal,"
" with declared speedup %lg x when using %d threads\n",dt,sf,tn);
}
else
{
printf("After %lfs, global autotuning declared speedup of %lg x,"
" when using threads count of %d and a new matrix:\n",dt,sf,tn);
printf("%s\n",ib);
}
printf("\n");
mtxAp = NULL;
}
mtxMp = NULL;
err:
printf("Program terminating with error.\n");
return errval;
}
int main(const int argc, char * const argv[])
{
struct rsb_mtx_t *mtxAp = NULL;
char ib[200];
const char*const is = "RSB_MIF_MATRIX_INFO__TO__CHAR_P";
if(argc > 1 && !isdigit(argv[1][0]) )
{
errval = tune_from_file(argv[1],wvat);
goto ret;
}
if(argc > 1)
{
nrA = ncA = atoi(argv[1]);
goto err;
nnzA = (nrA/rd)*(ncA/cd);
ldB = nrA;
ldC = ncA;
}
printf("Creating %d x %d matrix with %d nonzeroes.\n",nrA,ncA,nnzA);
IA = calloc(nnzA, si);
JA = calloc(nnzA, si);
VA = calloc(nnzA, so);
Bp = calloc(nrhs*ncA ,so);
Cp = calloc(nrhs*nrA ,so);
if( ! ( VA && IA && JA && Bp && Cp ) )
goto err;
for(nrhsi=0;nrhsi<nrhs;++nrhsi)
for(ci=0;ci<ncA/cd;++ci)
Bp[nrhsi*ldC+ci] = 1.0;
for(nrhsi=0;nrhsi<nrhs;++nrhsi)
for(ri=0;ri<nrA/rd;++ri)
Cp[nrhsi*ldC+ri] = 1.0;
ni = 0;
for(ci=0;ci<ncA/cd;++ci)
for(ri=0;ri<nrA/rd;++ri)
{
VA[ni] = nrA * ri + ci,
IA[ni] = ri;
JA[ni] = ci;
ni++;
}
VA,IA,JA,nnzA,typecode,nrA,ncA,bs,bs,
free(VA);
free(IA);
free(JA);
VA = NULL;
IA = NULL;
JA = NULL;
goto err;
printf("Allocated matrix of %zd nonzeroes:\n",(size_t)nnzA);
printf("%s\n\n",ib);
for(t=0;t<tt;++t)
rsb_spmm(transA,&alpha,mtxAp,nrhs,order,Bp,ldB,&beta,Cp,ldC);
odt = dt;
printf("Before auto-tuning, %d multiplications took %lfs.\n",tt,dt);
printf("Threads autotuning (may take more than %lfs)...\n",
oitmax*tmax);
&alpha, mtxAp, nrhs, order, Bp, ldB, &beta, Cp, ldC);
goto err;
if(tn == 0)
printf("After %lfs, autotuning routine did not find a better"
" threads count configuration.\n",dt);
else
printf("After %lfs, autotuning routine declared speedup of %lg x,"
" when using threads count of %d.\n",dt,sf,tn);
goto err;
printf("%s\n",ib);
for(t=0;t<tt;++t)
rsb_spmm(transA,&alpha,mtxAp,nrhs,order,Bp,ldB,&beta,Cp,ldC);
printf("After threads auto-tuning, %d multiplications took %lfs"
" -- effective speedup of %lg x\n",tt,dt,odt/dt);
odt = dt;
tn = 0;
goto err;
goto err;
printf("Matrix autotuning (may take more than %lfs; using %d"
" threads )...\n", oitmax*tmax, tn);
&alpha, NULL, nrhs, order, Bp, ldB, &beta, Cp, ldC);
goto err;
if(tn == 0)
printf("After %lfs, autotuning routine did not find a better"
" threads count configuration.\n",dt);
else
printf("After %lfs, autotuning routine declared speedup of %lg x,"
" when using threads count of %d.\n",dt,sf,tn);
printf("%s\n",ib);
for(t=0;t<tt;++t)
rsb_spmm(transA,&alpha,mtxAp,nrhs,order,Bp,ldB,&beta,Cp,ldC);
printf("After threads auto-tuning, %d multiplications took %lfs"
" -- further speedup of %lg x\n",tt,dt,odt/dt);
free(Cp);
free(Bp);
{
printf("librsb timer-based profiling is not supported in "
"this build. If you wish to have it, re-configure librsb "
"with its support. So you can safely ignore the error you"
" might just have seen printed out on screen.\n");
}
else
if(etime)
printf("Elapsed program time is %5.2lfs\n",etime);
ret:
goto err;
return EXIT_SUCCESS;;
err:
printf("Program terminating with error.\n");
return EXIT_FAILURE;
}
#include <stdio.h>
#include <stdlib.h>
int main(const int argc, char * const argv[])
{
#ifndef RSB_NUMERICAL_TYPE_DOUBLE
printf("Skipping a test because of 'double' type opted out.\n");
return EXIT_SUCCESS;
#else
rsb_char_t * filename = argc > 1 ? argv[1] :
"pd.mtx";
printf("Hello, RSB!\n");
{
printf("Error while initializing the library.\n");
goto err;
}
printf("Correctly initialized the library.\n");
typecode );
{
printf("Error while loading matrix %s from file.\n",
filename);
goto err;
}
printf("Correctly loaded and allocated a matrix"
" from file %s.\n",filename);
printf("Matrix is symmetric\n");
printf("Matrix is hermitian\n");
printf("Now SPMV with NULL vectors will be attempted,"
" resulting in an error (so don't worry).\n");
{
printf("Correctly detected an error condition.\n");
goto okerr;
}
printf("No error detected ?\nIf you see this line printed out,"
" please report as a bug, because the above NULL pointers"
" should have been detected\n");
return EXIT_FAILURE;
okerr:
printf("Program correctly recovered from intentional"
" error condition.\n");
{
printf("Error while freeing the matrix!\n");
goto err;
}
printf("Correctly freed the matrix.\n");
err:
{
printf("Failed finalizing the library.\n");
goto ferr;
}
printf("Correctly finalized the library.\n");
return EXIT_SUCCESS;
ferr:
return EXIT_FAILURE;
#endif
}
#include <stdio.h>
#include <stdlib.h>
int main(const int argc, char * const argv[])
{
struct rsb_mtx_t *mtxAp = NULL;
{
return EXIT_FAILURE;
}
VA,IA,JA,nnzA,typecode,nrA,ncA,
if(!mtxAp)
{
return EXIT_FAILURE;
}
{
goto err;
}
{
goto err;
}
{
goto err;
}
if(!mtxAp)
{
return EXIT_FAILURE;
}
{
goto err;
}
{
goto err;
}
{
goto err;
}
goto err;
if( vl != 6 )
{
goto err;
}
goto err;
{
unsigned char pixmap[3*2*2];
goto err;
}
{
goto err;
}
return EXIT_SUCCESS;
err:
return EXIT_FAILURE;
}
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int main(const int argc, char * const argv[])
{
int WANT_VERBOSE = 0;
struct rsb_mtx_t *mtxAp = NULL;
int i;
const int br = bs, bc = bs;
oldnorm = 1.0,
*b1 = NULL, *b2 = NULL,
*bnow = NULL, *bnext = NULL;
size_t ds = 0;
return EXIT_FAILURE;
if(!mtxAp)
return EXIT_FAILURE;
b1 = calloc(1,ds);
b2 = calloc(1,ds);
if(! (b1 && b2))
{
goto err;
}
for( i = 0; i < nrA; ++i )
b1[i] = 1;
bnow = b1, bnext = b2;
while( fabs(norm-oldnorm) > tol && it<maxit )
{
++ it;
oldnorm = norm;
goto err;
norm = 0;
for(i=0;i<nrA;++i)
norm += bnext[i]*bnext[i];
norm = sqrt(norm);
norm = 1.0/norm;
for(i=0;i<nrA;++i)
bnext[i] *= norm;
norm = 1.0/norm;
printf("it:%d norm:%lg norm diff:%lg\n",it,norm,norm-oldnorm);
{void *tmp=bnow;bnow=bnext;bnext=tmp;}
if(WANT_VERBOSE)
{
printf("norm:%lg\n",norm);
if(isinf(norm))
goto err;
for(i=0;i<2;++i)
printf("x[%d]=%lg\n",i,((double*)bnext)[i]);
}
}
free(b1);
free(b2);
goto err;
if( it == maxit )
{
printf("ERROR: hit iterations limit without convergence!");
}
return EXIT_SUCCESS;
err:
return EXIT_FAILURE;
}
SUBROUTINE blas_sparse_mod_example(res)
IMPLICIT NONE
INTEGER :: res, istat = 0, i, j
TYPE(c_ptr),TARGET :: mtxap = c_null_ptr
INTEGER :: a
INTEGER,PARAMETER :: incx = 1
INTEGER,PARAMETER :: incy = 1
REAL(KIND=8),PARAMETER :: alpha = 3
INTEGER,PARAMETER :: nr = 20
INTEGER,PARAMETER :: nc = nr
INTEGER,PARAMETER :: nnz = (nr*(nr+1))/2
INTEGER :: nt = 0
INTEGER :: ic, ir
INTEGER,PARAMETER :: nrhs = 2
INTEGER,PARAMETER :: ia(nnz) = (/ (((ir), ic=1,ir), ir=1,nr ) /)
INTEGER,PARAMETER :: ja(nnz) = (/ (((ic), ic=1,ir), ir=1,nr ) /)
REAL(KIND=8),PARAMETER :: va(nnz) = (/ ((1, ic=1,ir), ir=1,nr ) /)
REAL(KIND=8) :: x(nc,nrhs) = reshape((/((1), ic=1,nc*nrhs)/),[nc,nrhs
REAL(KIND=8),PARAMETER :: cy(nr,nrhs) = reshape((/((alpha+alpha*nr
REAL(KIND=8) :: y(nr,nrhs) = reshape((/((alpha), ir=1,nr*nrhs)/),[nr
res = 0
IF (res.NE.0) GOTO 9999
IF (istat.NE.0) GOTO 9997
IF (istat.NE.0) print *,"autotuning returned nonzero:", istat &
&," ...did you enable autotuning ?"
IF (istat.NE.0) GOTO 9997
IF (istat.NE.0) GOTO 9997
IF (nt.NE.0) print*,"autotuner chose ",nt," threads"
IF (istat.NE.0) GOTO 9997
DO j = 1, nrhs
CALL usmv(transn,alpha,a,x(:,j),incx,y(:,j),incy,istat)
END DO
IF (istat.NE.0) GOTO 9997
DO j = 1, nrhs
DO i = 1, nr
IF (y(i,j).NE.cy(i,j)) print *, "first check results are not ok"
IF (y(i,j).NE.cy(i,j)) GOTO 9997
END DO
END DO
y(:,:) = alpha
IF (istat.NE.0) GOTO 9997
DO j = 1, nrhs
CALL usmv(transn,alpha,a,x(:,j),incx,y(:,j),incy,istat)
END DO
IF (istat.NE.0) GOTO 9997
DO j = 1, nrhs
DO i = 1, nr
IF (y(i,j).NE.cy(i,j)) print *,"second check results are not ok"
IF (y(i,j).NE.cy(i,j)) GOTO 9997
END DO
END DO
print *, "check results are ok"
GOTO 9998
9997 res = -1
9998 CONTINUE
IF (istat.NE.0) res = -1
9999 CONTINUE
end SUBROUTINE blas_sparse_mod_example
PROGRAM main
USE iso_c_binding
IMPLICIT NONE
INTEGER :: res = 0, passed = 0, failed = 0
TYPE(c_ptr),PARAMETER :: eo = c_null_ptr
TYPE(c_ptr),PARAMETER :: io = c_null_ptr
INTEGER,TARGET::ione=1
CALL blas_sparse_mod_example(res)
IF (res.LT.0) failed = failed + 1
IF (res.EQ.0) passed = passed + 1
print *, "FAILED:", failed
print *, "PASSED:", passed
IF (failed .GT. 0) THEN
stop 1
END IF
END PROGRAM
SUBROUTINE rsb_mod_example1(res)
USE iso_c_binding
IMPLICIT NONE
INTEGER ::res
INTEGER,TARGET :: istat = 0, i
INTEGER :: incx = 1, incy = 1
REAL(KIND=8),TARGET :: alpha = 3, beta = 1
INTEGER :: nnz = 4
INTEGER :: nr = 2
INTEGER :: nc = 2
INTEGER :: nrhs = 1
INTEGER,TARGET :: ia(4) = (/0, 1, 1,0/)
INTEGER,TARGET :: ja(4) = (/0, 0, 1,1/)
REAL(KIND=8),TARGET :: va(4) = (/1,1,1,1/)
REAL(KIND=8),TARGET :: x(2) = (/1, 1/)
REAL(KIND=8),TARGET :: cy(2) = (/9, 9/)
REAL(KIND=8),TARGET :: y(2) = (/3, 3/)
TYPE(c_ptr),TARGET :: mtxap = c_null_ptr
REAL(KIND=8) :: tmax = 2.0
INTEGER :: titmax = 2
INTEGER,TARGET :: ont = 0
res = 0
istat =
rsb_tune_spmm(c_loc(mtxap),c_null_ptr,c_null_ptr,titmax,&
& tmax,&
& transt,c_loc(alpha),c_null_ptr,nrhs,order,c_loc(x),nr,&
& c_loc(beta),c_loc(y),nc)
& tmax,&
& transt,c_loc(alpha),mtxap,nrhs,order,c_loc(x),nr,c_loc(beta),&
& c_loc(y),nc)
print *, "Optimal number of threads:", ont
y(:) = (/3, 3/)
istat =
rsb_spmv(transt,c_loc(alpha),mtxap,c_loc(x),incx,&
& c_loc(beta),c_loc(y),incy)
DO i = 1, 2
IF (y(i).NE.cy(i)) print *, "type=d dims=2x2 sym=g diag=g &
&blocks=1x1 usmv alpha= 3 beta= 1 incx=1 incy=1 trans=n is not ok"
IF (y(i).NE.cy(i)) GOTO 9997
END DO
print*,"type=d dims=2x2 sym=g diag=g blocks=1x1 usmv alpha= 3&
& beta= 1 incx=1 incy=1 trans=n is ok"
GOTO 9998
9997 res = -1
9998 CONTINUE
end SUBROUTINE rsb_mod_example1
SUBROUTINE rsb_mod_example2(res)
USE iso_c_binding
IMPLICIT NONE
INTEGER,TARGET :: errval
INTEGER :: res
INTEGER :: incx = 1, incb = 1
REAL(KIND=8),TARGET :: alpha = 3,beta = 1
INTEGER :: nnza = 4, nra = 3, nca = 3
INTEGER,TARGET :: ia(4) = (/1, 2, 3, 3/)
INTEGER,TARGET :: ja(4) = (/1, 2, 1, 3/)
REAL(KIND=8),TARGET :: va(4) = (/11.0, 22.0, 13.0, 33.0/)
REAL(KIND=8),TARGET :: x(3) = (/ 0, 0, 0/)
REAL(KIND=8),TARGET :: b(3) = (/-1.0, -2.0, -2.0/)
TYPE(c_ptr),TARGET :: mtxap = c_null_ptr
TYPE(c_ptr) :: mtxapp = c_null_ptr
REAL(KIND=8),TARGET :: etime = 0.0
TYPE(c_ptr),PARAMETER :: eo = c_null_ptr
TYPE(c_ptr),PARAMETER :: io = c_null_ptr
& stop "error calling rsb_lib_init"
#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 5)
#define RSB_SKIP_BECAUSE_OLD_COMPILER 1
#endif
#ifndef RSB_SKIP_BECAUSE_OLD_COMPILER
& c_loc(errval))
& c_loc(va),c_loc(ia),c_loc(ja),nnza,flags)
mtxapp = c_loc(mtxap)
& stop "error calling rsb_mtx_set_vals"
& stop "error calling rsb_mtx_alloc_from_coo_end"
errval =
rsb_spmv(transt,c_loc(alpha),mtxap,c_loc(x),&
& incx,c_loc(beta),c_loc(b),incb)
& stop "error calling rsb_spmv"
& print*,"Time spent in librsb is:",etime
& stop "error calling rsb_mtx_free"
#else
print*,"You have an old Fortran compiler not supporting C_LOC."
print*,"Skipping a part of the test"
#endif
& stop "error calling rsb_lib_exit"
print *, "rsb module fortran test is ok"
res = errval
end SUBROUTINE rsb_mod_example2
PROGRAM main
IMPLICIT NONE
TYPE(c_ptr),PARAMETER :: eo = c_null_ptr
TYPE(c_ptr),PARAMETER :: io = c_null_ptr
CALL rsb_mod_example1(res)
IF (res.LT.0) failed = failed + 1
IF (res.EQ.0) passed = passed + 1
CALL rsb_mod_example2(res)
IF (res.LT.0) failed = failed + 1
IF (res.EQ.0) passed = passed + 1
print *, "FAILED:", failed
print *, "PASSED:", passed
IF (failed.GT.0) THEN
stop 1
END IF
END PROGRAM