<commit_before>/*******************************************************************************
* ALMA - Atacama Large Millimiter Array
* (c) European Southern Observatory, 2011
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*
* "@(#) $Id: bulkDataNTDDSSubscriber.cpp,v 1.18 2012/01/19 15:34:39 bjeram Exp $"
*
* who       when      what
* --------  --------  ----------------------------------------------
* bjeram  2011-04-19  created
*/

#include "bulkDataNTDDSSubscriber.h"
#include <iostream>

using namespace AcsBulkdata;
using namespace std;
using namespace ACSErrTypeCommon;
using namespace ACS_DDS_Errors;

BulkDataNTDDSSubscriber::BulkDataNTDDSSubscriber(DDS::DomainParticipant *p, const DDSConfiguration &ddsCfg) :
		BulkDataNTDDS(p, ddsCfg)
{
	subscriber_m = createDDSSubscriber();
}

BulkDataNTDDSSubscriber::~BulkDataNTDDSSubscriber()
{
	try
	{
		destroyDDSSubscriber();
	}
	catch(ACSErr::ACSbaseExImpl &ex)
	{
		ex.log();
	}
}//~BulkDataNTDDSSubscriber

DDS::Subscriber* BulkDataNTDDSSubscriber::createDDSSubscriber()
{
	AUTO_TRACE(__PRETTY_FUNCTION__);
	DDS::ReturnCode_t ret;

	if (participant_m==NULL)
	{
		printf("BulkDataNTDDSSubscriber::BulkDataNTDDSSubscriber participant NULL\n");
		return NULL;
	}

	DDS::Subscriber *sub = participant_m->create_subscriber_with_profile(
			ddsCfg_m.libraryQos.c_str(), ddsCfg_m.profileQos.c_str(),
			0, DDS::STATUS_MASK_NONE);
	if(sub==NULL)
	{
		DDSSubscriberCreateProblemExImpl ex(__FILE__, __LINE__, __PRETTY_FUNCTION__);
		throw ex;
	}

	ret = sub->enable();
	if (ret!=DDS::RETCODE_OK)
	{
		DDSSubscriberEnableProblemExImpl ex(__FILE__, __LINE__, __PRETTY_FUNCTION__);
		ex.setDDSTypeCode(ret);
	}

	return sub;
}//createDDSSubscriber

void BulkDataNTDDSSubscriber::destroyDDSSubscriber()
{
	AUTO_TRACE(__PRETTY_FUNCTION__);
	DDS::ReturnCode_t ret;
	ret = participant_m->delete_subscriber(subscriber_m);
	subscriber_m = 0;
	if (ret!=DDS::RETCODE_OK)
	{
		DDSSubscriberDestroyProblemExImpl ex(__FILE__, __LINE__, __PRETTY_FUNCTION__);
		ex.setDDSTypeCode(ret);
		throw ex;
	}//if
}//destroyDDSSubscriber

ACSBulkData::BulkDataNTFrameDataReader* BulkDataNTDDSSubscriber::createDDSReader(DDS::Topic *topic, DDS::DataReaderListener *listener)
{
	AUTO_TRACE(__PRETTY_FUNCTION__);

	if (subscriber_m==NULL || topic==NULL || listener==NULL)
	{
		NullPointerExImpl ex(__FILE__, __LINE__, __PRETTY_FUNCTION__);
		ex.setVariable("publisher_m, topic or listener");
		throw ex;
	}

	DDS::DataReader *dr = subscriber_m->create_datareader_with_profile(topic,
			ddsCfg_m.libraryQos.c_str(), ddsCfg_m.profileQos.c_str(),
			listener,
			DDS::STATUS_MASK_ALL);
	if(dr==NULL)
	{
		DDSDRCreateProblemExImpl ex(__FILE__, __LINE__, __PRETTY_FUNCTION__);
		throw ex;
	}//if

	return ACSBulkData::BulkDataNTFrameDataReader::narrow(dr);
}

void BulkDataNTDDSSubscriber::destroyDDSReader(ACSBulkData::BulkDataNTFrameDataReader *dr)
{
	AUTO_TRACE(__PRETTY_FUNCTION__);
	DDS::ReturnCode_t ret;

	ret = subscriber_m->delete_datareader(dr);
	if (ret!=DDS::RETCODE_OK)
	{
		ACS_SHORT_LOG((LM_ERROR, "Problem deleting data reader (%d)", ret));
	}
}
<commit_msg>create data reader disabled + enable it<commit_after>/*******************************************************************************
* ALMA - Atacama Large Millimiter Array
* (c) European Southern Observatory, 2011
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*
* "@(#) $Id: bulkDataNTDDSSubscriber.cpp,v 1.19 2012/01/19 15:53:55 bjeram Exp $"
*
* who       when      what
* --------  --------  ----------------------------------------------
* bjeram  2011-04-19  created
*/

#include "bulkDataNTDDSSubscriber.h"
#include <iostream>

using namespace AcsBulkdata;
using namespace std;
using namespace ACSErrTypeCommon;
using namespace ACS_DDS_Errors;

BulkDataNTDDSSubscriber::BulkDataNTDDSSubscriber(DDS::DomainParticipant *p, const DDSConfiguration &ddsCfg) :
		BulkDataNTDDS(p, ddsCfg)
{
	subscriber_m = createDDSSubscriber();
}

BulkDataNTDDSSubscriber::~BulkDataNTDDSSubscriber()
{
	try
	{
		destroyDDSSubscriber();
	}
	catch(ACSErr::ACSbaseExImpl &ex)
	{
		ex.log();
	}
}//~BulkDataNTDDSSubscriber

DDS::Subscriber* BulkDataNTDDSSubscriber::createDDSSubscriber()
{
	AUTO_TRACE(__PRETTY_FUNCTION__);
	DDS::ReturnCode_t ret;
	DDS::SubscriberQos sub_qos;

	if (participant_m==NULL)
	{
		printf("BulkDataNTDDSSubscriber::BulkDataNTDDSSubscriber participant NULL\n");
		return NULL;
	}

	DDS::Subscriber *sub = participant_m->create_subscriber_with_profile(
			ddsCfg_m.libraryQos.c_str(), ddsCfg_m.profileQos.c_str(),
			0, DDS::STATUS_MASK_NONE);
	if(sub==NULL)
	{
		DDSSubscriberCreateProblemExImpl ex(__FILE__, __LINE__, __PRETTY_FUNCTION__);
		throw ex;
	}

	ret = sub->get_qos(sub_qos);
	if (ret!=DDS::RETCODE_OK)
	{
		DDSQoSGetProblemExImpl ex(__FILE__, __LINE__, __PRETTY_FUNCTION__);
		ex.setDDSTypeCode(ret);
		ex.setQoS("sub->get_qos()");
		throw ex;
	}//if

	/// dr has to be created disabled
	sub_qos.entity_factory.autoenable_created_entities=DDS_BOOLEAN_FALSE;

	ret = sub->set_qos(sub_qos);
	if (ret!=DDS::RETCODE_OK)
	{
		DDSQoSSetProblemExImpl ex(__FILE__, __LINE__, __PRETTY_FUNCTION__);
		ex.setDDSTypeCode(ret);
		ex.setQoS("sub->set_qos()");
		throw ex;
	}//if

	ret = sub->enable();
	if (ret!=DDS::RETCODE_OK)
	{
		DDSSubscriberEnableProblemExImpl ex(__FILE__, __LINE__, __PRETTY_FUNCTION__);
		ex.setDDSTypeCode(ret);
	}

	return sub;
}//createDDSSubscriber

void BulkDataNTDDSSubscriber::destroyDDSSubscriber()
{
	AUTO_TRACE(__PRETTY_FUNCTION__);
	DDS::ReturnCode_t ret;
	ret = participant_m->delete_subscriber(subscriber_m);
	subscriber_m = 0;
	if (ret!=DDS::RETCODE_OK)
	{
		DDSSubscriberDestroyProblemExImpl ex(__FILE__, __LINE__, __PRETTY_FUNCTION__);
		ex.setDDSTypeCode(ret);
		throw ex;
	}//if
}//destroyDDSSubscriber

ACSBulkData::BulkDataNTFrameDataReader* BulkDataNTDDSSubscriber::createDDSReader(DDS::Topic *topic, DDS::DataReaderListener *listener)
{
	AUTO_TRACE(__PRETTY_FUNCTION__);
	DDS::ReturnCode_t ret;

	if (subscriber_m==NULL || topic==NULL || listener==NULL)
	{
		NullPointerExImpl ex(__FILE__, __LINE__, __PRETTY_FUNCTION__);
		ex.setVariable("publisher_m, topic or listener");
		throw ex;
	}

	DDS::DataReader *dr = subscriber_m->create_datareader_with_profile(topic,
			ddsCfg_m.libraryQos.c_str(), ddsCfg_m.profileQos.c_str(),
			listener,
			DDS::STATUS_MASK_ALL);
	if(dr==NULL)
	{
		DDSDRCreateProblemExImpl ex(__FILE__, __LINE__, __PRETTY_FUNCTION__);
		throw ex;
	}//if
/*
	if (noOfReaders==1)
			{
				//multicast
				struct DDS_TransportMulticastSettings_t* multicast_locator = NULL;
				// DDS_TransportMulticastSettingsSeq_ensure_length(&, 1, 1);
				dr_qos.multicast.value.ensure_length(1,1);
				// DDS_TransportMulticastSettingsSeq_get_reference(&qos.multicast.value,0);
				multicast_locator = &dr_qos.multicast.value[0];

				string mcasta="225.3.2.1";
				DDS_String_replace(&multicast_locator->receive_address,	mcasta.c_str()	);
				cout << "going to listen on multicast address: " << mcasta << endl;

				dr_qos.resource_limits.initial_samples *= 1;//multicast_reader_count;
				if (dr_qos.resource_limits.initial_samples >
					dr_qos.resource_limits.max_samples) {
					dr_qos.resource_limits.max_samples =
							dr_qos.resource_limits.initial_samples;
				}
				dr_qos.reader_resource_limits.max_samples_per_remote_writer =
						dr_qos.resource_limits.initial_samples;
			}
			else
			{
				dr_qos.unicast.value.ensure_length(1,1);
			}

*/
	ret = dr->enable();
	if (ret!=DDS::RETCODE_OK)
	{
		DDSDREnableProblemExImpl ex(__FILE__, __LINE__, __PRETTY_FUNCTION__);
		ex.setDDSTypeCode(ret);
	}

	return ACSBulkData::BulkDataNTFrameDataReader::narrow(dr);
}

