Beispiel #1
0
 DLLEXPORT void XGBoosterBoostOneIter( void *handle, void *dtrain, 
                             float *grad, float *hess, size_t len, int bst_group ){
     Booster *bst = static_cast<Booster*>(handle);
     DMatrix *dtr = static_cast<DMatrix*>(dtrain);
     bst->CheckInit(); dtr->CheckInit(); 
     bst->BoostOneIter( *dtr, grad, hess, len, bst_group );
 }      
Beispiel #2
0
double SQPInternal::quad_form(const std::vector<double>& x, const DMatrix& A){
  // Assert dimensions
  casadi_assert(x.size()==A.size1() && x.size()==A.size2());
  
  // Access the internal data of A
  const std::vector<int> &A_rowind = A.rowind();
  const std::vector<int> &A_col = A.col();
  const std::vector<double> &A_data = A.data();
  
  // Return value
  double ret=0;

  // Loop over the rows of A
  for(int i=0; i<x.size(); ++i){
    // Loop over the nonzeros of A
    for(int el=A_rowind[i]; el<A_rowind[i+1]; ++el){
      // Get column
      int j = A_col[el];
      
      // Add contribution
      ret += x[i]*A_data[el]*x[j];
    }
  }
  
  return ret;
}
Beispiel #3
0
 DLLEXPORT void XGBoosterUpdateInteract( void *handle, void *dtrain, const char *action ){
     Booster *bst = static_cast<Booster*>(handle);
     DMatrix *dtr = static_cast<DMatrix*>(dtrain); 
     bst->CheckInit(); dtr->CheckInit(); 
     std::string act( action );
     bst->UpdateInteract( act, *dtr );
 }
