<commit_before>#include <Kernel/GL/vjGlxWindow.h>
#include <vjConfig.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <GL/glx.h>

#include <Kernel/GL/vjGlWindow.h>
#include <Kernel/vjKernel.h>
#include <Kernel/vjDebug.h>
#include <Kernel/vjDisplay.h>

vjGlxWindow::vjGlxWindow() {
   window_is_open = 0;
   window_width = window_height = -1;
}

void vjGlxWindow::swapBuffers() {
   glXSwapBuffers (x_display,  x_window);
}

int vjGlxWindow::open() {
   /* attempts to open the glxWindow & create the gl context.  Does nothing
    * if the window is already open (& returns true).
    * returns true for success, false for failure.
    * The newly opened window will be set as the calling proccess'
    * current gl context.
    */

   XEvent fooevent;
   XSetWindowAttributes w_attrib;
   int screen;

   vjDEBUG(2) << "glxWindow: Open window" << endl << vjDEBUG_FLUSH;

   if (window_is_open)
      return true;

   if (window_width == -1)
      vjDEBUG(1) << "ERROR: Window has not been configured\n" << vjDEBUG_FLUSH;

   if (! (x_display = XOpenDisplay (display_name)))
   {
      vjDEBUG(0) << "Unable to open display " << display_name << endl << vjDEBUG_FLUSH;
      return false;
   }

   screen = DefaultScreen (x_display);

   // get an XVisualInfo*, which we'll need below
   if ((visual_info = GetGlxVisInfo (x_display, screen)) == NULL)
   {
      vjDEBUG(0) << "glXChooseVisual failed\n" << flush << vjDEBUG_FLUSH;
      return false;
   }

   // window attributes.
   if ((w_attrib.colormap = XCreateColormap (x_display,
                                             RootWindow(x_display, screen),
                                             visual_info->visual,
                                             AllocNone)) == 0)
   {
      vjDEBUG(0) << "ERROR: XCreateColorMap failed on " << display_name << endl << vjDEBUG_FLUSH;
      return false;
   }
   w_attrib.event_mask = ExposureMask | StructureNotifyMask
                         | PointerMotionMask | KeyPressMask;
   w_attrib.border_pixel = 0x0;

   // create window
   if ((x_window = XCreateWindow (x_display, RootWindow(x_display, screen),
                                  origin_x, origin_y - window_height,
                                  window_width, window_height,
                                  0, visual_info->depth,
                                  InputOutput,
                                  visual_info->visual,
                                  CWEventMask | CWColormap | CWBorderPixel,
                                  /* ^--attrib mask*/
                                  &w_attrib))  /* Attributes */
       == 0)
   {
      vjDEBUG(0) << "ERROR: Couldn't create window for " << display_name << endl << vjDEBUG_FLUSH;
      return false;
   }

   /* Before we map the window, we need a name for it (this is also useful for
    * the resource cruft that'll get rid of the borders).
    */
   XClassHint *classhint = XAllocClassHint();
   classhint->res_name = (char*)window_name.c_str();
   classhint->res_class = "vj GLX";
   XSetClassHint (x_display, x_window, classhint);
   XFree (classhint);

   /* Get rid of window border, if configured to do so.
    * This technique doesn't require any modifications to the .XDefaults file
    * or anything, but it will only work with window managers based on MWM
    * (the Motif window manager).  That covers most cases.
    * Unfortunately, the generic X resources for communicating with a window
    * manager don't support this feature.
    */
   if (!border)
   {
      vjDEBUG(0) << "attempting to make window borderless" << endl << vjDEBUG_FLUSH;
      Atom vjMotifHints = XInternAtom (x_display, "_MOTIF_WM_HINTS", 0);
      if (vjMotifHints == None)
      {
         vjDEBUG(2) << "ERROR: Could not get X atom for _MOTIF_WM_HINTS." << endl << vjDEBUG_FLUSH;
      }
      else
      {
         MotifWmHints hints;
         hints.flags = MWM_HINTS_DECORATIONS;
         hints.decorations = 0;
         XChangeProperty(x_display, x_window,
                         vjMotifHints, vjMotifHints, 32,
                         PropModeReplace, (unsigned char *) &hints, 4);
      }
   }
/* END_BORDERLESS_STUFF*/

   /* The next few lines of crud are needed to get it through the window
    * manager's skull that yes, we DO have a REASON for wanting the window
    * to be positioned WHERE WE TOLD YOU TO, and not where YOU think it should
    * go, thank you very much, I'M the APPLICATION so stop $%^*&%#@! SECOND
    * GUESSING ME!
    */
   vjDEBUG(0) << "vjGlxWindow: Positioning window\n" << vjDEBUG_FLUSH;
   XSizeHints *sizehints = XAllocSizeHints();
   sizehints->flags = USPosition;
   XSetWMNormalHints (x_display, x_window, sizehints);
   XFree (sizehints);

   /* Now that we've straightened that out with a minimum of bloodshed,
    * we can actually map the window.  The XIfEvent lets us wait until
    * it's actually on screen.
    */

   XMapWindow (x_display, x_window);
   XIfEvent (x_display, &fooevent, EventIsMapNotify, (XPointer)x_window);

   vjDEBUG(0) << "vjGlxWindow: done map" << endl << vjDEBUG_FLUSH;

   if (! (glx_context = glXCreateContext (x_display,
                                          visual_info, NULL, True)))
   {
      vjDEBUG(0) << "ERROR: Couldn't create GlxContext for " << display_name << vjDEBUG_FLUSH
      << endl;
      return false;
   }

   if (!glXMakeCurrent ( x_display, x_window, glx_context  ))
   {
      vjDEBUG(0) << "ERROR: Couldn't set GlxContext for " << display_name << endl << vjDEBUG_FLUSH;
      return false;
   }

   /* allen found a hint online that if we have the controlling process
    * "disown" the gl context we just created, we could then have another
    * process pick it up and use it.  However, it doesn't seem to have
    * worked for us.
    */
   // glXMakeCurrent (x_display,0,0);

   window_is_open = 1;

   /*
   glEnable (GL_DEPTH_TEST);
   glClearDepth (1.0);
   glFlush();
   */
   return true;
}

int vjGlxWindow::close() {
   /* closes the window.
    * always returns true
    */
   /* note: this function mucks with the current rendering context */

   if (!window_is_open)
      return true;

   window_is_open = false;

   if (glx_context)
   {
      makeCurrent();
      glXDestroyContext (x_display,  glx_context);
      glFlush();
      glx_context = NULL;
   }
   if (x_window)
   {
      XDestroyWindow (x_display, x_window);
      x_window = NULL;
   }
   if (visual_info)
   {
      XFree (visual_info);
      visual_info = NULL;
   }
   if (x_display)
   {
      XCloseDisplay (x_display);
      x_display = NULL;
   }

   return true;

} /* close() */

bool vjGlxWindow::makeCurrent() {
   /* returns true for success,
    * false for failure (eg window not open or glXMakeCurrent fails)
    */
   if (!window_is_open)
      return false;

   return glXMakeCurrent ( x_display, x_window, glx_context  );
}

void vjGlxWindow::config(vjDisplay* _display)
{
   vjGlWindow::config(_display);

    // Get the vector of display chunks
   std::vector<vjConfigChunk*>* dispSysChunk;
   dispSysChunk = vjKernel::instance()->getInitialChunkDB()->getMatching("displaySystem");

   window_name = _display->getName();
   pipe = _display->getPipe();

   display_name = (*dispSysChunk)[0]->getProperty("xpipes", pipe);
   if(strcmp(display_name, "-1") == 0)    // Use display env
      strcpy(display_name, getenv("DISPLAY"));
   vjDEBUG(0) << "glxWindow display name is: " << display_name << endl << vjDEBUG_FLUSH;
}

/**** Static Helpers *****/
/* static */ bool vjGlxWindow::createHardwareSwapGroup(std::vector<vjGlWindow*> wins)
{
   // Convert to glx windows
   std::vector<vjGlxWindow*> glx_wins;

   if(wins.size() <= 0)
      vjDEBUG(0) << "WARNING: createHardwareSwapGroup called with no windows\n" << vjDEBUG_FLUSH;

   for(int i=0;i<wins.size();i++)
   {
      vjGlxWindow* glx_win = dynamic_cast<vjGlxWindow*>(wins[i]);
      vjASSERT(glx_win != NULL);    // Make sure we have the right type
      glx_wins.push_back(glx_win);
   }

   // Create hardware group
#ifdef VJ_OS_SGI
   for(i=0;i<glx_wins.size();i++)      // For each window
   {
      if(glx_wins[i] != this)    // If not me
      {                          //then add with me to the swap group
         glXJoinSwapGroupSGIX(x_display, x_window, glx_wins[i]->x_window);
      }
   }

#else
   vjDEBUG(0) << "WARNING: createHardwareSwapGroup not supported.\n" << vjDEBUG_FLUSH;
#endif
   return true;
}

/* private member functions.  these get profoundly painful */

XVisualInfo* vjGlxWindow::GetGlxVisInfo (Display *display, int screen)
{
   /* pre:  screen is a screen on the current XDisplay, and
    *       XDisplay is already defined and valid.
    * post: returns a pointer to an XVisualInfo to be used for GLX.
    *       Note that it doesn't necessarily have _all_ of the requested
    *       features... it will attempt to get a visual in mono or
    *       without alpha if it's virst attempts fail.
    *       Returns NULL if it can't come up with a reasonably close
    *       XVisualInfo, or if the display in question doesn't support
    *       GLX
    */

   XVisualInfo *vi;
   const int MaxAttributes = 32;
   int viattrib[MaxAttributes] = {
      GLX_DOUBLEBUFFER,
      GLX_RGBA,
      GLX_DEPTH_SIZE, 1,
      GLX_RED_SIZE, 1,
      GLX_GREEN_SIZE, 1,
      GLX_BLUE_SIZE, 1,
      GLX_ALPHA_SIZE, 1,
   };
   /* Notes on viattrib:  by using 1 for GLX_RED_SIZE et.al. we ask
    * for the _largest_ available buffers.  If this fails,  we might
    * want to try setting alpha size to 0 (smallest possible, maybe 0)
    * which is required eg. for alpha on the indys.
    *
    * Implementation note: the code below makes assumptions about the
    * exact order of the arguments in viattrib.  Alter those, & you'll
    * Need to redo the indices used.
    */
   int NumAttribs = 12;

   if (!glXQueryExtension (display, NULL, NULL))
   {
      vjDEBUG(0) << "ERROR: Display "<< display_name <<
      "doesn't support GLX.\n  Aborting.\n" <<flush << vjDEBUG_FLUSH;
      return NULL;
   }

   if (mDisplay->inStereo())
   {
      viattrib[NumAttribs++] = GLX_STEREO;
      viattrib[NumAttribs] = None;
      in_stereo = true;
   }
   else
      in_stereo = false;

   // first, see if we can get exactly what we want.
   if (vi = glXChooseVisual (display, screen, viattrib))
      return vi;

   // still no luck. if we were going for stereo, let's try without.
   if (mDisplay->inStereo())
   {
      vjDEBUG(0) << "WARNING: Display process for " << display_name
                 << "\n  Couldn't get display in stereo."
                 << "\n  Trying mono.\n" << vjDEBUG_FLUSH;
      in_stereo = false;
      viattrib[12] = GLX_USE_GL; // should be a reasonable 'ignore' tag
      if (vi = glXChooseVisual (display, screen, viattrib))
         return vi;
   }

   // if we reach here, we didn't.  Maybe we should make alpha optional.
   vjDEBUG(0) << "WARNING: Display process for " << display_name
              << "\n  Couldn't get display with alpha channel."
              << "\n  Trying without." << endl << vjDEBUG_FLUSH;
   viattrib[11] = 0;
   if (vi = glXChooseVisual (display, screen, viattrib))
      return vi;

   // But they told me to please go f___ myself
   // You know you just can't win.  -d. gilmour
   return NULL;
}

