<commit_before>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      2008-05-30
  Version:   2.2.0

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "otbSIXSTraits.h"

#include "otb_6S.h"
#include "main_6s.h"
#include "otbMacro.h"

#include <iomanip>

namespace otb
{

void
SIXSTraits::ComputeAtmosphericParameters(
  const double SolarZenithalAngle,                                        /** The Solar zenithal angle */
  const double SolarAzimutalAngle,                                        /** The Solar azimutal angle */
  const double ViewingZenithalAngle,                                      /** The Viewing zenithal angle */
  const double ViewingAzimutalAngle,                                      /** The Viewing azimutal angle */
  const unsigned int Month,                                               /** The Month */
  const unsigned int Day,                                                 /** The Day (in the month) */
  const double AtmosphericPressure,                                       /** The Atmospheric pressure */
  const double WaterVaporAmount,                                          /** The Water vapor amount (Total water vapor content over vertical atmospheric column) */
  const double OzoneAmount,                                               /** The Ozone amount (Stratospheric ozone layer content) */
  const AerosolModelType&      AerosolModel,                              /** The Aerosol model */
  const double AerosolOptical,                                            /** The Aerosol optical (radiative impact of aerosol for the reference wavelength 550-nm) */
  WavelengthSpectralType* WavelengthSpectralBand,                 /** Wavelength for the spectral band definition */
  /** Note : The Max wavelength spectral band value must be updated ! */
  double&                AtmosphericReflectance,                  /** Atmospheric reflectance */
  double&                AtmosphericSphericalAlbedo,              /** atmospheric spherical albedo */
  double&                TotalGaseousTransmission,                /** Total gaseous transmission */
  double&                DownwardTransmittance,                   /** downward transmittance */
  double&                UpwardTransmittance,                     /** upward transmittance */
  double&                UpwardDiffuseTransmittance,              /** upward diffuse transmittance */
  double&                UpwardDirectTransmittance,               /** Upward direct transmittance */
  double&                UpwardDiffuseTransmittanceForRayleigh,   /** upward diffuse transmittance for rayleigh */
  double&                UpwardDiffuseTransmittanceForAerosol     /** supward diffuse transmittance for aerosols */
  )
{
// geometrical conditions
  otb_6s_doublereal asol(static_cast<otb_6s_doublereal>(SolarZenithalAngle));
  otb_6s_doublereal phi0(static_cast<otb_6s_doublereal>(SolarAzimutalAngle));
  otb_6s_doublereal avis(static_cast<otb_6s_doublereal>(ViewingZenithalAngle));
  otb_6s_doublereal phiv(static_cast<otb_6s_doublereal>(ViewingAzimutalAngle));
  otb_6s_integer    month(static_cast<otb_6s_integer>(Month));
  otb_6s_integer    jday(static_cast<otb_6s_integer>(Day));
  otb_6s_doublereal pressure(static_cast<otb_6s_doublereal>(AtmosphericPressure));
  otb_6s_doublereal uw(static_cast<otb_6s_doublereal>(WaterVaporAmount));
  otb_6s_doublereal uo3(static_cast<otb_6s_doublereal>(OzoneAmount));
// atmospheric model
  otb_6s_integer    iaer(static_cast<otb_6s_integer>(AerosolModel));
  otb_6s_doublereal taer55(static_cast<otb_6s_doublereal>(AerosolOptical));

  // Init output parameters
  AtmosphericReflectance = 0.;
  AtmosphericSphericalAlbedo = 0.;
  TotalGaseousTransmission = 0.;
  DownwardTransmittance = 0.;
  UpwardTransmittance = 0.;
  UpwardDiffuseTransmittance = 0.;
  UpwardDirectTransmittance = 0.;
  UpwardDiffuseTransmittanceForRayleigh = 0.;
  UpwardDiffuseTransmittanceForAerosol = 0.;

  otb_6s_doublereal wlinf(0.), wlsup(0.);
  otb_6s_doublereal otb_ratm__(0.), sast(0.), tgasm(0.), sdtott(0.), sutott(0.);
  otb_6s_doublereal tdif_up(0.), tdir_up(0.), tdif_up_ray(0.), tdif_up_aer(0.);

  // 6S official Wavelength Spectral Band step value
  const float SIXSStepOfWavelengthSpectralBandValues = .0025;
  // Generate 6s Wavelength Spectral Band with the offcicial step value
  ComputeWavelengthSpectralBandValuesFor6S(SIXSStepOfWavelengthSpectralBandValues,
                                           WavelengthSpectralBand        // Update
                                           );
  try
    {

    // 6S official tab size Wavelength Spectral
    const otb_6s_integer S_6S_SIZE = 1501;
    // Generate WavelengthSpectralBand  in 6S compatible buffer s[1501]
    wlinf = static_cast<otb_6s_doublereal>(WavelengthSpectralBand->GetMinSpectralValue());
    wlsup = static_cast<otb_6s_doublereal>(WavelengthSpectralBand->GetMaxSpectralValue());
    otb_6s_integer iinf =
      static_cast<otb_6s_integer>((wlinf - (float) .25) / SIXSStepOfWavelengthSpectralBandValues + (float) 1.5);
    otb_6s_integer      cpt = iinf - 1;
    otb_6s_doublereal * s(ITK_NULLPTR);
    s = new otb_6s_doublereal[S_6S_SIZE];
    memset(s, 0, S_6S_SIZE * sizeof(otb_6s_doublereal));
    const ValuesVectorType& FilterFunctionValues6S = WavelengthSpectralBand->GetFilterFunctionValues6S();
    // Set the values of FilterFunctionValues6S in s between [iinf-1; isup]
    for (unsigned int i = 0; i < FilterFunctionValues6S.size() && cpt < S_6S_SIZE; ++i)
      {
      s[cpt] = FilterFunctionValues6S[i];
      ++cpt;
      }

    // Call 6s main function
    otbMsgDevMacro(<< "Start call 6S main function ...");
    otb_6s_ssssss_otb_main_function(&asol, &phi0, &avis, &phiv, &month, &jday,
                                    &pressure, &uw, &uo3,
                                    &iaer,
                                    &taer55,
                                    &wlinf, &wlsup,
                                    s,
                                    &otb_ratm__,
                                    &sast,
                                    &tgasm,
                                    &sdtott,
                                    &sutott,
                                    &tdif_up,
                                    &tdir_up,
                                    &tdif_up_ray,
                                    &tdif_up_aer);
    otbMsgDevMacro(<< "Done call 6S main function!");
    delete[] s;
    s = ITK_NULLPTR;
    }
  catch (std::bad_alloc& err)
    {
    itkGenericExceptionMacro(<< "Exception bad_alloc in SIXSTraits class: " << (char*) err.what());
    }
  catch (...)
    {
    itkGenericExceptionMacro(<< "Unknown exception in SIXSTraits class (catch(...)");
    }

  // Set outputs parameters
  AtmosphericReflectance = static_cast<double>(otb_ratm__);
  AtmosphericSphericalAlbedo = static_cast<double>(sast);
  TotalGaseousTransmission = static_cast<double>(tgasm);
  DownwardTransmittance = static_cast<double>(sdtott);
  UpwardTransmittance = static_cast<double>(sutott);
  UpwardDiffuseTransmittance = static_cast<double>(tdif_up);
  UpwardDirectTransmittance = static_cast<double>(tdir_up);
  UpwardDiffuseTransmittanceForRayleigh = static_cast<double>(tdif_up_ray);
  UpwardDiffuseTransmittanceForAerosol = static_cast<double>(tdif_up_aer);
}

void
SIXSTraits::ComputeWavelengthSpectralBandValuesFor6S(
  const double SIXSStepOfWavelengthSpectralBandValues,
  WavelengthSpectralType*         WavelengthSpectralBand
  )
{
  const double            epsilon(.000001);
  const double            L_min = static_cast<double>(WavelengthSpectralBand->GetMinSpectralValue());
  const double            L_max = static_cast<double>(WavelengthSpectralBand->GetMaxSpectralValue());
  const double            L_userStep = static_cast<double>(WavelengthSpectralBand->GetUserStep());
  const ValuesVectorType& FilterFunctionValues = WavelengthSpectralBand->GetFilterFunctionValues();
  unsigned int            i = 1;
  unsigned int            j = 1;
  const double            invStep = static_cast<double>(1. / L_userStep);
  double                  value(0.);

  if (FilterFunctionValues.size() <= 1)
    {
    itkGenericExceptionMacro(<< "The FilterFunctionValues vector must have more than 1 values !");
    }
  if (! (L_min + static_cast<double>(FilterFunctionValues.size() - 1) * L_userStep < (L_max + epsilon) ) )
    {
    itkGenericExceptionMacro(
      << "The following condition: " << L_min << "+(" << FilterFunctionValues.size() << "-1)*" << L_userStep <<
      " < (" << L_max << "+" << epsilon << ") is not respected !" << "val1 " << L_min + static_cast<double>(FilterFunctionValues.size() - 1) * L_userStep << " val2 " << L_max - epsilon);
    }

  // Generate WavelengthSpectralBand if the step is not the offical 6S step value
  if (vcl_abs(L_userStep - SIXSStepOfWavelengthSpectralBandValues) > epsilon)
    {
    ValuesVectorType values(1, FilterFunctionValues[0]); //vector size 1 with the value vect[0]

    // Stop the interpolation at the max spectral value.
    value = SIXSStepOfWavelengthSpectralBandValues;
    while (L_min + value <= L_max)
      {
      // Search the User interval that surround the StepOfWavelengthSpectralBandValues current value.

      // removed the <= here, might be wrong
      while (j * L_userStep < value)
        {
        ++j;
        }

      // Check if we are not out of bound
      if (j >= FilterFunctionValues.size())
        {
        itkGenericExceptionMacro(
          << "Index " << j << " out of bound for FilterFunctionValues vector (size: " << FilterFunctionValues.size() <<
          ")." << " and value is " << value << " and SIXSStepOfWavelengthSpectralBandValues is " << SIXSStepOfWavelengthSpectralBandValues<< " and i is " << i);
        }

      double valueTemp;
      valueTemp = static_cast<double>(FilterFunctionValues[j - 1])
                  + ((static_cast<double>(FilterFunctionValues[j]) -
                      static_cast<double>(FilterFunctionValues[j - 1])) * invStep)
                  * (value - L_userStep * (j - 1));
      values.push_back(static_cast<WavelengthSpectralBandType>(valueTemp));

      ++i;
      value += SIXSStepOfWavelengthSpectralBandValues;
      }

    if (L_min + (i - 1) * SIXSStepOfWavelengthSpectralBandValues != L_max)
      {
      values.push_back(0);
      }
    // Store this values
    WavelengthSpectralBand->SetFilterFunctionValues6S(values);
    // Store the new Max MaxSpectralValue
    WavelengthSpectralBand->SetMaxSpectralValue(static_cast<WavelengthSpectralBandType>(L_min + i *
                                                                                SIXSStepOfWavelengthSpectralBandValues));

    }
  else
    {
    // Init with copy of FilterFunctionValues input vector values
    WavelengthSpectralBand->SetFilterFunctionValues6S(FilterFunctionValues);
    }
}

void
SIXSTraits::ComputeEnvironmentalContribution(const double diffuseTransmittanceForRayleighScattering,
                                             const double diffuseTransmittanceForAerosolScattering,
                                             const double radiusInKilometers,
                                             const double altitude,
                                             const double cosineOfViewingAngle,
                                             double& rayleighEstimation,
                                             double& aerosolEstimation,
                                             double& globalEstimation)
{
  otb_6s_doublereal difr(static_cast<otb_6s_doublereal>(diffuseTransmittanceForRayleighScattering));
  otb_6s_doublereal difa(static_cast<otb_6s_doublereal>(diffuseTransmittanceForAerosolScattering));
  otb_6s_doublereal rad(static_cast<otb_6s_doublereal>(radiusInKilometers));
  otb_6s_doublereal palt(static_cast<otb_6s_doublereal>(altitude));
  otb_6s_doublereal xmuv(static_cast<otb_6s_doublereal>(cosineOfViewingAngle));
  otb_6s_doublereal fra(0.), fae(0.), fr(0.);
  otb_6s_enviro_(&difr, &difa, &rad, &palt, &xmuv, &fra, &fae, &fr);
  rayleighEstimation = static_cast<double>(fra);
  aerosolEstimation = static_cast<double>(fae);
  globalEstimation = static_cast<double>(fr);
}

} // namespace otb
<commit_msg>BUG: use non-pointer array inside try/catch<commit_after>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      2008-05-30
  Version:   2.2.0

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "otbSIXSTraits.h"