void BulkDataNTDDSSubscriber::destroyDDSReader(ACSBulkData::BulkDataNTFrameDataReader *dr)
{
	AUTO_TRACE(__PRETTY_FUNCTION__);
	DDS::ReturnCode_t ret;

	ret = subscriber_m->delete_datareader(dr);
	if (ret!=DDS::RETCODE_OK)
	{
		ACS_SHORT_LOG((LM_ERROR, "Problem deleting data reader (%d)", ret));
	}
}
<|endoftext|>


<commit_before>/*! \file unitTestKeplerPropagator.cpp
 *    Source file that defines a unit test that tests the Kepler propagator included in Tudat.
 *
 *    Path              : /Astrodynamics/Propagators/
 *    Version           : 4
 *    Check status      : Checked
 *
 *    Author            : K. Kumar
 *    Affiliation       : Delft University of Technology
 *    E-mail address    : K.Kumar@tudelft.nl
 *
 *    Checker           : E. Iorfida
 *    Affiliation       : Delft University of Technology
 *    E-mail address    : elisabetta_iorfida@yahoo.it
 *
 *    Date created      : 16 February, 2011
 *    Last modified     : 20 September, 2011
 *
 *    References
 *      Melman, J. Propagate software, J.C.P.Melman@tudelft.nl, 2010.
 *
 *    Notes
 *      Test runs code and verifies result against expected value.
 *      If the tested code is erroneous, the test function returns a boolean
 *      true; if the code is correct, the function returns a boolean false.
 *
 *      Currently, this file makes use of benchmark data provided by J. Melman.
 *      In future, it is desirable that the benchmark data is the direct output
 *      of a commercial package such as STK, where are initial conditions of
 *      the simulation are known.
 *
 *    Copyright (c) 2010-2011 Delft University of Technology.
 *
 *    This software is protected by national and international copyright.
 *    Any unauthorized use, reproduction or modification is unlawful and
 *    will be prosecuted. Commercial and non-private application of the
 *    software in any form is strictly prohibited unless otherwise granted
 *    by the authors.
 *
 *    The code is provided without any warranty; without even the implied
 *    warranty of merchantibility or fitness for a particular purpose.
 *
 *    Changelog
 *      YYMMDD    Author            Comment
 *      110216    K. Kumar          First creation of code.
 *      110217    E. Iorfida        Minor changes made.
 *      110221    K. Kumar          Updated variable-naming to comply with protocol.
 *      110920    K. Kumar          Corrected simple errors outlined by M. Persson.
 */

// Include statements.
#include <cmath>
#include <iostream>
#include <fstream>
#include <map>
#include <string>
#include "Astrodynamics/Bodies/celestialBody.h"
#include "Astrodynamics/Bodies/planet.h"
#include "Astrodynamics/Bodies/vehicle.h"
#include "Astrodynamics/Propagators/keplerPropagator.h"
#include "Astrodynamics/Propagators/seriesPropagator.h"
#include "Astrodynamics/States/cartesianElements.h"
#include "Astrodynamics/States/state.h"
#include "Basics/basicFunctions.h"
#include "Mathematics/basicMathematicsFunctions.h"
#include "Mathematics/RootFindingMethods/newtonRaphson.h"
#include "Mathematics/unitConversions.h"

//! Test implementation of Kepler propagator class.
int main( )
{
    // Using declarations.
    using namespace tudat;

    // Test to see if the orbit of a satellite around the Earth is correctly
    // reproduced with respect to benchmark reference data.

    // Test result initialised to false.
    bool isKeplerPropagatorErroneous = false;

    // Load benchmark data.
    // This data originates from J. Melman and is generated by the software
    // package Propagate. The benchmark data was verified against output from
    // Satellite Toolkit (STK).

    // Load file with benchmark data.
    std::string relativePathToBenchmarkData = "Astrodynamics/Propagators/twoBodyKeplerData.dat";

    std::string absolutePathToBenchmarkData = basic_functions::getRootPath( )
            + relativePathToBenchmarkData;

    std::ifstream twoBodyKeplerBenchmarkFile( absolutePathToBenchmarkData.c_str( ) );

    // Check if file could be opened.
    if ( !twoBodyKeplerBenchmarkFile )
    {
        std::cerr << "Error: Two-body Kepler benchmark data file could not be opened."
                  << std::endl;
        std::cerr << absolutePathToBenchmarkData << std::endl;
    }

    // Create propagation history map for benchmark data to be stored in.
    std::map < double, CartesianElements > benchmarkKeplerPropagationHistory;

    // Declare elapsed time.
    double elapsedTime = 0.0;

    // Initialize counter.
    unsigned int twoBodyKeplerDataCounter = 0;

    // Populate propagation history map with benchmark data from file.
    while ( !twoBodyKeplerBenchmarkFile.eof( ) )
    {
        // Store elapsed time which is given in first coloumn.
        twoBodyKeplerBenchmarkFile >> elapsedTime;

        // Store state date from file.
        for ( unsigned int i = 0; i < 6; i++ )
        {
            twoBodyKeplerBenchmarkFile >> benchmarkKeplerPropagationHistory[
                                          twoBodyKeplerDataCounter * 3600.0 ].state( i );
        }

        // Increment counter.
        twoBodyKeplerDataCounter++;
    }

    // Close benchmark data file.
    twoBodyKeplerBenchmarkFile.close( );

    // Run Kepler propagator simulation.

    // Create pointer to the state of satellite Asterix given in Cartesian
    // elements.
    CartesianElements stateOfAsterix;

    // Fill initial state vector with position and
    // velocity given for Asterix.
    // Position is given in kilometers and
    // velocity is given in kilometers per second.
    stateOfAsterix.setCartesianElementX( 6.75e3 );
    stateOfAsterix.setCartesianElementY( 0.0 );
    stateOfAsterix.setCartesianElementZ( 0.0 );
    stateOfAsterix.setCartesianElementXDot( 0.0 );
    stateOfAsterix.setCartesianElementYDot( 8.0595973215 );
    stateOfAsterix.setCartesianElementZDot( 0.0 );

    // Convert initial state vector to meters from
    // kilometers.
    stateOfAsterix.state = unit_conversions::convertKilometersToMeters( stateOfAsterix.state );

    // Create map of propagation history of Asterix using a Kepler propagator
    // and a map iterator.
    std::map < double, State > asterixKeplerPropagationHistory;
    std::map < double, State >::iterator iteratorAsterixKeplerPropagationHistory;

    // Create a pointer to new vehicle for Asterix.
    Vehicle asterix;

    // Create pre-defined Earth object.
    Planet predefinedEarth;
    predefinedEarth.setPredefinedPlanetSettings( Planet::earth );

    // Create Newton-Raphson object.
    NewtonRaphson newtonRaphson;

    // Create Kepler propagator object.
    KeplerPropagator keplerPropagator;

    // Set Newton-Raphson method.
    keplerPropagator.setNewtonRaphson( &newtonRaphson );

    // Add Asterix as the body that has to be propagated.
    keplerPropagator.addBody( &asterix );

    // Set the central body for Asterix
    keplerPropagator.setCentralBody( &asterix, &predefinedEarth );

    // Create series propagator.
    SeriesPropagator seriesPropagator;

    // Set the series propagation start time.
    seriesPropagator.setSeriesPropagationStart( 0.0 );

    // Set the propagation end time.
    seriesPropagator.setSeriesPropagationEnd( 86400.0 );

    // Set fixed output interval for series propagation.
    seriesPropagator.setFixedOutputInterval( 3600.0 );

    // Set Kepler propagator for series propagation.
    seriesPropagator.setPropagator( &keplerPropagator );

    // Set initial state of Asterix.
    seriesPropagator.setInitialState( &asterix, &stateOfAsterix );

    // Run simulation.
    seriesPropagator.execute( );

    // Get series propagation history of Asterix.
    asterixKeplerPropagationHistory
            = seriesPropagator
              .getPropagationHistoryAtFixedOutputIntervals( &asterix );

    // Compute propagation history state data from meters to kilometers.
    for ( iteratorAsterixKeplerPropagationHistory = asterixKeplerPropagationHistory.begin( );
          iteratorAsterixKeplerPropagationHistory != asterixKeplerPropagationHistory.end( );
          iteratorAsterixKeplerPropagationHistory++ )
    {
        iteratorAsterixKeplerPropagationHistory->second.state
                = unit_conversions::convertMetersToKilometers(
                    iteratorAsterixKeplerPropagationHistory->second.state );
    }

    // Declare tolerance between benchmark data and simulation data.
    double toleranceBetweenBenchmarkAndSimulationData = 1e-6;

    // Declare difference between benchmark data and simulation data.
    double differenceKeplerData;

    // Check if results match benchmark data.
    for ( unsigned int i = 0; i < ( seriesPropagator.getSeriesPropagationStart( )
                                    / seriesPropagator.getFixedOutputInterval( ) ); i++ )
    {
        // Initialize difference in data.
        differenceKeplerData = 0.0;

        for ( unsigned int i = 0; i < 6; i++ )
        {
            differenceKeplerData += std::fabs(
                        asterixKeplerPropagationHistory[ i * seriesPropagator
                        .getFixedOutputInterval( ) ].state( i )
                        - benchmarkKeplerPropagationHistory[  i * seriesPropagator
                        .getFixedOutputInterval( ) ].state( i ) );
        }

        if ( differenceKeplerData > toleranceBetweenBenchmarkAndSimulationData )
        {
            isKeplerPropagatorErroneous = true;

            std::cerr << "The Kepler propagator does not produce consistent results, as running a "
                      << "simulation with does not yield the same results as the benchmark data "
                      << "given the same initial conditions." << std::endl;
        }
    }

    // Return test result.
    // If test is successful return false; if test fails, return true.
    if ( isKeplerPropagatorErroneous )
    {
        std::cerr << "testKeplerPropagator failed!" << endl;
    }

    return isKeplerPropagatorErroneous;
}

