<commit_before>/**
 * @file
 * @brief Inheritance example
 * @date 28.12.12
 * @author Felix Sulima
 */

#include <framework/example/self.h>

#include <new>
#include <cstdio>

// TEST: include all C++ headers
#include <cassert>
#include <cctype>
#include <cerrno>
#include <cmath>
#include <csetjmp>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <exception>
#include <new>
#include <typeinfo>
// END TEST

EMBOX_EXAMPLE(run);

class Base;
typedef void (* pbase_fn_t) (Base &base);

class Base {
public:
	Base(pbase_fn_t fn) {
		std::printf(">> [obj %p] Base(%p)\n", this, fn);
		if (fn) {
			fn(*this);
		}
	}
	virtual void testPureVirtual(void) = 0;
	virtual ~Base() = 0;
};

Base::~Base() {
	std::printf(">> [obj %p] ~Base()\n", this);
}

class Derived : public Base {
public:
	virtual void testPureVirtual(void) { std::printf(">> [obj %p] Derived.testPureVirtual() without any arguments\n", this); }
	Derived(pbase_fn_t fn) : Base(fn) { std::printf(">> [obj %p] Derived(%p)\n", this, fn); }
	~Derived() { std::printf(">> [obj %p] ~Derived()\n", this); }
};

static void callPureVirtual(Base& base) {
	assert(true);
	base.testPureVirtual();
}

static int run(int argc, char **argv) {

	// stack
	{
		std::puts("Derived without any arguments -- on stack");
		Derived derived();
	}

	// Null argument
	{
		std::puts("Derived with NULL argument -- on stack");
		Derived derived(NULL);
	}

	// Calling pure virtual function
	{
		std::puts("Calling pure virtual function");
		Derived derived(callPureVirtual);
	}

	return 0;
}

<commit_msg>tests: cxx: Fix inheritance test<commit_after>/**
 * @file
 * @brief Inheritance example
 * @date 28.12.12
 * @author Felix Sulima
 */

#include <new>
#include <cstdio>

#include <embox/test.h>
#include "test_cxx.h"

EMBOX_TEST_SUITE_EXT("c++ inheritance test", NULL, NULL, NULL, NULL);

namespace {

class Base {
public:
	Base(int val) {
		test_emit('a');
	}
	virtual void pure_virtual_fn(void) = 0;
	virtual ~Base() = 0;
};

Base::~Base() {
	test_emit('b');
}

class Derived : public Base {
public:
	Derived(int val) : Base(val) {test_emit('c');}
	~Derived() { test_emit('d');}
	void pure_virtual_fn(void) {test_emit('e');}
};

TEST_CASE("Inheritance test") {
	{
		Derived derived(0);
	}
	test_assert_emitted("acdb");
}

TEST_CASE("Calling virtual function") {
	{
		Derived derived(0);
		derived.pure_virtual_fn();
	}
	test_assert_emitted("acedb");
}
} /* namespace */
<|endoftext|>


<commit_before>// Copyright (c) 2020 Intel Corporation
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include "mfx_common.h"
#if defined(MFX_ENABLE_H265_VIDEO_ENCODE) && defined(MFX_VA_LINUX)

#include "hevcehw_g9_dirty_rect_lin.h"
#include "hevcehw_g9_va_packer_lin.h"

using namespace HEVCEHW;
using namespace HEVCEHW::Gen9;

void Linux::Gen9::DirtyRect::InitAlloc(const FeatureBlocks& /*blocks*/, TPushIA Push)
{
    Push(BLK_SetCallChains
        , [this](StorageRW& global, StorageRW& /*local*/) -> mfxStatus
    {
        auto& vaPacker = VAPacker::CC::Get(global);

        vaPacker.AddPerPicMiscData[VAEncMiscParameterTypeDirtyRect].Push([this](
            VAPacker::CallChains::TAddMiscData::TExt
            , const StorageR& global
            , const StorageR& s_task
            , std::list<std::vector<mfxU8>>& data)
        {
            auto dirtyRect = GetRTExtBuffer<mfxExtDirtyRect>(global, s_task);

            mfxU32 log2blkSize = Glob::EncodeCaps::Get(global).BlockSize + 3;

            auto& vaDirtyRect = AddVaMisc<VAEncMiscParameterBufferDirtyRect>(VAEncMiscParameterTypeDirtyRect, data);

            vaDirtyRect.num_roi_rectangle = 0;
            m_vaDirtyRects.clear();

            for (int i = 0; i < dirtyRect.NumRect; i++)
            {
                if (SkipRectangle(dirtyRect.Rect[i]))
                    continue;

                /* Driver expects a rect with the 'close' right bottom edge but
                MSDK uses the 'open' edge rect, thus the right bottom edge which
                is decreased by 1 below converts 'open' -> 'close' notation
                We expect here boundaries are already aligned with the BlockSize
                and Right > Left and Bottom > Top */
                m_vaDirtyRects.push_back({
                   int16_t(dirtyRect.Rect[i].Top)
                   , int16_t(dirtyRect.Rect[i].Left)
                   , uint16_t((dirtyRect.Rect[i].Right - dirtyRect.Rect[i].Left) - (1 << log2blkSize))
                   , uint16_t((dirtyRect.Rect[i].Bottom - dirtyRect.Rect[i].Top) - (1 << log2blkSize))
                });

                ++vaDirtyRect.num_roi_rectangle;

            }
            vaDirtyRect.roi_rectangle = vaDirtyRect.num_roi_rectangle ? m_vaDirtyRects.data() : nullptr;

            return vaDirtyRect.num_roi_rectangle ? 1 : 0;
        });

        return MFX_ERR_NONE;
    });
}

#endif //defined(MFX_ENABLE_H265_VIDEO_ENCODE)
<commit_msg>[hevce r] Fix dirty rect parameters<commit_after>// Copyright (c) 2020 Intel Corporation
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include "mfx_common.h"
#if defined(MFX_ENABLE_H265_VIDEO_ENCODE) && defined(MFX_VA_LINUX)

#include "hevcehw_g9_dirty_rect_lin.h"
#include "hevcehw_g9_va_packer_lin.h"

using namespace HEVCEHW;
using namespace HEVCEHW::Gen9;

void Linux::Gen9::DirtyRect::InitAlloc(const FeatureBlocks& /*blocks*/, TPushIA Push)
{
    Push(BLK_SetCallChains
        , [this](StorageRW& global, StorageRW& /*local*/) -> mfxStatus
    {
        auto& vaPacker = VAPacker::CC::Get(global);

        vaPacker.AddPerPicMiscData[VAEncMiscParameterTypeDirtyRect].Push([this](
            VAPacker::CallChains::TAddMiscData::TExt
            , const StorageR& global
            , const StorageR& s_task
            , std::list<std::vector<mfxU8>>& data)
        {
            auto dirtyRect = GetRTExtBuffer<mfxExtDirtyRect>(global, s_task);

            mfxU32 log2blkSize = Glob::EncodeCaps::Get(global).BlockSize + 3;

            auto& vaDirtyRect = AddVaMisc<VAEncMiscParameterBufferDirtyRect>(VAEncMiscParameterTypeDirtyRect, data);

            vaDirtyRect.num_roi_rectangle = 0;
            m_vaDirtyRects.clear();

            for (int i = 0; i < dirtyRect.NumRect; i++)
            {
                if (SkipRectangle(dirtyRect.Rect[i]))
                    continue;

                /* Driver expects a rect with the 'close' right bottom edge but
                MSDK uses the 'open' edge rect, thus the right bottom edge which
                is decreased by 1 below converts 'open' -> 'close' notation
                We expect here boundaries are already aligned with the BlockSize
                and Right > Left and Bottom > Top */
                m_vaDirtyRects.push_back({
                   int16_t(dirtyRect.Rect[i].Left)
                   , int16_t(dirtyRect.Rect[i].Top)
                   , uint16_t((dirtyRect.Rect[i].Right - dirtyRect.Rect[i].Left) - (1 << log2blkSize))
                   , uint16_t((dirtyRect.Rect[i].Bottom - dirtyRect.Rect[i].Top) - (1 << log2blkSize))
                });

                ++vaDirtyRect.num_roi_rectangle;

            }
            vaDirtyRect.roi_rectangle = vaDirtyRect.num_roi_rectangle ? m_vaDirtyRects.data() : nullptr;

            return vaDirtyRect.num_roi_rectangle ? 1 : 0;
        });

        return MFX_ERR_NONE;
    });
}

#endif //defined(MFX_ENABLE_H265_VIDEO_ENCODE)
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: debug.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: as $ $Date: 2001-05-02 13:00:40 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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 Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef __FRAMEWORK_MACROS_DEBUG_HXX_
#define __FRAMEWORK_MACROS_DEBUG_HXX_

//*****************************************************************************************************************
//  Disable all feature of this file in produkt version!
//  But enable normal assertion handling (as messagebox) in normal debug version.
//  User can overwrite these adjustment with his own values! We will do it only if nothing is set.
//*****************************************************************************************************************

#ifndef DEBUG
    #undef  ENABLE_LOGMECHANISM
    #undef  ENABLE_ASSERTIONS
    #undef  ENABLE_EVENTDEBUG
    #undef  ENABLE_MUTEXDEBUG
    #undef  ENABLE_REGISTRATIONDEBUG
    #undef  ENABLE_TARGETINGDEBUG
    #undef  ENABLE_PLUGINDEBUG
#else
    // Enable log mechanism for assertion handling.
    #ifndef ENABLE_LOGMECHANISM
        #define ENABLE_LOGMECHANISM
    #endif
    // Enable assertion handling himself.
    // The default logtype is MESSAGEBOX.
    // see "assertion.hxx" for further informations
    #ifndef ENABLE_ASSERTIONS
        #define ENABLE_ASSERTIONS
    #endif
    #ifndef ENABLE_MUTEXDEBUG
        #define ENABLE_MUTEXDEBUG
    #endif
#endif

//*****************************************************************************************************************
//  generic macros for logging
//*****************************************************************************************************************

#ifndef __FRAMEWORK_MACROS_DEBUG_LOGMECHANISM_HXX_
#include <macros/debug/logmechanism.hxx>
#endif

//*****************************************************************************************************************
//  special macros for assertion handling
//*****************************************************************************************************************

#ifndef __FRAMEWORK_MACROS_DEBUG_ASSERTION_HXX_
#include <macros/debug/assertion.hxx>
#endif

//*****************************************************************************************************************
//  special macros for event handling
//*****************************************************************************************************************

#ifndef __FRAMEWORK_MACROS_DEBUG_EVENT_HXX_
#include <macros/debug/event.hxx>
#endif

//*****************************************************************************************************************
//  special macros to debug mutex handling
//*****************************************************************************************************************

#ifndef __FRAMEWORK_MACROS_DEBUG_MUTEX_HXX_
#include <macros/debug/mutex.hxx>
#endif

//*****************************************************************************************************************
//  special macros to debug service registration
//*****************************************************************************************************************

#ifndef __FRAMEWORK_MACROS_DEBUG_REGISTRATION_HXX_
#include <macros/debug/registration.hxx>
#endif

//*****************************************************************************************************************
//  special macros to debug targeting of frames
//*****************************************************************************************************************