#include "otb_6S.h"
#include "main_6s.h"
#include "otbMacro.h"

#include <iomanip>

namespace otb
{

void
SIXSTraits::ComputeAtmosphericParameters(
  const double SolarZenithalAngle,                                        /** The Solar zenithal angle */
  const double SolarAzimutalAngle,                                        /** The Solar azimutal angle */
  const double ViewingZenithalAngle,                                      /** The Viewing zenithal angle */
  const double ViewingAzimutalAngle,                                      /** The Viewing azimutal angle */
  const unsigned int Month,                                               /** The Month */
  const unsigned int Day,                                                 /** The Day (in the month) */
  const double AtmosphericPressure,                                       /** The Atmospheric pressure */
  const double WaterVaporAmount,                                          /** The Water vapor amount (Total water vapor content over vertical atmospheric column) */
  const double OzoneAmount,                                               /** The Ozone amount (Stratospheric ozone layer content) */
  const AerosolModelType&      AerosolModel,                              /** The Aerosol model */
  const double AerosolOptical,                                            /** The Aerosol optical (radiative impact of aerosol for the reference wavelength 550-nm) */
  WavelengthSpectralType* WavelengthSpectralBand,                 /** Wavelength for the spectral band definition */
  /** Note : The Max wavelength spectral band value must be updated ! */
  double&                AtmosphericReflectance,                  /** Atmospheric reflectance */
  double&                AtmosphericSphericalAlbedo,              /** atmospheric spherical albedo */
  double&                TotalGaseousTransmission,                /** Total gaseous transmission */
  double&                DownwardTransmittance,                   /** downward transmittance */
  double&                UpwardTransmittance,                     /** upward transmittance */
  double&                UpwardDiffuseTransmittance,              /** upward diffuse transmittance */
  double&                UpwardDirectTransmittance,               /** Upward direct transmittance */
  double&                UpwardDiffuseTransmittanceForRayleigh,   /** upward diffuse transmittance for rayleigh */
  double&                UpwardDiffuseTransmittanceForAerosol     /** supward diffuse transmittance for aerosols */
  )
{
// geometrical conditions
  otb_6s_doublereal asol(static_cast<otb_6s_doublereal>(SolarZenithalAngle));
  otb_6s_doublereal phi0(static_cast<otb_6s_doublereal>(SolarAzimutalAngle));
  otb_6s_doublereal avis(static_cast<otb_6s_doublereal>(ViewingZenithalAngle));
  otb_6s_doublereal phiv(static_cast<otb_6s_doublereal>(ViewingAzimutalAngle));
  otb_6s_integer    month(static_cast<otb_6s_integer>(Month));
  otb_6s_integer    jday(static_cast<otb_6s_integer>(Day));
  otb_6s_doublereal pressure(static_cast<otb_6s_doublereal>(AtmosphericPressure));
  otb_6s_doublereal uw(static_cast<otb_6s_doublereal>(WaterVaporAmount));
  otb_6s_doublereal uo3(static_cast<otb_6s_doublereal>(OzoneAmount));
// atmospheric model
  otb_6s_integer    iaer(static_cast<otb_6s_integer>(AerosolModel));
  otb_6s_doublereal taer55(static_cast<otb_6s_doublereal>(AerosolOptical));

  // Init output parameters
  AtmosphericReflectance = 0.;
  AtmosphericSphericalAlbedo = 0.;
  TotalGaseousTransmission = 0.;
  DownwardTransmittance = 0.;
  UpwardTransmittance = 0.;
  UpwardDiffuseTransmittance = 0.;
  UpwardDirectTransmittance = 0.;
  UpwardDiffuseTransmittanceForRayleigh = 0.;
  UpwardDiffuseTransmittanceForAerosol = 0.;

  otb_6s_doublereal wlinf(0.), wlsup(0.);
  otb_6s_doublereal otb_ratm__(0.), sast(0.), tgasm(0.), sdtott(0.), sutott(0.);
  otb_6s_doublereal tdif_up(0.), tdir_up(0.), tdif_up_ray(0.), tdif_up_aer(0.);

  // 6S official Wavelength Spectral Band step value
  const float SIXSStepOfWavelengthSpectralBandValues = .0025;
  // Generate 6s Wavelength Spectral Band with the offcicial step value
  ComputeWavelengthSpectralBandValuesFor6S(SIXSStepOfWavelengthSpectralBandValues,
                                           WavelengthSpectralBand        // Update
                                           );
  try
    {

    // 6S official tab size Wavelength Spectral
    const otb_6s_integer S_6S_SIZE = 1501;
    // Generate WavelengthSpectralBand  in 6S compatible buffer s[1501]
    wlinf = static_cast<otb_6s_doublereal>(WavelengthSpectralBand->GetMinSpectralValue());
    wlsup = static_cast<otb_6s_doublereal>(WavelengthSpectralBand->GetMaxSpectralValue());
    otb_6s_integer iinf =
      static_cast<otb_6s_integer>((wlinf - (float) .25) / SIXSStepOfWavelengthSpectralBandValues + (float) 1.5);
    otb_6s_integer      cpt = iinf - 1;
    otb_6s_doublereal s[S_6S_SIZE];
    const ValuesVectorType& FilterFunctionValues6S = WavelengthSpectralBand->GetFilterFunctionValues6S();
    // Set the values of FilterFunctionValues6S in s between [iinf-1; isup]
    for (unsigned int i = 0; i < FilterFunctionValues6S.size() && cpt < S_6S_SIZE; ++i)
      {
      s[cpt] = FilterFunctionValues6S[i];
      ++cpt;
      }

    // Call 6s main function
    otbMsgDevMacro(<< "Start call 6S main function ...");
    otb_6s_ssssss_otb_main_function(&asol, &phi0, &avis, &phiv, &month, &jday,
                                    &pressure, &uw, &uo3,
                                    &iaer,
                                    &taer55,
                                    &wlinf, &wlsup,
                                    s,
                                    &otb_ratm__,
                                    &sast,
                                    &tgasm,
                                    &sdtott,
                                    &sutott,
                                    &tdif_up,
                                    &tdir_up,
                                    &tdif_up_ray,
                                    &tdif_up_aer);
    otbMsgDevMacro(<< "Done call 6S main function!");
    }
  catch (std::bad_alloc& err)
    {
    itkGenericExceptionMacro(<< "Exception bad_alloc in SIXSTraits class: " << (char*) err.what());
    }
  catch (...)
    {
    itkGenericExceptionMacro(<< "Unknown exception in SIXSTraits class (catch(...)");
    }

  // Set outputs parameters
  AtmosphericReflectance = static_cast<double>(otb_ratm__);
  AtmosphericSphericalAlbedo = static_cast<double>(sast);
  TotalGaseousTransmission = static_cast<double>(tgasm);
  DownwardTransmittance = static_cast<double>(sdtott);
  UpwardTransmittance = static_cast<double>(sutott);
  UpwardDiffuseTransmittance = static_cast<double>(tdif_up);
  UpwardDirectTransmittance = static_cast<double>(tdir_up);
  UpwardDiffuseTransmittanceForRayleigh = static_cast<double>(tdif_up_ray);
  UpwardDiffuseTransmittanceForAerosol = static_cast<double>(tdif_up_aer);
}

void
SIXSTraits::ComputeWavelengthSpectralBandValuesFor6S(
  const double SIXSStepOfWavelengthSpectralBandValues,
  WavelengthSpectralType*         WavelengthSpectralBand
  )
{
  const double            epsilon(.000001);
  const double            L_min = static_cast<double>(WavelengthSpectralBand->GetMinSpectralValue());
  const double            L_max = static_cast<double>(WavelengthSpectralBand->GetMaxSpectralValue());
  const double            L_userStep = static_cast<double>(WavelengthSpectralBand->GetUserStep());
  const ValuesVectorType& FilterFunctionValues = WavelengthSpectralBand->GetFilterFunctionValues();
  unsigned int            i = 1;
  unsigned int            j = 1;
  const double            invStep = static_cast<double>(1. / L_userStep);
  double                  value(0.);

  if (FilterFunctionValues.size() <= 1)
    {
    itkGenericExceptionMacro(<< "The FilterFunctionValues vector must have more than 1 values !");
    }
  if (! (L_min + static_cast<double>(FilterFunctionValues.size() - 1) * L_userStep < (L_max + epsilon) ) )
    {
    itkGenericExceptionMacro(
      << "The following condition: " << L_min << "+(" << FilterFunctionValues.size() << "-1)*" << L_userStep <<
      " < (" << L_max << "+" << epsilon << ") is not respected !" << "val1 " << L_min + static_cast<double>(FilterFunctionValues.size() - 1) * L_userStep << " val2 " << L_max - epsilon);
    }

  // Generate WavelengthSpectralBand if the step is not the offical 6S step value
  if (vcl_abs(L_userStep - SIXSStepOfWavelengthSpectralBandValues) > epsilon)
    {
    ValuesVectorType values(1, FilterFunctionValues[0]); //vector size 1 with the value vect[0]

    // Stop the interpolation at the max spectral value.
    value = SIXSStepOfWavelengthSpectralBandValues;
    while (L_min + value <= L_max)
      {
      // Search the User interval that surround the StepOfWavelengthSpectralBandValues current value.

      // removed the <= here, might be wrong
      while (j * L_userStep < value)
        {
        ++j;
        }

      // Check if we are not out of bound
      if (j >= FilterFunctionValues.size())
        {
        itkGenericExceptionMacro(
          << "Index " << j << " out of bound for FilterFunctionValues vector (size: " << FilterFunctionValues.size() <<
          ")." << " and value is " << value << " and SIXSStepOfWavelengthSpectralBandValues is " << SIXSStepOfWavelengthSpectralBandValues<< " and i is " << i);
        }

      double valueTemp;
      valueTemp = static_cast<double>(FilterFunctionValues[j - 1])
                  + ((static_cast<double>(FilterFunctionValues[j]) -
                      static_cast<double>(FilterFunctionValues[j - 1])) * invStep)
                  * (value - L_userStep * (j - 1));
      values.push_back(static_cast<WavelengthSpectralBandType>(valueTemp));

      ++i;
      value += SIXSStepOfWavelengthSpectralBandValues;
      }

    if (L_min + (i - 1) * SIXSStepOfWavelengthSpectralBandValues != L_max)
      {
      values.push_back(0);
      }
    // Store this values
    WavelengthSpectralBand->SetFilterFunctionValues6S(values);
    // Store the new Max MaxSpectralValue
    WavelengthSpectralBand->SetMaxSpectralValue(static_cast<WavelengthSpectralBandType>(L_min + i *
                                                                                SIXSStepOfWavelengthSpectralBandValues));

    }
  else
    {
    // Init with copy of FilterFunctionValues input vector values
    WavelengthSpectralBand->SetFilterFunctionValues6S(FilterFunctionValues);
    }
}

void
SIXSTraits::ComputeEnvironmentalContribution(const double diffuseTransmittanceForRayleighScattering,
                                             const double diffuseTransmittanceForAerosolScattering,
                                             const double radiusInKilometers,
                                             const double altitude,
                                             const double cosineOfViewingAngle,
                                             double& rayleighEstimation,
                                             double& aerosolEstimation,
                                             double& globalEstimation)
{
  otb_6s_doublereal difr(static_cast<otb_6s_doublereal>(diffuseTransmittanceForRayleighScattering));
  otb_6s_doublereal difa(static_cast<otb_6s_doublereal>(diffuseTransmittanceForAerosolScattering));
  otb_6s_doublereal rad(static_cast<otb_6s_doublereal>(radiusInKilometers));
  otb_6s_doublereal palt(static_cast<otb_6s_doublereal>(altitude));
  otb_6s_doublereal xmuv(static_cast<otb_6s_doublereal>(cosineOfViewingAngle));
  otb_6s_doublereal fra(0.), fae(0.), fr(0.);
  otb_6s_enviro_(&difr, &difa, &rad, &palt, &xmuv, &fra, &fae, &fr);
  rayleighEstimation = static_cast<double>(fra);
  aerosolEstimation = static_cast<double>(fae);
  globalEstimation = static_cast<double>(fr);
}

} // namespace otb
<|endoftext|>