//--------------------------------------------------------------------------
double Performance(const DVector &ytest_truth, const DMatrix &Ytest_predict,
                   int NumClasses) {

  long n = ytest_truth.GetN();
  if (n != Ytest_predict.GetM() || Ytest_predict.GetN() != NumClasses ) {
    printf("Performance. Error: Size mismatch. Return NAN");
    return NAN;
  }
  if (NumClasses <= 2) {
    printf("Performance. Error: Not multiclass classification. Return NAN");
    return NAN;
  }
  double perf = 0.0;

  // Compute ytest_predict
  DVector ytest_predict(n);
  double *y = ytest_predict.GetPointer();
  for (long i = 0; i < n; i++) {
    DVector row(NumClasses);
    Ytest_predict.GetRow(i, row);
    long idx = -1;
    row.Max(idx);
    y[i] = (double)idx;
  }

  // Accuracy
  double *y1 = ytest_truth.GetPointer();
  double *y2 = ytest_predict.GetPointer();
  for (long i = 0; i < n; i++) {
    perf += ((int)y1[i])==((int)y2[i]) ? 1.0 : 0.0;
  }
  perf = perf/n * 100.0;

  return perf;
}
Beispiel #5
0
returnValue ModelData::setNARXmodel( const uint _delay, const DMatrix& _parms ) {

	if( rhs_name.empty() && NX2 == 0 && NX3 == 0 ) {
		NX2 = _parms.getNumRows();
		delay = _delay;
		uint numParms = 1;
		uint n = delay*getNX();
		if( delay >= 1 ) {
			numParms = numParms + n;
		}
		for( uint i = 1; i < delay; i++ ) {
			numParms = numParms + (n+1)*(uint)pow((double)n,(int)i)/2;
		}
		if( _parms.getNumCols() == numParms ) {
			parms = _parms;
		}
		else {
			return ACADOERROR( RET_UNABLE_TO_EXPORT_CODE );
		}

		export_rhs = BT_TRUE;
	}
	else {
		return ACADOERROR( RET_INVALID_OPTION );
	}
	return SUCCESSFUL_RETURN;
}
Beispiel #6
0
returnValue ConstraintElement::get(Function& function_, DMatrix& lb_, DMatrix& ub_)
{
	if ( fcn == NULL )
		return RET_INITIALIZE_FIRST;

	// This is not exactly bullet proof, but for now will serve the purpose
	function_ = fcn[ 0 ];

	int dimFcn = fcn[ 0 ].getDim();

	if ( dimFcn == 0 )
	{
		lb_.init(0, 0);
		ub_.init(0, 0);

		return SUCCESSFUL_RETURN;
	}

	lb_.init(nB, dimFcn);
	ub_.init(nB, dimFcn);

	int i, j;

	for (i = 0; i < nB; ++i)
		for (j = 0; j < dimFcn; ++j)
		{
			lb_(i, j) = lb[ i ][ j ];
			ub_(i, j) = ub[ i ][ j ];
		}

	return SUCCESSFUL_RETURN;
}
Beispiel #7
0
void GLEABC::set_BBT(const DMatrix& nBBT)
{
    if (n==0) set_size(nBBT.rows());
    if (A.rows()>0) fr_init=true;
    if (n!=nBBT.rows()) ERROR("Use set_size if you want to change matrix size.");
    if (n!=nBBT.cols()) ERROR("Square matrix expected.");
    BBT=nBBT; fr_c=false;
}
Beispiel #8
0
int EigenVectors::TrimSystem(DMatrix &dmat, DArray &darr) const {
    dmat.pop_back();
    darr.pop_back();
    int i, size = dmat.size();
    for(i = 0; i < size; ++i) {
        dmat[i].pop_back();
    }
    return size;
}
returnValue ExportIRK4StageSimplifiedNewton::setEigenvalues( const DMatrix& _eig ) {
    eig = _eig;

    if( _eig.getNumRows() != 2 || _eig.getNumCols() != 2 ) return ACADOERROR( RET_INVALID_ARGUMENTS );
    if( _eig.isZero() ) return ACADOERROR( RET_INVALID_ARGUMENTS );
    // each row represents a complex conjugate pair of eigenvalues

    return SUCCESSFUL_RETURN;
}
Beispiel #10
0
void EigenVectors::InitMatrix(DMatrix &dmat, int size) const {
    if(!dmat.empty()) {
        dmat.clear();
    }
    DArray darr(size, 0.);
    dmat.reserve(size);
    for(int i = 0; i < size; ++i) {
        dmat.push_back(darr);
    }
}
//--------------------------------------------------------------------------
void ConvertYtrain(const DVector &ytrain, DMatrix &Ytrain, int NumClasses) {
  Ytrain.Init(ytrain.GetN(), NumClasses);
  // Lingfei: the y label is supposed to start from 0.
  for (int i = 0; i < NumClasses; i++) {
    DVector y = ytrain;
    double *my = y.GetPointer();
    for (long j = 0; j < y.GetN(); j++) {
      my[j] = ((int)my[j])==i ? 1.0 : -1.0;
    }
    Ytrain.SetColumn(i, y);
  }
}
Beispiel #12
0
int main(int argc, char *argv[])
{
  /*
  DMatrix W { 5, 5, 
      {   0,   4, inf,   2, inf, 
	inf,   0,   3, inf,   1, 
	  5, inf,   0,   1, inf, 
          7, inf, inf,   0,   5,
	  3, inf, inf, inf,   0 } };
  */

  // Checking that the value of n is given
  if (argc != 2) {
    cerr << "floyd-sequential n" << endl;
    exit(1);
  }
  int n = atoi(argv[1]);
  if (n == 0) {
    cerr << argv[1] << " is a wrong parameter" << endl;
    exit(1);
  }
   
  srand(10);

  DMatrix W = generate_matrix(n);

  DMatrix dist(W.rows(),W.cols(),inf);
  IMatrix next(W.rows(),W.cols(),-1);


  double start = omp_get_wtime();
  floyd_warshall(W, dist, next); 

  
  path_t p = recover_path(dist,next,0,(rand()%(n-1))+1);
  double end = omp_get_wtime();

  if (p.size() == 0) {
    cout << "No path" << endl;
  } else {
    copy(p.begin(), p.end(), ostream_iterator<int>(cout, " "));
    cout << "\n";
    double cost = 0;
    #pragma omp parallel for reduction (+:cost)
    for (uint32_t i = 0; i < p.size()-1; ++i) {
      cost += dist(p[i],p[i+1]);
    }
    cout << "Cost: " << cost << "\n";
  }
  
  cout << "Elapsed time: " << (end-start) << endl;
}
Beispiel #13
0
void GLEABC::set_C(const DMatrix& nC)
{
    if (n==0) set_size(nC.rows());
    if (A.rows()>0) fr_init=true;
    if (n!=nC.rows()) ERROR("Use set_size if you want to change matrix size.");
    if (n!=nC.cols()) ERROR("Square matrix expected.");
    C=nC; fr_c=true;
    if (fr_init && fr_c)
    {
        //update BBT, it's so cheap we can do it routinely;
        DMatrix T; mult(A, C, BBT); transpose(BBT, T);  incr(BBT,T);
    }
}
Beispiel #14
0
returnValue RungeKuttaExport::initializeButcherTableau( const DMatrix& _AA, const DVector& _bb, const DVector& _cc ) {

	if( _cc.isEmpty() || !_AA.isSquare() || _AA.getNumRows() != _bb.getDim() || _bb.getDim() != _cc.getDim() ) return RET_INVALID_OPTION;

	numStages = _cc.getDim();
	is_symmetric = checkSymmetry( _cc );
//	std::cout << "Symmetry of the chosen method: " << is_symmetric << "\n";
	AA = _AA;
	bb = _bb;
	cc = _cc;

	return SUCCESSFUL_RETURN;
}
  void CSparseCholeskyInternal::prepare() {

    prepared_ = false;

    // Get a reference to the nonzeros of the linear system
    const vector<double>& linsys_nz = input().data();

    // Make sure that all entries of the linear system are valid
    for (int k=0; k<linsys_nz.size(); ++k) {
      casadi_assert_message(!isnan(linsys_nz[k]), "Nonzero " << k << " is not-a-number");
      casadi_assert_message(!isinf(linsys_nz[k]), "Nonzero " << k << " is infinite");
    }

    if (verbose()) {
      userOut() << "CSparseCholeskyInternal::prepare: numeric factorization" << endl;
      userOut() << "linear system to be factorized = " << endl;
      input(0).printSparse();
    }

    if (L_) cs_nfree(L_);
    L_ = cs_chol(&AT_, S_) ;                 // numeric Cholesky factorization
    if (L_==0) {
      DMatrix temp = input();
      temp.makeSparse();
      if (temp.sparsity().issingular()) {
        stringstream ss;
        ss << "CSparseCholeskyInternal::prepare: factorization failed due "
          "to matrix being singular. Matrix contains numerical zeros which are"
          " structurally non-zero. Promoting these zeros to be structural "
          "zeros, the matrix was found to be structurally rank deficient. "
          "sprank: " << sprank(temp.sparsity()) << " <-> " << temp.size2() << endl;
        if (verbose()) {
          ss << "Sparsity of the linear system: " << endl;
          input(LINSOL_A).sparsity().print(ss); // print detailed
        }
        throw CasadiException(ss.str());
      } else {
        stringstream ss;
        ss << "CSparseCholeskyInternal::prepare: factorization failed, "
            "check if Jacobian is singular" << endl;
        if (verbose()) {
          ss << "Sparsity of the linear system: " << endl;
          input(LINSOL_A).sparsity().print(ss); // print detailed
        }
        throw CasadiException(ss.str());
      }
    }
    casadi_assert(L_!=0);

    prepared_ = true;
  }