#ifndef __FRAMEWORK_MACROS_DEBUG_TARGETING_HXX_
#include <macros/debug/targeting.hxx>
#endif

//*****************************************************************************************************************
//  special macros to debug our plugin and his asynchronous methods!
//*****************************************************************************************************************

#ifndef __FRAMEWORK_MACROS_DEBUG_PLUGIN_HXX_
#include <macros/debug/plugin.hxx>
#endif

//*****************************************************************************************************************
//  end of file
//*****************************************************************************************************************

#endif  // #ifndef __FRAMEWORK_MACROS_DEBUG_HXX_
<commit_msg>enable assertions for non produkt version<commit_after>/*************************************************************************
 *
 *  $RCSfile: debug.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: as $ $Date: 2001-05-04 13:13:15 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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 Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef __FRAMEWORK_MACROS_DEBUG_HXX_
#define __FRAMEWORK_MACROS_DEBUG_HXX_

//*****************************************************************************************************************
//  Disable all feature of this file in produkt version!
//  But enable normal assertion handling (as messagebox) in normal debug version.
//  User can overwrite these adjustment with his own values! We will do it only if nothing is set.
//*****************************************************************************************************************

#ifndef _DEBUG
    #undef  ENABLE_LOGMECHANISM
    #undef  ENABLE_ASSERTIONS
    #undef  ENABLE_EVENTDEBUG
    #undef  ENABLE_MUTEXDEBUG
    #undef  ENABLE_REGISTRATIONDEBUG
    #undef  ENABLE_TARGETINGDEBUG
    #undef  ENABLE_PLUGINDEBUG
#else
    // Enable log mechanism for assertion handling.
    #ifndef ENABLE_LOGMECHANISM
        #define ENABLE_LOGMECHANISM
    #endif
    // Enable assertion handling himself.
    // The default logtype is MESSAGEBOX.
    // see "assertion.hxx" for further informations
    #ifndef ENABLE_ASSERTIONS
        #define ENABLE_ASSERTIONS
    #endif
    #ifndef ENABLE_MUTEXDEBUG
        #define ENABLE_MUTEXDEBUG
    #endif
#endif

//*****************************************************************************************************************
//  generic macros for logging
//*****************************************************************************************************************

#ifndef __FRAMEWORK_MACROS_DEBUG_LOGMECHANISM_HXX_
#include <macros/debug/logmechanism.hxx>
#endif

//*****************************************************************************************************************
//  special macros for assertion handling
//*****************************************************************************************************************

#ifndef __FRAMEWORK_MACROS_DEBUG_ASSERTION_HXX_
#include <macros/debug/assertion.hxx>
#endif

//*****************************************************************************************************************
//  special macros for event handling
//*****************************************************************************************************************

#ifndef __FRAMEWORK_MACROS_DEBUG_EVENT_HXX_
#include <macros/debug/event.hxx>
#endif

//*****************************************************************************************************************
//  special macros to debug mutex handling
//*****************************************************************************************************************

#ifndef __FRAMEWORK_MACROS_DEBUG_MUTEX_HXX_
#include <macros/debug/mutex.hxx>
#endif

//*****************************************************************************************************************
//  special macros to debug service registration
//*****************************************************************************************************************

#ifndef __FRAMEWORK_MACROS_DEBUG_REGISTRATION_HXX_
#include <macros/debug/registration.hxx>
#endif

//*****************************************************************************************************************
//  special macros to debug targeting of frames
//*****************************************************************************************************************

#ifndef __FRAMEWORK_MACROS_DEBUG_TARGETING_HXX_
#include <macros/debug/targeting.hxx>
#endif

//*****************************************************************************************************************
//  special macros to debug our plugin and his asynchronous methods!
//*****************************************************************************************************************

#ifndef __FRAMEWORK_MACROS_DEBUG_PLUGIN_HXX_
#include <macros/debug/plugin.hxx>
#endif

//*****************************************************************************************************************
//  end of file
//*****************************************************************************************************************

#endif  // #ifndef __FRAMEWORK_MACROS_DEBUG_HXX_
<|endoftext|>


<commit_before>#include <cmath>
#include <cstdio>
#include <omp.h>

// (Sub-optimum) Array of Structure - good OOP. Bad Performance.
// Structure of individual particle
//struct ParticleType {
//  float x, y, z;
//  float vx, vy, vz;
//};

// (Optimum) Structure of Array - bad OOP. Good performance.
struct ParticleSetType {
  float *x, *y, *z;
  float *vx, *vy, *vz;
};

// define a function that moves each particle due to interaction with other particles
void MoveParticles(const int nParticles, ParticleSetType & particle, const float dt) {

  const int TILE = 16;

#pragma omp parallel for
  // Loop over particles that experience force
  for (int ii = 0; ii < nParticles; ii+=TILE) {

    // Components of the gravity force on particle i
    float Fx[TILE], Fy[TILE], Fz[TILE];
     Fx[0:TILE] = Fy[0:TILE]  = Fz[0:TILE] = 0.0f;

     // Loop over particles that exert force: vectorization expected here
#pragma unroll(TILE)
    for (int j = 0; j < nParticles; j++) {

#pragma vector aligned
      // How much data in this tiled loop?
      // 16 (particles in a tile) * 3 floats * 4 bytes per floats = 192 bytes
      // enough to fit in the L1 Cache registery
      for (int i = ii; i < ii+TILE; i++) {

	// Avoid singularity and interaction with self
	const float softening = 1e-20;

	// Newton's law of universal gravity
	const float dx = particle.x[j] - particle.x[i];
	const float dy = particle.y[j] - particle.y[i];
	const float dz = particle.z[j] - particle.z[i];
	const float drSquared  = dx*dx + dy*dy + dz*dz + softening;

	const float oodr = 1.0f/sqrtf(drSquared);
	const float drPowerN3 = oodr*oodr*oodr;

	// Calculate the net force
	// Assume mass is 1 (for ease of computation)
	// F = ma = 1*a = a
	Fx[i-ii] += dx * oodr;  // scalar tuning
	Fy[i-ii] += dy * oodr;  // scalar tuning
	Fz[i-ii] += dz * oodr;  // scalar tuning
      }
    }

    // Accelerate particles in response to the gravitational force
    // Note: 1st order Euler Approximation.
    // http://spiff.rit.edu/classes/phys317/lectures/euler.html
    particle.vx[ii:TILE] += dt*Fx[0:TILE];
    particle.vy[ii:TILE] += dt*Fy[0:TILE];
    particle.vz[ii:TILE] += dt*Fz[0:TILE];
  }

#pragma omp parallel for
  // Move particles according to their velocities
  for (int i = 0 ; i < nParticles; i++) {
    particle.x[i]  += particle.vx[i]*dt;
    particle.y[i]  += particle.vy[i]*dt;
    particle.z[i]  += particle.vz[i]*dt;
  }

}

// Do it!
int main(const int argc, const char *argv[]) {

  // Problem size and other parameters
  const int nParticles = (argc > 1 ? atoi(argv[1]) : 16384);
  const int nSteps = 10;  // Duration of test
  const float dt = 0.01f; // Particle propagation time step

  // Particle data stored as an Array of Structures (AoS)
  // this is good object-oriented programming style,
  // but inefficient for the purposes of vectorization
  //ParticleType *particle = new ParticleType[nParticles];

  // Structure of Array (SoA) style
  // bad OOP style. But very efficient in terms of performance.
  ParticleSetType particle;

  // use Intel _mm_malloc to create objects that are stored on aligned memory.
  // For KNL, needs to align to start at multiple of 64 bytes.
  // use _mm_free to deallocate
  particle.x = (float*) _mm_malloc(sizeof(float)*nParticles, 64);
  particle.y = (float*) _mm_malloc(sizeof(float)*nParticles, 64);;
  particle.z = (float*) _mm_malloc(sizeof(float)*nParticles, 64);;
  particle.vx = (float*) _mm_malloc(sizeof(float)*nParticles, 64);;
  particle.vy = (float*) _mm_malloc(sizeof(float)*nParticles, 64);;
  particle.vz = (float*) _mm_malloc(sizeof(float)*nParticles, 64);;

  // Initialize random number generator and particles
  srand(0);
  for(int i = 0; i < nParticles; i++) {
    particle.x[i] = rand()/RAND_MAX;
    particle.y[i] = rand()/RAND_MAX;
    particle.z[i] = rand()/RAND_MAX;
    particle.vx[i] = rand()/RAND_MAX;
    particle.vy[i] = rand()/RAND_MAX;
    particle.vz[i] = rand()/RAND_MAX;
  }

  // Perform benchmark
  const int version = 10; // implementation version - update as needed
  printf("\n\033[1mNBODY Version %d\033[0m\n", version);
  const int num_threads = omp_get_max_threads();
  printf("\nPropagating %d particles using %d threads on %s...\n\n",
	 nParticles, num_threads,

#ifndef __MIC__
	 "CPU"
#else
	 "MIC"
#endif
	 );

  // Benchmarking data
  // rate and duration are for computing overall average performance and duration
  // dRate and dDuration are for computing the short-cut standard diviation later.
  double rate = 0, dRate = 0, duration = 0, dDuration = 0;

  // Skip first few steps in the computation of average performance. Likely warm-up on Xeon Phi processor
  const int skipSteps = 3;
  printf("\033[1m%5s %10s %10s %8s\033[0m\n", "Step", "Time, s", "Interact/s", "GFLOP/s");
  fflush(stdout);
  for (int step = 1; step <= nSteps; step++) {

    const double tStart = omp_get_wtime(); // Start timing
    MoveParticles(nParticles, particle, dt);
    const double tEnd = omp_get_wtime(); // End timing

    // Estimate total interactions and GFLOPS consumed
    const float HztoInts   = float(nParticles)*float(nParticles-1) ;
    const float HztoGFLOPs = 20.0*1e-9*float(nParticles)*float(nParticles-1);

    // For average performance and short-cut method standard deviation computation
    if (step > skipSteps) { // Collect statistics
      rate  += HztoGFLOPs/(tEnd - tStart);
      dRate += HztoGFLOPs*HztoGFLOPs/((tEnd - tStart)*(tEnd-tStart));
      duration += (tEnd - tStart);
      dDuration += (tEnd - tStart)*(tEnd - tStart);
    }

    printf("%5d %10.3e %10.3e %8.1f %s\n",
	   step, (tEnd-tStart), HztoInts/(tEnd-tStart), HztoGFLOPs/(tEnd-tStart), (step<=skipSteps?"*":""));
    fflush(stdout);
  }

  // Compute the short-cut method standard deviaion.
  rate/=(double)(nSteps-skipSteps);
  dRate=sqrt(dRate/(double)(nSteps-skipSteps)-rate*rate);
  duration/=(double)(nSteps-skipSteps);
  dDuration=sqrt(dDuration/(double)(nSteps-skipSteps)-duration*duration);

  printf("-----------------------------------------------------\n");
  printf("\033[1m%s %4s \033[42m%10.1f +- %.1f GFLOP/s\033[0m\n",
	 "Average performance:", "", rate, dRate);
  printf("\033[1m%s %4s \033[42m%10.3e +- %10.3e s\033[0m\n",
	 "Average duration:", "", duration, dDuration);
printf("\033[1m%s %4s \033[42m%.3f +- %.3f ms\033[0m\n",
	 "Average duration:", "", duration*1000.0, dDuration*1000.0);
  printf("-----------------------------------------------------\n");
  printf("* - warm-up, not included in average\n\n");

  // free memory
  _mm_free(particle.x);
  _mm_free(particle.y);
  _mm_free(particle.z);
  _mm_free(particle.vx);
  _mm_free(particle.vy);
  _mm_free(particle.vz);
}

<commit_msg>Update nbody.cc<commit_after>#include <cmath>
#include <cstdio>
#include <omp.h>

// (Sub-optimum) Array of Structure - good OOP. Bad Performance.
// Structure of individual particle
//struct ParticleType {
//  float x, y, z;
//  float vx, vy, vz;
//};

// (Optimum) Structure of Array - bad OOP. Good performance.
struct ParticleSetType {
  float *x, *y, *z;
  float *vx, *vy, *vz;
};

// define a function that moves each particle due to interaction with other particles
void MoveParticles(const int nParticles, ParticleSetType & particle, const float dt) {

  const int TILE = 16;

#pragma omp parallel for
  // Loop over particles that experience force
  for (int ii = 0; ii < nParticles; ii+=TILE) {

    // Components of the gravity force on particle i
    float Fx[TILE], Fy[TILE], Fz[TILE];
     Fx[0:TILE] = Fy[0:TILE]  = Fz[0:TILE] = 0.0f;

     // Loop over particles that exert force: vectorization expected here
#pragma unroll(TILE)
    for (int j = 0; j < nParticles; j++) {

#pragma vector aligned
      // How much data in this tiled loop?
      // 16 (particles in a tile) * 3 floats * 4 bytes per floats = 192 bytes
      // enough to fit in the L1 Cache registery
      for (int i = ii; i < ii+TILE; i++) {

	// Avoid singularity and interaction with self
	const float softening = 1e-20;

	// Newton's law of universal gravity
	const float dx = particle.x[j] - particle.x[i];
	const float dy = particle.y[j] - particle.y[i];
	const float dz = particle.z[j] - particle.z[i];
	const float drSquared  = dx*dx + dy*dy + dz*dz + softening;

	const float oodr = 1.0f/sqrtf(drSquared);
	const float drPowerN3 = oodr*oodr*oodr;

	// Calculate the net force
	// Assume mass is 1 (for ease of computation)
	// F = ma = 1*a = a
	Fx[i-ii] += dx * drPowerN3;  // scalar tuning
	Fy[i-ii] += dy * drPowerN3;  // scalar tuning
	Fz[i-ii] += dz * drPowerN3;  // scalar tuning
      }
    }

    // Accelerate particles in response to the gravitational force
    // Note: 1st order Euler Approximation.
    // http://spiff.rit.edu/classes/phys317/lectures/euler.html
    particle.vx[ii:TILE] += dt*Fx[0:TILE];
    particle.vy[ii:TILE] += dt*Fy[0:TILE];
    particle.vz[ii:TILE] += dt*Fz[0:TILE];
  }

#pragma omp parallel for
  // Move particles according to their velocities
  for (int i = 0 ; i < nParticles; i++) {
    particle.x[i]  += particle.vx[i]*dt;
    particle.y[i]  += particle.vy[i]*dt;
    particle.z[i]  += particle.vz[i]*dt;
  }

}

// Do it!
int main(const int argc, const char *argv[]) {

  // Problem size and other parameters
  const int nParticles = (argc > 1 ? atoi(argv[1]) : 16384);
  const int nSteps = 10;  // Duration of test
  const float dt = 0.01f; // Particle propagation time step

  // Particle data stored as an Array of Structures (AoS)
  // this is good object-oriented programming style,
  // but inefficient for the purposes of vectorization
  //ParticleType *particle = new ParticleType[nParticles];

  // Structure of Array (SoA) style
  // bad OOP style. But very efficient in terms of performance.
  ParticleSetType particle;

  // use Intel _mm_malloc to create objects that are stored on aligned memory.
  // For KNL, needs to align to start at multiple of 64 bytes.
  // use _mm_free to deallocate
  particle.x = (float*) _mm_malloc(sizeof(float)*nParticles, 64);
  particle.y = (float*) _mm_malloc(sizeof(float)*nParticles, 64);;
  particle.z = (float*) _mm_malloc(sizeof(float)*nParticles, 64);;
  particle.vx = (float*) _mm_malloc(sizeof(float)*nParticles, 64);;
  particle.vy = (float*) _mm_malloc(sizeof(float)*nParticles, 64);;
  particle.vz = (float*) _mm_malloc(sizeof(float)*nParticles, 64);;

  // Initialize random number generator and particles
  srand(0);
  for(int i = 0; i < nParticles; i++) {
    particle.x[i] = rand()/RAND_MAX;
    particle.y[i] = rand()/RAND_MAX;
    particle.z[i] = rand()/RAND_MAX;
    particle.vx[i] = rand()/RAND_MAX;
    particle.vy[i] = rand()/RAND_MAX;
    particle.vz[i] = rand()/RAND_MAX;
  }

  // Perform benchmark
  const int version = 10; // implementation version - update as needed
  printf("\n\033[1mNBODY Version %d\033[0m\n", version);
  const int num_threads = omp_get_max_threads();
  printf("\nPropagating %d particles using %d threads on %s...\n\n",
	 nParticles, num_threads,

#ifndef __MIC__
	 "CPU"
#else
	 "MIC"
#endif
	 );

  // Benchmarking data
  // rate and duration are for computing overall average performance and duration
  // dRate and dDuration are for computing the short-cut standard diviation later.
  double rate = 0, dRate = 0, duration = 0, dDuration = 0;

  // Skip first few steps in the computation of average performance. Likely warm-up on Xeon Phi processor
  const int skipSteps = 3;
  printf("\033[1m%5s %10s %10s %8s\033[0m\n", "Step", "Time, s", "Interact/s", "GFLOP/s");
  fflush(stdout);
  for (int step = 1; step <= nSteps; step++) {

    const double tStart = omp_get_wtime(); // Start timing
    MoveParticles(nParticles, particle, dt);
    const double tEnd = omp_get_wtime(); // End timing

    // Estimate total interactions and GFLOPS consumed
    const float HztoInts   = float(nParticles)*float(nParticles-1) ;
    const float HztoGFLOPs = 20.0*1e-9*float(nParticles)*float(nParticles-1);

    // For average performance and short-cut method standard deviation computation
    if (step > skipSteps) { // Collect statistics
      rate  += HztoGFLOPs/(tEnd - tStart);
      dRate += HztoGFLOPs*HztoGFLOPs/((tEnd - tStart)*(tEnd-tStart));
      duration += (tEnd - tStart);
      dDuration += (tEnd - tStart)*(tEnd - tStart);
    }

    printf("%5d %10.3e %10.3e %8.1f %s\n",
	   step, (tEnd-tStart), HztoInts/(tEnd-tStart), HztoGFLOPs/(tEnd-tStart), (step<=skipSteps?"*":""));
    fflush(stdout);
  }

  // Compute the short-cut method standard deviaion.
  rate/=(double)(nSteps-skipSteps);
  dRate=sqrt(dRate/(double)(nSteps-skipSteps)-rate*rate);
  duration/=(double)(nSteps-skipSteps);
  dDuration=sqrt(dDuration/(double)(nSteps-skipSteps)-duration*duration);

  printf("-----------------------------------------------------\n");
  printf("\033[1m%s %4s \033[42m%10.1f +- %.1f GFLOP/s\033[0m\n",
	 "Average performance:", "", rate, dRate);
  printf("\033[1m%s %4s \033[42m%10.3e +- %10.3e s\033[0m\n",
	 "Average duration:", "", duration, dDuration);
printf("\033[1m%s %4s \033[42m%.3f +- %.3f ms\033[0m\n",
	 "Average duration:", "", duration*1000.0, dDuration*1000.0);
  printf("-----------------------------------------------------\n");
  printf("* - warm-up, not included in average\n\n");

  // free memory
  _mm_free(particle.x);
  _mm_free(particle.y);
  _mm_free(particle.z);
  _mm_free(particle.vx);
  _mm_free(particle.vy);
  _mm_free(particle.vz);
}

<|endoftext|>


<commit_before>
#ifndef MANAGER_HPP_
#define MANAGER_HPP_

#include <vector>
#include <map>
#include <random>

#include "Chromosome.hpp"

#define MINIMUM_NUMBER 0

template <class T>
class Manager {
protected:

	unsigned int population_size;
	unsigned int chromosome_size;

	unsigned int max_generation_number;

	T max_chromosome_value;
	T min_chromosome_value;

	bool use_self_adaptive;
	double mutation_rate;
	double mutation_change_rate;
	double similarity_index;

	double clonning_rate;

	double crossover_rate;

	std::vector<Chromosome<T > > population;

	// Need to have some way of ensure no duplication of solutions
	std::vector<Chromosome<T > > solutions;

	std::mt19937 rand_engine;
	std::uniform_real_distribution<> op_dist;
	std::uniform_real_distribution<> chrom_dist;

public:

	/**
	 * Create a manager for GA.
	 * @param population_size The size of population.
	 * @param chromosome_size The size of each chromosome.
	 * @param max_chromosome_value The maximum possible value for the chromosome.
	 * @param min_chromosome_value The minimum possible value for the chromosome.
	 * @param use_self_adaptive Whether to use a self adaptive approach. If this is true
	 * then the mutation rate will be updated based on the similarity of the population.
	 * @param mutation_rate The mutation rate that is used. This is the likelihood that the
	 * mutation operation is applied. If the self adaptive approach is used then this is
	 * the initial mutation rate.
	 * @param mutation_change_rate The rate by which the mutation rate will be updated.
	 * If use_self_adaptive is set to false then this parameter is ignored.
	 * @param similarity_index The threshold at which the similarity mutation rate is
	 * updated.
	 * @param crossover_rate The crossover rate, the likelihood that a chromosome
	 * has the crossover operation applied to it.
	 * @param clonning_rate The clonning rate, the likelihood that a cromosome will be
	 * cloned into the new population.
	 */
	Manager(unsigned int population_size, unsigned int chromosome_size, unsigned int max_generations_number,
			T max_chromosome_value, T min_chromosome_value, bool use_self_adaptive,
			double mutation_rate, double mutation_change_rate, double similarity_index,
			double crossover_rate, double clonning_rate) : population_size(population_size),
			chromosome_size(chromosome_size), max_generation_number(max_generation_number),
			max_chromosome_value(max_chromosome_value), min_chromosome_value(min_chromosome_value),
			use_self_adaptive(use_self_adaptive), mutation_rate(mutation_rate),
			mutation_change_rate(mutation_change_rate), similarity_index(similarity_index),
			clonning_rate(clonning_rate), crossover_rate(crossover_rate),
			population(population_size) {

		initialize();
	}

	/**
	 * Create a non self-adaptive GA manager
	 * @param population_size The size of population.
	 * @param chromosome_size The size of each chromosome.
	 * @param max_chromosome_value The maximum possible value for the chromosome.
	 * @param min_chromosome_value The minimum possible value for the chromosome.
	 * @param mutation_rate The mutation rate that is used. This is the likelihood that the
	 * mutation operation is applied. If the self adaptive approach is used then this is
	 * the initial mutation rate.
	 * @param crossover_rate The crossover rate, the likelihood that a chromosome
	 * has the crossover operation applied to it.
	 * @param clonning_rate The clonning rate, the likelihood that a cromosome will be
	 * cloned into the new population.
	 */
	Manager(unsigned int population_size, unsigned int chromosome_size, unsigned int max_generation_number,
				T max_chromosome_value, T min_chromosome_value, double mutation_rate,
				double crossover_rate, double clonning_rate) : population_size(population_size),
				chromosome_size(chromosome_size), max_generation_number(max_generation_number),
				max_chromosome_value(max_chromosome_value), min_chromosome_value(min_chromosome_value),
				use_self_adaptive(false), mutation_rate(mutation_rate), mutation_change_rate(0),
				similarity_index(0), clonning_rate(clonning_rate), crossover_rate(crossover_rate),
				population(population_size) {

		initialize();

	}

        /**
	 * Run the algorithm for the specificed number of generations
	 */
	void run() {
		for(unsigned int i = 0; i < max_generation_number; i++) {
			runGeneration();
		}
	}

	/**
	 * Apply the fitness function to the population. Given the result of the
	 * fitness function, the next population is bread.
	 */
	void runGeneration() {
		// Fitness function would be a generic method passed as an argument that is apply to each chromosome
		// Given that threads are going to be used:
			// - Create a thread pool and attempt to assign a reduced set of chromosomes to each thread
			// - Since each chromosome is independent for the execution of the fitness function they can be 1 thread per chromosome (hypothedically)
		// Given that MPI is being used
			// - Reduce the chromosomes into smaller sets and assign them to a node
			// - Each node can then divide the subpopulation further (possibly to a per-chromosome per thread) depending on availablity. (this step is similar to the second step with threading.
			// Apply the fitness function

		// Could potentially have a second generic method that you could use to apply heuristics to a found solution.
			// eg; in N-Queens you can rotate the board in order to find more solutions.

		// Can be done concurrently with the fitness function
		if(use_self_adaptive) {
			selfAdapt();
		}

		// Main thread will wait for all children to finish executing before proceeding.
		// Construct the list of results for the fitness function in a map which maps the chromosome's index to the chromosome's fitness value. The type of the result of the fitness function can be any desired type however primitive is desired. eg:
		std::map<unsigned int, int > fitness_results;
		breed(fitness_results);
	}

	/**
	 * Prepare the population for the next generation by apply the genetic operations.
	 */
	template <typename F>
	void breed(std::map<unsigned int, F > fitness_result) {
		std::vector<Chromosome<T > > new_population;

		// Iterate through the chromosomes
		while(new_population.size() < population_size) {
			// TODO Using a specific selection (eg roulette wheel without replacement) to pick a chromosome
			// Use a random number between to identify which operation to apply (each operation gets a slice of the range)
			int selected_operation = 0;
			int selected_chromosome = getRandChromosome();
			if(selected_operation == 0) {
				// Mutation
				population[selected_chromosome].mutation(new_population);
			}
			else if(selected_operation == 1) {
				// Crossover
				// Pick another chromosome from the population that is not the already selected chromosome. (TODO can the chromosome be the same as the initally selected on?)
				int other_selected_chromosome = getRandChromosome(selected_chromosome);

				population[selected_chromosome].crossover(population[other_selected_chromosome], new_population);

			}
			else {
				// Clone
				population[selected_chromosome].clone(new_population);
			}
		}

		// Update the population to the new population
		population = new_population; // Check if this creates a shallow copy (since we aren't going to change new_population so we just want it to be deallocated at the end of the method).

	}

	/**
 	 * Apply the self-adaptive operation to determine the similarity of the chromosomes
	 * and update the mutation rate accordingly.
	 */
	void selfAdapt() {
		// Determine how similar the chromosome is to the rest of the population

		// Sequencial solution
		// Iterate through the chromosomes
			// Calculate the current chromosome with each of the others in the population

		// Based on the similarity of the population identify adjust the mutaiton rate
			//if the similarity is too high (above threshold), increase mutation rate
			//if similarity is too low (below threshold), decrease mutation rate
			//otherwise (same as threshold), do nothing
	}

	// Instead of taking a fitness function it might be better to take a function pointer and call that function for the fitness function
	// void *fitness_function(std::vector<Chromosome<T > > population);

	/*static void *fitness_function(std::vector<Chromosome<T > > population) {

		return NULL;
	}*/
