예제 #1
0
int main()
{
  size_t nb_block = 1000;
  static const size_t BlockSize = 6;
  size_t rows = nb_block*BlockSize, cols = nb_block*BlockSize;

  Dense dense(rows,cols,BlockSize);
  Sparse sparse(dense);
  Blocks<BlockSize> blocks(dense);

  utils::Tic<true> ticd("dense");
  compute(dense);
  ticd.disp();

  utils::Tic<true> tics("sparse");
  compute(sparse);
  tics.disp();


  utils::Tic<true> ticb("blocks");
  compute(blocks);
  ticb.disp();
  

  // std::cout << m << std::endl;
  // std::cout << std::endl;
  // std::cout << v.transpose() << std::endl;

  //r = s * v;

  return 0;
}
예제 #2
0
파일: test-lexing.c 프로젝트: 8l/sparse
int main(int argc, char **argv)
{
	struct string_list *filelist = NULL;
	char *file;

	preprocess_only = 1;
	sparse_initialize(argc, argv, &filelist);
	FOR_EACH_PTR_NOTAG(filelist, file) {
		sparse(file);
	} END_FOR_EACH_PTR_NOTAG(file);
예제 #3
0
//---------------------------------------------------------------------
// generate the test problem for benchmark 6
// makea generates a sparse matrix with a
// prescribed sparsity distribution
//
// parameter    type        usage
//
// input
//
// n            i           number of cols/rows of matrix
// nz           i           nonzeros as declared array size
// rcond        r*8         condition number
// shift        r*8         main diagonal shift
//
// output
//
// a            r*8         array for nonzeros
// colidx       i           col indices
// rowstr       i           row pointers
//
// workspace
//
// iv, arow, acol i
// aelt           r*8
//---------------------------------------------------------------------
static void makea(int n,
                  int nz,
                  double a[],
                  int colidx[],
                  int rowstr[],
                  int firstrow,
                  int lastrow,
                  int firstcol,
                  int lastcol,
                  int arow[],
                  int acol[][NONZER+1],
                  double aelt[][NONZER+1],
                  int iv[])
{
  int iouter, ivelt, nzv, nn1;
  int ivc[NONZER+1];
  double vc[NONZER+1];

  //---------------------------------------------------------------------
  // nonzer is approximately  (int(sqrt(nnza /n)));
  //---------------------------------------------------------------------

  //---------------------------------------------------------------------
  // nn1 is the smallest power of two not less than n
  //---------------------------------------------------------------------
  nn1 = 1;
  do {
    nn1 = 2 * nn1;
  } while (nn1 < n);

  //---------------------------------------------------------------------
  // Generate nonzero positions and save for the use in sparse.
  //---------------------------------------------------------------------
  for (iouter = 0; iouter < n; iouter++) {
    nzv = NONZER;
    sprnvc(n, nzv, nn1, vc, ivc);
    vecset(n, vc, ivc, &nzv, iouter+1, 0.5);
    arow[iouter] = nzv;
    
    for (ivelt = 0; ivelt < nzv; ivelt++) {
      acol[iouter][ivelt] = ivc[ivelt] - 1;
      aelt[iouter][ivelt] = vc[ivelt];
    }
  }

  //---------------------------------------------------------------------
  // ... make the sparse matrix from list of elements with duplicates
  //     (iv is used as  workspace)
  //---------------------------------------------------------------------
  sparse(a, colidx, rowstr, n, nz, NONZER, arow, acol, 
         aelt, firstrow, lastrow,
         iv, RCOND, SHIFT);
}
예제 #4
0
TEST(Arguments, CpuSparseMatrix) {
  CpuSparseMatrix sparse(200, 300, 50);
  CheckBufferArg check = [=](const BufferArg& arg) {
    EXPECT_EQ(arg.shape().ndims(), 2U);
    EXPECT_EQ(arg.shape()[0], 200U);
    EXPECT_EQ(arg.shape()[1], 300U);
    EXPECT_EQ(arg.data(), sparse.getData());
    // CHECK_EQ(arg.sparse().nnz(), 50);
    // CHECK_EQ(arg.sparse().dataFormat(), SPARSE_CSR_FORMAT);
    // CHECK_EQ(arg.sparse().dataType(), SPARSE_FLOAT_VALUE);
    EXPECT_EQ(arg.sparse().getRowBuf(), sparse.getRows());
    EXPECT_EQ(arg.sparse().getColBuf(), sparse.getCols());
  };

  BufferArgs argments;
  argments.addArg(sparse);
  std::vector<CheckBufferArg> checkFunc;
  checkFunc.push_back(check);
  testBufferArgs(argments, checkFunc);
}
예제 #5
0
size_t SiconosMatrix::nnz(double tol)
{
  size_t nnz = 0;
  if (_num == 1) //dense
  {
    double* arr = getArray();
    for (size_t i = 0; i < size(0)*size(1); ++i)
    {
      if (fabs(arr[i]) > tol) { nnz++; }
    }
  }
  else if (_num == 4)
  {
    nnz = sparse()->nnz();
  }
  else
  {
     SiconosMatrixException::selfThrow("SiconosMatrix::nnz not implemented for the given matrix type");
  }

  return nnz;

}
예제 #6
0
파일: splay.c 프로젝트: pombreda/splay
int main(int argc, char **argv)
{
	struct string_list *filelist = NULL;
	struct symbol_list *builtins;
	char *file;

	builtins = sparse_initialize(argc, argv, &filelist);
	FOR_EACH_PTR_NOTAG(filelist, file) {
		struct symbol_list *syms;
		module_t m;

		syms = sparse(file);
		if (die_if_error)
			return 1;
		m = alloc_module(file);
		compile(m, builtins);
		compile(m, syms);
		verify_module(m);
		print_module(m, STDOUT_FILENO);
		free_module(m);
	} END_FOR_EACH_PTR_NOTAG(file);
	return 0;
}
예제 #7
0
파일: main.c 프로젝트: farewellkou/xen
static void call_main(void *p)
{
    char *c, quote;
#ifdef CONFIG_QEMU_XS_ARGS
    char *domargs, *msg;
#endif
    int argc;
    char **argv;
    char *envp[] = { NULL };
#ifdef CONFIG_QEMU_XS_ARGS
    char *vm;
    char path[128];
    int domid;
#endif
    int i;

    /* Let other parts initialize (including console output) before maybe
     * crashing. */
    //sleep(1);

    //printk("Start call_main : main.c\n");
#ifdef CONFIG_SPARSE_BSS
    sparse((unsigned long) &__app_bss_start, &__app_bss_end - &__app_bss_start);
#endif
#if defined(HAVE_LWIP) && defined(CONFIG_START_NETWORK) && defined(CONFIG_NETFRONT)
    start_networking();
#endif
#ifdef CONFIG_PCIFRONT
    create_thread("pcifront", pcifront_watches, NULL);
#endif

#ifdef CONFIG_QEMU_XS_ARGS
    /* Fetch argc, argv from XenStore */
    domid = xenbus_read_integer("target");
    if (domid == -1) {
        printk("Couldn't read target\n");
        do_exit();
    }

    snprintf(path, sizeof(path), "/local/domain/%d/vm", domid);
    msg = xenbus_read(XBT_NIL, path, &vm);
    if (msg) {
        printk("Couldn't read vm path\n");
        do_exit();
    }
    printk("dom vm is at %s\n", vm);

    snprintf(path, sizeof(path), "%s/image/dmargs", vm);
    free(vm);
    msg = xenbus_read(XBT_NIL, path, &domargs);

    if (msg) {
        printk("Couldn't get stubdom args: %s\n", msg);
        domargs = strdup("");
    }
#endif

    argc = 1;

#define PARSE_ARGS(ARGS,START,QUOTE,END) \
    c = ARGS; \
    quote = 0; \
    while (*c) { \
	if (*c != ' ') { \
	    START; \
	    while (*c) { \
		if (quote) { \
		    if (*c == quote) { \
			quote = 0; \
			QUOTE; \
			continue; \
		    } \
		} else if (*c == ' ') \
		    break; \
		if (*c == '"' || *c == '\'') { \
		    quote = *c; \
		    QUOTE; \
		    continue; \
		} \
		c++; \
	    } \
	} else { \
            END; \
	    while (*c == ' ') \
		c++; \
	} \
    } \
    if (quote) {\
	printk("Warning: unterminated quotation %c\n", quote); \
	quote = 0; \
    }
#define PARSE_ARGS_COUNT(ARGS) PARSE_ARGS(ARGS, argc++, c++, )
#define PARSE_ARGS_STORE(ARGS) PARSE_ARGS(ARGS, argv[argc++] = c, memmove(c, c + 1, strlen(c + 1) + 1), *c++ = 0)

    PARSE_ARGS_COUNT((char*)start_info.cmd_line);
#ifdef CONFIG_QEMU_XS_ARGS
    PARSE_ARGS_COUNT(domargs);
#endif

    argv = alloca((argc + 1) * sizeof(char *));
    argv[0] = "main";
    argc = 1;

    PARSE_ARGS_STORE((char*)start_info.cmd_line)
#ifdef CONFIG_QEMU_XS_ARGS
    PARSE_ARGS_STORE(domargs)
#endif

    argv[argc] = NULL;

    for (i = 0; i < argc; i++)
	printf("\"%s\" ", argv[i]);
    //printf("\n");

    __libc_init_array();
    environ = envp;
    for (i = 0; __CTOR_LIST__[i] != 0; i++)
        ((void((*)(void)))__CTOR_LIST__[i]) ();
    tzset();

    exit(main(argc, argv, envp));
}
예제 #8
0
/***********************************************************************//**
 * @brief Test value assignment
 ***************************************************************************/
void TestGMatrixSparse::assign_values(void)
{
    // Setup 3x3 matrix
    GMatrixSparse test(3,3);
    
    // Assignment individual values
    for (int i = 0; i < 3; ++i) {
        for (int k = 0; k < 3; ++k) {
            double value = i*2.0 + k*2.0;
            test(i,k)   = value;
        }
    }

    // Check assignment of individual values
    for (int i = 0; i < 3; ++i) {
        for (int k = 0; k < 3; ++k) {
            double value = i*2.0 + k*2.0;
            test_value(test(i,k), value, 1.0e-10, "Test matrix element assignment");
        }
    }

    // Check value assignment
    const double ref = 37.89;
    test = ref;
    for (int i = 0; i < 3; ++i) {
        for (int k = 0; k < 3; ++k) {
            test_value(test(i,k), ref, 1.0e-10, "Test matrix element assignment");
        }
    }
    test = 0.0;
    for (int i = 0; i < 3; ++i) {
        for (int k = 0; k < 3; ++k) {
            test_value(test(i,k), 0.0, 1.0e-10, "Test matrix element assignment");
        }
    }

    // Verify range checking
    #ifdef G_RANGE_CHECK
    test_try("Verify range checking");
    try {
        test.at(3,3) = 1.0;
        test_try_failure("Expected GException::out_of_range exception.");
    }
    catch (GException::out_of_range &e) {
        test_try_success();
    }
    catch (std::exception &e) {
        test_try_failure(e);
    }
    #endif

    // Setup 10x10 matrix and keep for reference
	GMatrixSparse sparse(10,10);
	for (int i = 3; i < 5; ++i) {
        sparse(i,i) = 5.0;
    }
	GMatrixSparse initial   = sparse;
	GMatrixSparse reference = sparse;

    // Insert column into 10 x 10 matrix using large matrix stack and the
    // add_col(GVector) method
	sparse.stack_init(100,50);
	GVector column(10);
    for (int j = 0; j < 10; ++j) {
        int col = int(0.8 * j + 0.5);    // This allows that some columns are twice
        if (col > 9) col -= 10;          // This avoids overflow
        int i_min = (j < 2) ?  0 : j-2;
        int i_max = (j > 8) ? 10 : j+2;
        column = 0.0;
        for (int i = i_min; i < i_max; ++i) {
            column[i]         = (i+1)*1;
            reference(i,col) += column[i];
        }
        sparse.add_to_column(col, column);
	}
	sparse.stack_destroy();
    test_assert((sparse == reference),
                "Test stack fill with large stack using add_col(GVector) method",
                "Found:\n"+sparse.print()+"\nExpected:\n"+reference.print());

    // Insert column into 10 x 10 matrix using small matrix stack and the
    // add_col(GVector) method
    sparse = initial;
	sparse.stack_init(100,3);
    for (int j = 0; j < 10; ++j) {
        int col = int(0.8 * j + 0.5);    // This allows that some columns are twice
        if (col > 9) col -= 10;          // This avoids overflow
        int i_min = (j < 2) ?  0 : j-2;
        int i_max = (j > 8) ? 10 : j+2;
        column = 0.0;
        for (int i = i_min; i < i_max; ++i) {
            column[i]         = (i+1)*1;
        }
        sparse.add_to_column(col, column);
	}
	sparse.stack_destroy();
    test_assert((sparse == reference),
                "Test stack fill with small stack using add_col(GVector) method",
                "Found:\n"+sparse.print()+"\nExpected:\n"+reference.print());

    // Insert column into 10 x 10 matrix using tiny matrix stack and the
    // add_col(GVector) method
    sparse = initial;
	sparse.stack_init(8,3);
    for (int j = 0; j < 10; ++j) {
        int col = int(0.8 * j + 0.5);    // This allows that some columns are twice
        if (col > 9) col -= 10;          // This avoids overflow
        int i_min = (j < 2) ?  0 : j-2;
        int i_max = (j > 8) ? 10 : j+2;
        column = 0.0;
        for (int i = i_min; i < i_max; ++i) {
            column[i]         = (i+1)*1;
        }
        sparse.add_to_column(col, column);
	}
	sparse.stack_destroy();
    test_assert((sparse == reference),
                "Test stack fill with tiny stack using add_col(GVector) method",
                "Found:\n"+sparse.print()+"\nExpected:\n"+reference.print());

    // Insert column into 10 x 10 matrix using no matrix stack and the
    // add_col(GVector) method
    sparse = initial;
    for (int j = 0; j < 10; ++j) {
        int col = int(0.8 * j + 0.5);    // This allows that some columns are twice
        if (col > 9) col -= 10;          // This avoids overflow
        int i_min = (j < 2) ?  0 : j-2;
        int i_max = (j > 8) ? 10 : j+2;
        column = 0.0;
        for (int i = i_min; i < i_max; ++i) {
            column[i]         = (i+1)*1;
        }
        sparse.add_to_column(col, column);
	}
	sparse.stack_destroy();
    test_assert((sparse == reference),
                "Test fill using add_col(GVector) method",
                "Found:\n"+sparse.print()+"\nExpected:\n"+reference.print());

	// Set-up workspace for compressed column adding
	double* wrk_data = new double[10];
	int*    wrk_row  = new int[10];

    // Compressed tests
    test_try("Verify compressed column add_col() method");
    try {

        // Insert column into 10 x 10 matrix using large matrix stack and the
        // compressed column add_col() method
        sparse    = initial;
        reference = initial;
        sparse.stack_init(100,50);
        for (int j = 0; j < 10; ++j) {
            int col = int(0.8 * j + 0.5);    // This allows that some columns are twice
            if (col > 9) col -= 10;          // This avoids overflow
            int inx   = 0;
            int i_min = (j < 3) ?  0 : j-3;
            int i_max = (j > 8) ? 10 : j+2;
            for (int i = i_min; i < i_max; ++i) {
                wrk_data[inx]     = (i+1)*3.7;
                wrk_row[inx]      = i;
                reference(i,col) += wrk_data[inx];
                inx++;
            }
            sparse.add_to_column(col, wrk_data, wrk_row, inx);
        }
        sparse.stack_destroy();
        test_assert((sparse == reference),
                    "Test stack fill with large stack using compressed add_col() method",
                    "Found:\n"+sparse.print()+"\nExpected:\n"+reference.print());

        // Insert column into 10 x 10 matrix using small matrix stack and the
        // compressed column add_col() method
        sparse = initial;
        sparse.stack_init(100,2);
        for (int j = 0; j < 10; ++j) {
            int col = int(0.8 * j + 0.5);    // This allows that some columns are twice
            if (col > 9) col -= 10;          // This avoids overflow
            int inx   = 0;
            int i_min = (j < 3) ?  0 : j-3;
            int i_max = (j > 8) ? 10 : j+2;
            for (int i = i_min; i < i_max; ++i) {
                wrk_data[inx] = (i+1)*3.7;
                wrk_row[inx]  = i;
                inx++;
            }
            sparse.add_to_column(col, wrk_data, wrk_row, inx);
        }
        sparse.stack_destroy();
        test_assert((sparse == reference),
                    "Test stack fill with small stack using compressed add_col() method",
                    "Found:\n"+sparse.print()+"\nExpected:\n"+reference.print());

        // Insert column into 10 x 10 matrix using tiny matrix stack and the
        // compressed column add_col() method
        sparse = initial;
        sparse.stack_init(3,2);
        for (int j = 0; j < 10; ++j) {
            int col = int(0.8 * j + 0.5);    // This allows that some columns are twice
            if (col > 9) col -= 10;          // This avoids overflow
            int inx   = 0;
            int i_min = (j < 3) ?  0 : j-3;
            int i_max = (j > 8) ? 10 : j+2;
            for (int i = i_min; i < i_max; ++i) {
                wrk_data[inx] = (i+1)*3.7;
                wrk_row[inx]  = i;
                inx++;
            }
            sparse.add_to_column(col, wrk_data, wrk_row, inx);
        }
        sparse.stack_destroy();
        test_assert((sparse == reference),
                    "Test stack fill with tiny stack using compressed add_col() method",
                    "Found:\n"+sparse.print()+"\nExpected:\n"+reference.print());

        // Insert column into 10 x 10 matrix using no matrix stack and the
        // compressed column add_col() method
        sparse = initial;
        for (int j = 0; j < 10; ++j) {
            int col = int(0.8 * j + 0.5);    // This allows that some columns are twice
            if (col > 9) col -= 10;          // This avoids overflow
            int inx   = 0;
            int i_min = (j < 3) ?  0 : j-3;
            int i_max = (j > 8) ? 10 : j+2;
            for (int i = i_min; i < i_max; ++i) {
                wrk_data[inx] = (i+1)*3.7;
                wrk_row[inx]  = i;
                inx++;
            }
            sparse.add_to_column(col, wrk_data, wrk_row, inx);
        }
        sparse.stack_destroy();
        test_assert((sparse == reference),
                    "Test fill using compressed add_col() method",
                    "Found:\n"+sparse.print()+"\nExpected:\n"+reference.print());

        // Signal success
        test_try_success();
    }
    catch (std::exception &e) {
        test_try_failure(e);
    }

	// Free workspace
	delete [] wrk_data;
	delete [] wrk_row;

    // Return
    return;
}
예제 #9
0
bool SiconosMatrix::fillCSC(CSparseMatrix* csc, size_t row_off, size_t col_off, double tol)
{
  assert(csc);
  double* Mx = csc->x; // data
  CS_INT* Mi = csc->i; // row indx
  CS_INT* Mp = csc->p; // column pointers

  assert(Mp[col_off] >= 0);
  size_t nz = csc->p[col_off];

  size_t nrow = size(0);
  size_t ncol = size(1);

  CS_INT pval = Mp[col_off];

  if (_num == 1) //dense
  {
    double* arr = getArray();
    for (size_t j = 0, joff = col_off; j < ncol; ++j)
    {
      for (size_t i = 0; i < nrow; ++i)
      {
        // col-major
        double elt_val = arr[i + j*nrow];
        // std::cout << " a(i=" << i << ",j=" << j << ") = "<< elt_val << std::endl;
        if (fabs(elt_val) > tol)
        {
          Mx[pval] = elt_val;
          Mi[pval] = i + row_off;
          // std::cout << "Mx[" <<pval <<"] = " << Mx[pval]<<   std::endl;
          // std::cout << "Mp[" <<pval <<"] = " << Mi[pval]<<   std::endl;
          ++pval;
        }
      }
      // std::cout << "joff" << joff << std::endl;
      Mp[++joff] = pval;

    }
  }
  else if (_num == 4)
  {
    const Index& ptr = sparse()->index1_data();
    const Index& indx = sparse()->index2_data();
    const ublas::unbounded_array<double>& vals = sparse()->value_data();

    size_t nnz =  sparse()->nnz();

    assert(ptr.size() == ncol + 1);
    assert(indx.size() == nnz);
    assert(vals.size() == nnz);

    for (size_t i = 0; i < nnz; ++i)
    {
      Mx[pval] = vals[i];
      Mi[pval++] = row_off + indx[i];
    }
    for (size_t j = 1, joff = col_off + 1; j < ncol+1; ++j, ++joff)
    {
      Mp[joff] = nz + ptr[j];
    }
  }
  else
  {
     SiconosMatrixException::selfThrow("SiconosMatrix::fillCSC not implemented for the given matrix type");
  }

  return true;
}
예제 #10
0
 static MatType sparse(const std::pair<int, int>& rc) { return sparse(rc.first, rc.second);}
예제 #11
0
파일: cg.c 프로젝트: 8l/rose
/*---------------------------------------------------------------------
c       generate the test problem for benchmark 6
c       makea generates a sparse matrix with a
c       prescribed sparsity distribution
c
c       parameter    type        usage
c
c       input
c
c       n            i           number of cols/rows of matrix
c       nz           i           nonzeros as declared array size
c       rcond        r*8         condition number
c       shift        r*8         main diagonal shift
c
c       output
c
c       a            r*8         array for nonzeros
c       colidx       i           col indices
c       rowstr       i           row pointers
c
c       workspace
c
c       iv, arow, acol i
c       v, aelt        r*8
c---------------------------------------------------------------------*/
static void makea(
    int n,
    int nz,
    double a[],		/* a[1:nz] */
    int colidx[],	/* colidx[1:nz] */
    int rowstr[],	/* rowstr[1:n+1] */
    int nonzer,
    int firstrow,
    int lastrow,
    int firstcol,
    int lastcol,
    double rcond,
    int arow[],		/* arow[1:nz] */
    int acol[],		/* acol[1:nz] */
    double aelt[],	/* aelt[1:nz] */
    double v[],		/* v[1:n+1] */
    int iv[],		/* iv[1:2*n+1] */
    double shift )
{
    int i, nnza, iouter, ivelt, ivelt1, irow, nzv;

/*--------------------------------------------------------------------
c      nonzer is approximately  (int(sqrt(nnza /n)));
c-------------------------------------------------------------------*/

    double size, ratio, scale;
    int jcol;

    size = 1.0;
    ratio = pow(rcond, (1.0 / (double)n));
    nnza = 0;

/*---------------------------------------------------------------------
c  Initialize colidx(n+1 .. 2n) to zero.
c  Used by sprnvc to mark nonzero positions
c---------------------------------------------------------------------*/
#pragma omp parallel for 
    for (i = 1; i <= n; i++) {
	colidx[n+i] = 0;
    }
    for (iouter = 1; iouter <= n; iouter++) {
	nzv = nonzer;
	sprnvc(n, nzv, v, iv, &(colidx[0]), &(colidx[n]));
	vecset(n, v, iv, &nzv, iouter, 0.5);
	for (ivelt = 1; ivelt <= nzv; ivelt++) {
	    jcol = iv[ivelt];
	    if (jcol >= firstcol && jcol <= lastcol) {
		scale = size * v[ivelt];
		for (ivelt1 = 1; ivelt1 <= nzv; ivelt1++) {
	            irow = iv[ivelt1];
                    if (irow >= firstrow && irow <= lastrow) {
			nnza = nnza + 1;
			if (nnza > nz) {
			    printf("Space for matrix elements exceeded in"
                                   " makea\n");
                            printf("nnza, nzmax = %d, %d\n", nnza, nz);
			    printf("iouter = %d\n", iouter);
			    exit(1);
			}
			acol[nnza] = jcol;
			arow[nnza] = irow;
			aelt[nnza] = v[ivelt1] * scale;
		    }
		}
	    }
	}
	size = size * ratio;
    }

/*---------------------------------------------------------------------
c       ... add the identity * rcond to the generated matrix to bound
c           the smallest eigenvalue from below by rcond
c---------------------------------------------------------------------*/
    for (i = firstrow; i <= lastrow; i++) {
	if (i >= firstcol && i <= lastcol) {
	    iouter = n + i;
	    nnza = nnza + 1;
	    if (nnza > nz) {
		printf("Space for matrix elements exceeded in makea\n");
		printf("nnza, nzmax = %d, %d\n", nnza, nz);
		printf("iouter = %d\n", iouter);
		exit(1);
	    }
	    acol[nnza] = i;
	    arow[nnza] = i;
	    aelt[nnza] = rcond - shift;
	}
    }

/*---------------------------------------------------------------------
c       ... make the sparse matrix from list of elements with duplicates
c           (v and iv are used as  workspace)
c---------------------------------------------------------------------*/
    sparse(a, colidx, rowstr, n, arow, acol, aelt,
           firstrow, lastrow, v, &(iv[0]), &(iv[n]), nnza);
}