/**
 * @brief Performs a two-dimensional inverse Fourier transform on
 * complex data.
 * 
 * @param input A rectangular array of complex numbers to tranform, of
 * size n*m.
 *
 * @param n The width of the input array.
 *
 * @param m The height of the input array.
 * 
 * @return The inverse Fourier transform of the input.
 */
ComplexNumber *FourierTransform::inverseTransform(ComplexNumber *input,
    int n, int m)
{
    int height = m;
    int width = n;
    
    ComplexNumber *output = new ComplexNumber[width*height];
    
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j ++)
        {
            ndx(output, j, i, n) = ndx(input, j, i, n).conj();
        }
    }
    
    ComplexNumber *trans = transform(output, n, m);
    
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            ndx(output, j, i, n) = ndx(trans, j, i, n).conj() * (1. / (height * width));
        }
    }

    delete[] trans;
    return output;
}
/**
 * @brief Performs a two-dimensional (forward) Fourier transform on
 * real data.
 * 
 * @param input A rectangular array of complex numbers to tranform, of
 * size n*m.
 *
 * @param n The width of the input array.
 *
 * @param m The height of the input array.
 * 
 * @return The Fourier transform of the input.
 */
ComplexNumber *FourierTransform::transform(double *input, int n, int m)
{
    ComplexNumber *complex = new ComplexNumber[n*m];
    
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            ndx(complex, j, i, n) = ComplexNumber::fromReal(ndx(input, j, i, n));

    return transform(complex, n, m);
}
/**
 * @brief Performs a two-dimensional (forward) Fourier transform on
 * complex data.
 * 
 * @param input A rectangular array of complex numbers to tranform, of
 * size n*m.
 *
 * @param n The width of the input array.
 *
 * @param m The height of the input array.
 * 
 * @return The Fourier transform of the input.
 */
ComplexNumber *FourierTransform::transform(ComplexNumber *input, int n, int m)
{
    int height = m;
    int width = n;
    
    ComplexNumber *step1 = new ComplexNumber[height*width];
    ComplexNumber *row = new ComplexNumber[width];
    
    for (int i = 0; i < height; i++)
    {        
        for (int j = 0; j < width; j++)
        {
            row[j] = ndx(input, j, i, n);
        }

        ComplexNumber *rowtrans = transform(row, width);

        for (int j = 0; j < width; j++)
        {
            ndx(step1, j, i, n) = rowtrans[j];
        }

        delete[] rowtrans;
    }

    delete[] row;

    ComplexNumber *step2 = new ComplexNumber[height*width];
    ComplexNumber *column = new ComplexNumber[height];
    
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            column[j] = ndx(step1, i, j, n);
        }

        ComplexNumber *coltrans = transform(column, height);
        
        for (int j = 0; j < height; j++)
        {
            ndx(step2, i, j, n) = coltrans[j];
        }

        delete[] coltrans;
    }

    delete[] column;
    delete[] step1;
    return step2;
}
inline typename VariableType<T>::Ptr Variable( int startndx, int nrofderiv)
{
        std::vector<int> ndx(nrofderiv);
        for (int i=0;i<nrofderiv;++i) {
            ndx[i] = startndx+i;
        }
        return Variable<T>(ndx);
}
Example #5
0
static PyObject* PyView_append(PyView *o, PyObject* _args, PyObject* kwargs) {
  try {
    PWOSequence args(_args);
    PWONumber ndx(o->GetSize());
    if (args.len() == 0)
      o->insertAt(ndx, kwargs);
    else
      o->insertAt(ndx, args[0]);
    return ndx.disOwn();
  }
  catch (...) { return 0; }
}
Example #6
0
/**
 * Gauss-Legendre quadature.
 * computes knots and weights of a Gauss-Legendre quadrature formula.
 * \param a Left endpoint of interval
 * \param b Right endpoint of interval
 * \param _t array of abscissa
 * \param _wts array of corresponding wights
 */
void gauss_legendre( double a, double b, const dvector& _t,
  const dvector& _wts )