<commit_before>#include "stdafx.h"
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* 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 <d3dx9.h>

#include "BoundingBox.h"
#include "BoundingSphere.h"
#include "Plane.h"
#include "Ray.h"

using namespace System;
using namespace System::Globalization;

namespace SlimDX
{
	Ray::Ray( Vector3 position, Vector3 direction )
	{
		Position = position;
		Direction = direction;
	}

	bool Ray::Intersects( Ray ray, Plane plane, [Out] float% distance )
	{
		float dotDirection = (plane.Normal.X * ray.Direction.X) + (plane.Normal.Y * ray.Direction.Y) + (plane.Normal.Z * ray.Direction.Z);

		if( Math::Abs( dotDirection ) < 0.000001f )
		{
			distance = 0;
			return false;
		}

		float dotPosition = (plane.Normal.X * ray.Position.X) + (plane.Normal.Y * ray.Position.Y) + (plane.Normal.Z * ray.Position.Z);
		float num = ( -plane.D - dotPosition ) / dotDirection;

		if( num < 0.0f )
		{
			if( num < -0.000001f )
			{
				distance = 0;
				return false;
			}
			num = 0.0f;
		}

		distance = num;
		return true;
	}

	bool Ray::Intersects( Ray ray, Vector3 vertex1, Vector3 vertex2, Vector3 vertex3, [Out] float% distance )
	{
		FLOAT u, v;
		pin_ptr<float> pinnedDist = &distance;

		if( D3DXIntersectTri( reinterpret_cast<D3DXVECTOR3*>( &vertex1 ),
			reinterpret_cast<D3DXVECTOR3*>( &vertex2 ), reinterpret_cast<D3DXVECTOR3*>( &vertex3 ),
			reinterpret_cast<D3DXVECTOR3*>( &ray.Position ), reinterpret_cast<D3DXVECTOR3*>( &ray.Direction ),
			&u, &v, reinterpret_cast<FLOAT*>( pinnedDist ) ) )
			return true;
		else
			return false;
	}

	bool Ray::Intersects( Ray ray, BoundingBox box, [Out] float% distance )
	{
		float d = 0.0f;
		float maxValue = float::MaxValue;

		if( Math::Abs( ray.Direction.X ) < 0.0000001 )
		{
			if( ray.Position.X < box.Minimum.X || ray.Position.X > box.Maximum.X )
			{
				distance = 0.0f;
				return false;
			}
		}
		else
		{
			float inv = 1.0f / ray.Direction.X;
			float min = (box.Minimum.X - ray.Position.X) * inv;
			float max = (box.Maximum.X - ray.Position.X) * inv;

			if( min > max )
			{
				float temp = min;
				min = max;
				max = temp;
			}

			d = Math::Max( min, d );
			maxValue = Math::Min( max, maxValue );

			if( d > maxValue )
			{
				distance = 0.0f;
				return false;
			}
		}

		if( Math::Abs( ray.Direction.Y ) < 0.0000001 )
		{
			if( ray.Position.Y < box.Minimum.Y || ray.Position.Y > box.Maximum.Y )
			{
				distance = 0.0f;
				return false;
			}
		}
		else
		{
			float inv = 1.0f / ray.Direction.Y;
			float min = (box.Minimum.Y - ray.Position.Y) * inv;
			float max = (box.Maximum.Y - ray.Position.Y) * inv;

			if( min > max )
			{
				float temp = min;
				min = max;
				max = temp;
			}

			d = Math::Max( min, d );
			maxValue = Math::Min( max, maxValue );

			if( d > maxValue )
			{
				distance = 0.0f;
				return false;
			}
		}

		if( Math::Abs( ray.Direction.Z ) < 0.0000001 )
		{
			if( ray.Position.Z < box.Minimum.Z || ray.Position.Z > box.Maximum.Z )
			{
				distance = 0.0f;
				return false;
			}
		}
		else
		{
			float inv = 1.0f / ray.Direction.Z;
			float min = (box.Minimum.Z - ray.Position.Z) * inv;
			float max = (box.Maximum.Z - ray.Position.Z) * inv;

			if( min > max )
			{
				float temp = min;
				min = max;
				max = temp;
			}

			d = Math::Max( min, d );
			maxValue = Math::Min( max, maxValue );

			if( d > maxValue )
			{
				distance = 0.0f;
				return false;
			}
		}

		distance = d;
		return true;
	}

	bool Ray::Intersects( Ray ray, BoundingSphere sphere, [Out] float% distance )
	{
		float x = sphere.Center.X - ray.Position.X;
		float y = sphere.Center.Y - ray.Position.Y;
		float z = sphere.Center.Z - ray.Position.Z;
		float pyth = (x * x) + (y * y) + (z * z);
		float rr = sphere.Radius * sphere.Radius;

		if( pyth <= rr )
		{
			distance = 0.0f;
			return true;
		}

		float dot = (x * ray.Direction.X) + (y * ray.Direction.Y) + (z * ray.Direction.Z);
		if( dot < 0.0f )
		{
			distance = 0.0f;
			return false;
		}

		float temp = pyth - (dot * dot);
		if( temp > rr )
		{
			distance = 0.0f;
			return false;
		}

		distance = dot - static_cast<float>( Math::Sqrt( static_cast<double>( rr - temp ) ) );
		return true;
	}

	bool Ray::operator == ( Ray left, Ray right )
	{
		return Ray::Equals( left, right );
	}

	bool Ray::operator != ( Ray left, Ray right )
	{
		return !Ray::Equals( left, right );
	}

	String^ Ray::ToString()
	{
		return String::Format( CultureInfo::CurrentCulture, "Position:{0} Direction:{1}", Position.ToString(), Direction.ToString() );
	}

	int Ray::GetHashCode()
	{
		return Position.GetHashCode() + Direction.GetHashCode();
	}

	bool Ray::Equals( Object^ value )
	{
		if( value == nullptr )
			return false;

		if( value->GetType() != GetType() )
			return false;

		return Equals( safe_cast<Ray>( value ) );
	}

	bool Ray::Equals( Ray value )
	{
		return ( Position == value.Position && Direction == value.Direction );
	}

	bool Ray::Equals( Ray% value1, Ray% value2 )
	{
		return ( value1.Position == value2.Position && value1.Direction == value2.Direction );
	}
}<commit_msg>Patching ray intersection methods to normalize the input ray's direction.<commit_after>#include "stdafx.h"
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* 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 <d3dx9.h>

#include "BoundingBox.h"
#include "BoundingSphere.h"
#include "Plane.h"
#include "Ray.h"

using namespace System;
using namespace System::Globalization;

namespace SlimDX
{
	Ray::Ray( Vector3 position, Vector3 direction )
	{
		Position = position;
		Direction = direction;
	}

	bool Ray::Intersects( Ray ray, Plane plane, [Out] float% distance )
	{
		ray.Direction.Normalize();
		float dotDirection = (plane.Normal.X * ray.Direction.X) + (plane.Normal.Y * ray.Direction.Y) + (plane.Normal.Z * ray.Direction.Z);

		if( Math::Abs( dotDirection ) < 0.000001f )
		{
			distance = 0;
			return false;
		}

		float dotPosition = (plane.Normal.X * ray.Position.X) + (plane.Normal.Y * ray.Position.Y) + (plane.Normal.Z * ray.Position.Z);
		float num = ( -plane.D - dotPosition ) / dotDirection;

		if( num < 0.0f )
		{
			if( num < -0.000001f )
			{
				distance = 0;
				return false;
			}
			num = 0.0f;
		}

		distance = num;
		return true;
	}

	bool Ray::Intersects( Ray ray, Vector3 vertex1, Vector3 vertex2, Vector3 vertex3, [Out] float% distance )
	{
		FLOAT u, v;
		pin_ptr<float> pinnedDist = &distance;

		if( D3DXIntersectTri( reinterpret_cast<D3DXVECTOR3*>( &vertex1 ),
			reinterpret_cast<D3DXVECTOR3*>( &vertex2 ), reinterpret_cast<D3DXVECTOR3*>( &vertex3 ),
			reinterpret_cast<D3DXVECTOR3*>( &ray.Position ), reinterpret_cast<D3DXVECTOR3*>( &ray.Direction ),
			&u, &v, reinterpret_cast<FLOAT*>( pinnedDist ) ) )
			return true;
		else
			return false;
	}

	bool Ray::Intersects( Ray ray, BoundingBox box, [Out] float% distance )
	{
		float d = 0.0f;
		float maxValue = float::MaxValue;

		ray.Direction.Normalize();
		if( Math::Abs( ray.Direction.X ) < 0.0000001 )
		{
			if( ray.Position.X < box.Minimum.X || ray.Position.X > box.Maximum.X )
			{
				distance = 0.0f;
				return false;
			}
		}
		else
		{
			float inv = 1.0f / ray.Direction.X;
			float min = (box.Minimum.X - ray.Position.X) * inv;
			float max = (box.Maximum.X - ray.Position.X) * inv;

			if( min > max )
			{
				float temp = min;
				min = max;
				max = temp;
			}

			d = Math::Max( min, d );
			maxValue = Math::Min( max, maxValue );

			if( d > maxValue )
			{
				distance = 0.0f;
				return false;
			}
		}

		if( Math::Abs( ray.Direction.Y ) < 0.0000001 )
		{
			if( ray.Position.Y < box.Minimum.Y || ray.Position.Y > box.Maximum.Y )
			{
				distance = 0.0f;
				return false;
			}
		}
		else
		{
			float inv = 1.0f / ray.Direction.Y;
			float min = (box.Minimum.Y - ray.Position.Y) * inv;
			float max = (box.Maximum.Y - ray.Position.Y) * inv;

			if( min > max )
			{
				float temp = min;
				min = max;
				max = temp;
			}

			d = Math::Max( min, d );
			maxValue = Math::Min( max, maxValue );

			if( d > maxValue )
			{
				distance = 0.0f;
				return false;
			}
		}

		if( Math::Abs( ray.Direction.Z ) < 0.0000001 )
		{
			if( ray.Position.Z < box.Minimum.Z || ray.Position.Z > box.Maximum.Z )
			{
				distance = 0.0f;
				return false;
			}
		}
		else
		{
			float inv = 1.0f / ray.Direction.Z;
			float min = (box.Minimum.Z - ray.Position.Z) * inv;
			float max = (box.Maximum.Z - ray.Position.Z) * inv;

			if( min > max )
			{
				float temp = min;
				min = max;
				max = temp;
			}

			d = Math::Max( min, d );
			maxValue = Math::Min( max, maxValue );

			if( d > maxValue )
			{
				distance = 0.0f;
				return false;
			}
		}

		distance = d;
		return true;
	}