// End of file.
<commit_msg>Commit of correction to Kepler propagator unit test.<commit_after>/*! \file unitTestKeplerPropagator.cpp
 *    Source file that defines a unit test that tests the Kepler propagator included in Tudat.
 *
 *    Path              : /Astrodynamics/Propagators/
 *    Version           : 4
 *    Check status      : Checked
 *
 *    Author            : K. Kumar
 *    Affiliation       : Delft University of Technology
 *    E-mail address    : K.Kumar@tudelft.nl
 *
 *    Checker           : E. Iorfida
 *    Affiliation       : Delft University of Technology
 *    E-mail address    : elisabetta_iorfida@yahoo.it
 *
 *    Date created      : 16 February, 2011
 *    Last modified     : 20 September, 2011
 *
 *    References
 *      Melman, J. Propagate software, J.C.P.Melman@tudelft.nl, 2010.
 *
 *    Notes
 *      Test runs code and verifies result against expected value.
 *      If the tested code is erroneous, the test function returns a boolean
 *      true; if the code is correct, the function returns a boolean false.
 *
 *      Currently, this file makes use of benchmark data provided by J. Melman.
 *      In future, it is desirable that the benchmark data is the direct output
 *      of a commercial package such as STK, where are initial conditions of
 *      the simulation are known.
 *
 *    Copyright (c) 2010-2011 Delft University of Technology.
 *
 *    This software is protected by national and international copyright.
 *    Any unauthorized use, reproduction or modification is unlawful and
 *    will be prosecuted. Commercial and non-private application of the
 *    software in any form is strictly prohibited unless otherwise granted
 *    by the authors.
 *
 *    The code is provided without any warranty; without even the implied
 *    warranty of merchantibility or fitness for a particular purpose.
 *
 *    Changelog
 *      YYMMDD    Author            Comment
 *      110216    K. Kumar          First creation of code.
 *      110217    E. Iorfida        Minor changes made.
 *      110221    K. Kumar          Updated variable-naming to comply with protocol.
 *      110920    K. Kumar          Corrected simple errors outlined by M. Persson.
 */

// Include statements.
#include <cmath>
#include <iostream>
#include <fstream>
#include <map>
#include <string>
#include "Astrodynamics/Bodies/celestialBody.h"
#include "Astrodynamics/Bodies/planet.h"
#include "Astrodynamics/Bodies/vehicle.h"
#include "Astrodynamics/EnvironmentModels/centralGravityField.h"
#include "Astrodynamics/Propagators/keplerPropagator.h"
#include "Astrodynamics/Propagators/seriesPropagator.h"
#include "Astrodynamics/States/cartesianElements.h"
#include "Astrodynamics/States/state.h"
#include "Basics/basicFunctions.h"
#include "Mathematics/basicMathematicsFunctions.h"
#include "Mathematics/RootFindingMethods/newtonRaphson.h"
#include "Mathematics/unitConversions.h"

//! Test implementation of Kepler propagator class.
int main( )
{
    // Using declarations.
    using namespace tudat;

    // Test to see if the orbit of a satellite around the Earth is correctly
    // reproduced with respect to benchmark reference data.

    // Test result initialised to false.
    bool isKeplerPropagatorErroneous = false;

    // Load benchmark data.
    // This data originates from J. Melman and is generated by the software
    // package Propagate. The benchmark data was verified against output from
    // Satellite Toolkit (STK).

    // Load file with benchmark data.
    std::string relativePathToBenchmarkData = "Astrodynamics/Propagators/twoBodyKeplerData.dat";

    std::string absolutePathToBenchmarkData = basic_functions::getRootPath( )
            + relativePathToBenchmarkData;

    std::ifstream twoBodyKeplerBenchmarkFile( absolutePathToBenchmarkData.c_str( ) );

    // Check if file could be opened.
    if ( !twoBodyKeplerBenchmarkFile )
    {
        std::cerr << "Error: Two-body Kepler benchmark data file could not be opened."
                  << std::endl;
        std::cerr << absolutePathToBenchmarkData << std::endl;
    }

    // Create propagation history map for benchmark data to be stored in.
    std::map < double, CartesianElements > benchmarkKeplerPropagationHistory;

    // Declare elapsed time.
    double elapsedTime = 0.0;

    // Initialize counter.
    unsigned int twoBodyKeplerDataCounter = 0;

    // Populate propagation history map with benchmark data from file.
    while ( !twoBodyKeplerBenchmarkFile.eof( ) )
    {
        // Store elapsed time which is given in first coloumn.
        twoBodyKeplerBenchmarkFile >> elapsedTime;

        // Store state date from file.
        for ( unsigned int i = 0; i < 6; i++ )
        {
            twoBodyKeplerBenchmarkFile >> benchmarkKeplerPropagationHistory[
                                          twoBodyKeplerDataCounter * 3600.0 ].state( i );
        }

        // Increment counter.
        twoBodyKeplerDataCounter++;
    }

    // Close benchmark data file.
    twoBodyKeplerBenchmarkFile.close( );

    // Run Kepler propagator simulation.

    // Create pointer to the state of satellite Asterix given in Cartesian
    // elements.
    CartesianElements stateOfAsterix;

    // Fill initial state vector with position and
    // velocity given for Asterix.
    // Position is given in kilometers and
    // velocity is given in kilometers per second.
    stateOfAsterix.setCartesianElementX( 6.75e3 );
    stateOfAsterix.setCartesianElementY( 0.0 );
    stateOfAsterix.setCartesianElementZ( 0.0 );
    stateOfAsterix.setCartesianElementXDot( 0.0 );
    stateOfAsterix.setCartesianElementYDot( 8.0595973215 );
    stateOfAsterix.setCartesianElementZDot( 0.0 );

    // Convert initial state vector to meters from
    // kilometers.
    stateOfAsterix.state = unit_conversions::convertKilometersToMeters( stateOfAsterix.state );

    // Create map of propagation history of Asterix using a Kepler propagator
    // and a map iterator.
    std::map < double, State > asterixKeplerPropagationHistory;
    std::map < double, State >::iterator iteratorAsterixKeplerPropagationHistory;

    // Create a pointer to new vehicle for Asterix.
    Vehicle asterix;

    // Create Earth central gravity field.
    CentralGravityField earthCentralGravityField;

    // Set Earth gravitational parameter.
    earthCentralGravityField.setGravitationalParameter( 3.986004415e14 );

    // Create Earth object and set central gravity field.
    Planet earth;
    earth.setGravityFieldModel( &earthCentralGravityField );

    // Create Newton-Raphson object.
    NewtonRaphson newtonRaphson;

    // Create Kepler propagator object.
    KeplerPropagator keplerPropagator;

    // Set Newton-Raphson method.
    keplerPropagator.setNewtonRaphson( &newtonRaphson );

    // Add Asterix as the body that has to be propagated.
    keplerPropagator.addBody( &asterix );

    // Set the central body for Asterix
    keplerPropagator.setCentralBody( &asterix, &earth );

    // Create series propagator.
    SeriesPropagator seriesPropagator;

    // Set the series propagation start time.
    seriesPropagator.setSeriesPropagationStart( 0.0 );

    // Set the propagation end time.
    seriesPropagator.setSeriesPropagationEnd( 86400.0 );

    // Set fixed output interval for series propagation.
    seriesPropagator.setFixedOutputInterval( 3600.0 );

    // Set Kepler propagator for series propagation.
    seriesPropagator.setPropagator( &keplerPropagator );

    // Set initial state of Asterix.
    seriesPropagator.setInitialState( &asterix, &stateOfAsterix );

    // Run simulation.
    seriesPropagator.execute( );

    // Get series propagation history of Asterix.
    asterixKeplerPropagationHistory
            = seriesPropagator
              .getPropagationHistoryAtFixedOutputIntervals( &asterix );

    // Compute propagation history state data from meters to kilometers.
    for ( iteratorAsterixKeplerPropagationHistory = asterixKeplerPropagationHistory.begin( );
          iteratorAsterixKeplerPropagationHistory != asterixKeplerPropagationHistory.end( );
          iteratorAsterixKeplerPropagationHistory++ )
    {
        iteratorAsterixKeplerPropagationHistory->second.state
                = unit_conversions::convertMetersToKilometers(
                    iteratorAsterixKeplerPropagationHistory->second.state );
    }

    // Declare tolerance between benchmark data and simulation data.
    double toleranceBetweenBenchmarkAndSimulationData = 1e-5;

    // Declare difference between benchmark data and simulation data.
    double differenceKeplerData;

    // Check if results match benchmark data.
    for ( unsigned int i = 1; i < ( seriesPropagator.getSeriesPropagationEnd( )
                                    / seriesPropagator.getFixedOutputInterval( ) ); i++ )
    {
        // Initialize difference in data.
        differenceKeplerData = 0.0;

        for ( unsigned int j = 0; j < 6; j++ )
        {
            differenceKeplerData += std::fabs(
                        asterixKeplerPropagationHistory[ i * seriesPropagator
                        .getFixedOutputInterval( ) ].state( j )
                        - benchmarkKeplerPropagationHistory[  i * seriesPropagator
                        .getFixedOutputInterval( ) ].state( j ) );
        }

        if ( differenceKeplerData > toleranceBetweenBenchmarkAndSimulationData )
        {
            isKeplerPropagatorErroneous = true;

            std::cerr << "The Kepler propagator does not produce consistent results, as running a "
                      << "simulation with does not yield the same results as the benchmark data "
                      << "given the same initial conditions." << std::endl;
            std::cerr << "Expected: " << benchmarkKeplerPropagationHistory
                         [ i * seriesPropagator.getFixedOutputInterval( ) ].state.transpose( )
                      << std::endl
                      << "Actual: " << asterixKeplerPropagationHistory
                         [ i * seriesPropagator.getFixedOutputInterval( ) ].state.transpose( )
                      << std::endl
                      << "Difference: " << differenceKeplerData << std::endl;
        }
    }

    // Return test result.
    // If test is successful return false; if test fails, return true.
    if ( isKeplerPropagatorErroneous )
    {
        std::cerr << "testKeplerPropagator failed!" << endl;
    }

    return isKeplerPropagatorErroneous;
}

// End of file.
<|endoftext|>


<commit_before>// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <qt/peertablemodel.h>

#include <qt/guiconstants.h>
#include <qt/guiutil.h>

#include <interfaces/node.h>

#include <utility>

#include <QDebug>
#include <QList>
#include <QTimer>

bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombinedStats &right) const
{
    const CNodeStats *pLeft = &(left.nodeStats);
    const CNodeStats *pRight = &(right.nodeStats);

    if (order == Qt::DescendingOrder)
        std::swap(pLeft, pRight);

    switch(column)
    {
    case PeerTableModel::NetNodeId:
        return pLeft->nodeid < pRight->nodeid;
    case PeerTableModel::Address:
        return pLeft->addrName.compare(pRight->addrName) < 0;
    case PeerTableModel::ConnectionType:
        return pLeft->m_conn_type < pRight->m_conn_type;
    case PeerTableModel::Network:
        return pLeft->m_network < pRight->m_network;
    case PeerTableModel::Ping:
        return pLeft->m_min_ping_usec < pRight->m_min_ping_usec;
    case PeerTableModel::Sent:
        return pLeft->nSendBytes < pRight->nSendBytes;
    case PeerTableModel::Received:
        return pLeft->nRecvBytes < pRight->nRecvBytes;
    case PeerTableModel::Subversion:
        return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0;
    }

    return false;
}

// private implementation
class PeerTablePriv
{
public:
    /** Local cache of peer information */
    QList<CNodeCombinedStats> cachedNodeStats;
    /** Column to sort nodes by (default to unsorted) */
    int sortColumn{-1};
    /** Order (ascending or descending) to sort nodes by */
    Qt::SortOrder sortOrder;
    /** Index of rows by node ID */
    std::map<NodeId, int> mapNodeRows;

    /** Pull a full list of peers from vNodes into our cache */
    void refreshPeers(interfaces::Node& node)
    {
        {
            cachedNodeStats.clear();

            interfaces::Node::NodesStats nodes_stats;
            node.getNodesStats(nodes_stats);
            cachedNodeStats.reserve(nodes_stats.size());
            for (const auto& node_stats : nodes_stats)
            {
                CNodeCombinedStats stats;
                stats.nodeStats = std::get<0>(node_stats);
                stats.fNodeStateStatsAvailable = std::get<1>(node_stats);
                stats.nodeStateStats = std::get<2>(node_stats);
                cachedNodeStats.append(stats);
            }
        }

        if (sortColumn >= 0)
            // sort cacheNodeStats (use stable sort to prevent rows jumping around unnecessarily)
            std::stable_sort(cachedNodeStats.begin(), cachedNodeStats.end(), NodeLessThan(sortColumn, sortOrder));

        // build index map
        mapNodeRows.clear();
        int row = 0;
        for (const CNodeCombinedStats& stats : cachedNodeStats)
            mapNodeRows.insert(std::pair<NodeId, int>(stats.nodeStats.nodeid, row++));
    }

    int size() const
    {
        return cachedNodeStats.size();
    }

    CNodeCombinedStats *index(int idx)
    {
        if (idx >= 0 && idx < cachedNodeStats.size())
            return &cachedNodeStats[idx];

        return nullptr;
    }
};

PeerTableModel::PeerTableModel(interfaces::Node& node, QObject* parent) :
    QAbstractTableModel(parent),
    m_node(node),
    timer(nullptr)
{
    priv.reset(new PeerTablePriv());

    // set up timer for auto refresh
    timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &PeerTableModel::refresh);
    timer->setInterval(MODEL_UPDATE_DELAY);

    // load initial data
    refresh();
}

PeerTableModel::~PeerTableModel()
{
    // Intentionally left empty
}

void PeerTableModel::startAutoRefresh()
{
    timer->start();
}

void PeerTableModel::stopAutoRefresh()
{
    timer->stop();
}

int PeerTableModel::rowCount(const QModelIndex &parent) const
{
    if (parent.isValid()) {
        return 0;
    }
    return priv->size();
}

int PeerTableModel::columnCount(const QModelIndex &parent) const
{
    if (parent.isValid()) {
        return 0;
    }
    return columns.length();
}

QVariant PeerTableModel::data(const QModelIndex &index, int role) const
{
    if(!index.isValid())
        return QVariant();

    CNodeCombinedStats *rec = static_cast<CNodeCombinedStats*>(index.internalPointer());

    if (role == Qt::DisplayRole) {
        switch(index.column())
        {
        case NetNodeId:
            return (qint64)rec->nodeStats.nodeid;
        case Address:
            // prepend to peer address down-arrow symbol for inbound connection and up-arrow for outbound connection
            return QString(rec->nodeStats.fInbound ? "↓ " : "↑ ") + QString::fromStdString(rec->nodeStats.addrName);
        case ConnectionType:
            return GUIUtil::ConnectionTypeToQString(rec->nodeStats.m_conn_type, /* prepend_direction */ false);
        case Network:
            return GUIUtil::NetworkToQString(rec->nodeStats.m_network);
        case Ping:
            return GUIUtil::formatPingTime(rec->nodeStats.m_min_ping_usec);
        case Sent:
            return GUIUtil::formatBytes(rec->nodeStats.nSendBytes);
        case Received:
            return GUIUtil::formatBytes(rec->nodeStats.nRecvBytes);
        case Subversion:
            return QString::fromStdString(rec->nodeStats.cleanSubVer);
        }
    } else if (role == Qt::TextAlignmentRole) {
        switch (index.column()) {
            case ConnectionType:
            case Network:
                return QVariant(Qt::AlignCenter);
            case Ping:
            case Sent:
            case Received:
                return QVariant(Qt::AlignRight | Qt::AlignVCenter);
            default:
                return QVariant();
        }
    } else if (role == StatsRole) {
        switch (index.column()) {
        case NetNodeId: return QVariant::fromValue(rec);
        default: return QVariant();
        }
    }

    return QVariant();
}

QVariant PeerTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if(orientation == Qt::Horizontal)
    {
        if(role == Qt::DisplayRole && section < columns.size())
        {
            return columns[section];
        }
    }
    return QVariant();
}

Qt::ItemFlags PeerTableModel::flags(const QModelIndex &index) const
{
    if (!index.isValid()) return Qt::NoItemFlags;

    Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
    return retval;
}

QModelIndex PeerTableModel::index(int row, int column, const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    CNodeCombinedStats *data = priv->index(row);

    if (data)
        return createIndex(row, column, data);
    return QModelIndex();
}

void PeerTableModel::refresh()
{
    Q_EMIT layoutAboutToBeChanged();
    priv->refreshPeers(m_node);
    Q_EMIT layoutChanged();
}

int PeerTableModel::getRowByNodeId(NodeId nodeid)
{
    std::map<NodeId, int>::iterator it = priv->mapNodeRows.find(nodeid);
    if (it == priv->mapNodeRows.end())
        return -1;

    return it->second;
}

void PeerTableModel::sort(int column, Qt::SortOrder order)
{
    priv->sortColumn = column;
    priv->sortOrder = order;
    refresh();
}
<commit_msg>qt, refactor: Use enum type as switch argument in PeerTableModel<commit_after>// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <qt/peertablemodel.h>

#include <qt/guiconstants.h>
#include <qt/guiutil.h>

#include <interfaces/node.h>

#include <utility>

#include <QDebug>
#include <QList>
#include <QTimer>

bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombinedStats &right) const
{
    const CNodeStats *pLeft = &(left.nodeStats);
    const CNodeStats *pRight = &(right.nodeStats);

    if (order == Qt::DescendingOrder)
        std::swap(pLeft, pRight);

    switch (static_cast<PeerTableModel::ColumnIndex>(column)) {
    case PeerTableModel::NetNodeId:
        return pLeft->nodeid < pRight->nodeid;
    case PeerTableModel::Address:
        return pLeft->addrName.compare(pRight->addrName) < 0;
    case PeerTableModel::ConnectionType:
        return pLeft->m_conn_type < pRight->m_conn_type;
    case PeerTableModel::Network:
        return pLeft->m_network < pRight->m_network;
    case PeerTableModel::Ping:
        return pLeft->m_min_ping_usec < pRight->m_min_ping_usec;
    case PeerTableModel::Sent:
        return pLeft->nSendBytes < pRight->nSendBytes;
    case PeerTableModel::Received:
        return pLeft->nRecvBytes < pRight->nRecvBytes;
    case PeerTableModel::Subversion:
        return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0;
    } // no default case, so the compiler can warn about missing cases
    assert(false);
}

// private implementation
class PeerTablePriv
{
public:
    /** Local cache of peer information */
    QList<CNodeCombinedStats> cachedNodeStats;
    /** Column to sort nodes by (default to unsorted) */
    int sortColumn{-1};
    /** Order (ascending or descending) to sort nodes by */
    Qt::SortOrder sortOrder;
    /** Index of rows by node ID */
    std::map<NodeId, int> mapNodeRows;

    /** Pull a full list of peers from vNodes into our cache */
    void refreshPeers(interfaces::Node& node)
    {
        {
            cachedNodeStats.clear();

            interfaces::Node::NodesStats nodes_stats;
            node.getNodesStats(nodes_stats);
            cachedNodeStats.reserve(nodes_stats.size());
            for (const auto& node_stats : nodes_stats)
            {
                CNodeCombinedStats stats;
                stats.nodeStats = std::get<0>(node_stats);
                stats.fNodeStateStatsAvailable = std::get<1>(node_stats);
                stats.nodeStateStats = std::get<2>(node_stats);
                cachedNodeStats.append(stats);
            }
        }

        if (sortColumn >= 0)
            // sort cacheNodeStats (use stable sort to prevent rows jumping around unnecessarily)
            std::stable_sort(cachedNodeStats.begin(), cachedNodeStats.end(), NodeLessThan(sortColumn, sortOrder));

        // build index map
        mapNodeRows.clear();
        int row = 0;
        for (const CNodeCombinedStats& stats : cachedNodeStats)
            mapNodeRows.insert(std::pair<NodeId, int>(stats.nodeStats.nodeid, row++));
    }

    int size() const
    {
        return cachedNodeStats.size();
    }

    CNodeCombinedStats *index(int idx)
    {
        if (idx >= 0 && idx < cachedNodeStats.size())
            return &cachedNodeStats[idx];

        return nullptr;
    }
};

PeerTableModel::PeerTableModel(interfaces::Node& node, QObject* parent) :
    QAbstractTableModel(parent),
    m_node(node),
    timer(nullptr)
{
    priv.reset(new PeerTablePriv());

    // set up timer for auto refresh
    timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &PeerTableModel::refresh);
    timer->setInterval(MODEL_UPDATE_DELAY);

    // load initial data
    refresh();
}