//
//  Purpose:
//
//    computes knots and weights of a Gauss-Legendre quadrature formula.
//
//  Discussion:
//
//    The user may specify the interval (A,B).
//
//    Only simple knots are produced.
//
//    Use routine EIQFS to evaluate this quadrature formula.
//
//  Licensing:
//
//    This code is distributed under the GNU LGPL license.
//
//  Modified:
//
//    September 2010 by Derek Seiple
//
//  Author:
//
//    Original FORTRAN77 version by Sylvan Elhay, Jaroslav Kautsky.
//    C++ version by John Burkardt.
//
//  Reference:
//
//    Sylvan Elhay, Jaroslav Kautsky,
//    Algorithm 655: IQPACK, FORTRAN Subroutines for the Weights of
//    Interpolatory Quadrature,
//    ACM Transactions on Mathematical Software,
//    Volume 13, Number 4, December 1987, pages 399-415.
//
//  Parameters:
//
//    Input, double A, B, the interval endpoints, or
//    other parameters.
//
//    Output, double T[NT], the knots.
//
//    Output, double WTS[NT], the weights.
//
{
  dvector t=(dvector&) _t;
  dvector wts=(dvector&) _wts;

  if( t.indexmax()!=wts.indexmax() )
  {
    cerr << "Incompatible sizes in void "
"mygauss_legendre(double a, double b, const dvector& _t, const dvector& _wts)"
    << endl;
    ad_exit(-1);
  }

  t.shift(0);
  wts.shift(0);
  int nt = t.indexmax() + 1;
  int ub = nt-1;

  int i;
  int k;
  int l;
  double al;
  double ab;
  double abi;
  double abj;
  double be;
  double p;
  double shft;
  double slp;
  double temp;
  double tmp;
  double zemu;

  //  Compute the Gauss quadrature formula for default values of A and B.
  dvector aj(0,ub);
  dvector bj(0,ub);

  ab = 0.0;
  zemu = 2.0 / ( ab + 1.0 );
  for ( i = 0; i < nt; i++ )
  {
    aj[i] = 0.0;
  }
  for ( i = 1; i <= nt; i++ )
  {
    abi = i + ab * ( i % 2 );
    abj = 2 * i + ab;
    bj[i-1] = sqrt ( abi * abi / ( abj * abj - 1.0 ) );
  }

  //  Compute the knots and weights.
  if ( zemu <= 0.0 )  //  Exit if the zero-th moment is not positive.
  {
    cout << "\n";
    cout << "Fatal error!\n";
    cout << "  ZEMU <= 0.\n";
    exit ( 1 );
  }

  //  Set up vectors for IMTQLX.
  for ( i = 0; i < nt; i++ )
  {
    t[i] = aj[i];
  }
  wts[0] = sqrt ( zemu );
  for ( i = 1; i < nt; i++ )
  {
    wts[i] = 0.0;
  }

  //  Diagonalize the Jacobi matrix.
  imtqlx (t, bj, wts );

  for ( i = 0; i < nt; i++ )
  {
    wts[i] = wts[i] * wts[i];
  }

  //  Prepare to scale the quadrature formula to other weight function with
  //  valid A and B.
  ivector mlt(0,ub);
  for ( i = 0; i < nt; i++ )
  {
    mlt[i] = 1;
  }
  ivector ndx(0,ub);
  for ( i = 0; i < nt; i++ )
  {
    ndx[i] = i + 1;
  }

  dvector st(0,ub);
  dvector swts(0,ub);

  temp = 3.0e-14;
  al = 0.0;
  be = 0.0;
  if ( fabs ( b - a ) <= temp )
  {
    cout << "\n";
    cout << "Fatal error!\n";
    cout << "  |B - A| too small.\n";
    exit ( 1 );
  }
  shft = ( a + b ) / 2.0;
  slp = ( b - a ) / 2.0;

  p = pow ( slp, al + be + 1.0 );

  for ( k = 0; k < nt; k++ )
  {
    st[k] = shft + slp * t[k];
    l = abs ( ndx[k] );

    if ( l != 0 )
    {
      tmp = p;
      for ( i = l - 1; i <= l - 1 + mlt[k] - 1; i++ )
      {
        swts[i] = wts[i] * tmp;
        tmp = tmp * slp;
      }
    }
  }

  for(i=0;i<nt;i++)
  {
    t(i) = st(ub-i);
    wts(i) = swts(ub-i);
  }

  return;
}
Example #7
0
int main(int argc, char *argv[]) {
	cout << "Pulse of Prices Databases Ver 1.10 creator of "
		  << __DATE__ << "\n"
			  "Copyright (c) 1995, 1996 by Sergey Gershtein. Ural-Relcom, Ltd.\n"
			  "---------------------------------------------------------------\n"
			  "This program converts Oferta's Pulse database files from "
			  "current directory\n"
			  "into Pulse of Prices Viewer format.\n\n";

#ifndef DEBUG
	char *final_dir=".\\";
	if (argc>1)
		if (argv[1][0]=='?' || argv[1][1]=='?') {
			cout << "Usage: " << argv[0] << " <dest_dir>\n\n"
			"All the Oferta *.dbf files and optionally payments.ini file\n"
			"must be in current directory.  The resulting pulse.* files will\n"
			"be stored in the <dest_dir> directory.\n"
			"Be prepared that it may take a long time to create the bases.\n"
			"You can stop the program at any time by pressing Ctrl-C.\n";
			return 0;
		} else
		final_dir=argv[1];
#else
	if (argc>1)
		cout << "### This version was compiled with DEBUG option set.\n"
		"### It does not understand your argument '"<<argv[1]<<"'\n";
#endif

	cout << "Opening files:\n";

// clearing all the read-only attrs and stuff
   _rtl_chmod(b_address,1,0);
   _rtl_chmod(b_offer,1,0);
   _rtl_chmod(b_product,1,0);
   _rtl_chmod(b_prodtype,1,0);
// opening the bases
   BSS *o_address=open_dbf(b_address);
   cout << "   " << b_address;
   if (!o_address) {
      cout << " - error opening file\n";
      return 1;
   } else
      cout << endl;
   BSS *o_offer = open_dbf(b_offer);
   cout << "   " << b_offer;
   if (!o_offer) {
      cout << " - error opening file\n";
      return 1;
	} else
      cout << endl;
   BSS *o_product = open_dbf(b_product);
   cout << "   " << b_product;
   if (!o_product) {
      cout << " - error opening file\n";
      return 1;
   } else
      cout << endl;
   BSS *o_prodtype = open_dbf(b_prodtype);
   cout << "   " << b_prodtype;
   if (!o_prodtype) {
      cout << " - error opening file\n";
      return 1;
   } else
      cout << endl;

// bases opened.  Now reading... ------------------------ PPF ---------------
#ifndef NOPPF
{
   cout << "Creating pulse.ppf... ";
   if (!ppf.create(final_dir,(ushort)o_address->Amount)) {
      cout << "file creation error!\n";
      return 1;
   }
   ppf.firm = new char[17];
   ppf.address = new char[61];
   ppf.fullname = new char[120];
   for (ushort n=1; n<=o_address->Amount; n++) { // for each record
		if (n%10==1) {
         cout.width(6);
         cout << n << ' ';
         cout << "\x8\x8\x8\x8\x8\x8\x8";
      }
      if (read_dbf(o_address,n)) {
         cout << "Error reading database record!\n";
         return 1;
      }
      if (read_buf(o_address,ppf.firm,NULL,ppf.address,ppf.fullname,
         &ppf.phone[0],&ppf.phone[1],&ppf.phone[2],&ppf.phone[3],&ppf.area)) {
         cout << "Error parsing database record!\n";
         return 1;
      }
      for (char *s=ppf.firm; (*s=upcase(*s))!=0; s++) ; // upcase firm name
      if (!ppf.write()) {
         cout << "Error writing record!\n";
         return 1;
      }
   }
   delete[] ppf.firm;
   delete[] ppf.address;
   delete[] ppf.fullname;
   ppf.close();
   cout << n << " records processed.\n";
}
#endif
// --------------------------- creating PPG file -----------------------------
#ifndef NOPPG
{  int n;
   long dsup=0, ddem=0;
   cout << "Reading groups information...         ";
   for (n=0; n<o_product->Amount; n++) {
      nidx[n]=n+1;
      cout << "\x8\x8\x8\x8\x8\x8\x8";
      cout.width(6);
      cout << (int)n << ' ';
      if (read_dbf(o_product,n+1)) {
         cout << "Error reading database record!\n";
         return 1;
      }
      unsigned int recno;                  
      long last;
      if (read_buf(o_product,NULL,&recno,&g1[n],&last)) {
         cout << "Error parsing database record!\n";
         return 1;
      }
      if (read_dbf(o_prodtype,recno)) {
         cout << "Error reading database prodtyp_.dbf!\n";
         return 1;
      }
      int supply;
      if (read_buf(o_prodtype,NULL,NULL,NULL,&supply)) {
         cout << "Error parsing database prodtyp_.dbf record!\n";
         return 1;
      }
      if (supply) {
         dsup+=last-g1[n]+1;
			g1[n]-=ddem;
      } else { // demand
         ddem+=last-g1[n]+1;
         g1[n]-=dsup;
      }
      g1[n]--; // we start from zero, not one
   }

   cout << "\nSorting groups with InsertSort... ";
   for (int k=(int)o_product->Amount-2; k>=0; k--) {
      char save=nidx[k];   // save k-th element
      long sav1=g1[k];
      for (int j=k+1; (j<=o_product->Amount-1) &&
            cmpgr(o_product,save,nidx[j])>0; j++) {
         nidx[j-1]=nidx[j];
         g1[j-1]=g1[j];
      }
      nidx[j-1] = save;
      g1[j-1] = sav1;
      if (k%7==0) {
         cout.width(3);
         cout << k << "\x8\x8\x8";
      }
   }
   cout << "Done sorting.  \n";

   cout << "Creating pulse.ppg...        ";
   if (!ppg.create(final_dir,(ushort)o_product->Amount)) {
      cout << "file creation error!\n";
		return 1;
   }
   ppg.gname = new char[61];
   for (n=0; n<o_product->Amount; n++) { // for each record
      cout << "\x8\x8\x8\x8\x8\x8\x8";
      cout.width(6);
      cout << (int)n << ' ';
      if (read_dbf(o_product,nidx[n])) {
         cout << "Error reading database record!\n";
         return 1;
      }
      unsigned int recno;
      if (read_buf(o_product,ppg.gname,&recno,&ppg.gfirst,&ppg.gsize)) {
         cout << "Error parsing database record!\n";
         return 1;
      }
      ppg.gsize-=(--ppg.gfirst); // number of records, not the last record
      long gf=ppg.gfirst;
      ppg.gfirst=g1[n];   // not absolute one, but address in the index
      if (read_dbf(o_prodtype,recno)) {
         cout << "Error reading database prodtyp_.dbf!\n";
         return 1;
      }
      int supply;
      if (read_buf(o_prodtype,NULL,NULL,NULL,&supply)) {
         cout << "Error parsing database prodtyp_.dbf record!\n";
         return 1;
      }
      ppg.issupply = !(ppg.isdemand=(supply==0));
		if (!ppg.write()) {
         cout << "Error writing record!\n";
         return 1;
      }
      g1[n]=gf; // now g1 contains what gfirst used to be
   }
   delete[] ppg.gname;
   ppg.close();
   cout << "records processed.\n";
}
#endif
// creating .ppd file (uff..)
{
   try {
      ppi.paym = new Paym[30];   // let's start with 30 payment methods
      ulong pmno[30];            // number of times payment methods are used
      ppi.npaym = 0;
#ifdef DEBUG
      cout << "## coreleft: " << coreleft() << endl;
#endif
		ushort cblno=(ushort)((coreleft()-20000)/2048/4);
		VArrayL ndx(o_offer->Amount*2+2,"s_index.$$$",2048,cblno);
		cout << "Virtual array created: " << cblno << " 2048-element blocks allocated"
				  " for buffer\n";
		cout << "Memory should left afterwards: " << (coreleft() - ((long)cblno)*2048*4) << endl;
		cout << "Creating pulse.ppd... ";
		ppd.dupdate.Today();
		ppd.dcreate = ppd.dupdate;
		if (!ppd.create(final_dir)) {
			cout << "file creation error!\n";
			return 1;
		}
		for (long n=1; n<=o_offer->Amount; n++) { // for each record
			if (n%19==1) {
				cout.width(7);
				cout << n << ' ';
				cout << "\x8\x8\x8\x8\x8\x8\x8\x8";
         }
         if (read_dbf(o_offer,n)) {
            cout << "Error reading database record!\n";
            return 1;
         }
         double dprice;
         char payment[4];
         char date[7];
         if (read_buf(o_offer,NULL,NULL,&ppd.drec.fcode,NULL,&dprice,
             payment,date,ppd.drec.ad)) {
            cout << "Error parsing database record!\n";
            return 1;
         }
         ppd.drec.price=dprice;
         ppd.drec.fcode--;
         date[2]=date[5]=0;
         ppd.drec.dsubmit = Date(atoi(date),atoi(date+3),ppd.dcreate.year());

         for (int i=0; i<ppi.npaym; i++)// do we know this payment method?
            if (upcase(ppi.paym[i].abbr[0])==upcase(payment[0]) &&
                upcase(ppi.paym[i].abbr[1])==upcase(payment[1]) &&
                upcase(ppi.paym[i].abbr[2])==upcase(payment[2]))
                  break;
         if (i>=ppi.npaym) { // new payment method
				ppi.npaym = i+1;
            pmno[i]=0;
            for (int j=0; j<4; j++)
               ppi.paym[i].abbr[j]=payment[j];
            ppi.paym[i].coef=1;  // roubles form by default.
         }
         ppd.drec.pcode = i;
         pmno[i]++;
         for (char *s=ppd.drec.ad; (*s=upcase(*s))!=0; s++) ;
         if ((ndx[n-1]=ppd.write())==0) {
            cout << "Error writing record!\n";
            return 1;
         }
      }
      ppd.close();
      cout << (n-1) << " records processed.\n";
      cout << (int)ppi.npaym << " payment methods were encountered:\n";
      for (int i=0; i<ppi.npaym; i++) {
         if (i>0)
           cout << ", ";
         for (int j=0; j<4; j++)
            cout << ppi.paym[i].abbr[j];
         cout << " - ";
         cout.width(7);
         cout << pmno[i];
      }
      cout << endl;

      // finding minimum course
		cout << "Looking for the USD course... ";
      if (!ppg.open(final_dir)) {
         cout << "Error opening pulse.ppg!\n";
         return 1;
      }
      for (int i0=0; i0<ppg.Ngroups(); i0++) {
         if (!ppg.read()) {
            cout << "Error reading pulse.ppg record "<<i0<<"!\n";
            return 1;
         }
         if (strstr(ppg.gname,"‚€‹ž’€") && ppg.issupply)
            break;
      }
      double usdk=1e+10;
      if(!ppd.open(final_dir)) {
         cout << "Error opening pulse.ppd!\n";
         return 1;
      }
      if (i0>=ppg.Ngroups()) {
         cout << "!!!!!!!!!!!!!!!!! Not found !!!!!!!!!!!!!!!!!!!\n";
         usdk=4700;         // ????
      } else {
         for (i=0;i<ppg.gsize;i++) { // looking for course
            if (!ppd.read(ndx[g1[i0]+i])) {
               cout << "Error reading pulse.ppd records!\n";
               return 1;
            }
            if (strstr(ppd.drec.ad,"��Ž„€†€ USD") &&
                ppd.drec.price<usdk) // found
					 usdk = ppd.drec.price;
         }
         if (usdk<1e+9)
            cout << usdk << " roubles/$\n";
         else {
            cout << "Records not found!\n";
            usdk = 0;
         }
      }
      ppg.close();

      // working with payments.ini file

      cout << "Checking "<<payments_ini<<" file... ";
      ifstream inif(payments_ini,ios::in);
      if (!inif)
         cout << "File not found.\n";
      else { // working with the file
         cout << "File found\n";
         while (!inif.eof()) {
            char pmt[4];
            char line[30];
            inif.read(pmt,4); // read four characters of payment type
            if (inif.eof())
               break;
            inif.getline(line,29);
            for (i=0; i<ppi.npaym; i++)
               if (upcase(ppi.paym[i].abbr[0])==upcase(pmt[0]) &&
                   upcase(ppi.paym[i].abbr[1])==upcase(pmt[1]) &&
						 upcase(ppi.paym[i].abbr[2])==upcase(pmt[2])) { // found
                  char *c;
                  for (c=line; *c<=' '; c++); // skip leading blanks
                  if (*c=='$')  // dollar conversion coef
                     ppi.paym[i].coef = atof(++c)*usdk;
                  else
                     ppi.paym[i].coef = atof(c);
                  cout << "   ";
                  for (int j=0; j<4; j++)
                     cout << ppi.paym[i].abbr[j];
                  cout << " = " << ppi.paym[i].coef << " roubles\n";
                  break;
               } // payment methods found
         } // while not eof
         inif.close();
      } // .ini file found

      // building demand and supply lists
      cout << "Building demand and supply lists... ";
      long nsup=0, ndem=0; // number of supply and demand records
      if (!ppg.open(final_dir)) {
         cout << "Error opening pulse.ppg!\n";
         return 1;
      }
      for (i=0; i<ppg.Ngroups(); i++) {
         if (!ppg.read()) {
            cout << "Error reading pulse.ppg record "<<i<<"!\n";
            return 1;
         }
			if (ppg.issupply)
            nsup+=ppg.gsize;
         else if (ppg.isdemand) {
            ndem+=ppg.gsize;
            for (int j=0; j<ppg.gsize; j++) // set high bit to 1 for demand
               ndx[g1[i]+j]=ndx(g1[i]+j) | 0x80000000l;
         }
         cout.width(7);
         cout << (ndem+nsup) << "\x8\x8\x8\x8\x8\x8\x8";
      }
      cout << "Done           \n   " << nsup << " supply records.\n   "
           << ndem << " demand records.\n";
      ppg.close();
      // creating ppi file -------------------------------------

      cout << "Creating pulse.ppi:\n   ";
      if (!ppi.create(final_dir)) {
         cout << "File creation error!\n";
         return 1;
      }
      if (!ppi.write()) { // writing initial payment info records
         cout << "Error writing payment info records!\n";
         return 1;
      } else
         cout << "Payment information stored.\n";

      cout << "   Writing supply records list... ";
      if (!ppi.iselect(iSupply)) {
         cout << "Error storing index offset!\n";
			return 1;
      }
      for (n=0; n<o_offer->Amount; n++) // for each element
         if ((ndx(n) & 0x80000000l)==0) // supply
            if (!ppi.write(ndx(n))) {
               cout << "Error writing index element!\n";
               return 1;
            } else if (n%33==1) {
               cout.width(7);
               cout << n << "\x8\x8\x8\x8\x8\x8\x8";
            }
      cout << "Done.        \n";

      cout << "   Writing demand records list... ";
      if (!ppi.iselect(iDemand)) {
         cout << "Error storing index offset!\n";
         return 1;
      }
      for (n=0; n<o_offer->Amount; n++) // for each element
         if ((ndx(n) & 0x80000000l)!=0) // demand
            if (!ppi.write(ndx(n)&0x7fffffffl)) {
               cout << "Error writing index element!\n";
               return 1;
            } else if (n%33==1) {
               cout.width(7);
               cout << n << "\x8\x8\x8\x8\x8\x8\x8";
            }
      cout << "Done.        \n";
#ifndef NOASORT
		qsortads(ppd,ndx,0,o_offer->Amount-1);  // quick sort by names
      cout << "   Writing supply records list... ";
      if (!ppi.iselect(iSrtSupply)) {
         cout << "Error storing index offset!\n";
         return 1;
      }
      for (n=0; n<o_offer->Amount; n++) // for each element
         if ((ndx(n) & 0x80000000l)==0) // supply
            if (!ppi.write(n)) {
               cout << "Error writing index element!\n";
               return 1;
            } else if (n%33==1) {
               cout.width(7);
               cout << n << "\x8\x8\x8\x8\x8\x8\x8";
            }
      cout << "Done.        \n";

      cout << "   Writing demand records list... ";
      if (!ppi.iselect(iSrtDemand)) {
         cout << "Error storing index offset!\n";
         return 1;
      }
      for (n=0; n<o_offer->Amount; n++) // for each element
         if ((ndx(n) & 0x80000000l)!=0) // demand
            if (!ppi.write(n/*ndx(n)&0x7fffffffl*/)) {
               cout << "Error writing index element!\n";
               return 1;
            } else if (n%33==1) {
               cout.width(7);
					cout << n << "\x8\x8\x8\x8\x8\x8\x8";
            }
      cout << "Done.        \n";
#endif // alpha sort

      cout << "Building indexes for each payment type:\n";
      cout << "   Supply... ";
      ulong pmcur[30];  // index positions for each payment type
      pmcur[0]=0;
      for (n=0; n<ppi.npaym-1; n++) {
         pmcur[(int)n+1]=pmcur[(int)n]+pmno[(int)n];
         pmno[(int)n]=pmcur[(int)n];

#ifdef DEBUG
         cout << "pmcur[" << n << "]=" << pmcur[n] << " ";
#endif

      }

#ifdef DEBUG
      cout << endl;
#endif

      pmno[(int)n]=pmcur[(int)n];
// now pmno points to the beginnings of the lists, pmcur - to the endings
//      long ll=0;
      for (n=0; n<nsup; n++) {
         if (!ppd.read(ppi(n,TRUE),FALSE)) { // not reading ad string
            cerr << "Error reading data #1!\n";
				return 1;
         }
         union {
            ulong l;
            float f;
         } u;
         u.f = ppd.drec.price;

#ifdef DEBUG
   if (pmcur[ppd.drec.pcode]+o_offer->Amount+1>=o_offer->Amount*2+2) {
      cerr << "@1: pcode=" << (int)ppd.drec.pcode <<
              ", pmcur[pcode]=" << (long)pmcur[ppd.drec.pcode] <<
              ", Amount=" << o_offer->Amount << endl;
   }
#endif

         ndx[pmcur[ppd.drec.pcode]+o_offer->Amount+1]=u.l;
         ndx[pmcur[ppd.drec.pcode]++]=n;

         if (n%13==1) {
            cout.width(7);
            cout << n << "\x8\x8\x8\x8\x8\x8\x8";
         }
      }
      cout << n << " elements done.\n";
      cout << "   Sorting the lists:\n";

      for (n=0; n<ppi.npaym; n++) {  // sorting all lists
         if (pmno[(int)n]>=pmcur[(int)n])
				continue;   // no records for this payment type
#ifdef HEAPSORT
         cout << "     HeapSorting ";
#else
         cout << "     QuickSorting ";
#endif
         for (int j=0; j<4; j++)
            cout << ppi.paym[(int)n].abbr[j];
         cout << "... ";
#ifdef HEAPSORT
         heapsort(ppd,ppi,ndx,pmno[(int)n],pmcur[(int)n]-1,TRUE);
#else
         qsortprice(ppd,ppi,ndx,pmno[(int)n],pmcur[(int)n]-1,
            TRUE,o_offer->Amount+1);
#endif
#ifdef SORTCHECK
         cout << "DEBUG: Checking sort order...";
         if (!ppd.read(ppi(ndx(pmno[(int)n]),TRUE),FALSE)) {
            cout << "ee!";
            return -1;
         }
         for (long ll=pmno[(int)n]+1; ll<pmcur[(int)n]; ll++) {
            float pr=ppd.drec.price;
            union {
               ulong l;
               float f;
            } u1;
            u1.l=ndx(ll+o_offer->Amount+1);
            if (!ppd.read(ppi(ndx(ll),TRUE))) {
					cout << "ee!";
               return -1;
            }
            if (pr>ppd.drec.price) {
               cout << ll << ": SORT ERROR!\n";
         //      return -1;
            }
            cout.width(8);
            cout << ll << "\x8\x8\x8\x8\x8\x8\x8\x8";
         }
         cout << "Sort OK\n";
#endif
      }

      cout << "   Storing indexes... ";
      for (int jj=0; jj<o_product->Amount; jj++)
         nidx0[nidx[jj]-1]=jj;
      for (int pc=0; pc<ppi.npaym; pc++) {
         ppi.iselect(iPaym+pc*2);
         for (int gr=0; gr<o_product->Amount; gr++)
            gfirst[gr]=glast[gr]=-1;
         for (long n=pmno[pc]; n<pmcur[pc]; n++) {
            ppi.write(ndx(n));
            // finding to which group ndx(n) belongs... Binary search
            int left=0, right=(int)(o_product->Amount-1), mid;
            while (left<right) {
                  mid=(right+left)/2;
                  if (ndx(n)<g1[nidx0[mid]])
                     right=mid-1;
						else if (ndx(n)>=g1[nidx0[mid]] &&
                     (mid==o_product->Amount-1 || ndx(n)<g1[nidx0[mid+1]])) {
                     // found
                     left=mid;
                     break;
                  } else
                     left=mid+1;
               }
            // group found
            if (gfirst[nidx0[left]]==-1)
               gfirst[nidx0[left]]=n-pmno[pc];
            glast[nidx0[left]]=n-pmno[pc];
            // information stored in the array
            if (n%13==1) {
               cout.width(7);
               cout << n << "\x8\x8\x8\x8\x8\x8\x8";
            }
         }
         for (gr=0; gr<o_product->Amount; gr++)
            ppi.writeg(gr,gfirst[gr],glast[gr]);
      }
      cout << nsup << " elements done.\n";

      for (n=0; n<ppi.npaym; n++) {
         pmno[(int)n]=pmcur[(int)n];
      }

// now pmno points to the beginnings of the lists, pmcur - to the endings
      cout << "   Demand... ";
		for (n=0; n<ndem; n++) {
         if (!ppd.read(ppi(n,FALSE),FALSE)) { // demand records
            cerr << "Error reading data #1!\n";
            return 1;
         }
         union {
            ulong l;
            float f;
         } u;
         u.f = ppd.drec.price;
         ndx[pmcur[ppd.drec.pcode]+o_offer->Amount+1]=u.l;
         ndx[pmcur[ppd.drec.pcode]++]=n;
         if (n%13==1) {
            cout.width(7);
            cout << n << "\x8\x8\x8\x8\x8\x8\x8";
         }
      }
      cout << n << " elements done.\n";
      cout << "   Sorting the lists:\n";

      for (n=0; n<ppi.npaym; n++) {  // sorting all lists
         if (pmno[(int)n]>=pmcur[(int)n])
            continue;   // no records for this payment type
#ifdef HEAPSORT
         cout << "     HeapSorting ";
#else
         cout << "     QuickSorting ";
#endif
         for (int j=0; j<4; j++)
				cout << ppi.paym[(int)n].abbr[j];
         cout << "... ";
#ifdef HEAPSORT
         heapsort(ppd,ppi,ndx,pmno[(int)n],pmcur[(int)n]-1,FALSE);
#else
         qsortprice(ppd,ppi,ndx,pmno[(int)n],pmcur[(int)n]-1,
               FALSE,o_offer->Amount+1);
#endif
      }

      cout << "   Storing indexes... ";
      for (pc=0; pc<ppi.npaym; pc++) {
         ppi.iselect(iPaym+pc*2+1);
         for (long n=pmno[pc]; n<pmcur[pc]; n++) {
            ppi.write(ndx(n));
            if (n%13==1) {
               cout.width(7);
               cout << n << "\x8\x8\x8\x8\x8\x8\x8";
            }
         }
      }
      cout << ndem << " elements done.\n";

      ppd.close(); // NOT TO FORGET
      ppi.close();
      delete[] ppi.paym;
   } catch (VArrayErr err) {
      cout << "Virtual array exception #" << (int)err.code() << "\n";
      return 1;
	} catch (xalloc xa) {
      cout << "Memory allocation failure: " << xa.requested() << "bytes.\n";
      return 1;
   } catch (...) {
      cout << "Unhandled exception!\n";
      return 1;
   }
}

   cout << "Closing Oferta's files... ";
   if (close_dbf(o_address) || close_dbf(o_product) || close_dbf(o_prodtype) ||
      close_dbf(o_offer)) {
         cout << "Error closing Oferta's bases!\n";
         return 1;
      }

   cout << "Done.\n";
   return 0;
}