	bool Ray::Intersects( Ray ray, BoundingSphere sphere, [Out] float% distance )
	{
		float x = sphere.Center.X - ray.Position.X;
		float y = sphere.Center.Y - ray.Position.Y;
		float z = sphere.Center.Z - ray.Position.Z;
		float pyth = (x * x) + (y * y) + (z * z);
		float rr = sphere.Radius * sphere.Radius;

		if( pyth <= rr )
		{
			distance = 0.0f;
			return true;
		}

		ray.Direction.Normalize();
		float dot = (x * ray.Direction.X) + (y * ray.Direction.Y) + (z * ray.Direction.Z);
		if( dot < 0.0f )
		{
			distance = 0.0f;
			return false;
		}

		float temp = pyth - (dot * dot);
		if( temp > rr )
		{
			distance = 0.0f;
			return false;
		}

		distance = dot - static_cast<float>( Math::Sqrt( static_cast<double>( rr - temp ) ) );
		return true;
	}

	bool Ray::operator == ( Ray left, Ray right )
	{
		return Ray::Equals( left, right );
	}

	bool Ray::operator != ( Ray left, Ray right )
	{
		return !Ray::Equals( left, right );
	}

	String^ Ray::ToString()
	{
		return String::Format( CultureInfo::CurrentCulture, "Position:{0} Direction:{1}", Position.ToString(), Direction.ToString() );
	}

	int Ray::GetHashCode()
	{
		return Position.GetHashCode() + Direction.GetHashCode();
	}

	bool Ray::Equals( Object^ value )
	{
		if( value == nullptr )
			return false;

		if( value->GetType() != GetType() )
			return false;

		return Equals( safe_cast<Ray>( value ) );
	}

	bool Ray::Equals( Ray value )
	{
		return ( Position == value.Position && Direction == value.Direction );
	}

	bool Ray::Equals( Ray% value1, Ray% value2 )
	{
		return ( value1.Position == value2.Position && value1.Direction == value2.Direction );
	}
}<|endoftext|>


<commit_before>#ifndef HMLIB_ALGORITHM_COMPARE_INC
#define HMLIB_ALGORITHM_COMPARE_INC 201
#
/*===algorithm::compare===
大小関係のアルゴリズムを提供
algorithm::compare v2_00/170207 hmIto
	sort_value is now renamed to sorting_swap
algorithm::compare v2_01/170207 hmIto
	Rename sort_value to sorting_swap
algorithm::compare v2_00/160509 hmIto
	Rename min/max with multiple arguments to min_value/max_value
	Rename swap_sort to sort_value
algorithm::compare v1_00/130328 hmIto
	Indepdendent from algorithm.hpp
*/
#include<algorithm>
#include<array>
namespace hmLib{
	//sort non-container variables
	template<typename T>
	inline void sorting_swap(T& val1,T& val2){
		if(val1>val2)std::swap(val1,val2);
	}
	//sort non-container variables (three arguments)
	template<typename T>
	inline void sorting_swap(T& val1,T& val2, T& val3){
		if(val1>val2){
			if(val2>val3){
				//val3 < val2 < val1
				std::swap(val1,val3);
			}else if(val1>val3){
				//val2 < val3 < val1
				std::swap(val1,val2);
				std::swap(val2,val3);
			}else{
				//val2 < val1 < val3
				std::swap(val1,val2);
			}
		}else{
			if(val1>val3){
				//val3 < val1 < val2
				std::swap(val1,val3);
				std::swap(val2,val3);
			}else if(val2>val3){
				//val1 < val3 < val2
				std::swap(val2,val3);
			}else return;
		}
	}
	//median value of three arguments
	template<class T>
	inline constexpr T median(T val1,T val2,T val3){
		if(val1>val2){
			if(val2>val3)return val2;
			else if(val1>val3)return val3;
			else return val1;
		}else{
			if(val1>val3)return val1;
			else if(val2>val3)return val3;
			else return val2;
		}
	}

	//clamp value by lower and upper
	template<class T>
	inline constexpr T clamp(T val, T lower, T upper) {
		return std::min(std::max(lower, val), upper);
	}

	template<typename T, typename... Others>
	inline constexpr T min_value(T val1,T val2,Others... vals){return std::min(val1,min_value(val2,vals...));}
	template<typename T>
	inline constexpr T min_value(T val){return val;}
	template<typename T, typename... Others>
	inline constexpr T max_value(T val1,T val2,Others... vals){return std::max(val1,max_value(val2,vals...));}
	template<typename T>
	inline constexpr T max_value(T val){return val;}

	//mod with positive value
	template<class T>
	[[deprecated("please use euclidean_mod() function")]]
	inline T positive_mod(T num,T divisor){
		num %= divisor;
		if(num < 0)return num + divisor;
		return num;
	}

	template<class T>
	inline T euclidean_mod(T n, T divisor){
		n %= divisor;
		if(n < 0)return n + divisor;
		return n;
	}
	template<class T>
	inline T euclidean_div(T n, T divisor){
		return (n-euclidean_mod(n,divisor))/divisor;
	}
	template<class T>
	inline std::pair<T,T> eucledian_divmod(T n, T divisor){
		T m = euclidean_mod(n,divisor);
		return std::pair<T,T>((n-m)/divisor,m);
	}

}
#
#endif
<commit_msg>Fix: remove Japanese character <commit_after>#ifndef HMLIB_ALGORITHM_COMPARE_INC
#define HMLIB_ALGORITHM_COMPARE_INC 201
#
/*===algorithm::compare===
algorithm::compare v2_00/170207 hmIto
	sort_value is now renamed to sorting_swap
algorithm::compare v2_01/170207 hmIto
	Rename sort_value to sorting_swap
algorithm::compare v2_00/160509 hmIto
	Rename min/max with multiple arguments to min_value/max_value
	Rename swap_sort to sort_value
algorithm::compare v1_00/130328 hmIto
	Indepdendent from algorithm.hpp
*/
#include<algorithm>
#include<array>
namespace hmLib{
	//sort non-container variables
	template<typename T>
	inline void sorting_swap(T& val1,T& val2){
		if(val1>val2)std::swap(val1,val2);
	}
	//sort non-container variables (three arguments)
	template<typename T>
	inline void sorting_swap(T& val1,T& val2, T& val3){
		if(val1>val2){
			if(val2>val3){
				//val3 < val2 < val1
				std::swap(val1,val3);
			}else if(val1>val3){
				//val2 < val3 < val1
				std::swap(val1,val2);
				std::swap(val2,val3);
			}else{
				//val2 < val1 < val3
				std::swap(val1,val2);
			}
		}else{
			if(val1>val3){
				//val3 < val1 < val2
				std::swap(val1,val3);
				std::swap(val2,val3);
			}else if(val2>val3){
				//val1 < val3 < val2
				std::swap(val2,val3);
			}else return;
		}
	}
	//median value of three arguments
	template<class T>
	inline constexpr T median(T val1,T val2,T val3){
		if(val1>val2){
			if(val2>val3)return val2;
			else if(val1>val3)return val3;
			else return val1;
		}else{
			if(val1>val3)return val1;
			else if(val2>val3)return val3;
			else return val2;
		}
	}

	//clamp value by lower and upper
	template<class T>
	inline constexpr T clamp(T val, T lower, T upper) {
		return std::min(std::max(lower, val), upper);
	}

	template<typename T, typename... Others>
	inline constexpr T min_value(T val1,T val2,Others... vals){return std::min(val1,min_value(val2,vals...));}
	template<typename T>
	inline constexpr T min_value(T val){return val;}
	template<typename T, typename... Others>
	inline constexpr T max_value(T val1,T val2,Others... vals){return std::max(val1,max_value(val2,vals...));}
	template<typename T>
	inline constexpr T max_value(T val){return val;}

	//mod with positive value
	template<class T>
	[[deprecated("please use euclidean_mod() function")]]
	inline T positive_mod(T num,T divisor){
		num %= divisor;
		if(num < 0)return num + divisor;
		return num;
	}

	template<class T>
	inline T euclidean_mod(T n, T divisor){
		n %= divisor;
		if(n < 0)return n + divisor;
		return n;
	}
	template<class T>
	inline T euclidean_div(T n, T divisor){
		return (n-euclidean_mod(n,divisor))/divisor;
	}
	template<class T>
	inline std::pair<T,T> eucledian_divmod(T n, T divisor){
		T m = euclidean_mod(n,divisor);
		return std::pair<T,T>((n-m)/divisor,m);
	}

}
#
#endif
<|endoftext|>


<commit_before>/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium
team <http://www.bh107.org>.

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

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

You should have received a copy of the
GNU Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/

#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/foreach.hpp>
#include <fstream>

#include <jitk/fuser.hpp>

using namespace std;