void Solver::applyIntegrationOnRigidBodies(DMatrix& s_next, DMatrix& u_next)
{
	for (int i = 0; i< m_rigidBodies.size(); i++)
	{
		RigidBody_c* rb = m_rigidBodies[i];
		rb->m_position.x = s_next.Get(i * 7 + 0);
		rb->m_position.y = s_next.Get(i * 7 + 1);
		rb->m_position.z = s_next.Get(i * 7 + 2);
		rb->m_orientation.w = s_next.Get(i * 7 + 3);
		rb->m_orientation.x = s_next.Get(i * 7 + 4);
		rb->m_orientation.y = s_next.Get(i * 7 + 5);
		rb->m_orientation.z = s_next.Get(i * 7 + 6);
		rb->m_linearVelocity.x = u_next.Get(i * 6 + 0);
		rb->m_linearVelocity.y = u_next.Get(i * 6 + 1);
		rb->m_linearVelocity.z = u_next.Get(i * 6 + 2);
		rb->m_angularVelocity.x = u_next.Get(i * 6 + 3);
		rb->m_angularVelocity.y = u_next.Get(i * 6 + 4);
		rb->m_angularVelocity.z = u_next.Get(i * 6 + 5);
		rb->m_force = XMFLOAT3(0, 0, 0);
		rb->m_torque = XMFLOAT3(0, 0, 0);
		
		XMVECTOR normalQuaternion = XMQuaternionNormalize(XMLoadFloat4(&rb->m_orientation));
		XMStoreFloat4(&rb->m_orientation, normalQuaternion);
	}
}
DMatrix readVariable(const std::string &folder, const std::string filename)
{
    std::ifstream file;
    DMatrix variable;

    file.open(folder + filename);

    if(!file)
        throw std::runtime_error("Couldn't open the file " + folder + filename + ".");

    variable.read(file);
    file.close();
    return variable;
}
Beispiel #18
0
VariablesGrid::VariablesGrid(	const DMatrix& arg,
								VariableType _type
								) : MatrixVariablesGrid( arg.getNumCols()-1,1,arg.getNumRows(),_type )
{
	uint i,j;

	for( i=0; i<arg.getNumRows(); ++i )
	{
		setTime( i,arg( i,0 ) );

		for( j=1; j<arg.getNumCols(); ++j )
			operator()( i,j-1 ) = arg( i,j );
	}
}
/**
 * save a real matrix into a text file
 *
 * row_index  col_index   matrix_element
 */