private:
	void initialize() {
		// Create the random objects that will be used
		std::random_device rd;
		rand_engine = std::mt19937 (rd());
		op_dist = std::uniform_real_distribution<> (0, 100);
		chrom_dist = std::uniform_real_distribution<> (MINIMUM_NUMBER, population_size-1);
		Chromosome<T >::initialize(chromosome_size, min_chromosome_value, max_chromosome_value);
	}

	/**
         * Get a number between 0 and population.size() - 1
	 * @return A number between 0 and population.size()-1
         */
	unsigned int getRandChromosome() {
		return chrom_dist(rand_engine);
	}

	/**
	 * Get a random number between 0 and population.size()-1 that is not index
	 * @param index The only value within the range that the return cannot be.
	 * @return A number within the defined range that is not index.
	 */
	unsigned int getRandChromosome(unsigned int index) {
		unsigned int val = getRandChromosome();

		while(val == index) {
			val = getRandChromosome();
		}
		return val;
	}
};

#endif /* MANAGER_HPP_ */
<commit_msg>ADDED: function pointer reference<commit_after>
#ifndef MANAGER_HPP_
#define MANAGER_HPP_

#include <vector>
#include <map>
#include <random>

#include "Chromosome.hpp"

#define MINIMUM_NUMBER 0

