/* Compute random polytopes by generating points on the surface
   of an n-dimensional sphere.
   Copyright (C) 2001-2004 Roberto Bagnara <bagnara@cs.unipr.it>

This file is part of the Parma Polyhedra Library (PPL).

The PPL is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.

The PPL is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA.

For the most up-to-date information see the Parma Polyhedra Library
site: http://www.cs.unipr.it/ppl/ . */

#include "ppl_test.hh"
#include <vector>
#include <cmath>

using namespace std;
using namespace Parma_Polyhedra_Library;
using namespace Parma_Polyhedra_Library::IO_Operators;

#ifndef NOISY
#define NOISY 0
#endif

#ifndef M_PI
# define M_PI           3.14159265358979323846  /* pi */
#endif

// Please note: the following function picks up random point on the
// n-dimensional sphere, but they are not uniformly distributed.
// See the following paper on how to obtain a uniform distribution:

// J. S. Hicks, R. F. Wheeling.
// An efficient method for generating uniformly distributed points
// on the surface of an n-dimensional sphere,
// Communications of the ACM, Volume 2, Issue 4, pp. 17-19, April 1959.
//
// M. E. Muller.
// A note on a method for generating points uniformly on n-dimensional spheres,
// Communications of the ACM, Volume 2 Issue 4, pp. 19-20, April 1959.
//
// G. F. Schrack.
// Remark on algorithm 381 [G5],
// Communications of the ACM, Volume 15 Issue 6, p. 468, June 1972.

static void
point_on_the_unit_n_sphere(unsigned n,
			   const vector<float>& theta,
			   vector<float>& coordinate) {
  assert(n >= 2);
  if (n == 2) {
    coordinate[0] *= sin(theta[0]);
    coordinate[1] *= cos(theta[0]);
  }
  else {
    point_on_the_unit_n_sphere(n-1, theta, coordinate);
    float sin_theta_n_2 = sin(theta[n-2]);
    for (unsigned i = n-1; i-- > 0; )
      coordinate[i] *= sin_theta_n_2;
    coordinate[n-1] *= cos(theta[n-2]);
  }
}

static void
random_polytope(C_Polyhedron& ph, unsigned dimension, unsigned num_points,
		float radius = 1.0) {
  if (dimension < 2)
    abort();

  vector<float> theta(dimension-1);
  vector<float> coordinate(dimension);

  for (unsigned n = num_points; n > 0; --n) {
    // Compute n-1 random angles.
    for (unsigned i = dimension-1; i-- > 0; )
      theta[i] = 2.0*M_PI*static_cast<double>(rand())/RAND_MAX;
    // Compute float coordinates.
    for (unsigned i = dimension; i-- > 0; )
      coordinate[i] = radius;
    point_on_the_unit_n_sphere(dimension, theta, coordinate);

    LinExpression le;
    for (unsigned i = dimension; i-- > 0; )
      le += Variable(i)*Integer(coordinate[i]*1000000.0);
    ph.add_generator(point(le));
  }
}


int
main() TRY {
  set_handlers();

  for (int dimension = 2; dimension <= 6; ++dimension) {
    C_Polyhedron ph(dimension, C_Polyhedron::EMPTY);
    random_polytope(ph, dimension, dimension*dimension);
    const ConSys& cs = ph.constraints();
    unsigned num_constraints = 0;
    for (ConSys::const_iterator i = cs.begin(), cs_end = cs.end();
	 i != cs_end;
	 ++i)
      ++num_constraints;
    const GenSys& gs = ph.generators();
    unsigned num_points = 0;
    for (GenSys::const_iterator i = gs.begin(), gs_end = gs.end();
	 i != gs_end;
	 ++i) {
      if (i->type() != Generator::POINT)
	exit(1);
      ++num_points;
    }

#if NOISY
    cout << "dimension = " << dimension
	 << ", points = " << num_points << " (" << dimension*dimension << ")"
	 << ", constraints = " << num_constraints << endl;
#endif
  }
  return 0;
}
CATCH


syntax highlighted by Code2HTML, v. 0.9.1