//!PRE:  window is an xwindow under display
//!POST: returns true if e is a mapnotify event for window, else false
//!NOTE: this is a utility function for InitGfx,  used to wait
//+       until a window has actually been mapped.
int vjGlxWindow::EventIsMapNotify (Display *display,  XEvent *e,  XPointer window) {

   return ((e->type == MapNotify) && (e->xmap.window == (Window)window));
}

<commit_msg>string use fix, linux compatibility fix<commit_after>#include <Kernel/GL/vjGlxWindow.h>
#include <vjConfig.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <GL/glx.h>

#include <Kernel/GL/vjGlWindow.h>
#include <Kernel/vjKernel.h>
#include <Kernel/vjDebug.h>
#include <Kernel/vjDisplay.h>

vjGlxWindow::vjGlxWindow() {
   window_is_open = 0;
   window_width = window_height = -1;
}

void vjGlxWindow::swapBuffers() {
   glXSwapBuffers (x_display,  x_window);
}

int vjGlxWindow::open() {
   /* attempts to open the glxWindow & create the gl context.  Does nothing
    * if the window is already open (& returns true).
    * returns true for success, false for failure.
    * The newly opened window will be set as the calling proccess'
    * current gl context.
    */

   XEvent fooevent;
   XSetWindowAttributes w_attrib;
   int screen;

   vjDEBUG(2) << "glxWindow: Open window" << endl << vjDEBUG_FLUSH;

   if (window_is_open)
      return true;

   if (window_width == -1)
      vjDEBUG(1) << "ERROR: Window has not been configured\n" << vjDEBUG_FLUSH;

   if (! (x_display = XOpenDisplay (display_name)))
   {
      vjDEBUG(0) << "Unable to open display " << display_name << endl << vjDEBUG_FLUSH;
      return false;
   }

   screen = DefaultScreen (x_display);

   // get an XVisualInfo*, which we'll need below
   if ((visual_info = GetGlxVisInfo (x_display, screen)) == NULL)
   {
      vjDEBUG(0) << "glXChooseVisual failed\n" << flush << vjDEBUG_FLUSH;
      return false;
   }

   // window attributes.
   if ((w_attrib.colormap = XCreateColormap (x_display,
                                             RootWindow(x_display, screen),
                                             visual_info->visual,
                                             AllocNone)) == 0)
   {
      vjDEBUG(0) << "ERROR: XCreateColorMap failed on " << display_name << endl << vjDEBUG_FLUSH;
      return false;
   }
   w_attrib.event_mask = ExposureMask | StructureNotifyMask
                         | PointerMotionMask | KeyPressMask;
   w_attrib.border_pixel = 0x0;

   // create window
   if ((x_window = XCreateWindow (x_display, RootWindow(x_display, screen),
                                  origin_x, origin_y - window_height,
                                  window_width, window_height,
                                  0, visual_info->depth,
                                  InputOutput,
                                  visual_info->visual,
                                  CWEventMask | CWColormap | CWBorderPixel,
                                  /* ^--attrib mask*/
                                  &w_attrib))  /* Attributes */
       == 0)
   {
      vjDEBUG(0) << "ERROR: Couldn't create window for " << display_name << endl << vjDEBUG_FLUSH;
      return false;
   }

   /* Before we map the window, we need a name for it (this is also useful for
    * the resource cruft that'll get rid of the borders).
    */
   XClassHint *classhint = XAllocClassHint();
   classhint->res_name = (char*)window_name.c_str();
   classhint->res_class = "vj GLX";
   XSetClassHint (x_display, x_window, classhint);
   XFree (classhint);

   /* Get rid of window border, if configured to do so.
    * This technique doesn't require any modifications to the .XDefaults file
    * or anything, but it will only work with window managers based on MWM
    * (the Motif window manager).  That covers most cases.
    * Unfortunately, the generic X resources for communicating with a window
    * manager don't support this feature.
    */
   if (!border)
   {
      vjDEBUG(0) << "attempting to make window borderless" << endl << vjDEBUG_FLUSH;
      Atom vjMotifHints = XInternAtom (x_display, "_MOTIF_WM_HINTS", 0);
      if (vjMotifHints == None)
      {
         vjDEBUG(2) << "ERROR: Could not get X atom for _MOTIF_WM_HINTS." << endl << vjDEBUG_FLUSH;
      }
      else
      {
         MotifWmHints hints;
         hints.flags = MWM_HINTS_DECORATIONS;
         hints.decorations = 0;
         XChangeProperty(x_display, x_window,
                         vjMotifHints, vjMotifHints, 32,
                         PropModeReplace, (unsigned char *) &hints, 4);
      }
   }
/* END_BORDERLESS_STUFF*/

   /* The next few lines of crud are needed to get it through the window
    * manager's skull that yes, we DO have a REASON for wanting the window
    * to be positioned WHERE WE TOLD YOU TO, and not where YOU think it should
    * go, thank you very much, I'M the APPLICATION so stop $%^*&%#@! SECOND
    * GUESSING ME!
    */
   vjDEBUG(0) << "vjGlxWindow: Positioning window\n" << vjDEBUG_FLUSH;
   XSizeHints *sizehints = XAllocSizeHints();
   sizehints->flags = USPosition;
   XSetWMNormalHints (x_display, x_window, sizehints);
   XFree (sizehints);

   /* Now that we've straightened that out with a minimum of bloodshed,
    * we can actually map the window.  The XIfEvent lets us wait until
    * it's actually on screen.
    */

   XMapWindow (x_display, x_window);
   XIfEvent (x_display, &fooevent, EventIsMapNotify, (XPointer)x_window);

   vjDEBUG(0) << "vjGlxWindow: done map" << endl << vjDEBUG_FLUSH;

   if (! (glx_context = glXCreateContext (x_display,
                                          visual_info, NULL, True)))
   {
      vjDEBUG(0) << "ERROR: Couldn't create GlxContext for " << display_name << vjDEBUG_FLUSH
      << endl;
      return false;
   }

   if (!glXMakeCurrent ( x_display, x_window, glx_context  ))
   {
      vjDEBUG(0) << "ERROR: Couldn't set GlxContext for " << display_name << endl << vjDEBUG_FLUSH;
      return false;
   }

   /* allen found a hint online that if we have the controlling process
    * "disown" the gl context we just created, we could then have another
    * process pick it up and use it.  However, it doesn't seem to have
    * worked for us.
    */
   // glXMakeCurrent (x_display,0,0);

   window_is_open = 1;

   /*
   glEnable (GL_DEPTH_TEST);
   glClearDepth (1.0);
   glFlush();
   */
   return true;
}

int vjGlxWindow::close() {
   /* closes the window.
    * always returns true
    */
   /* note: this function mucks with the current rendering context */

   if (!window_is_open)
      return true;

   window_is_open = false;

   if (glx_context)
   {
      makeCurrent();
      glXDestroyContext (x_display,  glx_context);
      glFlush();
      glx_context = NULL;
   }
   if (x_window)
   {
      XDestroyWindow (x_display, x_window);
      x_window = 0;
   }
   if (visual_info)
   {
      XFree (visual_info);
      visual_info = NULL;
   }
   if (x_display)
   {
      XCloseDisplay (x_display);
      x_display = NULL;
   }

   return true;

} /* close() */

bool vjGlxWindow::makeCurrent() {
   /* returns true for success,
    * false for failure (eg window not open or glXMakeCurrent fails)
    */
   if (!window_is_open)
      return false;

   return glXMakeCurrent ( x_display, x_window, glx_context  );
}

void vjGlxWindow::config(vjDisplay* _display)
{
   vjGlWindow::config(_display);

    // Get the vector of display chunks
   std::vector<vjConfigChunk*>* dispSysChunk;
   dispSysChunk = vjKernel::instance()->getInitialChunkDB()->getMatching("displaySystem");

   window_name = _display->getName();
   pipe = _display->getPipe();

   display_name = (*dispSysChunk)[0]->getProperty("xpipes", pipe).cstring();
   if(strcmp(display_name, "-1") == 0)    // Use display env
      strcpy(display_name, getenv("DISPLAY"));
   vjDEBUG(0) << "glxWindow display name is: " << display_name << endl << vjDEBUG_FLUSH;
}

/**** Static Helpers *****/
/* static */ bool vjGlxWindow::createHardwareSwapGroup(std::vector<vjGlWindow*> wins)
{
   // Convert to glx windows
   std::vector<vjGlxWindow*> glx_wins;

   if(wins.size() <= 0)
      vjDEBUG(0) << "WARNING: createHardwareSwapGroup called with no windows\n" << vjDEBUG_FLUSH;

   for(int i=0;i<wins.size();i++)
   {
      vjGlxWindow* glx_win = dynamic_cast<vjGlxWindow*>(wins[i]);
      vjASSERT(glx_win != NULL);    // Make sure we have the right type
      glx_wins.push_back(glx_win);
   }

   // Create hardware group
#ifdef VJ_OS_SGI
   for(i=0;i<glx_wins.size();i++)      // For each window
   {
      if(glx_wins[i] != this)    // If not me
      {                          //then add with me to the swap group
         glXJoinSwapGroupSGIX(x_display, x_window, glx_wins[i]->x_window);
      }
   }

#else
   vjDEBUG(0) << "WARNING: createHardwareSwapGroup not supported.\n" << vjDEBUG_FLUSH;
#endif
   return true;
}

/* private member functions.  these get profoundly painful */

XVisualInfo* vjGlxWindow::GetGlxVisInfo (Display *display, int screen)
{
   /* pre:  screen is a screen on the current XDisplay, and
    *       XDisplay is already defined and valid.
    * post: returns a pointer to an XVisualInfo to be used for GLX.
    *       Note that it doesn't necessarily have _all_ of the requested
    *       features... it will attempt to get a visual in mono or
    *       without alpha if it's virst attempts fail.
    *       Returns NULL if it can't come up with a reasonably close
    *       XVisualInfo, or if the display in question doesn't support
    *       GLX
    */

   XVisualInfo *vi;
   const int MaxAttributes = 32;
   int viattrib[MaxAttributes] = {
      GLX_DOUBLEBUFFER,
      GLX_RGBA,
      GLX_DEPTH_SIZE, 1,
      GLX_RED_SIZE, 1,
      GLX_GREEN_SIZE, 1,
      GLX_BLUE_SIZE, 1,
      GLX_ALPHA_SIZE, 1,
   };
   /* Notes on viattrib:  by using 1 for GLX_RED_SIZE et.al. we ask
    * for the _largest_ available buffers.  If this fails,  we might
    * want to try setting alpha size to 0 (smallest possible, maybe 0)
    * which is required eg. for alpha on the indys.
    *
    * Implementation note: the code below makes assumptions about the
    * exact order of the arguments in viattrib.  Alter those, & you'll
    * Need to redo the indices used.
    */
   int NumAttribs = 12;

   if (!glXQueryExtension (display, NULL, NULL))
   {
      vjDEBUG(0) << "ERROR: Display "<< display_name <<
      "doesn't support GLX.\n  Aborting.\n" <<flush << vjDEBUG_FLUSH;
      return NULL;
   }

   if (mDisplay->inStereo())
   {
      viattrib[NumAttribs++] = GLX_STEREO;
      viattrib[NumAttribs] = None;
      in_stereo = true;
   }
   else
      in_stereo = false;

   // first, see if we can get exactly what we want.
   if (vi = glXChooseVisual (display, screen, viattrib))
      return vi;

   // still no luck. if we were going for stereo, let's try without.
   if (mDisplay->inStereo())
   {
      vjDEBUG(0) << "WARNING: Display process for " << display_name
                 << "\n  Couldn't get display in stereo."
                 << "\n  Trying mono.\n" << vjDEBUG_FLUSH;
      in_stereo = false;
      viattrib[12] = GLX_USE_GL; // should be a reasonable 'ignore' tag
      if (vi = glXChooseVisual (display, screen, viattrib))
         return vi;
   }

   // if we reach here, we didn't.  Maybe we should make alpha optional.
   vjDEBUG(0) << "WARNING: Display process for " << display_name
              << "\n  Couldn't get display with alpha channel."
              << "\n  Trying without." << endl << vjDEBUG_FLUSH;
   viattrib[11] = 0;
   if (vi = glXChooseVisual (display, screen, viattrib))
      return vi;

   // But they told me to please go f___ myself
   // You know you just can't win.  -d. gilmour
   return NULL;
}