template <class T>
class Manager {
protected:

	unsigned int population_size;
	unsigned int chromosome_size;

	unsigned int max_generation_number;

	T max_chromosome_value;
	T min_chromosome_value;

	bool use_self_adaptive;
	double mutation_rate;
	double mutation_change_rate;
	double similarity_index;

	double clonning_rate;

	double crossover_rate;

	std::vector<Chromosome<T > > population;

	// Need to have some way of ensure no duplication of solutions
	std::vector<Chromosome<T > > solutions;

	std::mt19937 rand_engine;
	std::uniform_real_distribution<> op_dist;
	std::uniform_real_distribution<> chrom_dist;

public:

	/**
	 * Create a manager for GA.
	 * @param population_size The size of population.
	 * @param chromosome_size The size of each chromosome.
	 * @param max_chromosome_value The maximum possible value for the chromosome.
	 * @param min_chromosome_value The minimum possible value for the chromosome.
	 * @param use_self_adaptive Whether to use a self adaptive approach. If this is true
	 * then the mutation rate will be updated based on the similarity of the population.
	 * @param mutation_rate The mutation rate that is used. This is the likelihood that the
	 * mutation operation is applied. If the self adaptive approach is used then this is
	 * the initial mutation rate.
	 * @param mutation_change_rate The rate by which the mutation rate will be updated.
	 * If use_self_adaptive is set to false then this parameter is ignored.
	 * @param similarity_index The threshold at which the similarity mutation rate is
	 * updated.
	 * @param crossover_rate The crossover rate, the likelihood that a chromosome
	 * has the crossover operation applied to it.
	 * @param clonning_rate The clonning rate, the likelihood that a cromosome will be
	 * cloned into the new population.
	 */
	Manager(unsigned int population_size, unsigned int chromosome_size, unsigned int max_generations_number,
			T max_chromosome_value, T min_chromosome_value, bool use_self_adaptive,
			double mutation_rate, double mutation_change_rate, double similarity_index,
			double crossover_rate, double clonning_rate) : population_size(population_size),
			chromosome_size(chromosome_size), max_generation_number(max_generation_number),
			max_chromosome_value(max_chromosome_value), min_chromosome_value(min_chromosome_value),
			use_self_adaptive(use_self_adaptive), mutation_rate(mutation_rate),
			mutation_change_rate(mutation_change_rate), similarity_index(similarity_index),
			clonning_rate(clonning_rate), crossover_rate(crossover_rate),
			population(population_size) {

		initialize();
	}

	/**
	 * Create a non self-adaptive GA manager
	 * @param population_size The size of population.
	 * @param chromosome_size The size of each chromosome.
	 * @param max_chromosome_value The maximum possible value for the chromosome.
	 * @param min_chromosome_value The minimum possible value for the chromosome.
	 * @param mutation_rate The mutation rate that is used. This is the likelihood that the
	 * mutation operation is applied. If the self adaptive approach is used then this is
	 * the initial mutation rate.
	 * @param crossover_rate The crossover rate, the likelihood that a chromosome
	 * has the crossover operation applied to it.
	 * @param clonning_rate The clonning rate, the likelihood that a cromosome will be
	 * cloned into the new population.
	 */
	Manager(unsigned int population_size, unsigned int chromosome_size, unsigned int max_generation_number,
				T max_chromosome_value, T min_chromosome_value, double mutation_rate,
				double crossover_rate, double clonning_rate) : population_size(population_size),
				chromosome_size(chromosome_size), max_generation_number(max_generation_number),
				max_chromosome_value(max_chromosome_value), min_chromosome_value(min_chromosome_value),
				use_self_adaptive(false), mutation_rate(mutation_rate), mutation_change_rate(0),
				similarity_index(0), clonning_rate(clonning_rate), crossover_rate(crossover_rate),
				population(population_size) {

		initialize();

	}

        /**
	 * Run the algorithm for the specificed number of generations
	 */
	void run(void (* fptr)(void*)) {
		for(unsigned int i = 0; i < max_generation_number; i++) {
			runGeneration(&fptr);
		}
	}

	/**
	 * Apply the fitness function to the population. Given the result of the
	 * fitness function, the next population is bread.
	 */
	void runGeneration(void (* fptr)(void*)) {

		// Fitness function would be a generic method passed as an argument that is apply to each chromosome
		fptr(population);

		// Given that threads are going to be used:
			// - Create a thread pool and attempt to assign a reduced set of chromosomes to each thread
			// - Since each chromosome is independent for the execution of the fitness function they can be 1 thread per chromosome (hypothedically)
		// Given that MPI is being used
			// - Reduce the chromosomes into smaller sets and assign them to a node
			// - Each node can then divide the subpopulation further (possibly to a per-chromosome per thread) depending on availablity. (this step is similar to the second step with threading.
			// Apply the fitness function

		// Could potentially have a second generic method that you could use to apply heuristics to a found solution.
			// eg; in N-Queens you can rotate the board in order to find more solutions.

		// Can be done concurrently with the fitness function
		if(use_self_adaptive) {
			selfAdapt();
		}

		// Main thread will wait for all children to finish executing before proceeding.
		// Construct the list of results for the fitness function in a map which maps the chromosome's index to the chromosome's fitness value. The type of the result of the fitness function can be any desired type however primitive is desired. eg:
		std::map<unsigned int, int > fitness_results;
		breed(fitness_results);
	}