void saveMatrixText(std::string filename, DMatrix& m, bool exactValue) {
	std::ofstream out(filename.c_str());
	// print to full precision
	if (exactValue) {
		out.precision(dbl::digits10 + 2);
	}
	// use default precision to save space
	for (int row=0; row< m.rows(); ++row) {
		for (int col=0; col<m.cols(); ++col) {
			double v = m(row, col);
			out << row <<"  " << col << "  "
			<< v << std::endl;
		}
	}
	out.close();
}
Beispiel #20
0
void floyd_warshall(const DMatrix& W, 
		    DMatrix& dist, 
		    IMatrix& next)
{
  uint32_t nvertices = W.rows();
//#pragma omp parallel for
  for (uint32_t i = 0; i < nvertices; ++i) {
    for (uint32_t j = 0; j < nvertices; ++j) {
      dist(i,j) = W(i,j);
    }
  }

//#pragma omp parallel for
  for (uint32_t k=0; k < nvertices; ++k) {
    for (uint32_t i=0; i < nvertices; ++i) {
      for (uint32_t j=0; j < nvertices; ++j) {
	double tmp = dist(i,k) + dist(k,j);
	if (tmp < dist(i,j)) {
	  dist(i,j) = tmp;
	  next(i,j) = k;
	}
      }
    }
  }
}
Beispiel #21
0
//integrates the peak of the velocity-velocity correlation function from w*(1-d) to w*(1+d)
void harm_peak(const DMatrix& A, const DMatrix& BBT, double w, double d, double &pi)
{
    unsigned long n=A.rows();
    
    //prepares extended matrices
    toolbox::FMatrix<double> xA(n+1,n+1), xBBT(n+1,n+1), xC;
    xA*=0.; xBBT=xA;
    for (int i=0; i<n;++i)for (int j=0; j<n;++j)
    { xA(i+1,j+1)=A(i,j);  xBBT(i+1,j+1)=BBT(i,j); }
    xA(0,1)=-1; xA(1,0)=w*w;   //sets the harmonic hamiltonian part
    GLEABC abc; abc.set_A(xA); abc.set_BBT(xBBT);
    
    //std::cerr<<" ---  C in tauw "<<w<<" ----\n"<<xC<<" ---------- \n";
    abc.get_C(xC);
    
    //get power spectrum peak intensity (should program a better way to integrate....)
    //the total integral under the peak is Pi/2
    FMatrix<double> AW1(xA), AW2(xA), atAW1, atAW2;
    
    AW1*=(1./(w*(1.-d/2.)));
    AW2*=(1./(w*(1.+d/2.)));
    
    MatrixFunction(AW1,&atan,atAW1);
    MatrixFunction(AW2,&atan,atAW2);
    mult(atAW1,xC,AW1); mult(atAW2,xC,AW2);
    
    pi=2./toolbox::constant::pi*(AW1(1,1)-AW2(1,1))/xC(1,1);
}
Beispiel #22
0
    // xgboost implementation
    DLLEXPORT void *XGBoosterCreate( void *dmats[], size_t len ){

        std::vector<xgboost::regrank::DMatrix*> mats;
        for( size_t i = 0; i < len; ++i ){
            DMatrix *dtr = static_cast<DMatrix*>(dmats[i]);
            dtr->CheckInit();
            log_debug("XGBoosterCreate: * i=%u", (unsigned int)i);
            mats.push_back( dtr );
            log_debug("XGBoosterCreate: ** i=%u", (unsigned int)i);
        }
       
        log_debug("XGBoosterCreate: xxxx");
        log_debug("XGBoosterCreate: mats=%u", (unsigned int)mats.size());
        void *booster = new Booster( mats );
        log_debug("XGBoosterCreate: booster=%p", booster);
        return booster;
    }