//!PRE:  window is an xwindow under display
//!POST: returns true if e is a mapnotify event for window, else false
//!NOTE: this is a utility function for InitGfx,  used to wait
//+       until a window has actually been mapped.
int vjGlxWindow::EventIsMapNotify (Display *display,  XEvent *e,  XPointer window) {

   return ((e->type == MapNotify) && (e->xmap.window == (Window)window));
}

<|endoftext|>


<commit_before>/* -*- mode:linux -*- */
/**
 * \file tiles_state.cc
 *
 *
 *
 * \author Ethan Burns
 * \date 2008-11-03
 */

#include <assert.h>
#include <math.h>

#include <vector>
#include <iostream>

#include "tiles.h"
#include "tiles_state.h"

using namespace std;

TilesState::TilesState(SearchDomain *d, const State *parent, float g,
		       vector<unsigned int> tiles, unsigned int blank)
	: State(d, parent, g),
	  tiles(tiles),
	  blank(blank)
{
	assert(tiles[blank] == 0);
}

/**
 * Test if the tiles are in order.
 */
bool TilesState::is_goal(void) const
{
	Tiles * t= dynamic_cast<Tiles*>(domain);

	return t->is_goal(this);
}

int TilesState::hash(void) const
{
	int hash = 0;
	unsigned int max_size = tiles.size();

	// sum the place values
	for (unsigned int i = 0; i < max_size; i += 1)
		hash += (int) pow(max_size, i) * tiles[i];

	return hash;
}

State *TilesState::clone(void) const
{
	return new TilesState(domain, parent, g, tiles, blank);
}

void TilesState::print(ostream &o) const
{
	Tiles *t = dynamic_cast<Tiles*>(domain);
	unsigned int i = 0;

	for (unsigned int y = 0; y < t->get_height(); y += 1) {
		for (unsigned int x = 0; x < t->get_width(); x += 1) {
			o << tiles[i];
			if (x < t->get_width() - 1)
				o << "\t";
			i += 1;
		}
		o << endl;
	}
}

bool TilesState::equals(const State *s) const
{
	const TilesState *other = dynamic_cast<const TilesState *>(s);

	for (unsigned int i = 0; i < tiles.size(); i += 1)
		if (tiles[i] != other->tiles[i])
			return false;

	return true;
}

/**
 * Get the tile vector.
 */
vector<unsigned int> TilesState::get_tiles(void) const
{
	return tiles;
}

unsigned int TilesState::get_blank(void) const
{
	return blank;
}
<commit_msg>Add a few minor comments.<commit_after>/* -*- mode:linux -*- */
/**
 * \file tiles_state.cc
 *
 *
 *
 * \author Ethan Burns
 * \date 2008-11-03
 */

#include <assert.h>
#include <math.h>

#include <vector>
#include <iostream>

#include "tiles.h"
#include "tiles_state.h"

using namespace std;

TilesState::TilesState(SearchDomain *d, const State *parent, float g,
		       vector<unsigned int> tiles, unsigned int blank)
	: State(d, parent, g),
	  tiles(tiles),
	  blank(blank)
{
	assert(tiles[blank] == 0);
}

/**
 * Test if the tiles are in order.
 */
bool TilesState::is_goal(void) const
{
	Tiles * t= dynamic_cast<Tiles*>(domain);

	return t->is_goal(this);
}

int TilesState::hash(void) const
{
	int hash = 0;
	unsigned int max_size = tiles.size();

	// sum the place values
	for (unsigned int i = 0; i < max_size; i += 1)
		hash += (int) pow(max_size, i) * tiles[i];

	return hash;
}

State *TilesState::clone(void) const
{
	return new TilesState(domain, parent, g, tiles, blank);
}

void TilesState::print(ostream &o) const
{
	Tiles *t = dynamic_cast<Tiles*>(domain);
	unsigned int i = 0;

	for (unsigned int y = 0; y < t->get_height(); y += 1) {
		for (unsigned int x = 0; x < t->get_width(); x += 1) {
			o << tiles[i];
			if (x < t->get_width() - 1)
				o << "\t";
			i += 1;
		}
		o << endl;
	}
}

/**
 * Test if two states are the same configuration.
 */
bool TilesState::equals(const State *s) const
{
	const TilesState *other = dynamic_cast<const TilesState *>(s);

	for (unsigned int i = 0; i < tiles.size(); i += 1)
		if (tiles[i] != other->tiles[i])
			return false;

	return true;
}

/**
 * Get the tile vector.
 */
vector<unsigned int> TilesState::get_tiles(void) const
{
	return tiles;
}

/**
 * Get the blank position.
 */
unsigned int TilesState::get_blank(void) const
{
	return blank;
}
<|endoftext|>


<commit_before>/****************************************************************************
 *   Copyright (C) 2013-2014 by Savoir-Faire Linux                           *
 *   Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> *
 *                                                                          *
 *   This library is free software; you can redistribute it and/or          *
 *   modify it under the terms of the GNU Lesser General Public             *
 *   License as published by the Free Software Foundation; either           *
 *   version 2.1 of the License, or (at your option) any later version.     *
 *                                                                          *
 *   This library 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      *
 *   Lesser General Public License for more details.                        *
 *                                                                          *
 *   You should have received a copy of the GNU General Public License      *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
 ***************************************************************************/
#include "securityvalidationmodel.h"
#include "account.h"
#include "visitors/pixmapmanipulationvisitor.h"

#include <QtAlgorithms>

const QString SecurityValidationModel::messages[static_cast<const int>(SecurityFlaw::COUNT)] = {
   QObject::tr("Your communication negotation is secured, but not the media stream, please enable ZRTP or SDES"),
   QObject::tr("TLS is disabled, the negotiation wont be encrypted. Your communication will be vulnerable to "
   "snooping"),
   QObject::tr("Your certificate is expired, please contact your system administrator."),
   QObject::tr("Your certificate is self signed. This break the chain of trust."),
   QObject::tr("CA_CERTIFICATE_MISSING         "),
   QObject::tr("END_CERTIFICATE_MISSING        "),
   QObject::tr("None of your certificate provide a private key, this is required. Please select a private key"
   " or use a certificate with one built-in"),
   QObject::tr("CERTIFICATE_MISMATCH           "),
   QObject::tr("CERTIFICATE_STORAGE_PERMISSION "),
   QObject::tr("CERTIFICATE_STORAGE_FOLDER     "),
   QObject::tr("CERTIFICATE_STORAGE_LOCATION   "),
   QObject::tr("OUTGOING_SERVER_MISMATCH       "),
   QObject::tr("VERIFY_INCOMING_DISABLED       "),
   QObject::tr("VERIFY_ANSWER_DISABLED         "),
   QObject::tr("REQUIRE_CERTIFICATE_DISABLED   "),
};

const TypedStateMachine< SecurityValidationModel::SecurityLevel , SecurityValidationModel::SecurityFlaw >
SecurityValidationModel::maximumSecurityLevel = {{
   /* SRTP_DISABLED                  */ SecurityLevel::WEAK       ,
   /* TLS_DISABLED                   */ SecurityLevel::WEAK       ,
   /* CERTIFICATE_EXPIRED            */ SecurityLevel::MEDIUM     ,
   /* CERTIFICATE_SELF_SIGNED        */ SecurityLevel::MEDIUM     ,
   /* CA_CERTIFICATE_MISSING         */ SecurityLevel::MEDIUM     ,
   /* END_CERTIFICATE_MISSING        */ SecurityLevel::MEDIUM     ,
   /* PRIVATE_KEY_MISSING            */ SecurityLevel::MEDIUM     ,
   /* CERTIFICATE_MISMATCH           */ SecurityLevel::NONE       ,
   /* CERTIFICATE_STORAGE_PERMISSION */ SecurityLevel::ACCEPTABLE ,
   /* CERTIFICATE_STORAGE_FOLDER     */ SecurityLevel::ACCEPTABLE ,
   /* CERTIFICATE_STORAGE_LOCATION   */ SecurityLevel::ACCEPTABLE ,
   /* OUTGOING_SERVER_MISMATCH       */ SecurityLevel::ACCEPTABLE ,
   /* VERIFY_INCOMING_DISABLED       */ SecurityLevel::MEDIUM     ,
   /* VERIFY_ANSWER_DISABLED         */ SecurityLevel::MEDIUM     ,
   /* REQUIRE_CERTIFICATE_DISABLED   */ SecurityLevel::MEDIUM     ,
   /* MISSING_CERTIFICATE            */ SecurityLevel::NONE       ,
   /* MISSING_AUTHORITY              */ SecurityLevel::WEAK       ,
}};

const TypedStateMachine< SecurityValidationModel::Severity , SecurityValidationModel::SecurityFlaw >
SecurityValidationModel::flawSeverity = {{
   /* SRTP_DISABLED                  */ Severity::ISSUE   ,
   /* TLS_DISABLED                   */ Severity::ISSUE   ,
   /* CERTIFICATE_EXPIRED            */ Severity::WARNING ,
   /* CERTIFICATE_SELF_SIGNED        */ Severity::WARNING ,
   /* CA_CERTIFICATE_MISSING         */ Severity::ISSUE   ,
   /* END_CERTIFICATE_MISSING        */ Severity::ISSUE   ,
   /* PRIVATE_KEY_MISSING            */ Severity::ERROR   ,
   /* CERTIFICATE_MISMATCH           */ Severity::ERROR   ,
   /* CERTIFICATE_STORAGE_PERMISSION */ Severity::WARNING ,
   /* CERTIFICATE_STORAGE_FOLDER     */ Severity::INFORMATION ,
   /* CERTIFICATE_STORAGE_LOCATION   */ Severity::INFORMATION ,
   /* OUTGOING_SERVER_MISMATCH       */ Severity::WARNING ,
   /* VERIFY_INCOMING_DISABLED       */ Severity::ISSUE   ,
   /* VERIFY_ANSWER_DISABLED         */ Severity::ISSUE   ,
   /* REQUIRE_CERTIFICATE_DISABLED   */ Severity::ISSUE   ,
   /* MISSING_CERTIFICATE            */ Severity::ERROR   ,
   /* MISSING_AUTHORITY              */ Severity::ERROR   ,
}};

SecurityValidationModel::SecurityValidationModel(Account* account) : QAbstractListModel(account), m_pAccount(account)
{

}

SecurityValidationModel::~SecurityValidationModel()
{

}

QVariant SecurityValidationModel::data( const QModelIndex& index, int role) const
{
   if (index.isValid())  {
      if (role == Qt::DisplayRole) {
         return messages[static_cast<int>( m_lCurrentFlaws[index.row()].flaw )];
      }
      else if (role == Role::SeverityRole) {
         return static_cast<int>(m_lCurrentFlaws[index.row()].severity);
      }
      else if (role == Qt::DecorationRole) {
         return PixmapManipulationVisitor::instance()->serurityIssueIcon(index);
      }
   }
   return QVariant();
}

int SecurityValidationModel::rowCount( const QModelIndex& parent) const
{
   Q_UNUSED(parent)
   return m_lCurrentFlaws.size();
}

Qt::ItemFlags SecurityValidationModel::flags( const QModelIndex& index) const
{
   if (!index.isValid()) return Qt::NoItemFlags;
   return Qt::ItemIsEnabled|Qt::ItemIsSelectable;
}

bool SecurityValidationModel::setData( const QModelIndex& index, const QVariant &value, int role)
{
   Q_UNUSED(index)
   Q_UNUSED(value)
   Q_UNUSED(role )
   return false;
}