PeerTableModel::~PeerTableModel()
{
    // Intentionally left empty
}

void PeerTableModel::startAutoRefresh()
{
    timer->start();
}

void PeerTableModel::stopAutoRefresh()
{
    timer->stop();
}

int PeerTableModel::rowCount(const QModelIndex &parent) const
{
    if (parent.isValid()) {
        return 0;
    }
    return priv->size();
}

int PeerTableModel::columnCount(const QModelIndex &parent) const
{
    if (parent.isValid()) {
        return 0;
    }
    return columns.length();
}

QVariant PeerTableModel::data(const QModelIndex &index, int role) const
{
    if(!index.isValid())
        return QVariant();

    CNodeCombinedStats *rec = static_cast<CNodeCombinedStats*>(index.internalPointer());

    const auto column = static_cast<ColumnIndex>(index.column());
    if (role == Qt::DisplayRole) {
        switch (column) {
        case NetNodeId:
            return (qint64)rec->nodeStats.nodeid;
        case Address:
            // prepend to peer address down-arrow symbol for inbound connection and up-arrow for outbound connection
            return QString(rec->nodeStats.fInbound ? "↓ " : "↑ ") + QString::fromStdString(rec->nodeStats.addrName);
        case ConnectionType:
            return GUIUtil::ConnectionTypeToQString(rec->nodeStats.m_conn_type, /* prepend_direction */ false);
        case Network:
            return GUIUtil::NetworkToQString(rec->nodeStats.m_network);
        case Ping:
            return GUIUtil::formatPingTime(rec->nodeStats.m_min_ping_usec);
        case Sent:
            return GUIUtil::formatBytes(rec->nodeStats.nSendBytes);
        case Received:
            return GUIUtil::formatBytes(rec->nodeStats.nRecvBytes);
        case Subversion:
            return QString::fromStdString(rec->nodeStats.cleanSubVer);
        } // no default case, so the compiler can warn about missing cases
        assert(false);
    } else if (role == Qt::TextAlignmentRole) {
        switch (column) {
        case NetNodeId:
        case Address:
            return {};
        case ConnectionType:
        case Network:
            return QVariant(Qt::AlignCenter);
        case Ping:
        case Sent:
        case Received:
            return QVariant(Qt::AlignRight | Qt::AlignVCenter);
        case Subversion:
            return {};
        } // no default case, so the compiler can warn about missing cases
        assert(false);
    } else if (role == StatsRole) {
        switch (index.column()) {
        case NetNodeId: return QVariant::fromValue(rec);
        default: return QVariant();
        }
    }

    return QVariant();
}

QVariant PeerTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if(orientation == Qt::Horizontal)
    {
        if(role == Qt::DisplayRole && section < columns.size())
        {
            return columns[section];
        }
    }
    return QVariant();
}

Qt::ItemFlags PeerTableModel::flags(const QModelIndex &index) const
{
    if (!index.isValid()) return Qt::NoItemFlags;

    Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
    return retval;
}

QModelIndex PeerTableModel::index(int row, int column, const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    CNodeCombinedStats *data = priv->index(row);

    if (data)
        return createIndex(row, column, data);
    return QModelIndex();
}

void PeerTableModel::refresh()
{
    Q_EMIT layoutAboutToBeChanged();
    priv->refreshPeers(m_node);
    Q_EMIT layoutChanged();
}

int PeerTableModel::getRowByNodeId(NodeId nodeid)
{
    std::map<NodeId, int>::iterator it = priv->mapNodeRows.find(nodeid);
    if (it == priv->mapNodeRows.end())
        return -1;

    return it->second;
}

void PeerTableModel::sort(int column, Qt::SortOrder order)
{
    priv->sortColumn = column;
    priv->sortOrder = order;
    refresh();
}
<|endoftext|>


<commit_before>#include "enrichment_symbolic10.cpp"
<commit_msg>bumped up symbolic enrich<commit_after>#include "enrichment_symbolic40.cpp"
<|endoftext|>


<commit_before>#include <Turpitude.h>

zval* generateTurpitudeContext(JNIEnv* env, jobject ctx) {
    zval* context;
    MAKE_STD_ZVAL(context);
    ZVAL_LONG(context, 10);

    // create class entry
    zend_class_entry* ce;
    ce = (zend_class_entry*)emalloc(sizeof(zend_class_entry));
    ce->type = ZEND_USER_CLASS;
    ce->name = "TurpitudeContext";
    ce->name_length = strlen(ce->name);
    ce->parent = NULL;
    ce->refcount = 1;
    ce->constants_updated = 1;
    ce->ce_flags = 0;
    ce->interfaces = NULL;
    ce->num_interfaces = 0;
    ce->filename = "turpitude generated";
    ce->line_start = 1;
    ce->line_end = 1;
    ce->doc_comment = NULL;
    ce->doc_comment_len = 0;

    //zend_object_std_init(ce);
    // how to create a class entry?

    return context;
}

/**
 * copies the contents of a zval into a jobject
 */