	/**
	 * Prepare the population for the next generation by apply the genetic operations.
	 */
	template <typename F>
	void breed(std::map<unsigned int, F > fitness_result) {
		std::vector<Chromosome<T > > new_population;

		// Iterate through the chromosomes
		while(new_population.size() < population_size) {
			// TODO Using a specific selection (eg roulette wheel without replacement) to pick a chromosome
			// Use a random number between to identify which operation to apply (each operation gets a slice of the range)
			int selected_operation = 0;
			int selected_chromosome = getRandChromosome();
			if(selected_operation == 0) {
				// Mutation
				population[selected_chromosome].mutation(new_population);
			}
			else if(selected_operation == 1) {
				// Crossover
				// Pick another chromosome from the population that is not the already selected chromosome. (TODO can the chromosome be the same as the initally selected on?)
				int other_selected_chromosome = getRandChromosome(selected_chromosome);

				population[selected_chromosome].crossover(population[other_selected_chromosome], new_population);

			}
			else {
				// Clone
				population[selected_chromosome].clone(new_population);
			}
		}

		// Update the population to the new population
		population = new_population; // Check if this creates a shallow copy (since we aren't going to change new_population so we just want it to be deallocated at the end of the method).

	}

	/**
 	 * Apply the self-adaptive operation to determine the similarity of the chromosomes
	 * and update the mutation rate accordingly.
	 */
	void selfAdapt() {
		// Determine how similar the chromosome is to the rest of the population

		// Sequencial solution
		// Iterate through the chromosomes
			// Calculate the current chromosome with each of the others in the population

		// Based on the similarity of the population identify adjust the mutaiton rate
			//if the similarity is too high (above threshold), increase mutation rate
			//if similarity is too low (below threshold), decrease mutation rate
			//otherwise (same as threshold), do nothing
	}

	// Instead of taking a fitness function it might be better to take a function pointer and call that function for the fitness function
	// void *fitness_function(std::vector<Chromosome<T > > population);

	/*static void *fitness_function(std::vector<Chromosome<T > > population) {

		return NULL;
	}*/
private:
	void initialize() {
		// Create the random objects that will be used
		std::random_device rd;
		rand_engine = std::mt19937 (rd());
		op_dist = std::uniform_real_distribution<> (0, 100);
		chrom_dist = std::uniform_real_distribution<> (MINIMUM_NUMBER, population_size-1);
		Chromosome<T >::initialize(chromosome_size, min_chromosome_value, max_chromosome_value);
	}

	/**
         * Get a number between 0 and population.size() - 1
	 * @return A number between 0 and population.size()-1
         */
	unsigned int getRandChromosome() {
		return chrom_dist(rand_engine);
	}

	/**
	 * Get a random number between 0 and population.size()-1 that is not index
	 * @param index The only value within the range that the return cannot be.
	 * @return A number within the defined range that is not index.
	 */
	unsigned int getRandChromosome(unsigned int index) {
		unsigned int val = getRandChromosome();

		while(val == index) {
			val = getRandChromosome();
		}
		return val;
	}
};

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


<commit_before>//
// simrecomb.cpp
//
// Copyright 2012 Darren Kessner
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

#include "Population.hpp"
#include <iostream>
#include <cstring>
#include <fstream>
#include <sstream>
#include <map>
#include "boost/filesystem.hpp"
#include "boost/filesystem/fstream.hpp"

using namespace std;
using boost::shared_ptr;
namespace bfs = boost::filesystem;

struct SimulationConfig
{
    unsigned int seed;
    vector<string> geneticMapFilenames;
    vector< vector<Population::Config> > populationConfigs; // each generation is a vector<Population::Config>

    SimulationConfig() : seed(0) {}
};

ostream& operator<<(ostream& os, const SimulationConfig& simulationConfig)
{
    os << "seed " << simulationConfig.seed << endl << endl;

    os << "geneticMapFilenames " << simulationConfig.geneticMapFilenames.size() << endl;
    for (vector<string>::const_iterator it=simulationConfig.geneticMapFilenames.begin();
         it!=simulationConfig.geneticMapFilenames.end(); ++it)
        os << "geneticMapFilename " << *it << endl;
    os << endl;

    for (size_t i=0; i<simulationConfig.populationConfigs.size(); i++)
    {
        os << "generation " << i << endl;
        copy(simulationConfig.populationConfigs[i].begin(), simulationConfig.populationConfigs[i].end(),
             ostream_iterator<Population::Config>(os,"\n"));
        os << endl;
    }

    return os;
}

istream& operator>>(istream& is, SimulationConfig& simulationConfig)
{
    while (is)
    {
        // parse line by line

        string buffer;
        getline(is, buffer);
        if (!is) return is;

        vector<string> tokens;
        istringstream iss(buffer);
        copy(istream_iterator<string>(iss), istream_iterator<string>(), back_inserter(tokens));

        // switch on first token

        if (tokens.empty())
            continue;
        else if (tokens[0] == "seed" && tokens.size() == 2)
            simulationConfig.seed = atoi(tokens[1].c_str());
        else if (tokens[0] == "geneticMapFilenames")
            continue;
        else if (tokens[0] == "geneticMapFilename" && tokens.size()==2)
            simulationConfig.geneticMapFilenames.push_back(tokens[1]);
        else if (tokens[0] == "generation")
            simulationConfig.populationConfigs.push_back(vector<Population::Config>());
        else if (tokens[0] == "population")
        {
            simulationConfig.populationConfigs.back().push_back(Population::Config());
            istringstream temp(buffer);
            temp >> simulationConfig.populationConfigs.back().back();
        }
        else
            cerr << "Ignoring invalid configuration line:\n" << buffer << endl;
    }

    return is;
}

struct Config
{
    bfs::path configFilename;
    bfs::path outputDirectory;
    SimulationConfig simulationConfig;
};

void printPopulations(ostream& os, const Populations& populations, const string& label)
{
    os << "<" << label << ">\n";
    for (size_t i=0; i<populations.size(); i++)
    {
        os << "<population" << i << ">\n"
             << *populations[i]
             << "</population" << i << ">\n";
    }
    os << "</" << label << ">\n";
}

void initializeDefaultSimulationConfig(SimulationConfig& simulationConfig)
{
    const size_t chromosomePairCount_ = 3;
    const unsigned int populationSize_ = 10000;
    const double admixtureProportion_ = .8; // fraction of genes from 1st population

    for (size_t i=0; i<chromosomePairCount_; i++)
        simulationConfig.geneticMapFilenames.push_back("genetic_map_chr21_b36.txt"); // hack

    // generation 0 (ancestral populations)

    simulationConfig.populationConfigs.push_back(vector<Population::Config>(3));

    Population::Config* config = &simulationConfig.populationConfigs[0][0];
    config->size = 0;
    config->populationID = 0;

    config = &simulationConfig.populationConfigs[0][1];
    config->size = populationSize_;
    config->populationID = 1;
    config->chromosomePairCount = chromosomePairCount_;

    config = &simulationConfig.populationConfigs[0][2];
    config->size = populationSize_;
    config->populationID = 2;
    config->chromosomePairCount = chromosomePairCount_;

    // generation 1 (initial admixture)

    simulationConfig.populationConfigs.push_back(vector<Population::Config>(1));

    config = &simulationConfig.populationConfigs[1][0];
    config->size = populationSize_;
    double p = admixtureProportion_;
    config->matingDistribution.push_back(p*p, make_pair(1,1));
    config->matingDistribution.push_back(2*p*(1-p), make_pair(1,2));
    config->matingDistribution.push_back((1-p)*(1-p), make_pair(2,2));

    // subsequent generations - just recombination

    for (size_t generation=2; generation<8; generation++)
    {
        simulationConfig.populationConfigs.push_back(vector<Population::Config>(1));
        config = &simulationConfig.populationConfigs[generation][0];
        config->size = populationSize_;
        config->matingDistribution.push_back(1, make_pair(0,0));
    }
}

void initializeRecombinationMaps(const Config& config, const Random& random)
{
    Organism::recombinationPositionGenerator_ =
        shared_ptr<RecombinationPositionGenerator>(
            new RecombinationPositionGenerator_RecombinationMap(config.simulationConfig.geneticMapFilenames, random));
}

shared_ptr<Populations> createPopulations(shared_ptr<Populations> current,
                                          const vector<Population::Config>& populationConfigs,
                                          const Random& random)
{
    shared_ptr<Populations> result(new Populations);

    for (vector<Population::Config>::const_iterator it=populationConfigs.begin(); it!=populationConfigs.end(); ++it)
    {
        if (!current.get())
            result->push_back(shared_ptr<Population>(new Population(*it)));
        else
            result->push_back(shared_ptr<Population>(new Population(*it, *current, random)));
    }

    return result;
}

void simulate(const Config& config)
{
    bfs::ofstream osSimulationConfig(config.outputDirectory / "simrecomb_config.txt");
    osSimulationConfig << config.simulationConfig;
    osSimulationConfig.close();

    Random random(config.simulationConfig.seed);

    cout << "Initializing recombination maps.\n";
    initializeRecombinationMaps(config, random);

    bfs::ofstream osLog(config.outputDirectory / "log.txt");

    shared_ptr<Populations> current;
    for (size_t generation=0; generation<config.simulationConfig.populationConfigs.size(); generation++)
    {
        cout << "Generation " << generation << endl;
        shared_ptr<Populations> next =
            createPopulations(current, config.simulationConfig.populationConfigs[generation], random);
        current = next;
        ostringstream label;
        label << "gen" << generation;
        //printPopulations(osLog, *current, label.str());
        osLog << generation << endl;
    }

    osLog.close();

    // output the last generation

    for (size_t i=0; i<current->size(); ++i)
    {
        ostringstream filename;
        filename << "pop" << i << ".txt";
        bfs::ofstream os_pop(config.outputDirectory / filename.str());
        os_pop << *(*current)[i];
    }
}

Config parseCommandLine(int argc, char* argv[])
{
    if (argc==2 && !strcmp(argv[1],"default"))
    {
        SimulationConfig temp;
        initializeDefaultSimulationConfig(temp);
        cout << temp;
        exit(0);
    }

    if (argc != 3)
    {
        cout << "Usage: simrecomb <config_filename> <outputdir>\n";
        cout << "   or: simrecomb default (prints default config to stdout)\n";
        cout << "\n";
        cout << "Darren Kessner\n";
        cout << "John Novembre Lab, UCLA\n";
        throw runtime_error("");
    }

    Config config;
    config.configFilename = argv[1];
    config.outputDirectory = argv[2];

    if (!bfs::exists(config.configFilename))
    {
        ostringstream oss;
        oss << "Config file not found: " << config.configFilename;
        throw runtime_error(oss.str());
    }

    if (bfs::exists(config.outputDirectory))
    {
        ostringstream oss;
        oss << "File/directory already exists: " << config.outputDirectory;
        throw runtime_error(oss.str());
    }

    cout << "Reading configuration file " << config.configFilename << endl;
    bfs::ifstream is(config.configFilename);
    is >> config.simulationConfig;
    is.close();

    bfs::create_directories(config.outputDirectory);

    return config;
}

int main(int argc, char* argv[])
{
    try
    {
        Config config = parseCommandLine(argc, argv);
        simulate(config);
        return 0;
    }
    catch(exception& e)
    {
        cerr << e.what() << endl;
        return 1;
    }
    catch(...)
    {
        cerr << "Caught unknown exception.\n";
        return 1;
    }
}

<commit_msg>added subfunctions for testing binary read/write of populations<commit_after>//
// simrecomb.cpp
//
// Copyright 2012 Darren Kessner
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