namespace bohrium {
namespace jitk {

// Unnamed namespace for all fuser help functions
namespace {

// Check if 'a' and 'b' supports data-parallelism when merged
bool data_parallel_compatible(const bh_instruction *a, const bh_instruction *b)
{
    if(bh_opcode_is_system(a->opcode) || bh_opcode_is_system(b->opcode))
        return true;

    const int a_nop = bh_noperands(a->opcode);
    for(int i=0; i<a_nop; ++i)
    {
        if(not bh_view_disjoint(&b->operand[0], &a->operand[i])
           && not bh_view_aligned(&b->operand[0], &a->operand[i]))
            return false;
    }
    const int b_nop = bh_noperands(b->opcode);
    for(int i=0; i<b_nop; ++i)
    {
        if(not bh_view_disjoint(&a->operand[0], &b->operand[i])
           && not bh_view_aligned(&a->operand[0], &b->operand[i]))
            return false;
    }
    return true;
}

// Check if 'b1' and 'b2' supports data-parallelism when merged
bool data_parallel_compatible(const Block &b1, const Block &b2) {
    for (const bh_instruction *i1 : b1.getAllInstr()) {
        for (const bh_instruction *i2 : b2.getAllInstr()) {
            if (not data_parallel_compatible(i1, i2))
                return false;
        }
    }
    return true;
}

// Check if 'block' accesses the output of a sweep in 'sweeps'
bool sweeps_accessed_by_block(const set<bh_instruction*> &sweeps, const Block &block) {
    for (bh_instruction *instr: sweeps) {
        assert(bh_noperands(instr->opcode) > 0);
        auto bases = block.getAllBases();
        if (bases.find(instr->operand[0].base) != bases.end())
            return true;
    }
    return false;
}
} // Unnamed namespace

vector<Block> fuser_singleton(vector<bh_instruction> &instr_list, const set<bh_instruction*> &news) {

    // Creates the _block_list based on the instr_list
    vector<Block> block_list;
    for (auto instr=instr_list.begin(); instr != instr_list.end(); ++instr) {
        int nop = bh_noperands(instr->opcode);
        if (nop == 0)
            continue; // Ignore noop instructions such as BH_NONE or BH_TALLY

        // Let's try to simplify the shape of the instruction
        if (instr->reshapable()) {
            const vector<int64_t> dominating_shape = instr->dominating_shape();
            assert(dominating_shape.size() > 0);

            const int64_t totalsize = std::accumulate(dominating_shape.begin(), dominating_shape.end(), 1, \
                                                      std::multiplies<int64_t>());
            const vector<int64_t> shape = {totalsize};
            instr->reshape(shape);
        }
        // Let's create the block
        const vector<int64_t> dominating_shape = instr->dominating_shape();
        assert(dominating_shape.size() > 0);
        int64_t size_of_rank_dim = dominating_shape[0];
        vector<bh_instruction*> single_instr = {&instr[0]};
        block_list.push_back(create_nested_block(single_instr, 0, size_of_rank_dim, news));
    }
    return block_list;
}

// Merges the two blocks 'a' and 'a' (in that order)
pair<Block, bool> block_merge(const Block &a, const Block &b, const set<bh_instruction*> &news) {

    // First we check for data incompatibility
    if (b.isInstr() or not data_parallel_compatible(a, b) or sweeps_accessed_by_block(a._sweeps, b)) {
        return make_pair(Block(), false);
    }

    // Check for perfect match, which is directly mergeable
    if (a.size == b.size) {
        return make_pair(merge(a, b), true);
    }
    // Check fusibility of reshapable blocks
    if (b._reshapable && b.size % a.size == 0) {
        vector<bh_instruction *> cur_instr = a.getAllInstr();
        vector<bh_instruction *> it_instr = b.getAllInstr();
        cur_instr.insert(cur_instr.end(), it_instr.begin(), it_instr.end());
        return make_pair(create_nested_block(cur_instr, b.rank, a.size, news), true);
    }
    if (a._reshapable && a.size % b.size == 0) {
        vector<bh_instruction *> cur_instr = a.getAllInstr();
        vector<bh_instruction *> it_instr = b.getAllInstr();
        cur_instr.insert(cur_instr.end(), it_instr.begin(), it_instr.end());
        return make_pair(create_nested_block(cur_instr, a.rank, b.size, news), true);
    }
    return make_pair(Block(), false);
}

vector<Block> fuser_serial(vector<Block> &block_list, const set<bh_instruction*> &news) {
    vector<Block> ret;
    for (auto it = block_list.begin(); it != block_list.end(); ) {
        ret.push_back(*it);
        Block &cur = ret.back();
        ++it;
        if (cur.isInstr()) {
            continue; // We should never fuse instruction blocks
        }
        // Let's search for fusible blocks
        for (; it != block_list.end(); ++it) {
            const pair<Block, bool> res = block_merge(cur, *it, news);
            if (res.second) {
                cur = res.first;
            } else {
                break; // We couldn't find any shape match
            }
        }
        // Let's fuse at the next rank level
        cur._block_list = fuser_serial(cur._block_list, news);
    }
    return ret;
}

namespace dag {

//The type declaration of the boost graphs, vertices and edges.
typedef boost::adjacency_list<boost::setS, boost::vecS, boost::bidirectionalS, const Block*> DAG;
typedef typename boost::graph_traits<DAG>::edge_descriptor Edge;
typedef uint64_t Vertex;

/* Determines whether there exist a path from 'a' to 'b'
 *
 * Complexity: O(E + V)
 *
 * @a               The first vertex
 * @b               The second vertex
 * @dag             The DAG
 * @only_long_path  Only accept path of length greater than one
 * @return          True if there is a path
 */
bool path_exist(Vertex a, Vertex b, const DAG &dag, bool only_long_path) {
    using namespace boost;

    struct path_visitor:default_bfs_visitor {
        const Vertex dst;
        path_visitor(Vertex b):dst(b){};

        void examine_edge(Edge e, const DAG &g) const {
            if(target(e,g) == dst)
                throw runtime_error("");
        }
    };
    struct long_visitor:default_bfs_visitor {
        const Vertex src, dst;
        long_visitor(Vertex a, Vertex b):src(a),dst(b){};

        void examine_edge(Edge e, const DAG &g) const
        {
            if(source(e,g) != src and target(e,g) == dst)
                throw runtime_error("");
        }
    };
    try {
        if(only_long_path)
            breadth_first_search(dag, a, visitor(long_visitor(a,b)));
        else
            breadth_first_search(dag, a, visitor(path_visitor(b)));
    }
    catch (const runtime_error &e) {
        return true;
    }
    return false;
}

DAG from_block_list(const vector<Block> &block_list) {
    DAG graph;
    map<bh_base*, set<Vertex> > base2vertices;
    for (const Block &block: block_list) {
        Vertex vertex = boost::add_vertex(&block, graph);

        // Find all vertices that must connect to 'vertex'
        // using and updating 'base2vertices'
        set<Vertex> connecting_vertices;
        for (bh_base *base: block.getAllBases()) {
            set<Vertex> &vs = base2vertices[base];
            connecting_vertices.insert(vs.begin(), vs.end());
            vs.insert(vertex);
        }

        // Finally, let's add edges to 'vertex'
        BOOST_REVERSE_FOREACH (Vertex v, connecting_vertices) {
            if (vertex != v and block.depend_on(*graph[v])) {
                boost::add_edge(v, vertex, graph);
            }
        }
    }
    return graph;
}

void pprint(const DAG &dag, const string &filename) {

    //We define a graph and a kernel writer for graphviz
    struct graph_writer {
        const DAG &graph;
        graph_writer(const DAG &g) : graph(g) {};
        void operator()(std::ostream& out) const {
            out << "graph [bgcolor=white, fontname=\"Courier New\"]" << endl;
            out << "node [shape=box color=black, fontname=\"Courier New\"]" << endl;
        }
    };
    struct kernel_writer {
        const DAG &graph;
        kernel_writer(const DAG &g) : graph(g) {};
        void operator()(std::ostream& out, const Vertex& v) const {
            out << "[label=\"Kernel " << v;

            out << ", Instructions: \\l";
            for (const bh_instruction *instr: graph[v]->getAllInstr()) {
                out << *instr << "\\l";
            }
            out << "\"]";
        }
    };
    struct edge_writer {
        const DAG &graph;
        edge_writer(const DAG &g) : graph(g) {};
        void operator()(std::ostream& out, const Edge& e) const {

        }
    };

    static int count=0;
    stringstream ss;
    ss << filename << "-" << count++ << ".dot";
    ofstream file;
    cout << ss.str() << endl;
    file.open(ss.str());
    boost::write_graphviz(file, dag, kernel_writer(dag), edge_writer(dag), graph_writer(dag));
    file.close();
}

vector<Block> topological(DAG &dag) {
    vector<Block> ret;
    pprint(dag, "before");

    set<Vertex> roots; // Set of root vertices
    // Initiate 'roots'
    BOOST_FOREACH (Vertex v, boost::vertices(dag)) {
        if (boost::in_degree(v, dag) == 0) {
            roots.insert(v);
        }
    }

    while (not roots.empty()) {
        pprint(dag, "start");
        Vertex vertex = *roots.begin();
        roots.erase(vertex);
        ret.emplace_back(*dag[vertex]);
        Block &block = ret.back();

        BOOST_FOREACH (Vertex v, boost::adjacent_vertices(vertex, dag)) {
            if (boost::in_degree(v, dag) <= 1) {
                roots.insert(v);
            }
        }
        boost::clear_vertex(vertex, dag);

        vector<Vertex> merged_roots;
        for (Vertex v: roots) {
            const Block &b = *dag[v];
            if (b.isInstr())
                continue;
            if (not data_parallel_compatible(block, b))
                continue;
            if (sweeps_accessed_by_block(block._sweeps, b))
                continue;
            assert(block.rank == b.rank);

            // Check for perfect match, which is directly mergeable
            if (block.size == b.size) {
                block = merge(block, b);
            } else {
                continue;
            }
            pprint(dag, "merged");

            // Merged succeed
            merged_roots.push_back(v);
        }

        for (Vertex root: merged_roots) {
            roots.erase(root);
            BOOST_FOREACH (Vertex v, boost::adjacent_vertices(root, dag)) {
                if (boost::in_degree(v, dag) <= 1) {
                    roots.insert(v);
                }
            }
            boost::clear_vertex(root, dag);
        }
    }
    return ret;
}

} // dag

vector<Block> fuser_topological(vector<Block> &block_list, const set<bh_instruction*> &news) {

    dag::DAG dag = dag::from_block_list(block_list);

    return dag::topological(dag);
}

} // jitk
} // bohrium
<commit_msg>jitk: now topological fully fuse<commit_after>/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium
team <http://www.bh107.org>.

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

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

You should have received a copy of the
GNU Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/

#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/foreach.hpp>
#include <fstream>

#include <jitk/fuser.hpp>

using namespace std;

