From khansen at stat.Berkeley.EDU  Sun Apr 16 22:03:18 2006
From: khansen at stat.Berkeley.EDU (Kasper Daniel Hansen)
Date: Sun, 16 Apr 2006 13:03:18 -0700
Subject: [Rd] c++ code on amd64
In-Reply-To: <Pine.LNX.4.64.0604161151270.7975@gannet.stats.ox.ac.uk>
References: <EA2A797B-2427-4777-BD91-2E7217FCD318@stat.berkeley.edu>
	<Pine.LNX.4.64.0604161151270.7975@gannet.stats.ox.ac.uk>
Message-ID: <DB817703-6CF6-4E67-A3C9-AD1EE7D435F2@stat.Berkeley.EDU>

Prof Ripley (and others):

Thank you very much for the idea of the casting problems inside  
Rprintf. Unfortunately that did not work. I have now trimmed  
everything to a simple example, see below.

The cel methods are indeed defined as floats respectively integers like

class FusionCELData
{
   public:
   int IndexToX(int index);
   float GetIntensity(int index);
}

(the entire header is below).

Given that the idea of casting from float to double is undefined in  
Rprintf, I tried to do an explicit casting outside of the Rprintf  
statement, like
   double iTest = static_cast<double>(cel.GetIntensity(1))
and then printing
   Rprintf("Intensity: %f", iTest);
That did not work.

In the sake of completeness, below are the two source files I use and  
the header the FusionCELData class.