#include "Population.hpp"
#include <iostream>
#include <cstring>
#include <fstream>
#include <sstream>
#include <map>
#include "boost/filesystem.hpp"
#include "boost/filesystem/fstream.hpp"

using namespace std;
using boost::shared_ptr;
namespace bfs = boost::filesystem;

struct SimulationConfig
{
    unsigned int seed;
    vector<string> geneticMapFilenames;
    vector< vector<Population::Config> > populationConfigs; // each generation is a vector<Population::Config>

    SimulationConfig() : seed(0) {}
};

ostream& operator<<(ostream& os, const SimulationConfig& simulationConfig)
{
    os << "seed " << simulationConfig.seed << endl << endl;

    os << "geneticMapFilenames " << simulationConfig.geneticMapFilenames.size() << endl;
    for (vector<string>::const_iterator it=simulationConfig.geneticMapFilenames.begin();
         it!=simulationConfig.geneticMapFilenames.end(); ++it)
        os << "geneticMapFilename " << *it << endl;
    os << endl;

    for (size_t i=0; i<simulationConfig.populationConfigs.size(); i++)
    {
        os << "generation " << i << endl;
        copy(simulationConfig.populationConfigs[i].begin(), simulationConfig.populationConfigs[i].end(),
             ostream_iterator<Population::Config>(os,"\n"));
        os << endl;
    }

    return os;
}

istream& operator>>(istream& is, SimulationConfig& simulationConfig)
{
    while (is)
    {
        // parse line by line

        string buffer;
        getline(is, buffer);
        if (!is) return is;

        vector<string> tokens;
        istringstream iss(buffer);
        copy(istream_iterator<string>(iss), istream_iterator<string>(), back_inserter(tokens));

        // switch on first token

        if (tokens.empty())
            continue;
        else if (tokens[0] == "seed" && tokens.size() == 2)
            simulationConfig.seed = atoi(tokens[1].c_str());
        else if (tokens[0] == "geneticMapFilenames")
            continue;
        else if (tokens[0] == "geneticMapFilename" && tokens.size()==2)
            simulationConfig.geneticMapFilenames.push_back(tokens[1]);
        else if (tokens[0] == "generation")
            simulationConfig.populationConfigs.push_back(vector<Population::Config>());
        else if (tokens[0] == "population")
        {
            simulationConfig.populationConfigs.back().push_back(Population::Config());
            istringstream temp(buffer);
            temp >> simulationConfig.populationConfigs.back().back();
        }
        else
            cerr << "Ignoring invalid configuration line:\n" << buffer << endl;
    }

    return is;
}

void printPopulations(ostream& os, const Populations& populations, const string& label)
{
    os << "<" << label << ">\n";
    for (size_t i=0; i<populations.size(); i++)
    {
        os << "<population" << i << ">\n"
             << *populations[i]
             << "</population" << i << ">\n";
    }
    os << "</" << label << ">\n";
}

void initializeExampleSimulationConfig(SimulationConfig& simulationConfig)
{
    const size_t chromosomePairCount_ = 3;
    const unsigned int populationSize_ = 10000;
    const double admixtureProportion_ = .8; // fraction of genes from 1st population

    for (size_t i=0; i<chromosomePairCount_; i++)
        simulationConfig.geneticMapFilenames.push_back("genetic_map_chr21_b36.txt"); // hack

    // generation 0 (ancestral populations)

    simulationConfig.populationConfigs.push_back(vector<Population::Config>(3));

    Population::Config* config = &simulationConfig.populationConfigs[0][0];
    config->size = 0;
    config->populationID = 0;

    config = &simulationConfig.populationConfigs[0][1];
    config->size = populationSize_;
    config->populationID = 1;
    config->chromosomePairCount = chromosomePairCount_;

    config = &simulationConfig.populationConfigs[0][2];
    config->size = populationSize_;
    config->populationID = 2;
    config->chromosomePairCount = chromosomePairCount_;

    // generation 1 (initial admixture)

    simulationConfig.populationConfigs.push_back(vector<Population::Config>(1));

    config = &simulationConfig.populationConfigs[1][0];
    config->size = populationSize_;
    double p = admixtureProportion_;
    config->matingDistribution.push_back(p*p, make_pair(1,1));
    config->matingDistribution.push_back(2*p*(1-p), make_pair(1,2));
    config->matingDistribution.push_back((1-p)*(1-p), make_pair(2,2));

    // subsequent generations - just recombination

    for (size_t generation=2; generation<8; generation++)
    {
        simulationConfig.populationConfigs.push_back(vector<Population::Config>(1));
        config = &simulationConfig.populationConfigs[generation][0];
        config->size = populationSize_;
        config->matingDistribution.push_back(1, make_pair(0,0));
    }
}

void initializeRecombinationMaps(const SimulationConfig& simulationConfig, const Random& random)
{
    Organism::recombinationPositionGenerator_ =
        shared_ptr<RecombinationPositionGenerator>(
            new RecombinationPositionGenerator_RecombinationMap(simulationConfig.geneticMapFilenames, random));
}

shared_ptr<Populations> createPopulations(shared_ptr<Populations> current,
                                          const vector<Population::Config>& populationConfigs,
                                          const Random& random)
{
    shared_ptr<Populations> result(new Populations);

    for (vector<Population::Config>::const_iterator it=populationConfigs.begin(); it!=populationConfigs.end(); ++it)
    {
        if (!current.get())
            result->push_back(shared_ptr<Population>(new Population(*it)));
        else
            result->push_back(shared_ptr<Population>(new Population(*it, *current, random)));
    }

    return result;
}

void simulate(const SimulationConfig& simulationConfig, bfs::path outputDirectory)
{
    bfs::ofstream osSimulationConfig(outputDirectory / "simrecomb_config.txt");
    osSimulationConfig << simulationConfig;
    osSimulationConfig.close();

    Random random(simulationConfig.seed);

    cout << "Initializing recombination maps.\n";
    initializeRecombinationMaps(simulationConfig, random);

    bfs::ofstream osLog(outputDirectory / "log.txt");

    shared_ptr<Populations> current;
    for (size_t generation=0; generation<simulationConfig.populationConfigs.size(); generation++)
    {
        cout << "Generation " << generation << endl;
        shared_ptr<Populations> next =
            createPopulations(current, simulationConfig.populationConfigs[generation], random);
        current = next;
        ostringstream label;
        label << "gen" << generation;
        //printPopulations(osLog, *current, label.str());
        osLog << generation << endl;
    }

    osLog.close();

    // output the last generation

    for (size_t i=0; i<current->size(); ++i)
    {
        ostringstream filename;
        filename << "pop" << i << ".txt";
        bfs::ofstream os_pop(outputDirectory / filename.str());
        os_pop << *(*current)[i];
    }
}

int main(int argc, char* argv[])
{
    try
    {
        ostringstream usage;
        usage << "Usage: simrecomb <subfunction> [args]\n";
        usage << endl;
        usage << "Print example config file to stdout:\n";
        usage << "       simrecomb example\n";
        usage << endl;
        usage << "Run simulation:\n";
        usage << "       simrecomb sim <config_filename> <outputdir>\n";
        usage << endl;
        usage << "Darren Kessner\n";
        usage << "John Novembre Lab, UCLA\n";

        string subfunction = argc>1 ? argv[1] : "";

        if (subfunction == "sim")
        {
            if (argc < 4) throw runtime_error(usage.str().c_str());

            string configFilename = argv[2];
            string outputDirectory = argv[3];

            if (!bfs::exists(configFilename))
                throw runtime_error(("[simrecomb] Config file not found: " + configFilename).c_str());

            if (bfs::exists(outputDirectory))
                throw runtime_error(("[simrecomb] Directory exists: " + outputDirectory).c_str());

            cout << "Reading configuration file " << configFilename << endl;
            bfs::ifstream is(configFilename);
            SimulationConfig simulationConfig;
            is >> simulationConfig;
            is.close();

            bfs::create_directories(outputDirectory);

            simulate(simulationConfig, outputDirectory);
        }
        else if (subfunction == "example")
        {
            SimulationConfig temp;
            initializeExampleSimulationConfig(temp);
            cout << temp;
        }
        else if (subfunction == "txt2pop")
        {
            if (argc < 4) throw runtime_error(usage.str().c_str());
            string filename_in = argv[2];
            string filename_out = argv[3];

            cout << "reading " << filename_in << endl << flush;
            ifstream is(filename_in.c_str());
            if (!is) throw runtime_error(("[simrecomb] Unable to open file " + filename_in).c_str());
            Population p;
            is >> p;

            cout << "writing " << filename_out << endl << flush;
            ofstream os(filename_out.c_str(), ios::binary);
            p.write(os);
            os.close();
        }
        else if (subfunction == "pop2txt")
        {
            if (argc < 4) throw runtime_error(usage.str().c_str());
            string filename_in = argv[2];
            string filename_out = argv[3];

            cout << "reading " << filename_in << endl << flush;
            ifstream is(filename_in.c_str(), ios::binary);
            if (!is) throw runtime_error(("[simrecomb] Unable to open file " + filename_in).c_str());
            Population p;
            p.read(is);

            cout << "writing " << filename_out << endl << flush;
            ofstream os(filename_out.c_str());
            os << p;
            os.close();
        }
        else
        {
            throw runtime_error(usage.str().c_str());
        }

        return 0;
    }
    catch(exception& e)
    {
        cerr << e.what() << endl;
        return 1;
    }
    catch(...)
    {
        cerr << "Caught unknown exception.\n";
        return 1;
    }
}

<|endoftext|>


<commit_before><commit_msg>sal_Bool->bool<commit_after><|endoftext|>


<commit_before>// Copyright 2014 Alessio Sclocco <a.sclocco@vu.nl>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <string>
#include <x86intrin.h>

#include <utils.hpp>
#include <Observation.hpp>

#ifndef SNR_HPP
#define SNR_HPP

