Announcement

Collapse
No announcement yet.

Trouble converting from C to PB

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Trouble converting from C to PB

    Everybody, thank you very much for your previous help. I believe that I am now very close to conquering this!
    I have gotten the information needed to be able to continue this project.
    I now have everything working except the actual calling of the program that I receive a pointer to.


    Code:
    ////////////////////////////////////////////////////////////////////////////////////////
    // CalculateTrainingFitness
    // 
    // Calculates the fitness of an individual having direct access to the genetic
    // program itself, allowing you to do with it whatever you want.
    //
    // Parameters:
    //		pGeneticProgram		- Pointer to the genetic program. This is how you call it:
    //			(*pGeneticProgram) (Inputs, pOutputs)
    //
    //			Inputs is an array of floats used as the input of the program. The size of 
    //			this array must be equal to the number of inputs for the genetic program, 
    //			set in varable NrOfInputs.
    //
    //			pOutputs is a pointer to an array that contains the outputs of the
    //			program after the function has been called. The size of the array will be 
    //			NrOfOutputs.
    //
    // Return Value:
    //		The fitness value of the program. The lower the fitness value, the better
    //		the program.
    ////////////////////////////////////////////////////////////////////////////////////////
    
    float CalculateTrainingFitness(FUNCTION_PTR pGeneticProgram, long Length)
    {
    	// Init inputs. Note: Inputs[1] to Inputs[3] are never
    	// changed, so they are constants for the GP program
    	float Inputs[4]={ 0,0,0.5,1};
    
    	// Pointer to evolved program output
    	float *Outputs[8];
    
    	float Error;
    	float ErrorSum=0;
    	int NrOfFitnessCases=0;
    
    	for (float x=-2;x<2;x+=0.2f) // The stepsize here is 0.2
    	{
    		// Set the input
    		Inputs[0]=x;
    
    		// Call evolved program
    		(*pGeneticProgram)(Inputs,Outputs);
    
    		// Calculate error
    		Error=(float)fabs(*Outputs[0]-(x*x*x+x*x+x)); // We want to evolve x^3 + x^2 + x...
    		
    		// Square the error
    		Error*=Error;
    
    		// Sum up errors
    		ErrorSum+=Error;
    
    		// Count the number of fitness cases we tested
    		NrOfFitnessCases++;
    	};
    
    	// Return average squared error
    	return ErrorSum/NrOfFitnessCases;
    }
    
    
    **********************************************************
    +++++++++++++  PowerBasic Version  ++++++++++++++++++++
    **********************************************************
    
    DECLARE FUNCTION CallGP CDECL( BYVAL Inputs AS SINGLE PTR, BYVAL Outputs AS SINGLE PTR)
    
    FUNCTION   GPcalcVF CDECL ALIAS "CalculateValidationFitness" ( _ 
                            BYVAL aGP AS DWORD PTR ,_ 
                            BYVAL Length AS LONG  ) EXPORT AS SINGLE 
    
    	DIM pGP AS DWORD
          pGP = aGP 
    
        	DIM Inputs(3) AS SINGLE 
        	    Inputs(0)=0 : Inputs(1)=0 : Inputs(2)=.5 : Inputs(3)=1
    
        	DIM Outputs(7) AS SINGLE PTR
        
        	DIM ER!, ErrorSum!, NrOfFitnessCases&, x!, n1&, n2&, n3&, n4&
        	ER=0 : ErrorSum=0 : NrOfFitnessCases=0
    
    n1 = NrOfFitnessCases
    
        	FOR  x=-2 TO 1.999 STEP 0.2        ' // The stepsize here is 0.2
        	
        		Inputs(0)=x
    
    n2 = NrOfFitnessCases
       
                CALL DWORD aGP USING CallGP(VARPTR(Inputs(0)),VARPTR(Outputs(0)))
                                         
    n3 = NrOfFitnessCases   
        
        		ER= ABS(@Outputs(0)-(x*x*x+x*x+x))  ' // We want to evolve x^3 + x^2 + x...
        		ER=ER*ER
        		ErrorSum=ErrorSum+ER
         		NrOfFitnessCases=NrOfFitnessCases+1
    
    MSGBOX("n1  "+STR$(n1)+" n2  "+STR$(n2)+"  n3  "+STR$(n3)+" outptr "+STR$(Outputs(0)))
    
            NEXT x
                
        	FUNCTION = ErrorSum/NrOfFitnessCases
    
    END FUNCTION

    The call is successful because the returned values seem reasonable however the variable "NrOfFitnessCases" gets clobbered after the call.
    I believe that I have not defined Inputs or Outputs correctly or I am not passing them properly.
    One clue that I have is that it gets changed to the address Outputs(0)? Very strange to me.....

    Can anyone offer any suggestions?

    Thank you in advance for any more wonderful suggestion,
    Dennis


    [This message has been edited by Dennis Martell (edited November 19, 2006).]

  • #2
    Code:
    'declare sub pGeneticProgramPrototype cdecl alias "GeneticProgramPrototype" (byval Inputs AS SINGLE PTR ,BYVAL outputs AS single ptr)
    SUB pGeneticProgramPrototype CDECL ALIAS "GeneticProgramPrototype" (BYVAL Inputs AS SINGLE PTR ,BYVAL outputs AS SINGLE PTR)
        ' do ....
    END SUB
    '
    'float CalculateTrainingFitness(FUNCTION_PTR pGeneticProgram, long Length)
    FUNCTION  CalculateTrainingFitness(BYVAL pGeneticProgram AS DWORD,BYVAL Length AS LONG) AS SINGLE
    '    // Init inputs. Note: Inputs[1] to Inputs[3] are never
    '    // changed, so they are constants for the GP program
    '    float Inputs[4]={ 0,0,0.5,1};
         DIM arrInputs(3) AS LOCAL SINGLE
         LOCAL Inputs AS SINGLE PTR : Inputs = VARPTR(arrInputs(0))
         ARRAY ASSIGN arrInputs()= 0, 0, 0.5, 1
         '
    '    // Pointer to evolved program output
    '    float *Outputs[8];
         DIM arrOutputs(7) AS STATIC SINGLE
         LOCAL Outputs AS SINGLE PTR : Outputs=VARPTR(arrOutputs(0))
         '
    '    float Error;
         LOCAL fError AS SINGLE
    '    float ErrorSum=0;
         LOCAL ErrorSum AS SINGLE : ErrorSum=0
         '
    '    int NrOfFitnessCases=0;
         LOCAL  NrOfFitnessCases AS LONG :  NrOfFitnessCases=0
         '
    '    for (float x=-2;x<2;x+=0.2f) // The stepsize here is 0.2
         LOCAL x AS SINGLE
         x=-2!
         WHILE x<2
    '        // Set the input
            arrInputs(0)=x
            '
    '        // Call evolved program
    '        (*pGeneticProgram)(Inputs,Outputs);
            CALL DWORD pGeneticProgram  USING pGeneticProgramPrototype(BYVAL Inputs,BYVAL Outputs)
            '
    '        // Calculate error
            fError = ABS(arrOutputs(0)-(x*x*x+x*x+x))'; // We want to evolve x^3 + x^2 + x...
            '
            '// Square the error
            fError = fError * fError
            '
            '// Sum up errors
            ErrorSum = ErrorSum + fError
            '
            '// Count the number of fitness cases we tested
            'NrOfFitnessCases++;
            INCR NrOfFitnessCases
            x = x + 0.2! ' increment cycle variable
        WEND
        '
        '// Return average squared error
        'return ErrorSum/NrOfFitnessCases;
        FUNCTION =  ErrorSum / NrOfFitnessCases
    END FUNCTION
    '
    FUNCTION PBMAIN()
        LOCAL fRes AS SINGLE
        LOCAL lenght AS LONG
         '
         fRes=CalculateTrainingFitness (BYVAL CODEPTR(pGeneticProgramPrototype), BYVAL lenght)
         ? STR$ (fRes)
    END FUNCTION
    Sy,

    ------------------
    -=Alex=-
    -=Alex=-

    Comment


    • #3
      Alex, thank you very much for this.

      I tried it out with only 2 changes.
      The call to "CalculateTrainingFitness" comes from a program that I do not have the source code for so I had to add the alias reference.
      The other change was because I have PB7 and the array assign is a new command.

      I then added a msgbox instruction to see how things were progressing and the NrOfFitnessCases still gets clobbered.
      Any other possible ideas? I am inserting my code in case I messed anything up...


      <code>
      'declare sub pGeneticProgramPrototype cdecl alias "GeneticProgramPrototype" (byval Inputs AS SINGLE PTR ,BYVAL outputs AS single ptr)
      SUB pGeneticProgramPrototype CDECL ALIAS "GeneticProgramPrototype" (BYVAL Inputs AS SINGLE PTR ,BYVAL outputs AS SINGLE PTR)
      ' do ....
      END SUB

      'float CalculateTrainingFitness(FUNCTION_PTR pGeneticProgram, long Length)
      FUNCTION CalculateTrainingFitness CDECL ALIAS "CalculateTrainingFitness" (BYVAL pGeneticProgram AS DWORD,BYVAL Length AS LONG) EXPORT AS SINGLE
      ' // Init inputs. Note: Inputs[1] to Inputs[3] are never
      ' // changed, so they are constants for the GP program
      ' float Inputs[4]={ 0,0,0.5,1};
      DIM arrInputs(3) AS LOCAL SINGLE
      LOCAL Inputs AS SINGLE PTR : Inputs = VARPTR(arrInputs(0))
      ' ARRAY ASSIGN arrInputs()= 0, 0, 0.5, 1
      arrInputs(0)= 0 : arrInputs(1)= 0 : arrInputs(2)= .5 : arrInputs(3)= 1

      ' // Pointer to evolved program output
      ' float *Outputs[8];
      DIM arrOutputs(7) AS STATIC SINGLE
      LOCAL Outputs AS SINGLE PTR : Outputs=VARPTR(arrOutputs(0))
      '
      ' float Error;
      LOCAL fError AS SINGLE
      ' float ErrorSum=0;
      LOCAL ErrorSum AS SINGLE : ErrorSum=0
      '
      ' int NrOfFitnessCases=0;
      LOCAL NrOfFitnessCases AS LONG : NrOfFitnessCases=0
      '
      ' for (float x=-2;x<2;x+=0.2f) // The stepsize here is 0.2
      LOCAL x AS SINGLE
      x=-2!

      DIM n1&,n2&,n3&
      n1 = NrOfFitnessCases

      WHILE x<2
      ' // Set the input
      arrInputs(0)=x
      '
      ' // Call evolved program
      ' (*pGeneticProgram)(Inputs,Outputs);

      n2 = NrOfFitnessCases

      CALL DWORD pGeneticProgram USING pGeneticProgramPrototype(BYVAL Inputs,BYVAL Outputs)

      n3 = NrOfFitnessCases

      '
      ' // Calculate error
      fError = ABS(arrOutputs(0)-(x*x*x+x*x+x))'; // We want to evolve x^3 + x^2 + x...
      '
      '// Square the error
      fError = fError * fError
      '
      '// Sum up errors
      ErrorSum = ErrorSum + fError
      '
      '// Count the number of fitness cases we tested
      'NrOfFitnessCases++;
      INCR NrOfFitnessCases
      x = x + 0.2! ' increment cycle variable

      MSGBOX("TF n1 "+STR$(n1)+" n2 "+STR$(n2)+" n3 "+STR$(n3)+" outptr "+STR$(arrOutputs(0)))

      WEND
      '
      '// Return average squared error
      'return ErrorSum/NrOfFitnessCases;
      FUNCTION = ErrorSum / NrOfFitnessCases
      END FUNCTION
      '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
      [/code]

      Thank you again for your effort!
      Dennis


      ------------------

      Comment


      • #4
        '#1: when you assign literal value, then always put type specifier
        ' as arrInputs(2)= .5!
        ' In a future you can escape hard tracking errors.
        '#2 Something strange in C-function. Function has 2 parameters,
        ' first one is start-address of function pGeneticProgram, and second one "Length" as LONG.
        ' parameters Lenght never used in function "CalculateTrainingFitness"
        '#3 I guess you need to find H-header for function "pGeneticProgram".
        ' "pGeneticProgram" is your PB-function ? Or this function called from DLL ?
        ' If so, you have to figure out, what calling conversion it use STDCALL or CDECL, since
        ' C handle clearing of stack in other way.
        '#4 If that function "pGeneticProgram" used from DLL(can't see function it is or procedure),
        ' then you need declare it corecctly
        ' something like this: (looks like procedure since it doesn't return any value)
        ' declare sub pGeneticProgramPrototype LIB "Clib.DLL" CDECL/STDCALL alias "GeneticProgram" (byval Inputs AS SINGLE PTR ,BYVAL outputs AS single ptr)
        '#5 Keep in mind, names of function in DLL is case-sensitive, thats mean you must put name in ALIAS exactly as that function is exported.
        ' (Try some PEexplorer or other tools which show exported names of function in DLL if you don't have H-headers)
        '#6 How did you get start-address of that "GeneticProgram"- function ?
        ' before calling function "CalculateTrainingFitness" which you show us, you need determine address of "GeneticProgram"
        ' If that function located in DLL, then you can find correct addres for passing it to "CalculateTrainingFitness"
        ' like:
        ' hCmodule=GetModuleHandle("NameOfDLLwhereLocated[GeneticProgram-function].DLL"
        ' dwAddressOfGeneticProgram = GetProcessAddress(byval hCmodule,"GeneticProgram")
        ' and only after that you can call [CalculateTrainingFitness(ByVal dwAddressOfGeneticProgram, ByVal WhatEverSinceItNotused)]
        ' otherwise, if "GeneticProgram"- function is in you program, then just make a call like
        ' ...=CalculateTrainingFitness(ByVal CODEPTR(GeneticProgram), ByVal WhatEverSinceItNotused)

        'Sy,

        ------------------
        -=Alex=-
        -=Alex=-

        Comment


        • #5
          Alex, Thank you again!

          I will try to respond to your suggestions one at a time.
          1. OK, I will adopt this convention. Thank you.
          2. Length parameter in C-function is not used in this example.
          3. Please refer to this same topic name last posted to on Nov. 7 for additional information.
          I have purchased The Discipulus Genetic Program and I am writing the interface for a custom fitness function (CFF).
          Discipulus calls the my CFF (dll) and the vendor's example of how to do this is written in C++ posted above.
          According to the documentation my program calls a generated program at location pGeneticProgram and the results are in the array Outputs.
          I do not have Visual Studio or I would try to compile it.
          The calling convention is CDECL because the other 8 functions are now working properly using CDECL.
          Below I will post the header file included with this example. It mostly sets up values to be used by the other functions.
          4. The pGeneticProgram pointer is to an assembly language program that does not have a name.
          The program uses Inputs to calculate Outputs and returns.
          5. I am aware of case-sensitive.
          6. The procedure that Discipulus goes through is that it calls the other 8 functions that are already working in my dll to set itself up.
          It then generates an assembly language program and calls my dll via the function CalculateTrainingFitness.
          My function is supposed to fill Inputs with appropriate values and then call the assembly program at pGeneticProgram address.
          When the call returns, the results are in Outputs.
          My dll then uses the Output values to calculate fitness and returns the fitness value at the end of the CalculateTrainingFitness function.


          Code:
          // CustomFitnessCalculation.h : main header file for the CUSTOMFITNESSCALCULATION DLL
          //
          
          #if !defined(AFX_CUSTOMFITNESSCALCULATION_H__92578B88_A649_11D2_9959_004005A1C556__INCLUDED_)
          #define AFX_CUSTOMFITNESSCALCULATION_H__92578B88_A649_11D2_9959_004005A1C556__INCLUDED_
          
          #if _MSC_VER >= 1000
          #pragma once
          #endif // _MSC_VER >= 1000
          
          #ifndef __AFXWIN_H__
          	#error include 'stdafx.h' before including this file for PCH
          #endif
          
          #include "resource.h"		// main symbols
          
          ////////////////////////////////////////////////////////////////////////////////////////
          // Constants
          ////////////////////////////////////////////////////////////////////////////////////////
          
          // NrOfParameters - Set the number of parameters needed here.
          #define NR_OF_PARAMETERS 3
          
          // NR_OF_INPUTS - The number of inputs for a genetic program. Must be >0 and <=64.
          #define NR_OF_INPUTS 4
          
          // NR_OF_OUTPUTS - The number of outputs a genetic program produces. Must be >0 and <=8.
          #define NR_OF_OUTPUTS 1
          
          
          // DLL identification constants
          #define VECTOR_STYLE_DLL 1
          #define POINTER_STYLE_DLL 2
          
          
          /////////////////////////////////////////////////////////////////////////////
          // CCustomFitnessCalculationApp
          // See CustomFitnessCalculation.cpp for the implementation of this class
          //
          
          class CCustomFitnessCalculationApp : public CWinApp
          {
          public:
          	CCustomFitnessCalculationApp();
          
          // Overrides
          	// ClassWizard generated virtual function overrides
          	//{{AFX_VIRTUAL(CCustomFitnessCalculationApp)
          	public:
          	virtual BOOL InitInstance();
          	//}}AFX_VIRTUAL
          
          	//{{AFX_MSG(CCustomFitnessCalculationApp)
          		// NOTE - the ClassWizard will add and remove member functions here.
          		//    DO NOT EDIT what you see in these blocks of generated code !
          	//}}AFX_MSG
          	DECLARE_MESSAGE_MAP()
          };
          
          // Define FUNCTION_PTR
          typedef void (* FUNCTION_PTR) (float*, float**);
          
          ////////////////////////////////////////////////////////////////////////////////////////
          // Local Variables
          ////////////////////////////////////////////////////////////////////////////////////////
          
          // Parameter Information Struct
          struct ParameterInformation
          {
              CString ParameterName;	// Name of the parameter
              CString TypeInformation; // Type information for the parameter
          							// "0" - Integer
          							// "1" - Float
          							// "3" - Boolean (Value 0 = false, 1 = true)
              CString LowerBound;		// Lower Bound
              CString UpperBound;		// Upper Bound
              CString Value;			// Parameter value
          };
          
          //extern ParameterInformation Parameters[NR_OF_PARAMETERS]
          
          
          ////////////////////////////////////////////////////////////////////////////////////////
          // Local Functions
          ////////////////////////////////////////////////////////////////////////////////////////
          
          void InitParameters();
          
          
          /////////////////////////////////////////////////////////////////////////////
          
          //{{AFX_INSERT_LOCATION}}
          // Microsoft Developer Studio will insert additional declarations immediately before the previous line.
          
          #endif // !defined(AFX_CUSTOMFITNESSCALCULATION_H__92578B88_A649_11D2_9959_004005A1C556__INCLUDED_)

          I hope this clears up your questions.

          Thank you again for your input!
          Dennis



          ------------------

          Comment

          Working...
          X