Beispiel #23
0
returnValue OCP::minimizeLSQEndTerm( const DMatrix   & S,
                                     const Function & m,
                                     const DVector   & r  ){

	if ( S.isPositiveSemiDefinite() == BT_FALSE )
		return ACADOERROR( RET_NONPOSITIVE_WEIGHT );

    return objective->addLSQEndTerm( S, m, r );
}
Beispiel #24
0
returnValue OCP::minimizeLSQ( const DMatrix        &S,
                              const Function      &h,
                              const VariablesGrid &r ){

	if ( S.isPositiveSemiDefinite() == BT_FALSE )
		return ACADOERROR( RET_NONPOSITIVE_WEIGHT );

    MatrixVariablesGrid tmpS(S);
    return objective->addLSQ( &tmpS, h, &r );
}
Beispiel #25
0
void Legendre::FindPolynomial(DArray &dArray) {
 DMatrix dMatrix;
 dMatrix.reserve(nn);
 dArray.clear();
 dArray.reserve(nn);
//double dbg[6] = { -.7746, .5556, 0., .8889, .7746, .5556 };
 for(int i = 0; i < nn; ++i) {
  double rat = static_cast<double>(i + 1) / static_cast<double>(nn);
  dArray.push_back((i % 2) ? 1. - fabs(dArray[i - 1]) / (ul - ll) * 2. : (ll + (ul - ll) * rat));
  //dArray.push_back(rat);
//dArray.push_back(dbg[i]);
cerr << "Initially " << i << ": " << dArray[i] << endl;
  dMatrix.push_back(dIntegrals);
 }
 do {
  Increment(dMatrix, dArray);
  SolveSytem(dMatrix, dArray);
 } while(ComputeError(dArray) > precision);  
 ExtractPolynomial(dArray);
}
Beispiel #26
0
EigenValues::EigenValues(const DMatrix& input) {
 int size = input.size();
 input_.reserve(size);
 CDArray cdarr(size);
 for(int i = 0; i < size; ++i) {
  for(int j = 0; j < size; ++j) {
   cdarr[j] = cd(input[i][j], 0.); 
  } 
  input_.push_back(cdarr);
 } 
}
Beispiel #27
0
void harm_check(const DMatrix& A, const DMatrix& BBT, double w, double &tq2, double &tp2, double& th, double& q2, double& p2, double& pq, double& dwq, double& dwp, double& lambdafp)
{
    unsigned long n=A.rows();
    double w2=w*w, w4=w2*w2; 
    
    //prepares extended matrices
    toolbox::FMatrix<double> xA(n+1,n+1), xBBT(n+1,n+1), xC;
    xA*=0.; xBBT=xA;
    for (int i=0; i<n;++i)for (int j=0; j<n;++j)
    { xA(i+1,j+1)=A(i,j);  xBBT(i+1,j+1)=BBT(i,j); }
    xA(0,1)=-1; xA(1,0)=w2;   //sets the harmonic hamiltonian part
    GLEABC abc; abc.set_A(xA); abc.set_BBT(xBBT);
    
    std::valarray<std::complex<double> >eva; abc.get_evA(eva);
    lambdafp=eva[0].real(); 
    for (int i=0; i<n+1; i++) lambdafp=(eva[i].real()<lambdafp?eva[i].real():lambdafp);
    
//    std::cerr<<" ---  C in tauw "<<w<<" ----\n"<<xC<<" ---------- \n";
    abc.get_C(xC);
    double c00=xC(0,0), c01=xC(0,1), c11=xC(1,1); 
    
    q2=c00*w2;
    p2=c11;
    pq=c01*w;

    double t00, t01, t11;
    abc.get_tau2(0,0,0,0,t00); abc.get_tau2(0,0,1,1,t01); abc.get_tau2(1,1,1,1,t11);

    double qqqq=t00*w4;
    double qqpp=t01*w2;
    double ppqq=qqpp; //come on, the simmetry is evident. let's save time!
    double pppp=t11;

//    std::cerr<<"NEW: "<<qqqq<<","<<qqpp<<","<<ppqq<<","<<pppp<<"\n";
    double qqqq0=q2*q2;
    double qqpp0=pq*pq;
    double ppqq0=qqpp0;
    double pppp0=p2*p2;

    th=(pppp+qqqq+ppqq+qqpp)/(pppp0+qqqq0+ppqq0+qqpp0);
    tp2=pppp/pppp0;
    tq2=qqqq/qqqq0;
    
    //get power spectrum peak widths
    toolbox::FMatrix<double> t1, t2, xDELTA;
    mult(xA,xA,t1);                         //A^2
    for (int i=0; i<n+1;++i) t1(i,i)+=w2;   //A^2+w^2
    MatrixInverse(t1,t2);                   //1/(A^2+w^2)
    mult(xA,t2,t1);                         //A/(A^2+w^2)
    mult(t1,xC,xDELTA);                     //A/(A^2+w^2)C
    
    dwq=xC(0,0)/xDELTA(0,0);
    dwp=xC(1,1)/xDELTA(1,1);
}
Beispiel #28
0
 inline void BoostOneIter( const DMatrix &train, 
                           float *grad, float *hess, size_t len, int bst_group ){
     this->grad_.resize( len ); this->hess_.resize( len );
     memcpy( &this->grad_[0], grad, sizeof(float)*len );
     memcpy( &this->hess_[0], hess, sizeof(float)*len );
     
     if( grad_.size() == train.Size() ){
         if( bst_group < 0 ) bst_group = 0;
         base_gbm.DoBoost(grad_, hess_, train.data, train.info.root_index, bst_group);
     }else{
         utils::Assert( bst_group == -1, "must set bst_group to -1 to support all group boosting" );
         int ngroup = base_gbm.NumBoosterGroup();
         utils::Assert( grad_.size() == train.Size() * (size_t)ngroup, "BUG: UpdateOneIter: mclass" );
         std::vector<float> tgrad( train.Size() ), thess( train.Size() );
         for( int g = 0; g < ngroup; ++ g ){
             memcpy( &tgrad[0], &grad_[g*tgrad.size()], sizeof(float)*tgrad.size() );
             memcpy( &thess[0], &hess_[g*tgrad.size()], sizeof(float)*tgrad.size() );
             base_gbm.DoBoost(tgrad, thess, train.data, train.info.root_index, g );
         }
     }
 }