jobject zval_to_jobject(JNIEnv* env, zval* val) {
    if (NULL == val)
        return NULL;

    TSRMLS_FETCH();

    jclass cls = NULL;
    jobject obj = NULL;
    jmethodID mid = NULL;

    switch (Z_TYPE_P(val)) {
        case IS_LONG: {
            //printf("IS_LONG\n");
            cls = env->FindClass("java/lang/Long");
            mid = env->GetMethodID(cls, "<init>", "(J)V");
            obj = env->NewObject(cls, mid, val->value.lval);
            break; }
        case IS_DOUBLE: {
            //printf("IS_DOUBLE\n");
            cls = env->FindClass("java/lang/Double");
            mid = env->GetMethodID(cls, "<init>", "(D)V");
            obj = env->NewObject(cls, mid, val->value.dval);
            break; }
        case IS_BOOL: {
            //printf("IS_BOOL\n");
            cls = env->FindClass("java/lang/Boolean");
            mid = env->GetMethodID(cls, "<init>", "(Z)V");
            obj = env->NewObject(cls, mid, (val->value.lval)?true:false);
            break; }
        case IS_ARRAY: {
            //printf("IS_ARRAY\n");
            // get HashTable
            HashTable* ht = val->value.ht;
            HashPosition pos;
            zval** hashval;

            // allocate HashMap class and object
            cls = env->FindClass("java/util/HashMap");
            mid = env->GetMethodID(cls, "<init>", "()V");
            obj = env->NewObject(cls, mid);
            jmethodID putMID = env->GetMethodID(cls, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");

            // reset and iterate on HashTable
            zend_hash_internal_pointer_reset_ex(ht, &pos);
            while (zend_hash_get_current_data_ex(ht, (void **) &hashval, &pos) == SUCCESS) {
                char* key_name;
                ulong num_key;
                uint  str_len;

                //key object
                jobject keyObject = NULL;
                // extract current key
                switch (zend_hash_get_current_key_ex(ht, &key_name, &str_len, &num_key, 0, &pos)) {
                    case HASH_KEY_IS_STRING:
                        keyObject = env->NewStringUTF(key_name);
                    break;
                    case HASH_KEY_IS_LONG:
                        jclass keyClass = env->FindClass("java/lang/Long");
                        jmethodID keyConstructor = env->GetMethodID(keyClass, "<init>", "(J)V");
                        keyObject = env->NewObject(keyClass, keyConstructor, num_key);
                    break;
                }
                //efree(key_name);

                // value object
                jobject valObject = zval_to_jobject(env, *hashval);
                // insert pair into hashmap
                env->CallObjectMethod(obj, putMID, keyObject, valObject);

                zend_hash_move_forward_ex(ht, &pos);
            }
            break; }
        case IS_OBJECT: {
            //printf("IS_OBJECT\n");
            // get class entry and object value
            zend_class_entry* ce = Z_OBJCE_P(val);
            zend_object_value* zo = &(val->value.obj);

            // ############ remove
            printf("=====> %s\n", ce->doc_comment);
            // ############ remove

            // allocate class and object
            jstring phpclassname = env->NewStringUTF(ce->name);
            cls = env->FindClass("net/xp_framework/turpitude/PHPObject");
            mid = env->GetMethodID(cls, "<init>", "(Ljava/lang/String;)V");
            obj = env->NewObject(cls, mid, env->NewStringUTF(ce->name));

            // find methodID of PHPObject.setProperty
            jmethodID setPropID = env->GetMethodID(cls, "setProperty", "(Ljava/lang/String;Ljava/lang/Object;)V");

            // read properties
            HashTable* props = Z_OBJ_HT_P(val)->get_properties(val TSRMLS_CC);
            HashPosition pos;
            zval** prop;

            // reset and iterate on properties HashTable
            zend_hash_internal_pointer_reset_ex(props, &pos);
            while (zend_hash_get_current_data_ex(props, (void **) &prop, &pos) == SUCCESS) {
                // some local variables
                char* prop_name = NULL;
                char* key_val = NULL;
                uint  key_len, prop_name_len;
                ulong index;
                // extract current key, which is the property name
                if (zend_hash_get_current_key_ex(props, &key_val, &key_len, &index, 1, &pos) == HASH_KEY_IS_STRING) {
                    if (key_len) {
                        //printf("key: %s %d\n", key_val, key_len);
                        if (!key_val[0]) {
                            // moronic: private/protected member keys start with \0
                            // we have to "unmangle" them
                            char* class_name;
                            zend_unmangle_property_name(key_val, key_len, &class_name, &prop_name);
                            prop_name_len = strlen(prop_name) + 1;
                        } else {
                            prop_name = key_val;
                            prop_name_len = key_len;
                        }
                        // read member value
                        zval* member;
                        member = zend_read_property(ce, val, prop_name, prop_name_len - 1, 1 TSRMLS_CC);
                        //printf("propname: %s %d\n", prop_name, prop_name_len);
                        if (NULL != member) {
                            // convert member object
                            jobject mo = zval_to_jobject(env, member);
                            // key string
                            jstring keystr = env->NewStringUTF(prop_name);
                            // set property in PHPObject
                            env->CallVoidMethod(obj, setPropID, keystr, mo);
                        }
                    }
                    // housekeeping
                    efree(key_val);
                }
                // move to next HashTable entry
                zend_hash_move_forward_ex(props, &pos);
            }
            break; }
        case IS_CONSTANT:
        case IS_STRING: {
            //printf("IS_STRING or IS_CONSTANT\n");
            obj = env->NewStringUTF(val->value.str.val);
            break; }
        default:
            //printf("default\n");
            // probably null
            obj = NULL;
    }

    return obj;
}

<commit_msg>-- some more research on object creation<commit_after>#include <Turpitude.h>

void htdebug(HashTable* ht) {
    printf("HTDEBUG: \n");
    zval** hashval;
    HashPosition pos;
    // reset and iterate on HashTable
    zend_hash_internal_pointer_reset_ex(ht, &pos);
    while (zend_hash_get_current_data_ex(ht, (void **) &hashval, &pos) == SUCCESS) {
        char* key_name;
        ulong num_key;
        uint  str_len;

        printf("key: ");
        // extract current key
        switch (zend_hash_get_current_key_ex(ht, &key_name, &str_len, &num_key, 0, &pos)) {
            case HASH_KEY_IS_STRING:
                printf("string: %s\n", key_name);
            break;
            case HASH_KEY_IS_LONG:
                printf("long: %d\n", num_key);
            break;
        }
        //efree(key_name);
        //printf("val - type: %d", Z_TYPE_P(*hashval));
        //printf("\n");
        // value object
        // insert pair into hashmap
        zend_hash_move_forward_ex(ht, &pos);
    }
}

zval* generateTurpitudeContext(JNIEnv* env, jobject ctx) {
    zval* context;
    MAKE_STD_ZVAL(context);
    ZVAL_LONG(context, 10);

    // create class entry
    zend_class_entry* ce;
    ce = (zend_class_entry*)emalloc(sizeof(zend_class_entry));
    ce->type = ZEND_USER_CLASS;
    ce->name = "TurpitudeContext";
    ce->name_length = strlen(ce->name);
    ce->parent = NULL;
    ce->refcount = 1;
    ce->constants_updated = 1;
    ce->ce_flags = 0;
    ce->interfaces = NULL;
    ce->num_interfaces = 0;
    ce->filename = "turpitude generated";
    ce->line_start = 1;
    ce->line_end = 1;
    ce->doc_comment = NULL;
    ce->doc_comment_len = 0;

    //zend_hash_update - add class to global class directory?

    //zend_object_std_init(ce);
    // how to create a class entry?

    return context;
}

/**
 * copies the contents of a zval into a jobject
 */
jobject zval_to_jobject(JNIEnv* env, zval* val) {
    if (NULL == val)
        return NULL;

    TSRMLS_FETCH();

    jclass cls = NULL;
    jobject obj = NULL;
    jmethodID mid = NULL;

    switch (Z_TYPE_P(val)) {
        case IS_LONG: {
            //printf("IS_LONG\n");
            cls = env->FindClass("java/lang/Long");
            mid = env->GetMethodID(cls, "<init>", "(J)V");
            obj = env->NewObject(cls, mid, val->value.lval);
            break; }
        case IS_DOUBLE: {
            //printf("IS_DOUBLE\n");
            cls = env->FindClass("java/lang/Double");
            mid = env->GetMethodID(cls, "<init>", "(D)V");
            obj = env->NewObject(cls, mid, val->value.dval);
            break; }
        case IS_BOOL: {
            //printf("IS_BOOL\n");
            cls = env->FindClass("java/lang/Boolean");
            mid = env->GetMethodID(cls, "<init>", "(Z)V");
            obj = env->NewObject(cls, mid, (val->value.lval)?true:false);
            break; }
        case IS_ARRAY: {
            //printf("IS_ARRAY\n");
            // get HashTable
            HashTable* ht = val->value.ht;
            HashPosition pos;
            zval** hashval;

            // allocate HashMap class and object
            cls = env->FindClass("java/util/HashMap");
            mid = env->GetMethodID(cls, "<init>", "()V");
            obj = env->NewObject(cls, mid);
            jmethodID putMID = env->GetMethodID(cls, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");

            // reset and iterate on HashTable
            zend_hash_internal_pointer_reset_ex(ht, &pos);
            while (zend_hash_get_current_data_ex(ht, (void **) &hashval, &pos) == SUCCESS) {
                char* key_name;
                ulong num_key;
                uint  str_len;

                //key object
                jobject keyObject = NULL;
                // extract current key
                switch (zend_hash_get_current_key_ex(ht, &key_name, &str_len, &num_key, 0, &pos)) {
                    case HASH_KEY_IS_STRING:
                        keyObject = env->NewStringUTF(key_name);
                    break;
                    case HASH_KEY_IS_LONG:
                        jclass keyClass = env->FindClass("java/lang/Long");
                        jmethodID keyConstructor = env->GetMethodID(keyClass, "<init>", "(J)V");
                        keyObject = env->NewObject(keyClass, keyConstructor, num_key);
                    break;
                }
                //efree(key_name);

                // value object
                jobject valObject = zval_to_jobject(env, *hashval);
                // insert pair into hashmap
                env->CallObjectMethod(obj, putMID, keyObject, valObject);

                zend_hash_move_forward_ex(ht, &pos);
            }
            break; }
        case IS_OBJECT: {
            //printf("IS_OBJECT\n");
            // get class entry and object value
            zend_class_entry* ce = Z_OBJCE_P(val);
            zend_object_value* zo = &(val->value.obj);

            // ############ remove
            printf("=====> \n");
            htdebug(&(ce->function_table));
            htdebug(&(ce->default_properties));
            htdebug(&(ce->properties_info));
            htdebug(&(ce->default_static_members));
            htdebug(ce->static_members);
            htdebug(&(ce->constants_table));
            // ############ remove

            // allocate class and object
            jstring phpclassname = env->NewStringUTF(ce->name);
            cls = env->FindClass("net/xp_framework/turpitude/PHPObject");
            mid = env->GetMethodID(cls, "<init>", "(Ljava/lang/String;)V");
            obj = env->NewObject(cls, mid, env->NewStringUTF(ce->name));

            // find methodID of PHPObject.setProperty
            jmethodID setPropID = env->GetMethodID(cls, "setProperty", "(Ljava/lang/String;Ljava/lang/Object;)V");

            // read properties
            HashTable* props = Z_OBJ_HT_P(val)->get_properties(val TSRMLS_CC);
            HashPosition pos;
            zval** prop;

            // reset and iterate on properties HashTable
            zend_hash_internal_pointer_reset_ex(props, &pos);
            while (zend_hash_get_current_data_ex(props, (void **) &prop, &pos) == SUCCESS) {
                // some local variables
                char* prop_name = NULL;
                char* key_val = NULL;
                uint  key_len, prop_name_len;
                ulong index;
                // extract current key, which is the property name
                if (zend_hash_get_current_key_ex(props, &key_val, &key_len, &index, 1, &pos) == HASH_KEY_IS_STRING) {
                    if (key_len) {
                        //printf("key: %s %d\n", key_val, key_len);
                        if (!key_val[0]) {
                            // moronic: private/protected member keys start with \0
                            // we have to "unmangle" them
                            char* class_name;
                            zend_unmangle_property_name(key_val, key_len, &class_name, &prop_name);
                            prop_name_len = strlen(prop_name) + 1;
                        } else {
                            prop_name = key_val;
                            prop_name_len = key_len;
                        }
                        // read member value
                        zval* member;
                        member = zend_read_property(ce, val, prop_name, prop_name_len - 1, 1 TSRMLS_CC);
                        //printf("propname: %s %d\n", prop_name, prop_name_len);
                        if (NULL != member) {
                            // convert member object
                            jobject mo = zval_to_jobject(env, member);
                            // key string
                            jstring keystr = env->NewStringUTF(prop_name);
                            // set property in PHPObject
                            env->CallVoidMethod(obj, setPropID, keystr, mo);
                        }
                    }
                    // housekeeping
                    efree(key_val);
                }
                // move to next HashTable entry
                zend_hash_move_forward_ex(props, &pos);
            }
            break; }
        case IS_CONSTANT:
        case IS_STRING: {
            //printf("IS_STRING or IS_CONSTANT\n");
            obj = env->NewStringUTF(val->value.str.val);
            break; }
        default:
            //printf("default\n");
            // probably null
            obj = NULL;
    }

    return obj;
}

<|endoftext|>


<commit_before>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/lite/toco/tensorflow_graph_matching/resolve_svdf.h"

#include <ctype.h>
#include <stddef.h>
#include <algorithm>
#include <memory>
#include <string>
#include <vector>

#include "google/protobuf/map.h"
#include "tensorflow/lite/toco/model.h"
#include "tensorflow/lite/toco/tensorflow_graph_matching/cluster.h"
#include "tensorflow/lite/toco/tensorflow_graph_matching/cluster_utils.h"
#include "tensorflow/lite/toco/toco_port.h"
#include "tensorflow/lite/toco/tooling_util.h"

#include "tensorflow/core/framework/attr_value.pb.h"
#include "tensorflow/core/framework/graph.pb.h"
#include "tensorflow/core/framework/node_def.pb.h"
#include "tensorflow/core/framework/tensor.pb.h"
#include "tensorflow/core/framework/tensor_shape.pb.h"
#include "tensorflow/core/platform/logging.h"

using tensorflow::GraphDef;
using tensorflow::NodeDef;

namespace toco {

namespace {

// Receives a vector of cluster nodes and returns only those which are array
// partitions (of type 'Const' and have the pattern 'part_<.*>' in their name.
// Since these nodes are connected to a Concatenate node, it makes sure the
// axis value input of the Concatenate operator is 0.
void FilterPartitionedConstNodes(
    const string& const_pattern,
    const std::vector<const NodeDef*>& cluster_nodes,
    std::vector<const NodeDef*>* const_node_parts) {
  for (const NodeDef* node : cluster_nodes) {
    string node_name_to_upper = node->name();
    std::transform(node_name_to_upper.begin(), node_name_to_upper.end(),
                   node_name_to_upper.begin(), ::toupper);
    if (StrContains(node->name(), const_pattern) && node->op() == "Const") {
      if (StrContains(node_name_to_upper, "/PART_")) {
        const_node_parts->push_back(node);
      } else if (StrContains(node->name(), "AXIS") &&
                 StrContains(node->name(), "CONCAT")) {
        // For now only supporting Concatenate on Axix 0
        const auto& value_attr = node->attr().at("value");
        const tensorflow::TensorProto& tensor = value_attr.tensor();
        CHECK_EQ(tensor.int_val(0), 0);
      }
    }
  }
  sort(const_node_parts->begin(), const_node_parts->end(),
       [](const NodeDef* a, const NodeDef* b) {
         return (a->name().compare(b->name()) < 0 &&
                 (a->name().size() < b->name().size()));
       });
}

}  // namespace

// SvdfCluster methods

int SvdfCluster::InferFilterRank() {
  for (const NodeDef* node : nodes_) {
    if (StrContains(node->name(), "Reshape/shape")) {
      const auto& value_attr = node->attr().at("value");
      const tensorflow::TensorProto& tensor = value_attr.tensor();
      std::vector<int32> shape_values(
          tensor.tensor_content().size() / sizeof(int), 0);
      port::CopyToBuffer(tensor.tensor_content(),
                         reinterpret_cast<char*>(shape_values.data()));
      CHECK_EQ(shape_values.size(), 3);
      // shape_value array is arranged as:
      // [num_units, rank, -1]
      CHECK_EQ(shape_values[2], -1);
      return shape_values[1];
    }
  }
  return -1;
}

void SvdfCluster::CreateNodes() {
  for (const string& const_pattern : const_node_patterns_) {
    CreateConstNode(const_pattern);
  }
  std::unique_ptr<tensorflow::NodeDef> svdf_node(new NodeDef);
  svdf_node->set_op("Svdf");
  svdf_node->set_name(name_);
  svdf_node->set_device(device_);

  // Add the main input.
  svdf_node->add_input(inputs_[0]);

  // Add the rest of the inputs to Svdf cell: weights and bias.
  CHECK(new_nodes_.size() == 3 || new_nodes_.size() == 2);
  string* weights_feature_input = svdf_node->add_input();
  string* weights_time_input = svdf_node->add_input();
  string* bias_input;
  if (new_nodes_.size() == 3) {
    bias_input = svdf_node->add_input();
  }
  for (const std::unique_ptr<tensorflow::NodeDef>& node : new_nodes_) {
    const string node_name = node->name();
    if (StrContains(node_name, "SVDF_weights_feature")) {
      *weights_feature_input = node_name;
    } else if (StrContains(node_name, "SVDF_weights_time")) {
      *weights_time_input = node_name;
    } else if (StrContains(node_name, "SVDF_bias")) {
      CHECK(bias_input) << "Bias input cannot be provided when there are only "
                           "two Const input nodes!";
      *bias_input = node_name;
    } else {
      // Unexpected input for Svdf op.
      LOG(FATAL) << "Unexpected input node for SVDF op! Accepted inputs are: "
                    "weights_feature, weights_time and bias.";
    }
  }
  const int rank = InferFilterRank();
  CHECK_GT(rank, 0);

  // Add Svdf activation and rank.
  string activation_function =
      StrContains(outputs_[0], "Relu") ? "Relu" : "None";
  (*svdf_node->mutable_attr())["ActivationFunction"].set_s(activation_function);
  (*svdf_node->mutable_attr())["Rank"].set_i(rank);

  // Finally add it to the list of the newly created nodes.
  new_nodes_.push_back(std::move(svdf_node));
}

void SvdfCluster::CreateConstNode(const string& const_pattern) {
  // Find the nodes with pattern like: "const_pattern"/part_xxx of type Const.
  std::vector<const NodeDef*> const_node_parts;
  FilterPartitionedConstNodes(const_pattern, nodes_, &const_node_parts);

  if (const_node_parts.empty()) return;

  bool transpose_tensor_value =
      StrContains(const_pattern, "SVDF_weights_feature");

  // Merge them if necessary.
  std::unique_ptr<tensorflow::NodeDef> merged_node(new NodeDef);
  MaybeMergeConstNodes(const_node_parts, transpose_tensor_value, merged_node);
  new_nodes_.push_back(std::move(merged_node));
}

void SvdfCluster::MaybeMergeConstNodes(
    const std::vector<const NodeDef*>& const_node_parts,
    bool transpose_tensor_value,
    const std::unique_ptr<tensorflow::NodeDef>& merged_node) {
  merged_node->set_name(const_node_parts[0]->name());
  merged_node->set_op("Const");
  merged_node->set_device(const_node_parts[0]->device());
  (*merged_node->mutable_attr())["dtype"].set_type(
      const_node_parts[0]->attr().at("dtype").type());

  // Figuring out Value attribute for the merged node.
  // Assuming the partitioning is done on Axis 0.
  // The attributes which are inferred:
  // * Shape and dimensions
  // * Float content values

  // Inferring shape and dimension
  int dim0_size = 0;
  int dim1_size = 1;
  tensorflow::TensorProto* allocated_tensor =
      (*merged_node->mutable_attr())["value"].mutable_tensor();
  tensorflow::TensorShapeProto* allocated_tensor_shape =
      allocated_tensor->mutable_tensor_shape();
  auto tensor_shape_dim0 = allocated_tensor_shape->add_dim();
  int allocated_content_flat_size = 0;
  for (int i = 0; i < const_node_parts.size(); i++) {
    const auto& value_attr = const_node_parts[i]->attr().at("value");
    const tensorflow::TensorProto& tensor = value_attr.tensor();
    if (i == 0) {
      allocated_tensor->set_dtype(tensor.dtype());
    } else {
      CHECK_EQ(allocated_tensor->dtype(), tensor.dtype());
    }
    allocated_content_flat_size += tensor.tensor_content().size();
    CHECK(tensor.has_tensor_shape());
    const tensorflow::TensorShapeProto shape = tensor.tensor_shape();
    dim0_size += shape.dim(0).size();
    for (int d = 1; d < shape.dim_size(); d++) {
      if (i == 0) {
        allocated_tensor_shape->add_dim()->set_size(shape.dim(d).size());
        allocated_tensor_shape->set_unknown_rank(shape.unknown_rank());
        dim1_size *= shape.dim(d).size();
      } else {
        CHECK_EQ(shape.dim(d).size(), allocated_tensor_shape->dim(d).size());
        CHECK_EQ(allocated_tensor_shape->unknown_rank(), shape.unknown_rank());
      }
    }
  }

  // Copying the float content from each array partition.
  std::unique_ptr<char[]> allocated_content(
      new char[allocated_content_flat_size]);
  char* content_ptr = allocated_content.get();
  for (int i = 0; i < const_node_parts.size(); i++) {
    const auto& value_attr = const_node_parts[i]->attr().at("value");
    const tensorflow::TensorProto& tensor = value_attr.tensor();
    port::CopyToBuffer(tensor.tensor_content(), content_ptr);
    content_ptr += tensor.tensor_content().size();
  }

  // Transpose the tensor if needed.
  if (transpose_tensor_value) {
    // We use dimension 0 to show the row size for the tensor.
    // We use multiplication of the rest of dimension size to for the col size
    // of the tensor.
    std::unique_ptr<float[]> transposed_tensor(
        new float[dim0_size * dim1_size]);
    Transpose2DTensor(reinterpret_cast<float*>(allocated_content.get()),
                      dim0_size, dim1_size, transposed_tensor.get());
    allocated_tensor_shape->clear_dim();
    allocated_tensor_shape->add_dim()->set_size(dim1_size);
    allocated_tensor_shape->add_dim()->set_size(dim0_size);

    // Set the tensor attributes.
    allocated_tensor->set_tensor_content(
        string(reinterpret_cast<const char*>(transposed_tensor.get()),
               allocated_content_flat_size));
  } else {
    tensor_shape_dim0->set_size(dim0_size);

    // Set the tensor attributes.
    allocated_tensor->set_tensor_content(
        string(reinterpret_cast<const char*>(allocated_content.get()),
               allocated_content_flat_size));
  }
}

// SvdfClusterFactory methods

std::unique_ptr<Cluster> SvdfClusterFactory::CreateCluster(
    const NodeDef& node, const GraphDef& graph_def) const {
  std::vector<string> node_patterns = {"SVDF_weights_feature",
                                       "SVDF_weights_time", "SVDF_bias"};

  string node_name_to_upper = node.name();
  std::transform(node_name_to_upper.begin(), node_name_to_upper.end(),
                 node_name_to_upper.begin(), ::toupper);
  std::unique_ptr<SvdfCluster> cluster = nullptr;
  if (node_name_to_upper.find("SVDF", 0) != string::npos) {
    size_t weights_pos = node.name().find(node_patterns[0]);
    if (weights_pos != string::npos) {
      // Assuming the node name has a pattern like:
      // "SOMESTRING1/CELLNAME/SEARCH_PATTERN/SOMESTRING2", we use
      // CELLNAME as the cluster name.
      size_t cell_pos = node.name().rfind("/", weights_pos - 2) + 1;
      string cell_name =
          node.name().substr(cell_pos, weights_pos - cell_pos - 1);
      cluster = std::unique_ptr<SvdfCluster>(new SvdfCluster);
      cluster->SetName(cell_name);
      cluster->SetDevice(node.device());
      cluster->SetGraphDefInfo(&graph_def);
      CHECK(cluster->FindClusterInputsAndOutputs());

      for (const string& const_pattern : node_patterns) {
        cluster->AddConstNodePattern(const_pattern);
      }
    }
  }
  return std::move(cluster);
}

}  // end namespace toco
<commit_msg>Updated resolve_svdf.cc<commit_after>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/lite/toco/tensorflow_graph_matching/resolve_svdf.h"

#include <ctype.h>
#include <stddef.h>
#include <algorithm>
#include <memory>
#include <string>
#include <vector>

#include "google/protobuf/map.h"
#include "tensorflow/lite/toco/model.h"
#include "tensorflow/lite/toco/tensorflow_graph_matching/cluster.h"
#include "tensorflow/lite/toco/tensorflow_graph_matching/cluster_utils.h"
#include "tensorflow/lite/toco/toco_port.h"
#include "tensorflow/lite/toco/tooling_util.h"

#include "tensorflow/core/framework/attr_value.pb.h"
#include "tensorflow/core/framework/graph.pb.h"
#include "tensorflow/core/framework/node_def.pb.h"
#include "tensorflow/core/framework/tensor.pb.h"
#include "tensorflow/core/framework/tensor_shape.pb.h"
#include "tensorflow/core/platform/logging.h"

using tensorflow::GraphDef;
using tensorflow::NodeDef;

namespace toco {

namespace {

// Receives a vector of cluster nodes and returns only those which are array
// partitions (of type 'Const' and have the pattern 'part_<.*>' in their name.
// Since these nodes are connected to a Concatenate node, it makes sure the
// axis value input of the Concatenate operator is 0.
void FilterPartitionedConstNodes(
    const string& const_pattern,
    const std::vector<const NodeDef*>& cluster_nodes,
    std::vector<const NodeDef*>* const_node_parts) {
  for (const NodeDef* node : cluster_nodes) {
    string node_name_to_upper = node->name();
    std::transform(node_name_to_upper.begin(), node_name_to_upper.end(),
                   node_name_to_upper.begin(), ::toupper);
    if (StrContains(node->name(), const_pattern) && node->op() == "Const") {
      if (StrContains(node_name_to_upper, "/PART_")) {
        const_node_parts->push_back(node);
      } else if (StrContains(node->name(), "AXIS") &&
                 StrContains(node->name(), "CONCAT")) {
        // For now only supporting Concatenate on Axix 0
        const auto& value_attr = node->attr().at("value");
        const tensorflow::TensorProto& tensor = value_attr.tensor();
        CHECK_EQ(tensor.int_val(0), 0);
      }
    }
  }
  sort(const_node_parts->begin(), const_node_parts->end(),
       [](const NodeDef* a, const NodeDef* b) {
         return (a->name().compare(b->name()) < 0 &&
                 (a->name().size() < b->name().size()));
       });
}

}  // namespace

// SvdfCluster methods

int SvdfCluster::InferFilterRank() {
  for (const NodeDef* node : nodes_) {
    if (StrContains(node->name(), "Reshape/shape")) {
      const auto& value_attr = node->attr().at("value");
      const tensorflow::TensorProto& tensor = value_attr.tensor();
      std::vector<int32> shape_values(
          tensor.tensor_content().size() / sizeof(int), 0);
      port::CopyToBuffer(tensor.tensor_content(),
                         reinterpret_cast<char*>(shape_values.data()));
      CHECK_EQ(shape_values.size(), 3);
      // shape_value array is arranged as:
      // [num_units, rank, -1]
      CHECK_EQ(shape_values[2], -1);
      return shape_values[1];
    }
  }
  return -1;
}

void SvdfCluster::CreateNodes() {
  for (const string& const_pattern : const_node_patterns_) {
    CreateConstNode(const_pattern);
  }
  std::unique_ptr<tensorflow::NodeDef> svdf_node(new NodeDef);
  svdf_node->set_op("Svdf");
  svdf_node->set_name(name_);
  svdf_node->set_device(device_);

  // Add the main input.
  svdf_node->add_input(inputs_[0]);

  // Add the rest of the inputs to Svdf cell: weights and bias.
  CHECK(new_nodes_.size() == 3 || new_nodes_.size() == 2);
  string* weights_feature_input = svdf_node->add_input();
  string* weights_time_input = svdf_node->add_input();
  string* bias_input;
  if (new_nodes_.size() == 3) {
    bias_input = svdf_node->add_input();
  }
  for (const std::unique_ptr<tensorflow::NodeDef>& node : new_nodes_) {
    const string node_name = node->name();
    if (StrContains(node_name, "SVDF_weights_feature")) {
      *weights_feature_input = node_name;
    } else if (StrContains(node_name, "SVDF_weights_time")) {
      *weights_time_input = node_name;
    } else if (StrContains(node_name, "SVDF_bias")) {
      CHECK(bias_input) << "Bias input cannot be provided when there are only "
                           "two Const input nodes!";
      *bias_input = node_name;
    } else {
      // Unexpected input for Svdf op.
      LOG(FATAL) << "Unexpected input node for SVDF op! Accepted inputs are: "
                    "weights_feature, weights_time and bias.";
    }
  }
  const int rank = InferFilterRank();
  CHECK_GT(rank, 0);

  // Add Svdf activation and rank.
  string activation_function =
      StrContains(outputs_[0], "Relu") ? "Relu" : "None";
  (*svdf_node->mutable_attr())["ActivationFunction"].set_s(activation_function);
  (*svdf_node->mutable_attr())["Rank"].set_i(rank);

  // Finally add it to the list of the newly created nodes.
  new_nodes_.push_back(std::move(svdf_node));
}

void SvdfCluster::CreateConstNode(const string& const_pattern) {
  // Find the nodes with pattern like: "const_pattern"/part_xxx of type Const.
  std::vector<const NodeDef*> const_node_parts;
  FilterPartitionedConstNodes(const_pattern, nodes_, &const_node_parts);

  if (const_node_parts.empty()) return;

  bool transpose_tensor_value =
      StrContains(const_pattern, "SVDF_weights_feature");

  // Merge them if necessary.
  std::unique_ptr<tensorflow::NodeDef> merged_node(new NodeDef);
  MaybeMergeConstNodes(const_node_parts, transpose_tensor_value, merged_node);
  new_nodes_.push_back(std::move(merged_node));
}

void SvdfCluster::MaybeMergeConstNodes(
    const std::vector<const NodeDef*>& const_node_parts,
    bool transpose_tensor_value,
    const std::unique_ptr<tensorflow::NodeDef>& merged_node) {
  merged_node->set_name(const_node_parts[0]->name());
  merged_node->set_op("Const");
  merged_node->set_device(const_node_parts[0]->device());
  (*merged_node->mutable_attr())["dtype"].set_type(
      const_node_parts[0]->attr().at("dtype").type());

  // Figuring out Value attribute for the merged node.
  // Assuming the partitioning is done on Axis 0.
  // The attributes which are inferred:
  // * Shape and dimensions
  // * Float content values

  // Inferring shape and dimension
  int dim0_size = 0;
  int dim1_size = 1;
  tensorflow::TensorProto* allocated_tensor =
      (*merged_node->mutable_attr())["value"].mutable_tensor();
  tensorflow::TensorShapeProto* allocated_tensor_shape =
      allocated_tensor->mutable_tensor_shape();
  auto tensor_shape_dim0 = allocated_tensor_shape->add_dim();
  int allocated_content_flat_size = 0;
  for (size_t i = 0; i < const_node_parts.size(); i++) {
    const auto& value_attr = const_node_parts[i]->attr().at("value");
    const tensorflow::TensorProto& tensor = value_attr.tensor();
    if (i == 0) {
      allocated_tensor->set_dtype(tensor.dtype());
    } else {
      CHECK_EQ(allocated_tensor->dtype(), tensor.dtype());
    }
    allocated_content_flat_size += tensor.tensor_content().size();
    CHECK(tensor.has_tensor_shape());
    const tensorflow::TensorShapeProto shape = tensor.tensor_shape();
    dim0_size += shape.dim(0).size();
    for (int d = 1; d < shape.dim_size(); d++) {
      if (i == 0) {
        allocated_tensor_shape->add_dim()->set_size(shape.dim(d).size());
        allocated_tensor_shape->set_unknown_rank(shape.unknown_rank());
        dim1_size *= shape.dim(d).size();
      } else {
        CHECK_EQ(shape.dim(d).size(), allocated_tensor_shape->dim(d).size());
        CHECK_EQ(allocated_tensor_shape->unknown_rank(), shape.unknown_rank());
      }
    }
  }

  // Copying the float content from each array partition.
  std::unique_ptr<char[]> allocated_content(
      new char[allocated_content_flat_size]);
  char* content_ptr = allocated_content.get();
  for (size_t i = 0; i < const_node_parts.size(); i++) {
    const auto& value_attr = const_node_parts[i]->attr().at("value");
    const tensorflow::TensorProto& tensor = value_attr.tensor();
    port::CopyToBuffer(tensor.tensor_content(), content_ptr);
    content_ptr += tensor.tensor_content().size();
  }

  // Transpose the tensor if needed.
  if (transpose_tensor_value) {
    // We use dimension 0 to show the row size for the tensor.
    // We use multiplication of the rest of dimension size to for the col size
    // of the tensor.
    std::unique_ptr<float[]> transposed_tensor(
        new float[dim0_size * dim1_size]);
    Transpose2DTensor(reinterpret_cast<float*>(allocated_content.get()),
                      dim0_size, dim1_size, transposed_tensor.get());
    allocated_tensor_shape->clear_dim();
    allocated_tensor_shape->add_dim()->set_size(dim1_size);
    allocated_tensor_shape->add_dim()->set_size(dim0_size);

    // Set the tensor attributes.
    allocated_tensor->set_tensor_content(
        string(reinterpret_cast<const char*>(transposed_tensor.get()),
               allocated_content_flat_size));
  } else {
    tensor_shape_dim0->set_size(dim0_size);

    // Set the tensor attributes.
    allocated_tensor->set_tensor_content(
        string(reinterpret_cast<const char*>(allocated_content.get()),
               allocated_content_flat_size));
  }
}

// SvdfClusterFactory methods

std::unique_ptr<Cluster> SvdfClusterFactory::CreateCluster(
    const NodeDef& node, const GraphDef& graph_def) const {
  std::vector<string> node_patterns = {"SVDF_weights_feature",
                                       "SVDF_weights_time", "SVDF_bias"};

  string node_name_to_upper = node.name();
  std::transform(node_name_to_upper.begin(), node_name_to_upper.end(),
                 node_name_to_upper.begin(), ::toupper);
  std::unique_ptr<SvdfCluster> cluster = nullptr;
  if (node_name_to_upper.find("SVDF", 0) != string::npos) {
    size_t weights_pos = node.name().find(node_patterns[0]);
    if (weights_pos != string::npos) {
      // Assuming the node name has a pattern like:
      // "SOMESTRING1/CELLNAME/SEARCH_PATTERN/SOMESTRING2", we use
      // CELLNAME as the cluster name.
      size_t cell_pos = node.name().rfind("/", weights_pos - 2) + 1;
      string cell_name =
          node.name().substr(cell_pos, weights_pos - cell_pos - 1);
      cluster = std::unique_ptr<SvdfCluster>(new SvdfCluster);
      cluster->SetName(cell_name);
      cluster->SetDevice(node.device());
      cluster->SetGraphDefInfo(&graph_def);
      CHECK(cluster->FindClusterInputsAndOutputs());

      for (const string& const_pattern : node_patterns) {
        cluster->AddConstNodePattern(const_pattern);
      }
    }
  }
  return std::move(cluster);
}

}  // end namespace toco
<|endoftext|>