void SecurityValidationModel::update()
{
   m_lCurrentFlaws.clear();

   /**********************************
    *     Check general issues       *
    *********************************/

   /* If TLS is not enabled, everything else is worthless */
   if (!m_pAccount->isTlsEnable()) {
      m_lCurrentFlaws << Flaw(SecurityFlaw::TLS_DISABLED);
   }

   /* Check if the media stream is encrypted, it is something users
    * may care about if they get this far ;) */
   if (!m_pAccount->isSrtpEnabled()) {
      m_lCurrentFlaws << Flaw(SecurityFlaw::SRTP_DISABLED);
   }

   /* The user certificate need to have a private key, otherwise it wont
    * be possible to encrypt anything */
   if ((! m_pAccount->tlsCertificate()->hasPrivateKey()) && (!m_pAccount->tlsPrivateKeyCertificate()->exist())) {
      m_lCurrentFlaws << Flaw(SecurityFlaw::PRIVATE_KEY_MISSING,m_pAccount->tlsPrivateKeyCertificate()->type());
   }

   /**********************************
    *      Certificates issues       *
    *********************************/
   QList<Certificate*> certs;
   certs << m_pAccount->tlsCaListCertificate() << m_pAccount->tlsCertificate() << m_pAccount->tlsPrivateKeyCertificate();
   foreach (Certificate* cert, certs) {
      if (! cert->exist()) {
         m_lCurrentFlaws << Flaw(SecurityFlaw::END_CERTIFICATE_MISSING,cert->type());
      }
      if (! cert->isExpired()) {
         m_lCurrentFlaws << Flaw(SecurityFlaw::CERTIFICATE_EXPIRED,cert->type());
      }
      if (! cert->isSelfSigned()) {
         m_lCurrentFlaws << Flaw(SecurityFlaw::CERTIFICATE_SELF_SIGNED,cert->type());
      }
      if (! cert->hasProtectedPrivateKey()) {
         m_lCurrentFlaws << Flaw(SecurityFlaw::CERTIFICATE_STORAGE_PERMISSION,cert->type());
      }
      if (! cert->hasRightPermissions()) {
         m_lCurrentFlaws << Flaw(SecurityFlaw::CERTIFICATE_STORAGE_PERMISSION),cert->type();
      }
      if (! cert->hasRightFolderPermissions()) {
         m_lCurrentFlaws << Flaw(SecurityFlaw::CERTIFICATE_STORAGE_FOLDER,cert->type());
      }
      if (! cert->isLocationSecure()) {
         m_lCurrentFlaws << Flaw(SecurityFlaw::CERTIFICATE_STORAGE_LOCATION,cert->type());
      }
   }
   qSort(m_lCurrentFlaws);

   emit layoutChanged();
}

QList<SecurityValidationModel::Flaw> SecurityValidationModel::currentFlaws()
{
   return m_lCurrentFlaws;
}

<commit_msg>Fix typos and plurals<commit_after>/****************************************************************************
 *   Copyright (C) 2013-2014 by Savoir-Faire Linux                           *
 *   Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> *
 *                                                                          *
 *   This library is free software; you can redistribute it and/or          *
 *   modify it under the terms of the GNU Lesser General Public             *
 *   License as published by the Free Software Foundation; either           *
 *   version 2.1 of the License, or (at your option) any later version.     *
 *                                                                          *
 *   This library 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      *
 *   Lesser General Public License for more details.                        *
 *                                                                          *
 *   You should have received a copy of the GNU General Public License      *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
 ***************************************************************************/
#include "securityvalidationmodel.h"
#include "account.h"
#include "visitors/pixmapmanipulationvisitor.h"

#include <QtAlgorithms>

const QString SecurityValidationModel::messages[static_cast<const int>(SecurityFlaw::COUNT)] = {
   QObject::tr("Your communication negotiation is secured, but not the media stream, please enable ZRTP or SDES"),
   QObject::tr("TLS is disabled, the negotiation wont be encrypted. Your communication will be vulnerable to "
   "snooping"),
   QObject::tr("Your certificate is expired, please contact your system administrator."),
   QObject::tr("Your certificate is self signed. This break the chain of trust."),
   QObject::tr("CA_CERTIFICATE_MISSING         "),
   QObject::tr("END_CERTIFICATE_MISSING        "),
   QObject::tr("None of your certificate provide a private key, this is required. Please select a private key"
   " or use a certificate with one built-in"),
   QObject::tr("CERTIFICATE_MISMATCH           "),
   QObject::tr("CERTIFICATE_STORAGE_PERMISSION "),
   QObject::tr("CERTIFICATE_STORAGE_FOLDER     "),
   QObject::tr("CERTIFICATE_STORAGE_LOCATION   "),
   QObject::tr("OUTGOING_SERVER_MISMATCH       "),
   QObject::tr("VERIFY_INCOMING_DISABLED       "),
   QObject::tr("VERIFY_ANSWER_DISABLED         "),
   QObject::tr("REQUIRE_CERTIFICATE_DISABLED   "),
};

const TypedStateMachine< SecurityValidationModel::SecurityLevel , SecurityValidationModel::SecurityFlaw >
SecurityValidationModel::maximumSecurityLevel = {{
   /* SRTP_DISABLED                  */ SecurityLevel::WEAK       ,
   /* TLS_DISABLED                   */ SecurityLevel::WEAK       ,
   /* CERTIFICATE_EXPIRED            */ SecurityLevel::MEDIUM     ,
   /* CERTIFICATE_SELF_SIGNED        */ SecurityLevel::MEDIUM     ,
   /* CA_CERTIFICATE_MISSING         */ SecurityLevel::MEDIUM     ,
   /* END_CERTIFICATE_MISSING        */ SecurityLevel::MEDIUM     ,
   /* PRIVATE_KEY_MISSING            */ SecurityLevel::MEDIUM     ,
   /* CERTIFICATE_MISMATCH           */ SecurityLevel::NONE       ,
   /* CERTIFICATE_STORAGE_PERMISSION */ SecurityLevel::ACCEPTABLE ,
   /* CERTIFICATE_STORAGE_FOLDER     */ SecurityLevel::ACCEPTABLE ,
   /* CERTIFICATE_STORAGE_LOCATION   */ SecurityLevel::ACCEPTABLE ,
   /* OUTGOING_SERVER_MISMATCH       */ SecurityLevel::ACCEPTABLE ,
   /* VERIFY_INCOMING_DISABLED       */ SecurityLevel::MEDIUM     ,
   /* VERIFY_ANSWER_DISABLED         */ SecurityLevel::MEDIUM     ,
   /* REQUIRE_CERTIFICATE_DISABLED   */ SecurityLevel::MEDIUM     ,
   /* MISSING_CERTIFICATE            */ SecurityLevel::NONE       ,
   /* MISSING_AUTHORITY              */ SecurityLevel::WEAK       ,
}};

const TypedStateMachine< SecurityValidationModel::Severity , SecurityValidationModel::SecurityFlaw >
SecurityValidationModel::flawSeverity = {{
   /* SRTP_DISABLED                  */ Severity::ISSUE   ,
   /* TLS_DISABLED                   */ Severity::ISSUE   ,
   /* CERTIFICATE_EXPIRED            */ Severity::WARNING ,
   /* CERTIFICATE_SELF_SIGNED        */ Severity::WARNING ,
   /* CA_CERTIFICATE_MISSING         */ Severity::ISSUE   ,
   /* END_CERTIFICATE_MISSING        */ Severity::ISSUE   ,
   /* PRIVATE_KEY_MISSING            */ Severity::ERROR   ,
   /* CERTIFICATE_MISMATCH           */ Severity::ERROR   ,
   /* CERTIFICATE_STORAGE_PERMISSION */ Severity::WARNING ,
   /* CERTIFICATE_STORAGE_FOLDER     */ Severity::INFORMATION ,
   /* CERTIFICATE_STORAGE_LOCATION   */ Severity::INFORMATION ,
   /* OUTGOING_SERVER_MISMATCH       */ Severity::WARNING ,
   /* VERIFY_INCOMING_DISABLED       */ Severity::ISSUE   ,
   /* VERIFY_ANSWER_DISABLED         */ Severity::ISSUE   ,
   /* REQUIRE_CERTIFICATE_DISABLED   */ Severity::ISSUE   ,
   /* MISSING_CERTIFICATE            */ Severity::ERROR   ,
   /* MISSING_AUTHORITY              */ Severity::ERROR   ,
}};

SecurityValidationModel::SecurityValidationModel(Account* account) : QAbstractListModel(account), m_pAccount(account)
{

}

SecurityValidationModel::~SecurityValidationModel()
{

}

QVariant SecurityValidationModel::data( const QModelIndex& index, int role) const
{
   if (index.isValid())  {
      if (role == Qt::DisplayRole) {
         return messages[static_cast<int>( m_lCurrentFlaws[index.row()].flaw )];
      }
      else if (role == Role::SeverityRole) {
         return static_cast<int>(m_lCurrentFlaws[index.row()].severity);
      }
      else if (role == Qt::DecorationRole) {
         return PixmapManipulationVisitor::instance()->serurityIssueIcon(index);
      }
   }
   return QVariant();
}

int SecurityValidationModel::rowCount( const QModelIndex& parent) const
{
   Q_UNUSED(parent)
   return m_lCurrentFlaws.size();
}

Qt::ItemFlags SecurityValidationModel::flags( const QModelIndex& index) const
{
   if (!index.isValid()) return Qt::NoItemFlags;
   return Qt::ItemIsEnabled|Qt::ItemIsSelectable;
}

bool SecurityValidationModel::setData( const QModelIndex& index, const QVariant &value, int role)
{
   Q_UNUSED(index)
   Q_UNUSED(value)
   Q_UNUSED(role )
   return false;
}

void SecurityValidationModel::update()
{
   m_lCurrentFlaws.clear();

   /**********************************
    *     Check general issues       *
    *********************************/

   /* If TLS is not enabled, everything else is worthless */
   if (!m_pAccount->isTlsEnable()) {
      m_lCurrentFlaws << Flaw(SecurityFlaw::TLS_DISABLED);
   }

   /* Check if the media stream is encrypted, it is something users
    * may care about if they get this far ;) */
   if (!m_pAccount->isSrtpEnabled()) {
      m_lCurrentFlaws << Flaw(SecurityFlaw::SRTP_DISABLED);
   }

   /* The user certificate need to have a private key, otherwise it wont
    * be possible to encrypt anything */
   if ((! m_pAccount->tlsCertificate()->hasPrivateKey()) && (!m_pAccount->tlsPrivateKeyCertificate()->exist())) {
      m_lCurrentFlaws << Flaw(SecurityFlaw::PRIVATE_KEY_MISSING,m_pAccount->tlsPrivateKeyCertificate()->type());
   }

   /**********************************
    *      Certificates issues       *
    *********************************/
   QList<Certificate*> certs;
   certs << m_pAccount->tlsCaListCertificate() << m_pAccount->tlsCertificate() << m_pAccount->tlsPrivateKeyCertificate();
   foreach (Certificate* cert, certs) {
      if (! cert->exist()) {
         m_lCurrentFlaws << Flaw(SecurityFlaw::END_CERTIFICATE_MISSING,cert->type());
      }
      if (! cert->isExpired()) {
         m_lCurrentFlaws << Flaw(SecurityFlaw::CERTIFICATE_EXPIRED,cert->type());
      }
      if (! cert->isSelfSigned()) {
         m_lCurrentFlaws << Flaw(SecurityFlaw::CERTIFICATE_SELF_SIGNED,cert->type());
      }
      if (! cert->hasProtectedPrivateKey()) {
         m_lCurrentFlaws << Flaw(SecurityFlaw::CERTIFICATE_STORAGE_PERMISSION,cert->type());
      }
      if (! cert->hasRightPermissions()) {
         m_lCurrentFlaws << Flaw(SecurityFlaw::CERTIFICATE_STORAGE_PERMISSION),cert->type();
      }
      if (! cert->hasRightFolderPermissions()) {
         m_lCurrentFlaws << Flaw(SecurityFlaw::CERTIFICATE_STORAGE_FOLDER,cert->type());
      }
      if (! cert->isLocationSecure()) {
         m_lCurrentFlaws << Flaw(SecurityFlaw::CERTIFICATE_STORAGE_LOCATION,cert->type());
      }
   }
   qSort(m_lCurrentFlaws);

   emit layoutChanged();
}