Beispiel #29
0
int main() {
 DMatrix dmat;
#if 1
 ifstream ifs("data.dat");
 string line;
 while(getline(ifs, line)) {
  DArray darr;
  double val;
  stringstream iss(line);
  while(iss >> val) {
   darr.push_back(val);
  }
  dmat.push_back(darr);
 }
#else
 DArray darr;
 darr.push_back(2.);
 darr.push_back(7.);
 darr.push_back(1.);
 dmat.push_back(darr);
 darr[0] = 3.;
 darr[1] = 4.;
 darr[2] = 8.;
 dmat.push_back(darr);
 darr[0] = 4.;
 darr[1] = 3.;
 darr[2] = 4.;
 dmat.push_back(darr);
#endif
 EigenValues egv(dmat);
 egv.ComputeEigenValues();
 egv.GetDeterminant();
 Laplacian lpl(dmat);
 cout << "Matrix determinant (original): " << lpl.GetDeterminant() << endl << endl;
 return 0;
}
Beispiel #30
0
void EigenVectors::PopulateSystem(DMatrix &dmat, DArray &darr, const DMatrix &appld, int ind) const {
    int size = appld.size();
    for(int i1 = 0, i2 = 0; i1 < size; ++i1) {
        if(i1 != ind) {
            darr[i2] -= appld[i1][ind];
            for(int j1 = 0, j2 = 0; j1 < size; ++j1) {
                if(j1 != ind) {
                    dmat[i2][j2] = appld[i1][j1];
                    ++j2;
                }
            }
            ++i2;
        }
    }
}