namespace PulsarSearch {

template< typename T > using snrFunc = void (*)(const AstroData::Observation< T > &, const float *, float *);

// Sequential SNR
template< typename T > void snrFoldedTS(const AstroData::Observation< T > & observation, const std::vector< T > & foldedTS, std::vector< T > & snrs);
// OpenCL SNR
template< typename T > std::string * getSNROpenCL(const unsigned int nrDMsPerBlock, const unsigned int nrPeriodsPerBlock, const unsigned int nrDMsPerThread, const unsigned int nrPeriodsPerThread, std::string & dataType, const AstroData::Observation< T > & observation);
// SIMD SNR
std::string * getSNRSIMD(const unsigned int nrDMsPerThread, const unsigned int nrPeriodsPerThread, bool phi = false);

// Implementations
template< typename T > void snrFoldedTS(AstroData::Observation< T > & observation, const std::vector< T > & foldedTS, std::vector< T > & snrs) {
	for ( unsigned int period = 0; period < observation.getNrPeriods(); period++ ) {
		for ( unsigned int dm = 0; dm < observation.getNrDMs(); dm++ ) {
			T max = 0;
			float average = 0.0f;
			float rms = 0.0f;

			for ( unsigned int bin = 0; bin < observation.getNrBins(); bin++ ) {
				T value = foldedTS[(bin * observation.getNrPeriods() * observation.getNrPaddedDMs()) + (period * observation.getNrPaddedDMs()) + dm];

				average += value;
				rms += (value * value);

				if ( value > max ) {
					max = value;
				}
			}
			average /= observation.getNrBins();
			rms = sqrt(rms / observation.getNrBins());

			snrs[(period * observation.getNrPaddedDMs()) + dm] = (max - average) / rms;
		}
	}
}

template< typename T > std::string * getSNROpenCL(const unsigned int nrDMsPerBlock, const unsigned int nrPeriodsPerBlock, const unsigned int nrDMsPerThread, const unsigned int nrPeriodsPerThread, std::string & dataType, const AstroData::Observation< T > & observation) {
  std::string * code = new std::string();

  // Begin kernel's template
  std::string nrPaddedDMs_s = isa::utils::toString< unsigned int >(observation.getNrPaddedDMs());
  std::string nrBinsInverse_s = isa::utils::toString< float >(1.0f / observation.getNrBins());

  *code = "__kernel void snr(__global const " + dataType + " * const restrict foldedData, __global " + dataType + " * const restrict snrs) {\n"
    "<%DEF_DM%>"
    "<%DEF_PERIOD%>"
    + dataType + " globalItem = 0;\n"
    + dataType + " average = 0;\n"
    + dataType + " rms = 0;\n"
    + dataType + " max = 0;\n"
    "\n"
    "<%COMPUTE%>"
    "}\n";
    std::string defDMsTemplate = "const unsigned int dm<%DM_NUM%> = (get_group_id(0) * " + isa::utils::toString< unsigned int >(nrDMsPerBlock * nrDMsPerThread) + ") + get_local_id(0) + <%DM_NUM%>;\n";
  std::string defPeriodsTemplate = "const unsigned int period<%PERIOD_NUM%> = (get_group_id(1) * " + isa::utils::toString< unsigned int >(nrPeriodsPerBlock * nrPeriodsPerThread) + ") + get_local_id(1) + <%PERIOD_NUM%>;\n";
  std::string computeTemplate = "average = 0;\n"
    " rms = 0;\n"
    " max = 0;\n"
    "for ( unsigned int bin = 0; bin < " + isa::utils::toString< unsigned int >(observation.getNrBins()) + "; bin++ ) {\n"
    "globalItem = foldedData[(bin * " + isa::utils::toString< unsigned int >(observation.getNrPeriods()) + " * " + nrPaddedDMs_s + ") + ((period + <%PERIOD_NUM%>) * " + nrPaddedDMs_s + ") + dm + <%DM_NUM%>];\n"
    "average += globalItem;\n"
    "rms += (globalItem * globalItem);\n"
    "max = fmax(max, globalItem);\n"
    "}\n"
    "average *= " + nrBinsInverse_s + "f;\n"
    "rms *= " + nrBinsInverse_s + "f;\n"
    "snrs[((period + <%PERIOD_NUM%>) * " + nrPaddedDMs_s + ") + dm + <%DM_NUM%>] = (max - average) / native_sqrt(rms);\n";
  // End kernel's template

  std::string * defDM_s = new std::string();
  std::string * defPeriod_s = new std::string();
  std::string * compute_s = new std::string();

  for ( unsigned int dm = 0; dm < nrDMsPerThread; dm++ ) {
    std::string dm_s = isa::utils::toString< unsigned int >(dm);
    std::string * temp_s = 0;

    temp_s = isa::utils::replace(&defDMsTemplate, "<%DM_NUM%>", dm_s);
    defDM_s->append(*temp_s);
    delete temp_s;
  }
  for ( unsigned int period = 0; period < nrPeriodsPerThread; period++ ) {
    std::string period_s = isa::utils::toString< unsigned int >(period);
    std::string * temp_s = 0;

    temp_s = isa::utils::replace(&defPeriodsTemplate, "<%PERIOD_NUM%>", period_s);
    defPeriod_s->append(*temp_s);
    delete temp_s;

    for ( unsigned int dm = 0; dm < nrDMsPerThread; dm++ ) {
      std::string dm_s = isa::utils::toString< unsigned int >(dm);

      temp_s = isa::utils::replace(&computeTemplate, "<%PERIOD_NUM%>", period_s);
      temp_s = isa::utils::replace(temp_s, "<%DM_NUM%>", dm_s, true);
      compute_s->append(*temp_s);
      delete temp_s;
    }
  }

  code = isa::utils::replace(code, "<%DEF_DM%>", *defDM_s, true);
  code = isa::utils::replace(code, "<%DEF_PERIOD%>", *defPeriod_s, true);
  code = isa::utils::replace(code, "<%COMPUTE%>", *compute_s, true);

  return code;
}

std::string * getSNRSIMD(const unsigned int nrDMsPerThread, const unsigned int nrPeriodsPerThread, bool phi) {
  std::string * code = new std::string();
  std::string * computeTemplate = new string();

  // Begin kernel's template
  if ( !phi ) {
    *code = "namespace PulsarSearch {\n"
      "template< typename T > void snrAVX" + isa::utils::toString(nrDMsPerThread) + "x" + isa::utils::toString(nrPeriodsPerThread) + "(const AstroData::Observation< T > & observation, const float * const __restrict__ foldedData, float * const __restrict__ snrs) {\n"
      "{\n"
      "__m256 max = _mm256_setzero_ps();\n"
      "__m256 average = _mm256_setzero_ps();\n"
      "__m256 rms = _mm256_setzero_ps();\n"
      "#pragma omp parallel for schedule(static)\n"
      "for ( unsigned int period = 0; period < observation.getNrPeriods(); period += " + isa::utils::toString(nrPeriodsPerThread) + ") {\n"
      "#pragma omp parallel for schedule(static)\n"
      "for ( unsigned int dm = 0; dm < observation.getNrDMs(); dm += " + isa::utils::toString(nrPeriodsPerThread) + " * 8) {\n"
      "<%COMPUTE%>"
      "}\n"
      "}\n"
      "}\n"
      "}\n"
      "}\n";
    *computeTemplate = "max = _mm256_setzero_ps();\n"
      "average = _mm256_setzero_ps();\n"
      "rms = _mm256_setzero_ps();\n"
      "\n"
      "for ( unsigned int bin = 0; bin < observation.getNrBins(); bin++ ) {\n"
      "__m256 value = _mm256_load_ps(&(foldedData[(bin * observation.getNrPeriods() * observation.getNrPaddedDMs()) + ((period + <%PERIOD_NUM%>) * observation.getNrPaddedDMs()) + dm + <%DM_NUM%>]));\n"
      "\n"
      "average = _mm256_add_ps(average, value);\n"
      "rms = _mm256_add_ps(rms, _mm256_mul_ps(value, value));\n"
      "max = _mm256_max_ps(max, value);\n"
      "}\n"
      "average = _mm256_div_ps(average, _mm256_set1_ps(observation.getNrBins()));\n"
      "rms = _mm256_sqrt_ps(_mm256_div_ps(rms, _mm256_set1_ps(observation.getNrBins())));\n"
      "_mm256_store_ps(&(snrs[((period + <%PERIOD_NUM%>) * " + nrPaddedDMs_s + ") + dm + <%DM_NUM%>]),_mm256_div_ps(_mm256_sub_ps(max, average), rms));\n";
  } else {
    *code = "namespace PulsarSearch {\n"
      "template< typename T > void snrPhi" + isa::utils::toString(nrDMsPerThread) + "x" + isa::utils::toString(nrPeriodsPerThread) + "(const AstroData::Observation< T > & observation, const float * const __restrict__ foldedData, float * const __restrict__ snrs) {\n"
      "{\n"
      "__m512 max = _mm512_setzero_ps();\n"
      "__m512 average = _mm512_setzero_ps();\n"
      "__m512 rms = _mm512_setzero_ps();\n"
      "#pragma omp parallel for schedule(static)\n"
      "for ( unsigned int period = 0; period < observation.getNrPeriods(); period += " + isa::utils::toString(nrPeriodsPerThread) + ") {\n"
      "#pragma omp parallel for schedule(static)\n"
      "for ( unsigned int dm = 0; dm < observation.getNrDMs(); dm += " + isa::utils::toString(nrPeriodsPerThread) + " * 16) {\n"
      "<%COMPUTE%>"
      "}\n"
      "}\n"
      "}\n"
      "}\n"
      "}\n";
    *computeTemplate = "max = _mm512_setzero_ps();\n"
      "average = _mm512_setzero_ps();\n"
      "rms = _mm512_setzero_ps();\n"
      "\n"
      "for ( unsigned int bin = 0; bin < observation.getNrBins(); bin++ ) {\n"
      "__m512 value = _mm512_load_ps(&(foldedData[(bin * observation.getNrPeriods() * observation.getNrPaddedDMs()) + ((period + <%PERIOD_NUM%>) * observation.getNrPaddedDMs()) + dm + <%DM_NUM%>]));\n"
      "\n"
      "average = _mm512_add_ps(average, value);\n"
      "rms = _mm512_add_ps(rms, _mm512_mul_ps(value, value));\n"
      "max = _mm512_max_ps(max, value);\n"
      "}\n"
      "average = _mm512_div_ps(average, _mm512_set1_ps(observation.getNrBins()));\n"
      "rms = _mm512_sqrt_ps(_mm512_div_ps(rms, _mm512_set1_ps(observation.getNrBins())));\n"
      "_mm512_store_ps(&(snrs[((period + <%PERIOD_NUM%>) * " + nrPaddedDMs_s + ") + dm + <%DM_NUM%>]),_mm512_div_ps(_mm512_sub_ps(max, average), rms));\n";
  }
  // End kernel's template

  std::string * compute_s = new std::string();

  for ( unsigned int period = 0; period < nrPeriodsPerThread; period++ ) {
    std::string period_s = isa::utils::toString< unsigned int >(period);

    for ( unsigned int dm = 0; dm < nrDMsPerThread; dm++ ) {
      std::string dm_s = isa::utils::toString< unsigned int >(dm);
      std::string * temp_s = 0;

      temp_s = isa::utils::replace(computeTemplate, "<%PERIOD_NUM%>", period_s);
      temp_s = isa::utils::replace(temp_s, "<%DM_NUM%>", dm_s, true);
      compute_s->append(*temp_s);
      delete temp_s;
    }
  }
  code = isa::utils::replace(code, "<%COMPUTE%>", *compute_s, true);
  delete compute_s;

  delete computeTemplate;
  return code;
}

} // PulsarSearch

#endif // SNR_HPP

<commit_msg>Fixing a bug in SIMD code generation.<commit_after>// Copyright 2014 Alessio Sclocco <a.sclocco@vu.nl>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <string>
#include <x86intrin.h>

#include <utils.hpp>
#include <Observation.hpp>

#ifndef SNR_HPP
#define SNR_HPP