namespace bohrium {
namespace jitk {

// Unnamed namespace for all fuser help functions
namespace {

// Check if 'a' and 'b' supports data-parallelism when merged
bool data_parallel_compatible(const bh_instruction *a, const bh_instruction *b)
{
    if(bh_opcode_is_system(a->opcode) || bh_opcode_is_system(b->opcode))
        return true;

    const int a_nop = bh_noperands(a->opcode);
    for(int i=0; i<a_nop; ++i)
    {
        if(not bh_view_disjoint(&b->operand[0], &a->operand[i])
           && not bh_view_aligned(&b->operand[0], &a->operand[i]))
            return false;
    }
    const int b_nop = bh_noperands(b->opcode);
    for(int i=0; i<b_nop; ++i)
    {
        if(not bh_view_disjoint(&a->operand[0], &b->operand[i])
           && not bh_view_aligned(&a->operand[0], &b->operand[i]))
            return false;
    }
    return true;
}

// Check if 'b1' and 'b2' supports data-parallelism when merged
bool data_parallel_compatible(const Block &b1, const Block &b2) {
    for (const bh_instruction *i1 : b1.getAllInstr()) {
        for (const bh_instruction *i2 : b2.getAllInstr()) {
            if (not data_parallel_compatible(i1, i2))
                return false;
        }
    }
    return true;
}

// Check if 'block' accesses the output of a sweep in 'sweeps'
bool sweeps_accessed_by_block(const set<bh_instruction*> &sweeps, const Block &block) {
    for (bh_instruction *instr: sweeps) {
        assert(bh_noperands(instr->opcode) > 0);
        auto bases = block.getAllBases();
        if (bases.find(instr->operand[0].base) != bases.end())
            return true;
    }
    return false;
}
} // Unnamed namespace

vector<Block> fuser_singleton(vector<bh_instruction> &instr_list, const set<bh_instruction*> &news) {

    // Creates the _block_list based on the instr_list
    vector<Block> block_list;
    for (auto instr=instr_list.begin(); instr != instr_list.end(); ++instr) {
        int nop = bh_noperands(instr->opcode);
        if (nop == 0)
            continue; // Ignore noop instructions such as BH_NONE or BH_TALLY

        // Let's try to simplify the shape of the instruction
        if (instr->reshapable()) {
            const vector<int64_t> dominating_shape = instr->dominating_shape();
            assert(dominating_shape.size() > 0);

            const int64_t totalsize = std::accumulate(dominating_shape.begin(), dominating_shape.end(), 1, \
                                                      std::multiplies<int64_t>());
            const vector<int64_t> shape = {totalsize};
            instr->reshape(shape);
        }
        // Let's create the block
        const vector<int64_t> dominating_shape = instr->dominating_shape();
        assert(dominating_shape.size() > 0);
        int64_t size_of_rank_dim = dominating_shape[0];
        vector<bh_instruction*> single_instr = {&instr[0]};
        block_list.push_back(create_nested_block(single_instr, 0, size_of_rank_dim, news));
    }
    return block_list;
}

// Merges the two blocks 'a' and 'a' (in that order)
pair<Block, bool> block_merge(const Block &a, const Block &b, const set<bh_instruction*> &news) {

    // First we check for data incompatibility
    if (b.isInstr() or not data_parallel_compatible(a, b) or sweeps_accessed_by_block(a._sweeps, b)) {
        return make_pair(Block(), false);
    }
    // Check for perfect match, which is directly mergeable
    if (a.size == b.size) {
        return make_pair(merge(a, b), true);
    }
    // Check fusibility of reshapable blocks
    if (b._reshapable && b.size % a.size == 0) {
        vector<bh_instruction *> cur_instr = a.getAllInstr();
        vector<bh_instruction *> it_instr = b.getAllInstr();
        cur_instr.insert(cur_instr.end(), it_instr.begin(), it_instr.end());
        return make_pair(create_nested_block(cur_instr, b.rank, a.size, news), true);
    }
    if (a._reshapable && a.size % b.size == 0) {
        vector<bh_instruction *> cur_instr = a.getAllInstr();
        vector<bh_instruction *> it_instr = b.getAllInstr();
        cur_instr.insert(cur_instr.end(), it_instr.begin(), it_instr.end());
        return make_pair(create_nested_block(cur_instr, a.rank, b.size, news), true);
    }
    return make_pair(Block(), false);
}

vector<Block> fuser_serial(vector<Block> &block_list, const set<bh_instruction*> &news) {
    vector<Block> ret;
    for (auto it = block_list.begin(); it != block_list.end(); ) {
        ret.push_back(*it);
        Block &cur = ret.back();
        ++it;
        if (cur.isInstr()) {
            continue; // We should never fuse instruction blocks
        }
        // Let's search for fusible blocks
        for (; it != block_list.end(); ++it) {
            const pair<Block, bool> res = block_merge(cur, *it, news);
            if (res.second) {
                cur = res.first;
            } else {
                break; // We couldn't find any shape match
            }
        }
        // Let's fuse at the next rank level
        cur._block_list = fuser_serial(cur._block_list, news);
    }
    return ret;
}

namespace dag {

//The type declaration of the boost graphs, vertices and edges.
typedef boost::adjacency_list<boost::setS, boost::vecS, boost::bidirectionalS, const Block*> DAG;
typedef typename boost::graph_traits<DAG>::edge_descriptor Edge;
typedef uint64_t Vertex;

/* Determines whether there exist a path from 'a' to 'b'
 *
 * Complexity: O(E + V)
 *
 * @a               The first vertex
 * @b               The second vertex
 * @dag             The DAG
 * @only_long_path  Only accept path of length greater than one
 * @return          True if there is a path
 */
bool path_exist(Vertex a, Vertex b, const DAG &dag, bool only_long_path) {
    using namespace boost;

    struct path_visitor:default_bfs_visitor {
        const Vertex dst;
        path_visitor(Vertex b):dst(b){};

        void examine_edge(Edge e, const DAG &g) const {
            if(target(e,g) == dst)
                throw runtime_error("");
        }
    };
    struct long_visitor:default_bfs_visitor {
        const Vertex src, dst;
        long_visitor(Vertex a, Vertex b):src(a),dst(b){};

        void examine_edge(Edge e, const DAG &g) const
        {
            if(source(e,g) != src and target(e,g) == dst)
                throw runtime_error("");
        }
    };
    try {
        if(only_long_path)
            breadth_first_search(dag, a, visitor(long_visitor(a,b)));
        else
            breadth_first_search(dag, a, visitor(path_visitor(b)));
    }
    catch (const runtime_error &e) {
        return true;
    }
    return false;
}

DAG from_block_list(const vector<Block> &block_list) {
    DAG graph;
    map<bh_base*, set<Vertex> > base2vertices;
    for (const Block &block: block_list) {
        Vertex vertex = boost::add_vertex(&block, graph);

        // Find all vertices that must connect to 'vertex'
        // using and updating 'base2vertices'
        set<Vertex> connecting_vertices;
        for (bh_base *base: block.getAllBases()) {
            set<Vertex> &vs = base2vertices[base];
            connecting_vertices.insert(vs.begin(), vs.end());
            vs.insert(vertex);
        }

        // Finally, let's add edges to 'vertex'
        BOOST_REVERSE_FOREACH (Vertex v, connecting_vertices) {
            if (vertex != v and block.depend_on(*graph[v])) {
                boost::add_edge(v, vertex, graph);
            }
        }
    }
    return graph;
}

void pprint(const DAG &dag, const string &filename) {

    //We define a graph and a kernel writer for graphviz
    struct graph_writer {
        const DAG &graph;
        graph_writer(const DAG &g) : graph(g) {};
        void operator()(std::ostream& out) const {
            out << "graph [bgcolor=white, fontname=\"Courier New\"]" << endl;
            out << "node [shape=box color=black, fontname=\"Courier New\"]" << endl;
        }
    };
    struct kernel_writer {
        const DAG &graph;
        kernel_writer(const DAG &g) : graph(g) {};
        void operator()(std::ostream& out, const Vertex& v) const {
            out << "[label=\"Kernel " << v;

            out << ", Instructions: \\l";
            for (const bh_instruction *instr: graph[v]->getAllInstr()) {
                out << *instr << "\\l";
            }
            out << "\"]";
        }
    };
    struct edge_writer {
        const DAG &graph;
        edge_writer(const DAG &g) : graph(g) {};
        void operator()(std::ostream& out, const Edge& e) const {

        }
    };

    static int count=0;
    stringstream ss;
    ss << filename << "-" << count++ << ".dot";
    ofstream file;
    cout << ss.str() << endl;
    file.open(ss.str());
    boost::write_graphviz(file, dag, kernel_writer(dag), edge_writer(dag), graph_writer(dag));
    file.close();
}

vector<Block> topological(DAG &dag, const set<bh_instruction*> &news) {
    vector<Block> ret;
    vector<Vertex> roots; // Set of root vertices
    // Initiate 'roots'
    BOOST_FOREACH (Vertex v, boost::vertices(dag)) {
        if (boost::in_degree(v, dag) == 0) {
            roots.push_back(v);
        }
    }

    while (not roots.empty()) { // Each iteration creates a new block
        const Vertex vertex = roots.back();
        roots.erase(roots.end()-1);
        ret.emplace_back(*dag[vertex]);
        Block &block = ret.back();

        // Add adjacent vertices and remove the block from 'dag'
        BOOST_FOREACH (const Vertex v, boost::adjacent_vertices(vertex, dag)) {
            if (boost::in_degree(v, dag) <= 1) {
                roots.push_back(v);
            }
        }
        boost::clear_vertex(vertex, dag);

        // Roots not fusible with 'block'
        vector<Vertex> nonfusible_roots;
        // Search for fusible blocks within the root blocks
        while (not roots.empty()) {
            const Vertex v = roots.back();
            roots.erase(roots.end()-1);
            const Block &b = *dag[v];

            const pair<Block, bool> res = block_merge(block, b, news);
            if (res.second) {
                block = res.first;

                // Add adjacent vertices and remove the block 'b' from 'dag'
                BOOST_FOREACH (const Vertex adj, boost::adjacent_vertices(v, dag)) {
                    if (boost::in_degree(adj, dag) <= 1) {
                        roots.push_back(adj);
                    }
                }
                boost::clear_vertex(v, dag);
            } else {
                nonfusible_roots.push_back(v);
            }
        }
        roots = nonfusible_roots;
    }
    return ret;
}

} // dag

vector<Block> fuser_topological(vector<Block> &block_list, const set<bh_instruction*> &news) {

    dag::DAG dag = dag::from_block_list(block_list);

    return dag::topological(dag, news);
}

} // jitk
} // bohrium
<|endoftext|>


<commit_before>/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium
team <http://www.bh107.org>.

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

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

You should have received a copy of the
GNU Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/

#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/foreach.hpp>
#include <fstream>
#include <numeric>
#include <queue>

#include <jitk/fuser.hpp>

using namespace std;