Any other ideas? I do have a Makevars file in my package (which  
basically contains the various cpp files from the library (the exists  
in a sub directory of src) as well as include paths for the headers.  
I also use a Makefile (named _Makefile to avoid problems with R) to  
compile the stand alone c++ application, but to my eyes, the makefile  
is very standard. So I do not think the problem is in either of the two.

Again, this is very bewildering given that it works on other  
platforms and the code (to my eyes) is very simple.

/Kasper


Stand-along C++ program, compiled from the command line

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

using namespace std;
using namespace affymetrix_fusion_io;

int main(int argc, char **argv)
{
   const char* celFileName = argv[1];
   FusionCELData cel;
   cel.SetFileName(celFileName);
   if (cel.Read() == false)
     {
       cout << "Failed to read the file." << endl;
       return 0;
     }
   cout << "X: " << cel.IndexToX(1) << ", Intensity: " <<  
cel.GetIntensity(1)
        << endl;
   double iTest, xTest;
   iTest = static_cast<double>(cel.GetIntensity(1));
   xTest = static_cast<double>(cel.IndexToX(1));
   cout << "X as double: " << xTest << ", Intensity as double: " <<  
iTest
        << endl;
   return 0;
}

Output:

X: 1, Intensity: -17953
X as double: 1, Intensity as double: -17953

C++ code embedded in R:

#include "FusionCELData.h"
#include <iostream>
#include "R_affx_constants.h"

using namespace std;
using namespace affymetrix_fusion_io;

extern "C" {
   #include <R.h>
   #include <Rdefines.h>
   #include <wchar.h>
   #include <wctype.h>

   SEXP R_affx_test(SEXP fname)
   {
     FusionCELData cel;
     char* celFileName         = CHAR(STRING_ELT(fname,0));
     cel.SetFileName(celFileName);
     if (cel.Read(true) == false) {
       Rprintf("Unable to read file: %s\n", celFileName);
       return R_NilValue;
     }

     Rprintf("X: %d, Intensity: %f\n", cel.IndexToX(1),  
cel.GetIntensity(1));
     double iTest, xTest;
     iTest = static_cast<double>(cel.GetIntensity(1));
     xTest = static_cast<double>(cel.IndexToX(1));
     Rprintf("X as double: %f, Intensity as double: %f\n", xTest,  
iTest);
     return R_NilValue;
   }
} /* end extern "C" */

Output from R:

 > library(affxparser)
 > .Call("R_affx_test", "LatSq1.CEL")
X: 1, Intensity: 0.000000
X as double: 1.000000, Intensity as double: 0.000000

Header of FusionCELData:

class FusionCELData
{
public:
	/*! CEL file reading states */
	enum
	{
		CEL_ALL=1,
		CEL_DATA=2,
		CEL_OUTLIER=4,
		CEL_MASK=8
	};

public:
	/*! Constructor */
	FusionCELData();
	/*! Destructor */
	~FusionCELData();

public:
	/*! Set the file name.
	 *	@ value The file name.  Can have the full path or relative path
	 */
	void SetFileName(const char *value);

	/*! Get the file name.
	 *	@return File name
	 */
	std::string GetFileName() const;

	/*! Get the id of the file (only valid for Command Console "calvin"  
files)
	 * @return The unique file id.
	 */
	affymetrix_calvin_utilities::AffymetrixGuidType GetFileId() const;

	/*! Set the error string.
	 * @param value The error.
	 */
	void SetError(const wchar_t* value);

	/*! Retrieve error string
	 *  @return	Error string
	 */
	std::wstring GetError();

	/*! Accessors for header information. */
	std::wstring GetHeaderKey(const wchar_t* key);

	/*! Retrieve CEL file format version number.
	 *  @return CEL file format version number
	 */
	int GetVersion();

	/*!  Retrieve number of columns in array
	 *  @return Number of columns in array
	 */
	int GetCols();

	/*!	Retrieve number of rows in array
	 *	@return Number of rows in array
	 */
	int GetRows();

	/*! Retrieve number of cells in array
	 *	@return Number of cells in array
	 */
	int GetNumCells();

	/*!	Retrieve header in a single string
	 *	@return Header string
	 */
	std::wstring GetHeader();

	/*!	Retrieve algorithm name
	 *	@return Algorithm name
	 */
	std::wstring GetAlg();

	/*! Retrieve algorithm parameters
	 *  @return	Algorithm parameters
	 */
	std::wstring GetParams();

	/*!	Retrieve algorithm parameter of specified tag
	 *	@param tag Algorithm parameter tag
	 *	@return Algorithm parameter value
	 */
	std::wstring GetAlgorithmParameter(const wchar_t *tag);

	/*! Retrieves the algorithm parameter name (tag) for a given index  
position.
	 *	@param index The zero based index to the parameter array (0 to  
the number of alg parameters - 1).
	 *	@return The parameter name (tag).
	 */
	std::wstring GetAlgorithmParameterTag(int index);

	/*! Retrieves the number of algorithm parameters.
	 *	@return The number of algorithm parameters.
	 */
	int GetNumberAlgorithmParameters();

	/*! Retrieve algorithm parameters
	 *	@return Algorithm parameters
	 */
	std::wstring GetAlgorithmParameters();

	/*! Retreive the algorithm parameters in a list.
	 *	@return An STL list of algorithm parameters
	 */
	FusionTagValuePairTypeList &GetParameters();

	/*! Get the DatHeader string.
	 *	@return The DatHeader string.
	 */
	virtual std::wstring GetDatHeader();

	/*!	Retrieve chip type
	 *	@return	Chip type
	 */
	std::wstring GetChipType();

	/*!	Retrieve cell margin
	 *	@return Cell margin
	 */
	int GetCellMargin();

	/*!	Retrieve number of outliers
	 *	@return Number of outliers
	 */
	unsigned int GetNumOutliers();

	/*!	Retrieve number of masked cells
	 *	@return Number of masked cells
	 */
	unsigned int GetNumMasked();

	/*! Get the grid coordinates.
	 *  @return Returns the grid coordinates.
	 */
	FGridCoords GetGridCorners();

	// Index/position conversions
	/*!	Get x coordinates from index
	 *  @return X coordinates
	 */
	int IndexToX(int index);

	/*!	Get y coordinates from index
	 *	@return Y coordinates
	 */
	int IndexToY(int index);

	/*!	Convert x, y coordinates to index
	 *	@return Index
	 */
	int XYToIndex(int x, int y);

	/*! Maps X/Y coordinates to CEL file index.
	 * @param x The x coordinate.
	 * @param y The y coordinate.
	 * @param r The number of rows.
	 * @param c The number of columns.
	 * @return The index to the intensity arrays.
	 */
	static int XYToIndex(int x, int y, int r, int c)
	{
		return ((y*c) + x);
	}

	// Accessors for intensity information.

	/*! Retrieve a CEL file entry.
	 * @param index The index to the CEL file entries.
	 * @param entry The CEL file entry.
	 */
	void GetEntry(int index, FusionCELFileEntryType &entry);

	/*! Retrieve a CEL file entry.
	 * @param x The X coordinate.
	 * @param y The Y coordinate.
	 * @param entry The CEL file entry.
	 */
	void GetEntry(int x, int y, FusionCELFileEntryType &entry);

	/*! Retrieve a CEL file intensity.
	 * @param index The index to the CEL file entries.
	 * @return The CEL file intensity.
	 */
	float GetIntensity(int index);

	/*! Retrieve a CEL file intensity.
	 * @param x The X coordinate.
	 * @param y The Y coordinate.
	 * @return The CEL file intensity.
	 */
	float GetIntensity(int x, int y);

	/*! Retrieve a CEL file stdv value.
	 * @param index The index to the CEL file entries.
	 * @return The CEL file stdv value.
	 */
	float GetStdv(int index);

	/*! Retrieve a CEL file stdv value.
	 * @param x The X coordinate.
	 * @param y The Y coordinate.
	 * @return The CEL file stdv value.
	 */
	float GetStdv(int x, int y);

	/*! Retrieve a CEL file pixel count.
	 * @param index The index to the CEL file entries.
	 * @return The CEL file pixel count.
	 */
	short GetPixels(int index);

	/*! Retrieve a CEL file pixel count.
	 * @param x The X coordinate.
	 * @param y The Y coordinate.
	 * @return The CEL file pixel count.
	 */
	short GetPixels(int x, int y);

	// Accessors for the mask/outlier flags
	/*! Retrieve a CEL file mask flag.
	 * @param x The X coordinate.
	 * @param y The Y coordinate.
	 * @return True if the feature is masked.
	 */
	bool IsMasked(int x, int y);

	/*! Retrieve a CEL file mask flag.
	 * @param index The index to the CEL file entries.
	 * @return True if the feature is masked.
	 */
	bool IsMasked(int index);

	/*! Retrieve a CEL file outlier flag.
	 * @param x The X coordinate.
	 * @param y The Y coordinate.
	 * @return True if the feature is an outlier.
	 */
	bool IsOutlier(int x, int y);

	/*! Retrieve a CEL file outlier flag.
	 * @param index The index to the CEL file entries.
	 * @return True if the feature is an outlier.
	 */
	bool IsOutlier(int index);

	// For reading a file.
	/*! Closes the file */
	void Close();

	/*! Returns the file size.
	 * @return The file size.
	 */
	unsigned int GetFileSize();

	/*! Check if the file exists.
	 * @return True if the file exists.
	 */
	bool Exists();

	/*! Reads the header of the CEL file.
	 * @return True if successful.
	 */
	bool ReadHeader();

	/*! Reads the CEL file.
	 * @param bIncludeMaskAndOutliers Flag to indicate if the mask and  
outlier sections should also be read.
	 * @return True if successful.
	 */
	bool Read(bool bIncludeMaskAndOutliers=true);

	/*! Determine CEL file format and call appropriate function to read  
file using the specified file name.
	 * @param filename The name of the file.
	 * @param state Reading state
	 * @return bool	true if success, false if fail
	 *
	 * \a state can be one or combination of the following values:
	 *       CEL_ALL      Read all information in file (default)
	 *       CEL_DATA     Read header and intensities only
	 *		 CEL_OUTLIER  Read header, intensities and outliers
	 *		 CEL_MASK     Read header, intensities and masked cells
	 */
	bool ReadEx(const char *filename=0, int state=CEL_ALL);

	/*! Returns the reading state.
	 * @return The reading state.
	 */
	int GetReadState();

	// For writing a new CEL file

	/*! Clears the members. */
	void Clear();

	/*! Returns the GenericData object associated with a Calvin file,  
NULL for GCOS files. */
	affymetrix_calvin_io::GenericData *GetGenericData();

protected:
	/*! Factory method to create the appropriate adapter class.
	 *	@exception UnableToOpenFileException
	 */
	void CreateAdapter();

	/*! Delete the adapter member */
	void DeleteAdapter();

	/*! Check the adapter and throw exception if not set
	 *	@exception FileNotOpenException
	 */
	void CheckAdapter() const;

	/*!  */
	void FillParameterList();

private:
	/*! Pointer to the adapter */
	IFusionCELDataAdapter* adapter;
	/*! CEL file name including a relative path or the full path. */
	std::string filename;
	/*! A separate parallel parameter list that is sync'ed with the list  
in the adapter */
	FusionTagValuePairTypeList parameterList;
	/*! Indicates whether the parameter list has been read from the  
adapter */
	bool parameterListRead;
};

}