namespace PulsarSearch {

template< typename T > using snrFunc = void (*)(const AstroData::Observation< T > &, const float *, float *);

// Sequential SNR
template< typename T > void snrFoldedTS(const AstroData::Observation< T > & observation, const std::vector< T > & foldedTS, std::vector< T > & snrs);
// OpenCL SNR
template< typename T > std::string * getSNROpenCL(const unsigned int nrDMsPerBlock, const unsigned int nrPeriodsPerBlock, const unsigned int nrDMsPerThread, const unsigned int nrPeriodsPerThread, std::string & dataType, const AstroData::Observation< T > & observation);
// SIMD SNR
std::string * getSNRSIMD(const unsigned int nrDMsPerThread, const unsigned int nrPeriodsPerThread, bool phi = false);

// Implementations
template< typename T > void snrFoldedTS(AstroData::Observation< T > & observation, const std::vector< T > & foldedTS, std::vector< T > & snrs) {
	for ( unsigned int period = 0; period < observation.getNrPeriods(); period++ ) {
		for ( unsigned int dm = 0; dm < observation.getNrDMs(); dm++ ) {
			T max = 0;
			float average = 0.0f;
			float rms = 0.0f;

			for ( unsigned int bin = 0; bin < observation.getNrBins(); bin++ ) {
				T value = foldedTS[(bin * observation.getNrPeriods() * observation.getNrPaddedDMs()) + (period * observation.getNrPaddedDMs()) + dm];

				average += value;
				rms += (value * value);

				if ( value > max ) {
					max = value;
				}
			}
			average /= observation.getNrBins();
			rms = sqrt(rms / observation.getNrBins());

			snrs[(period * observation.getNrPaddedDMs()) + dm] = (max - average) / rms;
		}
	}
}

template< typename T > std::string * getSNROpenCL(const unsigned int nrDMsPerBlock, const unsigned int nrPeriodsPerBlock, const unsigned int nrDMsPerThread, const unsigned int nrPeriodsPerThread, std::string & dataType, const AstroData::Observation< T > & observation) {
  std::string * code = new std::string();

  // Begin kernel's template
  std::string nrPaddedDMs_s = isa::utils::toString< unsigned int >(observation.getNrPaddedDMs());
  std::string nrBinsInverse_s = isa::utils::toString< float >(1.0f / observation.getNrBins());

  *code = "__kernel void snr(__global const " + dataType + " * const restrict foldedData, __global " + dataType + " * const restrict snrs) {\n"
    "<%DEF_DM%>"
    "<%DEF_PERIOD%>"
    + dataType + " globalItem = 0;\n"
    + dataType + " average = 0;\n"
    + dataType + " rms = 0;\n"
    + dataType + " max = 0;\n"
    "\n"
    "<%COMPUTE%>"
    "}\n";
    std::string defDMsTemplate = "const unsigned int dm<%DM_NUM%> = (get_group_id(0) * " + isa::utils::toString< unsigned int >(nrDMsPerBlock * nrDMsPerThread) + ") + get_local_id(0) + <%DM_NUM%>;\n";
  std::string defPeriodsTemplate = "const unsigned int period<%PERIOD_NUM%> = (get_group_id(1) * " + isa::utils::toString< unsigned int >(nrPeriodsPerBlock * nrPeriodsPerThread) + ") + get_local_id(1) + <%PERIOD_NUM%>;\n";
  std::string computeTemplate = "average = 0;\n"
    " rms = 0;\n"
    " max = 0;\n"
    "for ( unsigned int bin = 0; bin < " + isa::utils::toString< unsigned int >(observation.getNrBins()) + "; bin++ ) {\n"
    "globalItem = foldedData[(bin * " + isa::utils::toString< unsigned int >(observation.getNrPeriods()) + " * " + nrPaddedDMs_s + ") + ((period + <%PERIOD_NUM%>) * " + nrPaddedDMs_s + ") + dm + <%DM_NUM%>];\n"
    "average += globalItem;\n"
    "rms += (globalItem * globalItem);\n"
    "max = fmax(max, globalItem);\n"
    "}\n"
    "average *= " + nrBinsInverse_s + "f;\n"
    "rms *= " + nrBinsInverse_s + "f;\n"
    "snrs[((period + <%PERIOD_NUM%>) * " + nrPaddedDMs_s + ") + dm + <%DM_NUM%>] = (max - average) / native_sqrt(rms);\n";
  // End kernel's template

  std::string * defDM_s = new std::string();
  std::string * defPeriod_s = new std::string();
  std::string * compute_s = new std::string();

  for ( unsigned int dm = 0; dm < nrDMsPerThread; dm++ ) {
    std::string dm_s = isa::utils::toString< unsigned int >(dm);
    std::string * temp_s = 0;

    temp_s = isa::utils::replace(&defDMsTemplate, "<%DM_NUM%>", dm_s);
    defDM_s->append(*temp_s);
    delete temp_s;
  }
  for ( unsigned int period = 0; period < nrPeriodsPerThread; period++ ) {
    std::string period_s = isa::utils::toString< unsigned int >(period);
    std::string * temp_s = 0;

    temp_s = isa::utils::replace(&defPeriodsTemplate, "<%PERIOD_NUM%>", period_s);
    defPeriod_s->append(*temp_s);
    delete temp_s;

    for ( unsigned int dm = 0; dm < nrDMsPerThread; dm++ ) {
      std::string dm_s = isa::utils::toString< unsigned int >(dm);

      temp_s = isa::utils::replace(&computeTemplate, "<%PERIOD_NUM%>", period_s);
      temp_s = isa::utils::replace(temp_s, "<%DM_NUM%>", dm_s, true);
      compute_s->append(*temp_s);
      delete temp_s;
    }
  }

  code = isa::utils::replace(code, "<%DEF_DM%>", *defDM_s, true);
  code = isa::utils::replace(code, "<%DEF_PERIOD%>", *defPeriod_s, true);
  code = isa::utils::replace(code, "<%COMPUTE%>", *compute_s, true);

  return code;
}

std::string * getSNRSIMD(const unsigned int nrDMsPerThread, const unsigned int nrPeriodsPerThread, bool phi) {
  std::string * code = new std::string();
  std::string * computeTemplate = new string();

  // Begin kernel's template
  if ( !phi ) {
    *code = "namespace PulsarSearch {\n"
      "template< typename T > void snrAVX" + isa::utils::toString(nrDMsPerThread) + "x" + isa::utils::toString(nrPeriodsPerThread) + "(const AstroData::Observation< T > & observation, const float * const __restrict__ foldedData, float * const __restrict__ snrs) {\n"
      "{\n"
      "__m256 max = _mm256_setzero_ps();\n"
      "__m256 average = _mm256_setzero_ps();\n"
      "__m256 rms = _mm256_setzero_ps();\n"
      "#pragma omp parallel for schedule(static)\n"
      "for ( unsigned int period = 0; period < observation.getNrPeriods(); period += " + isa::utils::toString(nrPeriodsPerThread) + ") {\n"
      "#pragma omp parallel for schedule(static)\n"
      "for ( unsigned int dm = 0; dm < observation.getNrDMs(); dm += " + isa::utils::toString(nrPeriodsPerThread) + " * 8) {\n"
      "<%COMPUTE%>"
      "}\n"
      "}\n"
      "}\n"
      "}\n"
      "}\n";
    *computeTemplate = "max = _mm256_setzero_ps();\n"
      "average = _mm256_setzero_ps();\n"
      "rms = _mm256_setzero_ps();\n"
      "\n"
      "for ( unsigned int bin = 0; bin < observation.getNrBins(); bin++ ) {\n"
      "__m256 value = _mm256_load_ps(&(foldedData[(bin * observation.getNrPeriods() * observation.getNrPaddedDMs()) + ((period + <%PERIOD_NUM%>) * observation.getNrPaddedDMs()) + dm + <%DM_NUM%>]));\n"
      "\n"
      "average = _mm256_add_ps(average, value);\n"
      "rms = _mm256_add_ps(rms, _mm256_mul_ps(value, value));\n"
      "max = _mm256_max_ps(max, value);\n"
      "}\n"
      "average = _mm256_div_ps(average, _mm256_set1_ps(observation.getNrBins()));\n"
      "rms = _mm256_sqrt_ps(_mm256_div_ps(rms, _mm256_set1_ps(observation.getNrBins())));\n"
      "_mm256_store_ps(&(snrs[((period + <%PERIOD_NUM%>) * observation.getNrPaddedDMs()) + dm + <%DM_NUM%>]),_mm256_div_ps(_mm256_sub_ps(max, average), rms));\n";
  } else {
    *code = "namespace PulsarSearch {\n"
      "template< typename T > void snrPhi" + isa::utils::toString(nrDMsPerThread) + "x" + isa::utils::toString(nrPeriodsPerThread) + "(const AstroData::Observation< T > & observation, const float * const __restrict__ foldedData, float * const __restrict__ snrs) {\n"
      "{\n"
      "__m512 max = _mm512_setzero_ps();\n"
      "__m512 average = _mm512_setzero_ps();\n"
      "__m512 rms = _mm512_setzero_ps();\n"
      "#pragma omp parallel for schedule(static)\n"
      "for ( unsigned int period = 0; period < observation.getNrPeriods(); period += " + isa::utils::toString(nrPeriodsPerThread) + ") {\n"
      "#pragma omp parallel for schedule(static)\n"
      "for ( unsigned int dm = 0; dm < observation.getNrDMs(); dm += " + isa::utils::toString(nrPeriodsPerThread) + " * 16) {\n"
      "<%COMPUTE%>"
      "}\n"
      "}\n"
      "}\n"
      "}\n"
      "}\n";
    *computeTemplate = "max = _mm512_setzero_ps();\n"
      "average = _mm512_setzero_ps();\n"
      "rms = _mm512_setzero_ps();\n"
      "\n"
      "for ( unsigned int bin = 0; bin < observation.getNrBins(); bin++ ) {\n"
      "__m512 value = _mm512_load_ps(&(foldedData[(bin * observation.getNrPeriods() * observation.getNrPaddedDMs()) + ((period + <%PERIOD_NUM%>) * observation.getNrPaddedDMs()) + dm + <%DM_NUM%>]));\n"
      "\n"
      "average = _mm512_add_ps(average, value);\n"
      "rms = _mm512_add_ps(rms, _mm512_mul_ps(value, value));\n"
      "max = _mm512_max_ps(max, value);\n"
      "}\n"
      "average = _mm512_div_ps(average, _mm512_set1_ps(observation.getNrBins()));\n"
      "rms = _mm512_sqrt_ps(_mm512_div_ps(rms, _mm512_set1_ps(observation.getNrBins())));\n"
      "_mm512_store_ps(&(snrs[((period + <%PERIOD_NUM%>) * observation.getNrPaddedDMs()) + dm + <%DM_NUM%>]),_mm512_div_ps(_mm512_sub_ps(max, average), rms));\n";
  }
  // End kernel's template

  std::string * compute_s = new std::string();

  for ( unsigned int period = 0; period < nrPeriodsPerThread; period++ ) {
    std::string period_s = isa::utils::toString< unsigned int >(period);

    for ( unsigned int dm = 0; dm < nrDMsPerThread; dm++ ) {
      std::string dm_s = isa::utils::toString< unsigned int >(dm);
      std::string * temp_s = 0;

      temp_s = isa::utils::replace(computeTemplate, "<%PERIOD_NUM%>", period_s);
      temp_s = isa::utils::replace(temp_s, "<%DM_NUM%>", dm_s, true);
      compute_s->append(*temp_s);
      delete temp_s;
    }
  }
  code = isa::utils::replace(code, "<%COMPUTE%>", *compute_s, true);
  delete compute_s;

  delete computeTemplate;
  return code;
}

} // PulsarSearch

#endif // SNR_HPP

<|endoftext|>