namespace bohrium {
namespace jitk {

// Unnamed namespace for all fuser help functions
namespace {

// Check if 'a' and 'b' supports data-parallelism when merged
bool data_parallel_compatible(const bh_instruction *a, const bh_instruction *b)
{
    if(bh_opcode_is_system(a->opcode) || bh_opcode_is_system(b->opcode))
        return true;

    const int a_nop = bh_noperands(a->opcode);
    for(int i=0; i<a_nop; ++i)
    {
        if(not bh_view_disjoint(&b->operand[0], &a->operand[i])
           && not bh_view_aligned(&b->operand[0], &a->operand[i]))
            return false;
    }
    const int b_nop = bh_noperands(b->opcode);
    for(int i=0; i<b_nop; ++i)
    {
        if(not bh_view_disjoint(&a->operand[0], &b->operand[i])
           && not bh_view_aligned(&a->operand[0], &b->operand[i]))
            return false;
    }
    return true;
}

// Check if 'b1' and 'b2' supports data-parallelism when merged
bool data_parallel_compatible(const Block &b1, const Block &b2) {
    for (const bh_instruction *i1 : b1.getAllInstr()) {
        for (const bh_instruction *i2 : b2.getAllInstr()) {
            if (not data_parallel_compatible(i1, i2))
                return false;
        }
    }
    return true;
}

// Check if 'block' accesses the output of a sweep in 'sweeps'
bool sweeps_accessed_by_block(const set<bh_instruction*> &sweeps, const Block &block) {
    for (bh_instruction *instr: sweeps) {
        assert(bh_noperands(instr->opcode) > 0);
        auto bases = block.getAllBases();
        if (bases.find(instr->operand[0].base) != bases.end())
            return true;
    }
    return false;
}
} // Unnamed namespace

vector<Block> fuser_singleton(vector<bh_instruction> &instr_list, const set<bh_instruction*> &news) {

    // Creates the _block_list based on the instr_list
    vector<Block> block_list;
    for (auto instr=instr_list.begin(); instr != instr_list.end(); ++instr) {
        int nop = bh_noperands(instr->opcode);
        if (nop == 0)
            continue; // Ignore noop instructions such as BH_NONE or BH_TALLY

        // Let's try to simplify the shape of the instruction
        if (instr->reshapable()) {
            const vector<int64_t> dominating_shape = instr->dominating_shape();
            assert(dominating_shape.size() > 0);

            const int64_t totalsize = std::accumulate(dominating_shape.begin(), dominating_shape.end(), 1, \
                                                      std::multiplies<int64_t>());
            const vector<int64_t> shape = {totalsize};
            instr->reshape(shape);
        }
        // Let's create the block
        const vector<int64_t> dominating_shape = instr->dominating_shape();
        assert(dominating_shape.size() > 0);
        int64_t size_of_rank_dim = dominating_shape[0];
        vector<bh_instruction*> single_instr = {&instr[0]};
        block_list.push_back(create_nested_block(single_instr, 0, size_of_rank_dim, news));
    }
    return block_list;
}

// Merges the two blocks 'a' and 'a' (in that order)
pair<Block, bool> block_merge(const Block &a, const Block &b, const set<bh_instruction*> &news) {
    assert(a.validation());
    assert(b.validation());

    // First we check for data incompatibility
    if (a.isInstr() or b.isInstr() or not data_parallel_compatible(a, b) or sweeps_accessed_by_block(a._sweeps, b)) {
        return make_pair(Block(), false);
    }
    // Check for perfect match, which is directly mergeable
    if (a.size == b.size) {
        return make_pair(merge(a, b), true);
    }

    // System-only blocks are very flexible because they array sizes does not have to match when reshaping
    // thus we can simply prepend/append system instructions without further checks.
    if (b.isSystemOnly()) {
        Block block(a);
        assert(block.validation());
        block.append_instr_list(b.getAllInstr());
        assert(block.validation());
        return make_pair(block, true);
    } else if (a.isSystemOnly()){
        Block block(b);
        assert(block.validation());
        block.prepend_instr_list(a.getAllInstr());
        assert(block.validation());
        return make_pair(block, true);
    }

    // Check fusibility of reshapable blocks
    if (b._reshapable && b.size % a.size == 0) {
        vector<bh_instruction *> cur_instr = a.getAllInstr();
        vector<bh_instruction *> it_instr = b.getAllInstr();
        cur_instr.insert(cur_instr.end(), it_instr.begin(), it_instr.end());
        return make_pair(create_nested_block(cur_instr, b.rank, a.size, news), true);
    }
    if (a._reshapable && a.size % b.size == 0) {
        vector<bh_instruction *> cur_instr = a.getAllInstr();
        vector<bh_instruction *> it_instr = b.getAllInstr();
        cur_instr.insert(cur_instr.end(), it_instr.begin(), it_instr.end());
        return make_pair(create_nested_block(cur_instr, a.rank, b.size, news), true);
    }
    return make_pair(Block(), false);
}

vector<Block> fuser_serial(const vector<Block> &block_list, const set<bh_instruction*> &news) {
    vector<Block> ret;
    for (auto it = block_list.begin(); it != block_list.end(); ) {
        ret.push_back(*it);
        Block &cur = ret.back();
        ++it;
        if (cur.isInstr()) {
            continue; // We should never fuse instruction blocks
        }
        // Let's search for fusible blocks
        for (; it != block_list.end(); ++it) {
            const pair<Block, bool> res = block_merge(cur, *it, news);
            if (res.second) {
                cur = res.first;
            } else {
                break; // We couldn't find any shape match
            }
        }
        // Let's fuse at the next rank level
        cur._block_list = fuser_serial(cur._block_list, news);
    }
    return ret;
}

namespace dag {

//The type declaration of the boost graphs, vertices and edges.
typedef boost::adjacency_list<boost::setS, boost::vecS, boost::bidirectionalS, const Block*> DAG;
typedef typename boost::graph_traits<DAG>::edge_descriptor Edge;
typedef uint64_t Vertex;

/* Determines whether there exist a path from 'a' to 'b'
 *
 * Complexity: O(E + V)
 *
 * @a               The first vertex
 * @b               The second vertex
 * @dag             The DAG
 * @only_long_path  Only accept path of length greater than one
 * @return          True if there is a path
 */
bool path_exist(Vertex a, Vertex b, const DAG &dag, bool only_long_path) {
    using namespace boost;

    struct path_visitor:default_bfs_visitor {
        const Vertex dst;
        path_visitor(Vertex b):dst(b){};

        void examine_edge(Edge e, const DAG &g) const {
            if(target(e,g) == dst)
                throw runtime_error("");
        }
    };
    struct long_visitor:default_bfs_visitor {
        const Vertex src, dst;
        long_visitor(Vertex a, Vertex b):src(a),dst(b){};

        void examine_edge(Edge e, const DAG &g) const
        {
            if(source(e,g) != src and target(e,g) == dst)
                throw runtime_error("");
        }
    };
    try {
        if(only_long_path)
            breadth_first_search(dag, a, visitor(long_visitor(a,b)));
        else
            breadth_first_search(dag, a, visitor(path_visitor(b)));
    }
    catch (const runtime_error &e) {
        return true;
    }
    return false;
}

// Create a DAG based on the 'block_list'
DAG from_block_list(const vector<Block> &block_list) {
    DAG graph;
    map<bh_base*, set<Vertex> > base2vertices;
    for (const Block &block: block_list) {
        assert(block.validation());
        Vertex vertex = boost::add_vertex(&block, graph);

        // Find all vertices that must connect to 'vertex'
        // using and updating 'base2vertices'
        set<Vertex> connecting_vertices;
        for (bh_base *base: block.getAllBases()) {
            set<Vertex> &vs = base2vertices[base];
            connecting_vertices.insert(vs.begin(), vs.end());
            vs.insert(vertex);
        }

        // Finally, let's add edges to 'vertex'
        BOOST_REVERSE_FOREACH (Vertex v, connecting_vertices) {
            if (vertex != v and block.depend_on(*graph[v])) {
                boost::add_edge(v, vertex, graph);
            }
        }
    }
    return graph;
}

// Pretty print the DAG. A "-<id>.dot" is append the filename.
void pprint(const DAG &dag, const string &filename) {

    //We define a graph and a kernel writer for graphviz
    struct graph_writer {
        const DAG &graph;
        graph_writer(const DAG &g) : graph(g) {};
        void operator()(std::ostream& out) const {
            out << "graph [bgcolor=white, fontname=\"Courier New\"]" << endl;
            out << "node [shape=box color=black, fontname=\"Courier New\"]" << endl;
        }
    };
    struct kernel_writer {
        const DAG &graph;
        kernel_writer(const DAG &g) : graph(g) {};
        void operator()(std::ostream& out, const Vertex& v) const {
            out << "[label=\"Kernel " << v;

            out << ", Instructions: \\l";
            for (const bh_instruction *instr: graph[v]->getAllInstr()) {
                out << *instr << "\\l";
            }
            out << "\"]";
        }
    };
    struct edge_writer {
        const DAG &graph;
        edge_writer(const DAG &g) : graph(g) {};
        void operator()(std::ostream& out, const Edge& e) const {

        }
    };

    static int count=0;
    stringstream ss;
    ss << filename << "-" << count++ << ".dot";
    ofstream file;
    cout << ss.str() << endl;
    file.open(ss.str());
    boost::write_graphviz(file, dag, kernel_writer(dag), edge_writer(dag), graph_writer(dag));
    file.close();
}

// Merges the vertices in 'dag' topologically using 'Queue' as the Vertex qeueue.
// 'Queue' is a collection of 'Vertex' that support push(), pop(), and empty().
template <typename Queue>
vector<Block> topological(DAG &dag, const set<bh_instruction*> &news) {
    vector<Block> ret;
    Queue roots; // The root vertices

    // Initiate 'roots'
    BOOST_FOREACH (Vertex v, boost::vertices(dag)) {
        if (boost::in_degree(v, dag) == 0) {
            roots.push(v);
        }
    }

    while (not roots.empty()) { // Each iteration creates a new block
        const Vertex vertex = roots.pop();
        ret.emplace_back(*dag[vertex]);
        Block &block = ret.back();

        // Add adjacent vertices and remove the block from 'dag'
        BOOST_FOREACH (const Vertex v, boost::adjacent_vertices(vertex, dag)) {
            if (boost::in_degree(v, dag) <= 1) {
                roots.push(v);
            }
        }
        boost::clear_vertex(vertex, dag);

        // Instruction blocks should never be merged
        if (block.isInstr()) {
            continue;
        }

        // Roots not fusible with 'block'
        Queue nonfusible_roots;
        // Search for fusible blocks within the root blocks
        while (not roots.empty()) {
            const Vertex v = roots.pop();
            const Block &b = *dag[v];
            const pair<Block, bool> res = block_merge(block, b, news);
            if (res.second) {
                block = res.first;
                assert(block.validation());

                // Add adjacent vertices and remove the block 'b' from 'dag'
                BOOST_FOREACH (const Vertex adj, boost::adjacent_vertices(v, dag)) {
                    if (boost::in_degree(adj, dag) <= 1) {
                        roots.push(adj);
                    }
                }
                boost::clear_vertex(v, dag);
            } else {
                nonfusible_roots.push(v);
            }
        }
        roots = nonfusible_roots;
    }
    return ret;
}

} // dag

vector<Block> fuser_breadth_first(const vector<Block> &block_list, const set<bh_instruction *> &news) {

    // Let's define a FIFO queue, which makes dag::topological() do a breadth first search
    class FifoQueue {
        queue<dag::Vertex> _queue;
    public:
        void push(dag::Vertex v) {
            _queue.push(v);
        }
        dag::Vertex pop() {
            dag::Vertex ret = _queue.front();
            _queue.pop();
            return ret;
        }
        bool empty() {
            return _queue.empty();
        }
    };

    dag::DAG dag = dag::from_block_list(block_list);
    vector<Block> ret = dag::topological<FifoQueue>(dag, news);

    // Let's fuse at the next rank level
    for (Block &b: ret) {
        if (not b.isInstr()) {
            b._block_list = fuser_breadth_first(b._block_list, news);
        }
    }
    return ret;
}

} // jitk
} // bohrium
<commit_msg>jitk: the queue template now takes the dag<commit_after>/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium
team <http://www.bh107.org>.

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

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

You should have received a copy of the
GNU Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/

#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/foreach.hpp>
#include <fstream>
#include <numeric>
#include <queue>

#include <jitk/fuser.hpp>

using namespace std;