QList<SecurityValidationModel::Flaw> SecurityValidationModel::currentFlaws()
{
   return m_lCurrentFlaws;
}

<|endoftext|>


<commit_before>/*
 * This program 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 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2011 Sergey Lisitsyn
 * Copyright (C) 2011 Berlin Institute of Technology and Max-Planck-Society
 */

#include <shogun/converter/Isomap.h>
#ifdef HAVE_LAPACK
#include <shogun/lib/common.h>
#include <shogun/lib/FibonacciHeap.h>
#include <shogun/mathematics/Math.h>
#include <shogun/io/SGIO.h>
#include <shogun/base/Parallel.h>
#include <shogun/lib/Signal.h>
#include <shogun/lib/CoverTree.h>

#ifdef HAVE_PTHREAD
#include <pthread.h>
#endif

using namespace shogun;

#ifndef DOXYGEN_SHOULD_SKIP_THIS
/* struct storing thread params
 */
struct DIJKSTRA_THREAD_PARAM
{
	/// fibonacci heap to be used
	CFibonacciHeap* heap;
	/// const matrix storing edges lengths (ith column
	/// contains lengths from ith object)
	const float64_t* edges_matrix;
	/// const matrix storing edges idxs (ith column
	/// contains indexes of end-point vertices)
	const int32_t* edges_idx_matrix;
	/// matrix to store shortest paths
	float64_t* shortest_D;
	/// starting index of loop
	int32_t i_start;
	/// stopping index of loop
	int32_t i_stop;
	/// step for loop
	int32_t i_step;
	/// k param
	int32_t m_k;
	/// (s)olution bool array
	bool* s;
	/// (f)rontier bool array
	bool* f;
};

class ISOMAP_COVERTREE_POINT
{
public:

	ISOMAP_COVERTREE_POINT(int32_t index, const SGMatrix<float64_t>& dmatrix)
	{
		point_index = index;
		distance_matrix = dmatrix;
	}

	inline double distance(const ISOMAP_COVERTREE_POINT& p) const
	{
		return distance_matrix[point_index*distance_matrix.num_rows+p.point_index];
	}

	inline bool operator==(const ISOMAP_COVERTREE_POINT& p) const
	{
		return (p.point_index==point_index);
	}

	int32_t point_index;
	SGMatrix<float64_t> distance_matrix;
};

#endif /* DOXYGEN_SHOULD_SKIP_THIS */

CIsomap::CIsomap() : CMultidimensionalScaling()
{
	m_k = 3;

	init();
}

void CIsomap::init()
{
	SG_ADD(&m_k, "k", "number of neighbors", MS_AVAILABLE);
}

CIsomap::~CIsomap()
{
}

void CIsomap::set_k(int32_t k)
{
	ASSERT(k>0);
	m_k = k;
}

int32_t CIsomap::get_k() const
{
	return m_k;
}

const char* CIsomap::get_name() const
{
	return "Isomap";
}

SGMatrix<float64_t> CIsomap::process_distance_matrix(SGMatrix<float64_t> distance_matrix)
{
	return isomap_distance(distance_matrix);
}

SGMatrix<float64_t> CIsomap::isomap_distance(SGMatrix<float64_t> D_matrix)
{
	int32_t N,i;
	N = D_matrix.num_cols;
	if (D_matrix.num_cols!=D_matrix.num_rows)
	{
		SG_ERROR("Given distance matrix is not square.\n");
	}
	if (m_k>=N)
	{
		SG_ERROR("K parameter should be less than number of given vectors (k=%d, N=%d)\n", m_k, N);
	}

	// cut by k-nearest neighbors
	int32_t* edges_idx_matrix = SG_MALLOC(int32_t, N*m_k);
	float64_t* edges_matrix = SG_MALLOC(float64_t, N*m_k);

	float64_t max_dist = CMath::max(D_matrix.matrix,N*N);
	CoverTree<ISOMAP_COVERTREE_POINT>* coverTree = new CoverTree<ISOMAP_COVERTREE_POINT>(max_dist);

	for (i=0; i<N; i++)
		coverTree->insert(ISOMAP_COVERTREE_POINT(i,D_matrix));

	for (i=0; i<N; i++)
	{
		ISOMAP_COVERTREE_POINT origin(i,D_matrix);
		std::vector<ISOMAP_COVERTREE_POINT> neighbors =
		   coverTree->kNearestNeighbors(origin,m_k+1);
		for (std::size_t m=1; m<neighbors.size(); m++)
		{
			edges_matrix[i*m_k+m-1] = origin.distance(neighbors[m]);
			edges_idx_matrix[i*m_k+m-1] = neighbors[m].point_index;
		}
	}

	delete coverTree;

#ifdef HAVE_PTHREAD
	int32_t t;
	// Parallel Dijkstra with Fibonacci Heap
	int32_t num_threads = parallel->get_num_threads();
	ASSERT(num_threads>0);
	// allocate threads and thread parameters
	pthread_t* threads = SG_MALLOC(pthread_t, num_threads);
	DIJKSTRA_THREAD_PARAM* parameters = SG_MALLOC(DIJKSTRA_THREAD_PARAM, num_threads);
	// allocate heaps
	CFibonacciHeap** heaps = SG_MALLOC(CFibonacciHeap*, num_threads);
	for (t=0; t<num_threads; t++)
		heaps[t] = new CFibonacciHeap(N);

#else
	int32_t num_threads = 1;
#endif

	// allocate (s)olution
	bool* s = SG_MALLOC(bool,N*num_threads);
	// allocate (f)rontier
	bool* f = SG_MALLOC(bool,N*num_threads);
	// init matrix to store shortest distances
	float64_t* shortest_D = D_matrix.matrix;

#ifdef HAVE_PTHREAD

	pthread_attr_t attr;
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
	for (t=0; t<num_threads; t++)
	{
		parameters[t].i_start = t;
		parameters[t].i_stop = N;
		parameters[t].i_step = num_threads;
		parameters[t].heap = heaps[t];
		parameters[t].edges_matrix = edges_matrix;
		parameters[t].edges_idx_matrix = edges_idx_matrix;
		parameters[t].s = s+t*N;
		parameters[t].f = f+t*N;
		parameters[t].m_k = m_k;
		parameters[t].shortest_D = shortest_D;
		pthread_create(&threads[t], &attr, CIsomap::run_dijkstra_thread, (void*)&parameters[t]);
	}
	for (t=0; t<num_threads; t++)
		pthread_join(threads[t], NULL);
	pthread_attr_destroy(&attr);
	for (t=0; t<num_threads; t++)
		delete heaps[t];
	SG_FREE(heaps);
	SG_FREE(parameters);
	SG_FREE(threads);
#else
	DIJKSTRA_THREAD_PARAM single_thread_param;
	single_thread_param.i_start = 0;
	single_thread_param.i_stop = N;
	single_thread_param.i_step = 1;
	single_thread_param.m_k = m_k;
	single_thread_param.heap = new CFibonacciHeap(N);
	single_thread_param.edges_matrix = edges_matrix;
	single_thread_param.edges_idx_matrix = edges_idx_matrix;
	single_thread_param.s = s;
	single_thread_param.f = f;
	single_thread_param.shortest_D = shortest_D;
	run_dijkstra_thread((void*)&single_thread_param);
	delete single_thread_param.heap;
#endif
	// cleanup
	SG_FREE(edges_matrix);
	SG_FREE(edges_idx_matrix);
	SG_FREE(s);
	SG_FREE(f);

	return SGMatrix<float64_t>(shortest_D,N,N);
}

void* CIsomap::run_dijkstra_thread(void *p)
{
	// get parameters from p
	DIJKSTRA_THREAD_PARAM* parameters = (DIJKSTRA_THREAD_PARAM*)p;
	CFibonacciHeap* heap = parameters->heap;
	int32_t i_start = parameters->i_start;
	int32_t i_stop = parameters->i_stop;
	int32_t i_step = parameters->i_step;
	bool* s = parameters->s;
	bool* f = parameters->f;
	const float64_t* edges_matrix = parameters->edges_matrix;
	const int32_t* edges_idx_matrix = parameters->edges_idx_matrix;
	float64_t* shortest_D = parameters->shortest_D;
	int32_t m_k = parameters->m_k;
	int32_t k,j,i,min_item,w;
	int32_t N = i_stop;

	// temporary vars
	float64_t dist,tmp;

	// main loop
	for (k=i_start; k<i_stop; k+=i_step)
	{
		// fill s and f with false, fill shortest_D with infinity
		for (j=0; j<N; j++)
		{
			shortest_D[k*N+j] = CMath::ALMOST_INFTY;
			s[j] = false;
			f[j] = false;
		}
		// set distance from k to k as zero
		shortest_D[k*N+k] = 0.0;

		// insert kth object to heap with zero distance and set f[k] true
		heap->insert(k,0.0);
		f[k] = true;

		// while heap is not empty
		while (heap->get_num_nodes()>0)
		{
			// extract min and set (s)olution state as true and (f)rontier as false
			min_item = heap->extract_min(tmp);
			s[min_item] = true;
			f[min_item] = false;

			// for-each edge (min_item->w)
			for (i=0; i<m_k; i++)
			{
				// get w idx
				w = edges_idx_matrix[min_item*m_k+i];
				// if w is not in solution yet
				if (s[w] == false)
				{
					// get distance from k to i through min_item
					dist = shortest_D[k*N+min_item] + edges_matrix[min_item*m_k+i];
					// if distance can be relaxed
					if (dist < shortest_D[k*N+w])
					{
						// relax distance
						shortest_D[k*N+w] = dist;
						// if w is in (f)rontier
						if (f[w])
						{
							// decrease distance in heap
							heap->decrease_key(w, dist);
						}
						else
						{
							// insert w to heap and set (f)rontier as true
							heap->insert(w, dist);
							f[w] = true;
						}
					}
				}
			}
		}
		// clear heap to re-use
		heap->clear();
	}
	return NULL;
}

#endif /* HAVE_LAPACK */
<commit_msg>Fix crasher in Isomap<commit_after>/*
 * This program 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 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2011 Sergey Lisitsyn
 * Copyright (C) 2011 Berlin Institute of Technology and Max-Planck-Society
 */

#include <shogun/converter/Isomap.h>
#ifdef HAVE_LAPACK
#include <shogun/lib/common.h>
#include <shogun/lib/FibonacciHeap.h>
#include <shogun/mathematics/Math.h>
#include <shogun/io/SGIO.h>
#include <shogun/base/Parallel.h>
#include <shogun/lib/Signal.h>
#include <shogun/lib/CoverTree.h>

#ifdef HAVE_PTHREAD
#include <pthread.h>
#endif

using namespace shogun;

#ifndef DOXYGEN_SHOULD_SKIP_THIS
/* struct storing thread params
 */
struct DIJKSTRA_THREAD_PARAM
{
	/// fibonacci heap to be used
	CFibonacciHeap* heap;
	/// const matrix storing edges lengths (ith column
	/// contains lengths from ith object)
	const float64_t* edges_matrix;
	/// const matrix storing edges idxs (ith column
	/// contains indexes of end-point vertices)
	const int32_t* edges_idx_matrix;
	/// matrix to store shortest paths
	float64_t* shortest_D;
	/// starting index of loop
	int32_t i_start;
	/// stopping index of loop
	int32_t i_stop;
	/// step for loop
	int32_t i_step;
	/// k param
	int32_t m_k;
	/// (s)olution bool array
	bool* s;
	/// (f)rontier bool array
	bool* f;
};

class ISOMAP_COVERTREE_POINT
{
public:

	ISOMAP_COVERTREE_POINT(int32_t index, const SGMatrix<float64_t>& dmatrix)
	{
		point_index = index;
		distance_matrix = dmatrix;
	}

	inline double distance(const ISOMAP_COVERTREE_POINT& p) const
	{
		return distance_matrix[point_index*distance_matrix.num_rows+p.point_index];
	}

	inline bool operator==(const ISOMAP_COVERTREE_POINT& p) const
	{
		return (p.point_index==point_index);
	}

	int32_t point_index;
	SGMatrix<float64_t> distance_matrix;
};

#endif /* DOXYGEN_SHOULD_SKIP_THIS */

CIsomap::CIsomap() : CMultidimensionalScaling()
{
	m_k = 3;

	init();
}

void CIsomap::init()
{
	SG_ADD(&m_k, "k", "number of neighbors", MS_AVAILABLE);
}

CIsomap::~CIsomap()
{
}

void CIsomap::set_k(int32_t k)
{
	ASSERT(k>0);
	m_k = k;
}

int32_t CIsomap::get_k() const
{
	return m_k;
}

const char* CIsomap::get_name() const
{
	return "Isomap";
}

SGMatrix<float64_t> CIsomap::process_distance_matrix(SGMatrix<float64_t> distance_matrix)
{
	return isomap_distance(distance_matrix);
}

SGMatrix<float64_t> CIsomap::isomap_distance(SGMatrix<float64_t> D_matrix)
{
	int32_t N,i;
	N = D_matrix.num_cols;
	if (D_matrix.num_cols!=D_matrix.num_rows)
	{
		SG_ERROR("Given distance matrix is not square.\n");
	}
	if (m_k>=N)
	{
		SG_ERROR("K parameter should be less than number of given vectors (k=%d, N=%d)\n", m_k, N);
	}

	// cut by k-nearest neighbors
	int32_t* edges_idx_matrix = SG_MALLOC(int32_t, N*m_k);
	float64_t* edges_matrix = SG_MALLOC(float64_t, N*m_k);

	float64_t max_dist = CMath::max(D_matrix.matrix,N*N);
	CoverTree<ISOMAP_COVERTREE_POINT>* coverTree = new CoverTree<ISOMAP_COVERTREE_POINT>(max_dist);

	for (i=0; i<N; i++)
		coverTree->insert(ISOMAP_COVERTREE_POINT(i,D_matrix));

	for (i=0; i<N; i++)
	{
		ISOMAP_COVERTREE_POINT origin(i,D_matrix);
		std::vector<ISOMAP_COVERTREE_POINT> neighbors =
		   coverTree->kNearestNeighbors(origin,m_k+1);
		for (std::size_t m=1; m<neighbors.size(); m++)
		{
			edges_matrix[i*m_k+m-1] = origin.distance(neighbors[m]);
			edges_idx_matrix[i*m_k+m-1] = neighbors[m].point_index;
		}
	}

	delete coverTree;

#ifdef HAVE_PTHREAD
	int32_t t;
	// Parallel Dijkstra with Fibonacci Heap
	int32_t num_threads = parallel->get_num_threads();
	ASSERT(num_threads>0);
	// allocate threads and thread parameters
	pthread_t* threads = SG_MALLOC(pthread_t, num_threads);
	DIJKSTRA_THREAD_PARAM* parameters = SG_MALLOC(DIJKSTRA_THREAD_PARAM, num_threads);
	// allocate heaps
	CFibonacciHeap** heaps = SG_MALLOC(CFibonacciHeap*, num_threads);
	for (t=0; t<num_threads; t++)
		heaps[t] = new CFibonacciHeap(N);

#else
	int32_t num_threads = 1;
#endif

	// allocate (s)olution
	bool* s = SG_MALLOC(bool,N*num_threads);
	// allocate (f)rontier
	bool* f = SG_MALLOC(bool,N*num_threads);
	// init matrix to store shortest distances
	float64_t* shortest_D = D_matrix.matrix;

#ifdef HAVE_PTHREAD

	pthread_attr_t attr;
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
	for (t=0; t<num_threads; t++)
	{
		parameters[t].i_start = t;
		parameters[t].i_stop = N;
		parameters[t].i_step = num_threads;
		parameters[t].heap = heaps[t];
		parameters[t].edges_matrix = edges_matrix;
		parameters[t].edges_idx_matrix = edges_idx_matrix;
		parameters[t].s = s+t*N;
		parameters[t].f = f+t*N;
		parameters[t].m_k = m_k;
		parameters[t].shortest_D = shortest_D;
		pthread_create(&threads[t], &attr, CIsomap::run_dijkstra_thread, (void*)&parameters[t]);
	}
	for (t=0; t<num_threads; t++)
		pthread_join(threads[t], NULL);
	pthread_attr_destroy(&attr);
	for (t=0; t<num_threads; t++)
		delete heaps[t];
	SG_FREE(heaps);
	SG_FREE(parameters);
	SG_FREE(threads);
#else
	DIJKSTRA_THREAD_PARAM single_thread_param;
	single_thread_param.i_start = 0;
	single_thread_param.i_stop = N;
	single_thread_param.i_step = 1;
	single_thread_param.m_k = m_k;
	single_thread_param.heap = new CFibonacciHeap(N);
	single_thread_param.edges_matrix = edges_matrix;
	single_thread_param.edges_idx_matrix = edges_idx_matrix;
	single_thread_param.s = s;
	single_thread_param.f = f;
	single_thread_param.shortest_D = shortest_D;
	run_dijkstra_thread((void*)&single_thread_param);
	delete single_thread_param.heap;
#endif
	// cleanup
	SG_FREE(edges_matrix);
	SG_FREE(edges_idx_matrix);
	SG_FREE(s);
	SG_FREE(f);

	return D_matrix;
}

void* CIsomap::run_dijkstra_thread(void *p)
{
	// get parameters from p
	DIJKSTRA_THREAD_PARAM* parameters = (DIJKSTRA_THREAD_PARAM*)p;
	CFibonacciHeap* heap = parameters->heap;
	int32_t i_start = parameters->i_start;
	int32_t i_stop = parameters->i_stop;
	int32_t i_step = parameters->i_step;
	bool* s = parameters->s;
	bool* f = parameters->f;
	const float64_t* edges_matrix = parameters->edges_matrix;
	const int32_t* edges_idx_matrix = parameters->edges_idx_matrix;
	float64_t* shortest_D = parameters->shortest_D;
	int32_t m_k = parameters->m_k;
	int32_t k,j,i,min_item,w;
	int32_t N = i_stop;

	// temporary vars
	float64_t dist,tmp;

	// main loop
	for (k=i_start; k<i_stop; k+=i_step)
	{
		// fill s and f with false, fill shortest_D with infinity
		for (j=0; j<N; j++)
		{
			shortest_D[k*N+j] = CMath::ALMOST_INFTY;
			s[j] = false;
			f[j] = false;
		}
		// set distance from k to k as zero
		shortest_D[k*N+k] = 0.0;

		// insert kth object to heap with zero distance and set f[k] true
		heap->insert(k,0.0);
		f[k] = true;

		// while heap is not empty
		while (heap->get_num_nodes()>0)
		{
			// extract min and set (s)olution state as true and (f)rontier as false
			min_item = heap->extract_min(tmp);
			s[min_item] = true;
			f[min_item] = false;

			// for-each edge (min_item->w)
			for (i=0; i<m_k; i++)
			{
				// get w idx
				w = edges_idx_matrix[min_item*m_k+i];
				// if w is not in solution yet
				if (s[w] == false)
				{
					// get distance from k to i through min_item
					dist = shortest_D[k*N+min_item] + edges_matrix[min_item*m_k+i];
					// if distance can be relaxed
					if (dist < shortest_D[k*N+w])
					{
						// relax distance
						shortest_D[k*N+w] = dist;
						// if w is in (f)rontier
						if (f[w])
						{
							// decrease distance in heap
							heap->decrease_key(w, dist);
						}
						else
						{
							// insert w to heap and set (f)rontier as true
							heap->insert(w, dist);
							f[w] = true;
						}
					}
				}
			}
		}
		// clear heap to re-use
		heap->clear();
	}
	return NULL;
}

#endif /* HAVE_LAPACK */
<|endoftext|>


<commit_before>/*
 * This program 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 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 1999-2008 Gunnar Raetsch
 * Written (W) 1999-2008,2011 Soeren Sonnenburg
 * Written (W) 2014 Parijat Mazumdar
 * Copyright (C) 1999-2009 Fraunhofer Institute FIRST and Max-Planck-Society
 * Copyright (C) 2011 Berlin Institute of Technology
 */
#include <shogun/lib/config.h>

#ifdef HAVE_EIGEN3
#include <shogun/preprocessor/PCA.h>
#include <shogun/mathematics/Math.h>
#include <shogun/preprocessor/DensePreprocessor.h>
#include <shogun/features/Features.h>
#include <shogun/io/SGIO.h>
#include <shogun/mathematics/eigen3.h>

using namespace shogun;
using namespace Eigen;

CPCA::CPCA(bool do_whitening, EPCAMode mode, float64_t thresh, EPCAMethod method, EPCAMemoryMode mem_mode)
: CDimensionReductionPreprocessor()
{
	init();
	m_whitening = do_whitening;
	m_mode = mode;
	m_thresh = thresh;
	m_mem_mode = mem_mode;
	m_method = method;
}

CPCA::CPCA(EPCAMethod method, bool do_whitening, EPCAMemoryMode mem_mode)
: CDimensionReductionPreprocessor()
{
	init();
	m_whitening = do_whitening;
	m_mem_mode = mem_mode;
	m_method = method;
}

void CPCA::init()
{
	m_transformation_matrix = SGMatrix<float64_t>();
	m_mean_vector = SGVector<float64_t>();
	m_eigenvalues_vector = SGVector<float64_t>();
	num_dim = 0;
	m_initialized = false;
	m_whitening = false;
	m_mode = FIXED_NUMBER;
	m_thresh = 1e-6;
	m_mem_mode = MEM_REALLOCATE;
	m_method = AUTO;
	m_eigenvalue_zero_tolerance=1e-15;

	SG_ADD(&m_transformation_matrix, "transformation_matrix",
	    "Transformation matrix (Eigenvectors of covariance matrix).",
	    MS_NOT_AVAILABLE);
	SG_ADD(&m_mean_vector, "mean_vector", "Mean Vector.", MS_NOT_AVAILABLE);
	SG_ADD(&m_eigenvalues_vector, "eigenvalues_vector",
	    "Vector with Eigenvalues.", MS_NOT_AVAILABLE);
	SG_ADD(&m_initialized, "initalized", "True when initialized.",
	    MS_NOT_AVAILABLE);
	SG_ADD(&m_whitening, "whitening", "Whether data shall be whitened.",
	    MS_AVAILABLE);
	SG_ADD((machine_int_t*) &m_mode, "mode", "PCA Mode.", MS_AVAILABLE);
	SG_ADD(&m_thresh, "m_thresh", "Cutoff threshold.", MS_AVAILABLE);
	SG_ADD((machine_int_t*) &m_mem_mode, "m_mem_mode",
		"Memory mode (in-place or reallocation).", MS_NOT_AVAILABLE);
	SG_ADD((machine_int_t*) &m_method, "m_method",
		"Method used for PCA calculation", MS_NOT_AVAILABLE);
	SG_ADD(&m_eigenvalue_zero_tolerance, "eigenvalue_zero_tolerance", "zero tolerance"
	" for determining zero eigenvalues during whitening to avoid numerical issues", MS_NOT_AVAILABLE);
}

CPCA::~CPCA()
{
}