On Apr 16, 2006, at 4:11 AM, Prof Brian Ripley wrote:

> You mention 'float' repeatedly.  A %f argument in Rprintf (and  
> printf) refers to a _double_.  Given how little you have shown us  
> it has to be entirely guesswork, but is cel.GetIntensity(1) perhaps  
> a float?  If so what happens is I believe undefined and compiler- 
> specific.  (Normally headers force conversions, but not for  
> variable-argument-list functions.)
>
> On Sun, 16 Apr 2006, Kasper Daniel Hansen wrote:
>
>> Hi
>>
>> Brief synopsis:
>>
>> I am having a rather peculiar problem regarding a C++ library. It
>> seems that functions from this library behave differently when
>> compiled using R as opposed to being compiled directly from the
>> command line. The problem is only seen on the amd64 platform (using
>> gcc 4.0.2) and not on either of Solaris (both 32 bit and 64 bit), Mac
>> OS and Windows.
>>
>> A bit more detail:
>>
>> Basically the c++ library contains a class and methods for parsing
>> text files in specific formats. These files contains integers as well
>> floats.
>>
>> If I write a stand-alone c++ program with a line like
>>
>>   ....
>>   cout << "x: " cel.GetIndexToX(1) << " intensity: " <<
>> cel.GetIntensity(1) << endl;
>>   ....
>>
>> (here cel is pointing to a specific file while GetIndexToX returns an
>> integer (in what is essentially the first row), while GetIntensity
>> returns a float), it works fine: the two numbers are printed to  
>> stdout.
>>
>> If I instead embed the code inside R like
>>
>> extern "C" {
>>    ....
>>    Rprintf("x: %d intensity: %f", cel.GetIndexToX(1),
>> cel.GetIntensity(1)):
>>   ...
>> }
>>
>> and do a R CMD INSTALL, I am able to read the integer from the file,
>> but not the float. The float always returns 0.00000. This is very
>> strange considering that the code is basically identical in the two
>> cases (except for the extern part and inclusion of the R header
>> files), and that the integer number is being read perfectly!
>>
>> I would say that the fact that the stand-alone program works is
>> indicating that the C++ library actually works. Further indication
>> that this is the case is the fact that our R package works fine on
>> Mac G4, Solaris and Windows.
>>
>> The only real difference I can see is that the amd64 platform is the
>> only little-endian 64-bit platform.
>>
>> My working hypothesis is that the float is being read and then
>> truncated.
>>
>> I am extremely baffled by this. Do anyone have an idea on where I
>> should start looking?
>>
>> System details:
>>
>> uname -a
>> Linux shadowfax.berkeley.edu 2.6.12-1-amd64-k8-smp #1 SMP Wed Sep 28
>> 02:57:49 CEST 2005 x86_64 GNU/Linux
>>
>> gcc --version
>> gcc (GCC) 4.0.2 20050808 (prerelease) (Ubuntu 4.0.1-4ubuntu9)
>>
>> R is version 2.2.1 build using a standard ./configure, make step.
>>
>>
>> /Kasper
>>
>> ______________________________________________
>> R-devel at r-project.org mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>>
>
> -- 
> Brian D. Ripley,                  ripley at stats.ox.ac.uk
> Professor of Applied Statistics,  http://www.stats.ox.ac.uk/~ripley/
> University of Oxford,             Tel:  +44 1865 272861 (self)
> 1 South Parks Road,                     +44 1865 272866 (PA)
> Oxford OX1 3TG, UK                Fax:  +44 1865 272595



[Rd] c++ code on amd64
Kasper Daniel Hansen