namespace bohrium {
namespace jitk {

// Unnamed namespace for all fuser help functions
namespace {

// Check if 'a' and 'b' supports data-parallelism when merged
bool data_parallel_compatible(const bh_instruction *a, const bh_instruction *b)
{
    if(bh_opcode_is_system(a->opcode) || bh_opcode_is_system(b->opcode))
        return true;

    const int a_nop = bh_noperands(a->opcode);
    for(int i=0; i<a_nop; ++i)
    {
        if(not bh_view_disjoint(&b->operand[0], &a->operand[i])
           && not bh_view_aligned(&b->operand[0], &a->operand[i]))
            return false;
    }
    const int b_nop = bh_noperands(b->opcode);
    for(int i=0; i<b_nop; ++i)
    {
        if(not bh_view_disjoint(&a->operand[0], &b->operand[i])
           && not bh_view_aligned(&a->operand[0], &b->operand[i]))
            return false;
    }
    return true;
}

// Check if 'b1' and 'b2' supports data-parallelism when merged
bool data_parallel_compatible(const Block &b1, const Block &b2) {
    for (const bh_instruction *i1 : b1.getAllInstr()) {
        for (const bh_instruction *i2 : b2.getAllInstr()) {
            if (not data_parallel_compatible(i1, i2))
                return false;
        }
    }
    return true;
}

// Check if 'block' accesses the output of a sweep in 'sweeps'
bool sweeps_accessed_by_block(const set<bh_instruction*> &sweeps, const Block &block) {
    for (bh_instruction *instr: sweeps) {
        assert(bh_noperands(instr->opcode) > 0);
        auto bases = block.getAllBases();
        if (bases.find(instr->operand[0].base) != bases.end())
            return true;
    }
    return false;
}
} // Unnamed namespace

vector<Block> fuser_singleton(vector<bh_instruction> &instr_list, const set<bh_instruction*> &news) {

    // Creates the _block_list based on the instr_list
    vector<Block> block_list;
    for (auto instr=instr_list.begin(); instr != instr_list.end(); ++instr) {
        int nop = bh_noperands(instr->opcode);
        if (nop == 0)
            continue; // Ignore noop instructions such as BH_NONE or BH_TALLY

        // Let's try to simplify the shape of the instruction
        if (instr->reshapable()) {
            const vector<int64_t> dominating_shape = instr->dominating_shape();
            assert(dominating_shape.size() > 0);

            const int64_t totalsize = std::accumulate(dominating_shape.begin(), dominating_shape.end(), 1, \
                                                      std::multiplies<int64_t>());
            const vector<int64_t> shape = {totalsize};
            instr->reshape(shape);
        }
        // Let's create the block
        const vector<int64_t> dominating_shape = instr->dominating_shape();
        assert(dominating_shape.size() > 0);
        int64_t size_of_rank_dim = dominating_shape[0];
        vector<bh_instruction*> single_instr = {&instr[0]};
        block_list.push_back(create_nested_block(single_instr, 0, size_of_rank_dim, news));
    }
    return block_list;
}

// Merges the two blocks 'a' and 'a' (in that order)
pair<Block, bool> block_merge(const Block &a, const Block &b, const set<bh_instruction*> &news) {
    assert(a.validation());
    assert(b.validation());

    // First we check for data incompatibility
    if (a.isInstr() or b.isInstr() or not data_parallel_compatible(a, b) or sweeps_accessed_by_block(a._sweeps, b)) {
        return make_pair(Block(), false);
    }
    // Check for perfect match, which is directly mergeable
    if (a.size == b.size) {
        return make_pair(merge(a, b), true);
    }

    // System-only blocks are very flexible because they array sizes does not have to match when reshaping
    // thus we can simply prepend/append system instructions without further checks.
    if (b.isSystemOnly()) {
        Block block(a);
        assert(block.validation());
        block.append_instr_list(b.getAllInstr());
        assert(block.validation());
        return make_pair(block, true);
    } else if (a.isSystemOnly()){
        Block block(b);
        assert(block.validation());
        block.prepend_instr_list(a.getAllInstr());
        assert(block.validation());
        return make_pair(block, true);
    }

    // Check fusibility of reshapable blocks
    if (b._reshapable && b.size % a.size == 0) {
        vector<bh_instruction *> cur_instr = a.getAllInstr();
        vector<bh_instruction *> it_instr = b.getAllInstr();
        cur_instr.insert(cur_instr.end(), it_instr.begin(), it_instr.end());
        return make_pair(create_nested_block(cur_instr, b.rank, a.size, news), true);
    }
    if (a._reshapable && a.size % b.size == 0) {
        vector<bh_instruction *> cur_instr = a.getAllInstr();
        vector<bh_instruction *> it_instr = b.getAllInstr();
        cur_instr.insert(cur_instr.end(), it_instr.begin(), it_instr.end());
        return make_pair(create_nested_block(cur_instr, a.rank, b.size, news), true);
    }
    return make_pair(Block(), false);
}

vector<Block> fuser_serial(const vector<Block> &block_list, const set<bh_instruction*> &news) {
    vector<Block> ret;
    for (auto it = block_list.begin(); it != block_list.end(); ) {
        ret.push_back(*it);
        Block &cur = ret.back();
        ++it;
        if (cur.isInstr()) {
            continue; // We should never fuse instruction blocks
        }
        // Let's search for fusible blocks
        for (; it != block_list.end(); ++it) {
            const pair<Block, bool> res = block_merge(cur, *it, news);
            if (res.second) {
                cur = res.first;
            } else {
                break; // We couldn't find any shape match
            }
        }
        // Let's fuse at the next rank level
        cur._block_list = fuser_serial(cur._block_list, news);
    }
    return ret;
}

namespace dag {

//The type declaration of the boost graphs, vertices and edges.
typedef boost::adjacency_list<boost::setS, boost::vecS, boost::bidirectionalS, const Block*> DAG;
typedef typename boost::graph_traits<DAG>::edge_descriptor Edge;
typedef uint64_t Vertex;

/* Determines whether there exist a path from 'a' to 'b'
 *
 * Complexity: O(E + V)
 *
 * @a               The first vertex
 * @b               The second vertex
 * @dag             The DAG
 * @only_long_path  Only accept path of length greater than one
 * @return          True if there is a path
 */
bool path_exist(Vertex a, Vertex b, const DAG &dag, bool only_long_path) {
    using namespace boost;

    struct path_visitor:default_bfs_visitor {
        const Vertex dst;
        path_visitor(Vertex b):dst(b){};

        void examine_edge(Edge e, const DAG &g) const {
            if(target(e,g) == dst)
                throw runtime_error("");
        }
    };
    struct long_visitor:default_bfs_visitor {
        const Vertex src, dst;
        long_visitor(Vertex a, Vertex b):src(a),dst(b){};

        void examine_edge(Edge e, const DAG &g) const
        {
            if(source(e,g) != src and target(e,g) == dst)
                throw runtime_error("");
        }
    };
    try {
        if(only_long_path)
            breadth_first_search(dag, a, visitor(long_visitor(a,b)));
        else
            breadth_first_search(dag, a, visitor(path_visitor(b)));
    }
    catch (const runtime_error &e) {
        return true;
    }
    return false;
}

// Create a DAG based on the 'block_list'
DAG from_block_list(const vector<Block> &block_list) {
    DAG graph;
    map<bh_base*, set<Vertex> > base2vertices;
    for (const Block &block: block_list) {
        assert(block.validation());
        Vertex vertex = boost::add_vertex(&block, graph);

        // Find all vertices that must connect to 'vertex'
        // using and updating 'base2vertices'
        set<Vertex> connecting_vertices;
        for (bh_base *base: block.getAllBases()) {
            set<Vertex> &vs = base2vertices[base];
            connecting_vertices.insert(vs.begin(), vs.end());
            vs.insert(vertex);
        }

        // Finally, let's add edges to 'vertex'
        BOOST_REVERSE_FOREACH (Vertex v, connecting_vertices) {
            if (vertex != v and block.depend_on(*graph[v])) {
                boost::add_edge(v, vertex, graph);
            }
        }
    }
    return graph;
}

// Pretty print the DAG. A "-<id>.dot" is append the filename.
void pprint(const DAG &dag, const string &filename) {

    //We define a graph and a kernel writer for graphviz
    struct graph_writer {
        const DAG &graph;
        graph_writer(const DAG &g) : graph(g) {};
        void operator()(std::ostream& out) const {
            out << "graph [bgcolor=white, fontname=\"Courier New\"]" << endl;
            out << "node [shape=box color=black, fontname=\"Courier New\"]" << endl;
        }
    };
    struct kernel_writer {
        const DAG &graph;
        kernel_writer(const DAG &g) : graph(g) {};
        void operator()(std::ostream& out, const Vertex& v) const {
            out << "[label=\"Kernel " << v;

            out << ", Instructions: \\l";
            for (const bh_instruction *instr: graph[v]->getAllInstr()) {
                out << *instr << "\\l";
            }
            out << "\"]";
        }
    };
    struct edge_writer {
        const DAG &graph;
        edge_writer(const DAG &g) : graph(g) {};
        void operator()(std::ostream& out, const Edge& e) const {

        }
    };

    static int count=0;
    stringstream ss;
    ss << filename << "-" << count++ << ".dot";
    ofstream file;
    cout << ss.str() << endl;
    file.open(ss.str());
    boost::write_graphviz(file, dag, kernel_writer(dag), edge_writer(dag), graph_writer(dag));
    file.close();
}

// Merges the vertices in 'dag' topologically using 'Queue' as the Vertex qeueue.
// 'Queue' is a collection of 'Vertex' that is constructoed with the DAG and supports push(), pop(), and empty()
template <typename Queue>
vector<Block> topological(DAG &dag, const set<bh_instruction*> &news) {
    vector<Block> ret;
    Queue roots(dag); // The root vertices

    // Initiate 'roots'
    BOOST_FOREACH (Vertex v, boost::vertices(dag)) {
        if (boost::in_degree(v, dag) == 0) {
            roots.push(v);
        }
    }

    while (not roots.empty()) { // Each iteration creates a new block
        const Vertex vertex = roots.pop();
        ret.emplace_back(*dag[vertex]);
        Block &block = ret.back();

        // Add adjacent vertices and remove the block from 'dag'
        BOOST_FOREACH (const Vertex v, boost::adjacent_vertices(vertex, dag)) {
            if (boost::in_degree(v, dag) <= 1) {
                roots.push(v);
            }
        }
        boost::clear_vertex(vertex, dag);

        // Instruction blocks should never be merged
        if (block.isInstr()) {
            continue;
        }

        // Roots not fusible with 'block'
        Queue nonfusible_roots(dag);
        // Search for fusible blocks within the root blocks
        while (not roots.empty()) {
            const Vertex v = roots.pop();
            const Block &b = *dag[v];
            const pair<Block, bool> res = block_merge(block, b, news);
            if (res.second) {
                block = res.first;
                assert(block.validation());

                // Add adjacent vertices and remove the block 'b' from 'dag'
                BOOST_FOREACH (const Vertex adj, boost::adjacent_vertices(v, dag)) {
                    if (boost::in_degree(adj, dag) <= 1) {
                        roots.push(adj);
                    }
                }
                boost::clear_vertex(v, dag);
            } else {
                nonfusible_roots.push(v);
            }
        }
        roots = nonfusible_roots;
    }
    return ret;
}

} // dag

vector<Block> fuser_breadth_first(const vector<Block> &block_list, const set<bh_instruction *> &news) {

    // Let's define a FIFO queue, which makes dag::topological() do a breadth first search
    class FifoQueue {
        queue<dag::Vertex> _queue;
    public:
        FifoQueue(const dag::DAG &dag) {}
        void push(dag::Vertex v) {
            _queue.push(v);
        }
        dag::Vertex pop() {
            dag::Vertex ret = _queue.front();
            _queue.pop();
            return ret;
        }
        bool empty() {
            return _queue.empty();
        }
    };

    dag::DAG dag = dag::from_block_list(block_list);
    vector<Block> ret = dag::topological<FifoQueue>(dag, news);

    // Let's fuse at the next rank level
    for (Block &b: ret) {
        if (not b.isInstr()) {
            b._block_list = fuser_breadth_first(b._block_list, news);
        }
    }
    return ret;
}

} // jitk
} // bohrium
<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int H, W, d;

char c[4] = {'R', 'Y', 'G', 'B'};

int area(int x, int y) {
  int cnt = x/(d+1) + y/d;
  return cnt%2;
}

int which(int x, int y) {
  int nx = x % (d+1);
  int ny = y % d;
  if (nx + ny < d) {
    return 0;
  } else {
    return 1;
  }
}

int main () {
  cin >> H >> W >> d;
  int ans[510][510];
  for (auto i = 0; i < H; ++i) {
    for (auto j = 0; j < W; ++j) {
      ans[i][j] = area(i, j) * 2 + which(i, j);
    }
  }
  for (auto i = 0; i < H; ++i) {
    for (auto j = 0; j < W; ++j) {
      cout << c[ans[i][j]];
      if (j == W-1) {
        cout << endl;
      }
    }
  }
}
<commit_msg>tried D.cpp to 'D'<commit_after>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int H, W, D, d;

char c[4] = {'R', 'Y', 'G', 'B'};

int area(int x, int y) {
  int cnt = x/(d+1) + y/d;
  return cnt%2;
}

int which(int x, int y) {
  int nx = x % (d+1);
  int ny = y % d;
  if (nx + ny < d) {
    return 0;
  } else {
    return 1;
  }
}

int main () {
  cin >> H >> W >> D;
  d = (D+1)/2;
  int ans[510][510];
  for (auto i = 0; i < H; ++i) {
    for (auto j = 0; j < W; ++j) {
      ans[i][j] = area(i, j) * 2 + which(i, j);
    }
  }
  for (auto i = 0; i < H; ++i) {
    for (auto j = 0; j < W; ++j) {
      cout << c[ans[i][j]];
      if (j == W-1) {
        cout << endl;
      }
    }
  }
}
<|endoftext|>