bool CPCA::init(CFeatures* features)
{
	if (!m_initialized)
	{
		REQUIRE(features->get_feature_class()==C_DENSE, "PCA only works with dense features")
		REQUIRE(features->get_feature_type()==F_DREAL, "PCA only works with real features")

		SGMatrix<float64_t> feature_matrix = ((CDenseFeatures<float64_t>*)features)
									->get_feature_matrix();
		int32_t num_vectors = feature_matrix.num_cols;
		int32_t num_features = feature_matrix.num_rows;
		SG_INFO("num_examples: %ld num_features: %ld \n", num_vectors, num_features)

		// max target dim allowed
		int32_t max_dim_allowed = CMath::min(num_vectors, num_features);
		num_dim=0;

		REQUIRE(m_target_dim<=max_dim_allowed,
			 "target dimension should be less or equal to than minimum of N and D")

		// center data
		Map<MatrixXd> fmatrix(feature_matrix.matrix, num_features, num_vectors);
		m_mean_vector = SGVector<float64_t>(num_features);
		Map<VectorXd> data_mean(m_mean_vector.vector, num_features);
 		data_mean = fmatrix.rowwise().sum()/(float64_t) num_vectors;
		fmatrix = fmatrix.colwise()-data_mean;

		m_eigenvalues_vector = SGVector<float64_t>(max_dim_allowed);
		Map<VectorXd> eigenValues(m_eigenvalues_vector.vector, max_dim_allowed);

		if (m_method == AUTO)
			m_method = (num_vectors>num_features) ? EVD : SVD;

		if (m_method == EVD)
		{
			// covariance matrix
			MatrixXd cov_mat(num_features, num_features);
			cov_mat = fmatrix*fmatrix.transpose();
			cov_mat /= (num_vectors-1);

			SG_INFO("Computing Eigenvalues ... ")
			// eigen value computed
			SelfAdjointEigenSolver<MatrixXd> eigenSolve =
					SelfAdjointEigenSolver<MatrixXd>(cov_mat);
			eigenValues = eigenSolve.eigenvalues().tail(max_dim_allowed);

			// target dimension
			switch (m_mode)
			{
				case FIXED_NUMBER :
					num_dim = m_target_dim;
					break;

				case VARIANCE_EXPLAINED :
					{
						float64_t eig_sum = eigenValues.sum();
						float64_t com_sum = 0;
						for (int32_t i=num_features-1; i<-1; i++)
						{
							num_dim++;
							com_sum += m_eigenvalues_vector.vector[i];
							if (com_sum/eig_sum>=m_thresh)
								break;
						}
					}
					break;

				case THRESHOLD :
					for (int32_t i=num_features-1; i<-1; i++)
					{
						if (m_eigenvalues_vector.vector[i]>m_thresh)
							num_dim++;
						else
							break;
					}
					break;
			};
			SG_INFO("Done\nReducing from %i to %i features..", num_features, num_dim)

			m_transformation_matrix = SGMatrix<float64_t>(num_features,num_dim);
			Map<MatrixXd> transformMatrix(m_transformation_matrix.matrix,
								 num_features, num_dim);
			num_old_dim = num_features;

			// eigenvector matrix
			transformMatrix = eigenSolve.eigenvectors().block(0,
						num_features-num_dim, num_features,num_dim);
			if (m_whitening)
			{
				for (int32_t i=0; i<num_dim; i++)
				{
					if (CMath::fequals_abs<float64_t>(0.0, eigenValues[i+max_dim_allowed-num_dim],
											m_eigenvalue_zero_tolerance))
					{
						SG_WARNING("Covariance matrix has almost zero Eigenvalue (ie "
							"Eigenvalue within a tolerance of %E around 0) at "
							"dimension %d. Consider reducing its dimension.",
							m_eigenvalue_zero_tolerance, i+max_dim_allowed-num_dim+1)

						transformMatrix.col(i) = MatrixXd::Zero(num_features,1);
						continue;
					}

					transformMatrix.col(i) /=
					CMath::sqrt(eigenValues[i+max_dim_allowed-num_dim]*(num_vectors-1));
				}
			}
		}

		else
		{
			// compute SVD of data matrix
			JacobiSVD<MatrixXd> svd(fmatrix.transpose(), ComputeThinU | ComputeThinV);

			// compute non-negative eigen values from singular values
			eigenValues = svd.singularValues();
			eigenValues = eigenValues.cwiseProduct(eigenValues)/(num_vectors-1);

			// target dimension
			switch (m_mode)
			{
				case FIXED_NUMBER :
					num_dim = m_target_dim;
					break;

				case VARIANCE_EXPLAINED :
					{
						float64_t eig_sum = eigenValues.sum();
						float64_t com_sum = 0;
						for (int32_t i=0; i<num_features; i++)
						{
							num_dim++;
							com_sum += m_eigenvalues_vector.vector[i];
							if (com_sum/eig_sum>=m_thresh)
								break;
						}
					}
					break;

				case THRESHOLD :
					for (int32_t i=0; i<num_features; i++)
					{
						if (m_eigenvalues_vector.vector[i]>m_thresh)
							num_dim++;
						else
							break;
					}
					break;
			};
			SG_INFO("Done\nReducing from %i to %i features..", num_features, num_dim)

			// right singular vectors form eigenvectors
			m_transformation_matrix = SGMatrix<float64_t>(num_features,num_dim);
			Map<MatrixXd> transformMatrix(m_transformation_matrix.matrix, num_features, num_dim);
			num_old_dim = num_features;
			transformMatrix = svd.matrixV().block(0, 0, num_features, num_dim);
			if (m_whitening)
			{
				for (int32_t i=0; i<num_dim; i++)
				{
					if (CMath::fequals_abs<float64_t>(0.0, eigenValues[i],
								m_eigenvalue_zero_tolerance))
					{
						SG_WARNING("Covariance matrix has almost zero Eigenvalue (ie "
							"Eigenvalue within a tolerance of %E around 0) at "
							"dimension %d. Consider reducing its dimension.",
							m_eigenvalue_zero_tolerance, i+1)

						transformMatrix.col(i) = MatrixXd::Zero(num_features,1);
						continue;
					}

					transformMatrix.col(i) /= CMath::sqrt(eigenValues[i]*(num_vectors-1));
				}
			}
		}

		// restore feature matrix
		fmatrix = fmatrix.colwise()+data_mean;
		m_initialized = true;
		return true;
	}

	return false;
}

void CPCA::cleanup()
{
	m_transformation_matrix=SGMatrix<float64_t>();
        m_mean_vector = SGVector<float64_t>();
        m_eigenvalues_vector = SGVector<float64_t>();
	m_initialized = false;
}

SGMatrix<float64_t> CPCA::apply_to_feature_matrix(CFeatures* features)
{
	ASSERT(m_initialized)
	SGMatrix<float64_t> m = ((CDenseFeatures<float64_t>*) features)->get_feature_matrix();
	int32_t num_vectors = m.num_cols;
	int32_t num_features = m.num_rows;

	SG_INFO("Transforming feature matrix\n")
	Map<MatrixXd> transform_matrix(m_transformation_matrix.matrix,
			m_transformation_matrix.num_rows, m_transformation_matrix.num_cols);

	if (m_mem_mode == MEM_IN_PLACE)
	{
		if (m.matrix)
		{
			SG_INFO("Preprocessing feature matrix\n")
			Map<MatrixXd> feature_matrix(m.matrix, num_features, num_vectors);
			VectorXd data_mean = feature_matrix.rowwise().sum()/(float64_t) num_vectors;
			feature_matrix = feature_matrix.colwise()-data_mean;

			feature_matrix.block(0,0,num_dim,num_vectors) =
					transform_matrix.transpose()*feature_matrix;

			SG_INFO("Form matrix of target dimension")
			for (int32_t col=0; col<num_vectors; col++)
			{
				for (int32_t row=0; row<num_dim; row++)
					m.matrix[col*num_dim+row] = feature_matrix(row,col);
			}
			m.num_rows = num_dim;
			m.num_cols = num_vectors;
		}

		((CDenseFeatures<float64_t>*) features)->set_feature_matrix(m);
		return m;
	}
	else
	{
		SGMatrix<float64_t> ret(num_dim, num_vectors);
		Map<MatrixXd> ret_matrix(ret.matrix, num_dim, num_vectors);
		if (m.matrix)
		{
			SG_INFO("Preprocessing feature matrix\n")
			Map<MatrixXd> feature_matrix(m.matrix, num_features, num_vectors);
			VectorXd data_mean = feature_matrix.rowwise().sum()/(float64_t) num_vectors;
			feature_matrix = feature_matrix.colwise()-data_mean;

			ret_matrix = transform_matrix.transpose()*feature_matrix;
		}
		((CDenseFeatures<float64_t>*) features)->set_feature_matrix(ret);
		return ret;
	}
}

SGVector<float64_t> CPCA::apply_to_feature_vector(SGVector<float64_t> vector)
{
	SGVector<float64_t> result = SGVector<float64_t>(num_dim);
	Map<VectorXd> resultVec(result.vector, num_dim);
	Map<VectorXd> inputVec(vector.vector, vector.vlen);

	Map<VectorXd> mean(m_mean_vector.vector, m_mean_vector.vlen);
	Map<MatrixXd> transformMat(m_transformation_matrix.matrix,
		 m_transformation_matrix.num_rows, m_transformation_matrix.num_cols);

	inputVec = inputVec-mean;
	resultVec = transformMat.transpose()*inputVec;
	inputVec = inputVec+mean;

	return result;
}

SGMatrix<float64_t> CPCA::get_transformation_matrix()
{
	return m_transformation_matrix;
}

SGVector<float64_t> CPCA::get_eigenvalues()
{
	return m_eigenvalues_vector;
}

SGVector<float64_t> CPCA::get_mean()
{
	return m_mean_vector;
}

EPCAMemoryMode CPCA::get_memory_mode() const
{
	return m_mem_mode;
}

void CPCA::set_memory_mode(EPCAMemoryMode e)
{
	m_mem_mode = e;
}

void CPCA::set_eigenvalue_zero_tolerance(float64_t eigenvalue_zero_tolerance)
{
	m_eigenvalue_zero_tolerance = eigenvalue_zero_tolerance;
}

float64_t CPCA::get_eigenvalue_zero_tolerance() const
{
	return m_eigenvalue_zero_tolerance;
}

#endif // HAVE_EIGEN3
<commit_msg>Fix spacing in PCA.cpp and add assertation for function parameter<commit_after>/*
 * This program 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 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 1999-2008 Gunnar Raetsch
 * Written (W) 1999-2008,2011 Soeren Sonnenburg
 * Written (W) 2014 Parijat Mazumdar
 * Copyright (C) 1999-2009 Fraunhofer Institute FIRST and Max-Planck-Society
 * Copyright (C) 2011 Berlin Institute of Technology
 */
#include <shogun/lib/config.h>

#ifdef HAVE_EIGEN3
#include <shogun/preprocessor/PCA.h>
#include <shogun/mathematics/Math.h>
#include <shogun/preprocessor/DensePreprocessor.h>
#include <shogun/features/Features.h>
#include <shogun/io/SGIO.h>
#include <shogun/mathematics/eigen3.h>

using namespace shogun;
using namespace Eigen;

CPCA::CPCA(bool do_whitening, EPCAMode mode, float64_t thresh, EPCAMethod method, EPCAMemoryMode mem_mode)
: CDimensionReductionPreprocessor()
{
	init();
	m_whitening = do_whitening;
	m_mode = mode;
	m_thresh = thresh;
	m_mem_mode = mem_mode;
	m_method = method;
}

CPCA::CPCA(EPCAMethod method, bool do_whitening, EPCAMemoryMode mem_mode)
: CDimensionReductionPreprocessor()
{
	init();
	m_whitening = do_whitening;
	m_mem_mode = mem_mode;
	m_method = method;
}

void CPCA::init()
{
	m_transformation_matrix = SGMatrix<float64_t>();
	m_mean_vector = SGVector<float64_t>();
	m_eigenvalues_vector = SGVector<float64_t>();
	num_dim = 0;
	m_initialized = false;
	m_whitening = false;
	m_mode = FIXED_NUMBER;
	m_thresh = 1e-6;
	m_mem_mode = MEM_REALLOCATE;
	m_method = AUTO;
	m_eigenvalue_zero_tolerance=1e-15;

	SG_ADD(&m_transformation_matrix, "transformation_matrix",
	    "Transformation matrix (Eigenvectors of covariance matrix).",
	    MS_NOT_AVAILABLE);
	SG_ADD(&m_mean_vector, "mean_vector", "Mean Vector.", MS_NOT_AVAILABLE);
	SG_ADD(&m_eigenvalues_vector, "eigenvalues_vector",
	    "Vector with Eigenvalues.", MS_NOT_AVAILABLE);
	SG_ADD(&m_initialized, "initalized", "True when initialized.",
	    MS_NOT_AVAILABLE);
	SG_ADD(&m_whitening, "whitening", "Whether data shall be whitened.",
	    MS_AVAILABLE);
	SG_ADD((machine_int_t*) &m_mode, "mode", "PCA Mode.", MS_AVAILABLE);
	SG_ADD(&m_thresh, "m_thresh", "Cutoff threshold.", MS_AVAILABLE);
	SG_ADD((machine_int_t*) &m_mem_mode, "m_mem_mode",
		"Memory mode (in-place or reallocation).", MS_NOT_AVAILABLE);
	SG_ADD((machine_int_t*) &m_method, "m_method",
		"Method used for PCA calculation", MS_NOT_AVAILABLE);
	SG_ADD(&m_eigenvalue_zero_tolerance, "eigenvalue_zero_tolerance", "zero tolerance"
	" for determining zero eigenvalues during whitening to avoid numerical issues", MS_NOT_AVAILABLE);
}

CPCA::~CPCA()
{
}

bool CPCA::init(CFeatures* features)
{
	if (!m_initialized)
	{
		REQUIRE(features->get_feature_class()==C_DENSE, "PCA only works with dense features")
		REQUIRE(features->get_feature_type()==F_DREAL, "PCA only works with real features")

		SGMatrix<float64_t> feature_matrix = ((CDenseFeatures<float64_t>*)features)
									->get_feature_matrix();
		int32_t num_vectors = feature_matrix.num_cols;
		int32_t num_features = feature_matrix.num_rows;
		SG_INFO("num_examples: %ld num_features: %ld \n", num_vectors, num_features)

		// max target dim allowed
		int32_t max_dim_allowed = CMath::min(num_vectors, num_features);
		num_dim=0;

		REQUIRE(m_target_dim<=max_dim_allowed,
			 "target dimension should be less or equal to than minimum of N and D")

		// center data
		Map<MatrixXd> fmatrix(feature_matrix.matrix, num_features, num_vectors);
		m_mean_vector = SGVector<float64_t>(num_features);
		Map<VectorXd> data_mean(m_mean_vector.vector, num_features);
 		data_mean = fmatrix.rowwise().sum()/(float64_t) num_vectors;
		fmatrix = fmatrix.colwise()-data_mean;

		m_eigenvalues_vector = SGVector<float64_t>(max_dim_allowed);
		Map<VectorXd> eigenValues(m_eigenvalues_vector.vector, max_dim_allowed);

		if (m_method == AUTO)
			m_method = (num_vectors>num_features) ? EVD : SVD;

		if (m_method == EVD)
		{
			// covariance matrix
			MatrixXd cov_mat(num_features, num_features);
			cov_mat = fmatrix*fmatrix.transpose();
			cov_mat /= (num_vectors-1);

			SG_INFO("Computing Eigenvalues ... ")
			// eigen value computed
			SelfAdjointEigenSolver<MatrixXd> eigenSolve =
					SelfAdjointEigenSolver<MatrixXd>(cov_mat);
			eigenValues = eigenSolve.eigenvalues().tail(max_dim_allowed);

			// target dimension
			switch (m_mode)
			{
				case FIXED_NUMBER :
					num_dim = m_target_dim;
					break;

				case VARIANCE_EXPLAINED :
					{
						float64_t eig_sum = eigenValues.sum();
						float64_t com_sum = 0;
						for (int32_t i=num_features-1; i<-1; i++)
						{
							num_dim++;
							com_sum += m_eigenvalues_vector.vector[i];
							if (com_sum/eig_sum>=m_thresh)
								break;
						}
					}
					break;

				case THRESHOLD :
					for (int32_t i=num_features-1; i<-1; i++)
					{
						if (m_eigenvalues_vector.vector[i]>m_thresh)
							num_dim++;
						else
							break;
					}
					break;
			};
			SG_INFO("Done\nReducing from %i to %i features..", num_features, num_dim)

			m_transformation_matrix = SGMatrix<float64_t>(num_features,num_dim);
			Map<MatrixXd> transformMatrix(m_transformation_matrix.matrix,
								 num_features, num_dim);
			num_old_dim = num_features;

			// eigenvector matrix
			transformMatrix = eigenSolve.eigenvectors().block(0,
						num_features-num_dim, num_features,num_dim);
			if (m_whitening)
			{
				for (int32_t i=0; i<num_dim; i++)
				{
					if (CMath::fequals_abs<float64_t>(0.0, eigenValues[i+max_dim_allowed-num_dim],
											m_eigenvalue_zero_tolerance))
					{
						SG_WARNING("Covariance matrix has almost zero Eigenvalue (ie "
							"Eigenvalue within a tolerance of %E around 0) at "
							"dimension %d. Consider reducing its dimension.",
							m_eigenvalue_zero_tolerance, i+max_dim_allowed-num_dim+1)

						transformMatrix.col(i) = MatrixXd::Zero(num_features,1);
						continue;
					}

					transformMatrix.col(i) /=
					CMath::sqrt(eigenValues[i+max_dim_allowed-num_dim]*(num_vectors-1));
				}
			}
		}

		else
		{
			// compute SVD of data matrix
			JacobiSVD<MatrixXd> svd(fmatrix.transpose(), ComputeThinU | ComputeThinV);

			// compute non-negative eigen values from singular values
			eigenValues = svd.singularValues();
			eigenValues = eigenValues.cwiseProduct(eigenValues)/(num_vectors-1);

			// target dimension
			switch (m_mode)
			{
				case FIXED_NUMBER :
					num_dim = m_target_dim;
					break;

				case VARIANCE_EXPLAINED :
					{
						float64_t eig_sum = eigenValues.sum();
						float64_t com_sum = 0;
						for (int32_t i=0; i<num_features; i++)
						{
							num_dim++;
							com_sum += m_eigenvalues_vector.vector[i];
							if (com_sum/eig_sum>=m_thresh)
								break;
						}
					}
					break;

				case THRESHOLD :
					for (int32_t i=0; i<num_features; i++)
					{
						if (m_eigenvalues_vector.vector[i]>m_thresh)
							num_dim++;
						else
							break;
					}
					break;
			};
			SG_INFO("Done\nReducing from %i to %i features..", num_features, num_dim)

			// right singular vectors form eigenvectors
			m_transformation_matrix = SGMatrix<float64_t>(num_features,num_dim);
			Map<MatrixXd> transformMatrix(m_transformation_matrix.matrix, num_features, num_dim);
			num_old_dim = num_features;
			transformMatrix = svd.matrixV().block(0, 0, num_features, num_dim);
			if (m_whitening)
			{
				for (int32_t i=0; i<num_dim; i++)
				{
					if (CMath::fequals_abs<float64_t>(0.0, eigenValues[i],
								m_eigenvalue_zero_tolerance))
					{
						SG_WARNING("Covariance matrix has almost zero Eigenvalue (ie "
							"Eigenvalue within a tolerance of %E around 0) at "
							"dimension %d. Consider reducing its dimension.",
							m_eigenvalue_zero_tolerance, i+1)

						transformMatrix.col(i) = MatrixXd::Zero(num_features,1);
						continue;
					}

					transformMatrix.col(i) /= CMath::sqrt(eigenValues[i]*(num_vectors-1));
				}
			}
		}

		// restore feature matrix
		fmatrix = fmatrix.colwise()+data_mean;
		m_initialized = true;
		return true;
	}

	return false;
}

void CPCA::cleanup()
{
	m_transformation_matrix=SGMatrix<float64_t>();
        m_mean_vector = SGVector<float64_t>();
        m_eigenvalues_vector = SGVector<float64_t>();
	m_initialized = false;
}

SGMatrix<float64_t> CPCA::apply_to_feature_matrix(CFeatures* features)
{
	ASSERT(m_initialized)
	ASSERT(features != NULL)
	SGMatrix<float64_t> m = ((CDenseFeatures<float64_t>*) features)->get_feature_matrix();
	int32_t num_vectors = m.num_cols;
	int32_t num_features = m.num_rows;

	SG_INFO("Transforming feature matrix\n")
	Map<MatrixXd> transform_matrix(m_transformation_matrix.matrix,
			m_transformation_matrix.num_rows, m_transformation_matrix.num_cols);

	if (m_mem_mode == MEM_IN_PLACE)
	{
		if (m.matrix)
		{
			SG_INFO("Preprocessing feature matrix\n")
			Map<MatrixXd> feature_matrix(m.matrix, num_features, num_vectors);
			VectorXd data_mean = feature_matrix.rowwise().sum()/(float64_t) num_vectors;
			feature_matrix = feature_matrix.colwise()-data_mean;

			feature_matrix.block(0,0,num_dim,num_vectors) =
					transform_matrix.transpose()*feature_matrix;

			SG_INFO("Form matrix of target dimension")
			for (int32_t col=0; col<num_vectors; col++)
			{
				for (int32_t row=0; row<num_dim; row++)
					m.matrix[col*num_dim+row] = feature_matrix(row,col);
			}
			m.num_rows = num_dim;
			m.num_cols = num_vectors;
		}

		((CDenseFeatures<float64_t>*) features)->set_feature_matrix(m);
		return m;
	}
	else
	{
		SGMatrix<float64_t> ret(num_dim, num_vectors);
		Map<MatrixXd> ret_matrix(ret.matrix, num_dim, num_vectors);
		if (m.matrix)
		{
			SG_INFO("Preprocessing feature matrix\n")
			Map<MatrixXd> feature_matrix(m.matrix, num_features, num_vectors);
			VectorXd data_mean = feature_matrix.rowwise().sum()/(float64_t) num_vectors;
			feature_matrix = feature_matrix.colwise()-data_mean;

			ret_matrix = transform_matrix.transpose()*feature_matrix;
		}
		((CDenseFeatures<float64_t>*) features)->set_feature_matrix(ret);
		return ret;
	}
}

SGVector<float64_t> CPCA::apply_to_feature_vector(SGVector<float64_t> vector)
{
	SGVector<float64_t> result = SGVector<float64_t>(num_dim);
	Map<VectorXd> resultVec(result.vector, num_dim);
	Map<VectorXd> inputVec(vector.vector, vector.vlen);

	Map<VectorXd> mean(m_mean_vector.vector, m_mean_vector.vlen);
	Map<MatrixXd> transformMat(m_transformation_matrix.matrix,
		 m_transformation_matrix.num_rows, m_transformation_matrix.num_cols);

	inputVec = inputVec-mean;
	resultVec = transformMat.transpose()*inputVec;
	inputVec = inputVec+mean;

	return result;
}

SGMatrix<float64_t> CPCA::get_transformation_matrix()
{
	return m_transformation_matrix;
}

SGVector<float64_t> CPCA::get_eigenvalues()
{
	return m_eigenvalues_vector;
}

SGVector<float64_t> CPCA::get_mean()
{
	return m_mean_vector;
}

EPCAMemoryMode CPCA::get_memory_mode() const
{
	return m_mem_mode;
}

void CPCA::set_memory_mode(EPCAMemoryMode e)
{
	m_mem_mode = e;
}

void CPCA::set_eigenvalue_zero_tolerance(float64_t eigenvalue_zero_tolerance)
{
	m_eigenvalue_zero_tolerance = eigenvalue_zero_tolerance;
}

float64_t CPCA::get_eigenvalue_zero_tolerance() const
{
	return m_eigenvalue_zero_tolerance;
}

#endif // HAVE_EIGEN3
<|endoftext|>