Adapt Polynomial Regression to C++ DLL

Pages: 12
In the code block, is a method for calculating a 3rd order polynomial regression fit. It is written in Easylanguage. I wish to convert this to a C++ dll in order to 1) teach myself how to make a C++ dll usable from Easylanguage, and 2) to see if there is a performance difference from using it natively in Easylanguage vs using as a dll which can be called from Easylanguage. The first two lines in the code show how a dll is accessed from Easylanguage, and I would want to pass the vector containing the data to the dll as an argument. I have installed Visual Studio 2019 and have been able to make very rudimentary C++ dll, which I can call from Easylanguage. I also have a C++ version of the calculation which uses cin, cout, etc. in order to run it. What I need to understand now is what the C++ code looks like which would receive the vector argument from Easylanguage. I've not been able to find an example of using __stdcall (or whatever it might be) to do this. That's my question.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//external: "PolyFitCPPDLL.dll", Long, "PolyFitFunction", Vector;
//print(PolyFitFunction(XMA1Vctr));

using elsystem;
using elsystem.collections;


const:
	int Deg(3);
		
var:
	vector XMA1Vctr(null);


//NOTE: THIS IS FOR A 3rd ORDER POLYNOMIAL
//ArA Size = 2*Deg + 1
//ArR Size = Deg + 1,Deg + 2	
//ArT Size = Deg + 2
array:
	intrabarpersist double ArA[7](0),
	intrabarpersist double ArR[4,5](0),
	intrabarpersist double ArT[5](0);
		
	

//METHOD
method double PolyRSq(Vector XMAVctr)
var:
	int NP,
	double II,
	double J,
	double K,
	double S,
	double Z,
	double PP,
	double QQ;
	
begin
	NP = XMAVctr.count;
	if NP <= 4 then return 1;
	
	for value1 = 1 to 7 begin
		ArA[value1] = 0;
	end;
	for value1 = 1 to 4 begin
	for value2 = 1 to 5 begin
		ArR[value1,value2] = 0;
	end;
	end;
	for value1 = 1 to 5 begin
		ArT[value1] = 0;
	end;
	
	II = 0;
	J = 0;
	K = 0;
	S = 0;
	Z = 0;
	PP = 0;
	QQ = 0;
	
	// POPULATE THE MATRIXES
	
	ArA[1] = NP;
	for II = 1 to NP begin
		for J = 2 to 2*Deg+1 begin
			ArA[J] = ArA[J] + power(II,(J-1));
		end;
	
		for K = 1 to Deg + 1 begin
			ArR[K,Deg+2] = ArT[K] + XMAVctr[II - 1] astype double*power(II,(K-1));
			ArT[K]=ArT[K] + XMAVctr[II - 1] astype double*power(II,(K-1));
		end;
			
		ArT[Deg+2]=ArT[Deg+2]+square(XMAVctr[II - 1] astype double);//190
	end;

	//START	///////////////////////////////////////////////////////////////////////
	for J=1 TO Deg+1 begin
	for K=1 to Deg+1 begin
		ArR[J,K] = ArA[J+K-1];
	end;
	end;

	for J=1 to Deg+1 begin
		K=J;
		if ArR[K,J] = 0 then K += 1;
		if K > 4 then K = 4;
		FOR II=1 TO Deg+2 begin
			S=ArR[J,II];
			ArR[J,II]=ArR[K,II];
			ArR[K,II]=S;
		end;
					
		if ArR[J,J] <> 0 then Z=1/ArR[J,J];
		
		FOR II=1 TO Deg+2 begin
			ArR[J,II]=Z*ArR[J,II];
		end;
		
		for K = 1 to Deg + 1 begin
			if K <> J then begin
				Z=-ArR[K,J];
				FOR II=1 TO Deg+2 begin
					ArR[K,II]=ArR[K,II]+Z*ArR[J,II];
				end;
			end;
		end;
	end;
	
	for J = 2 to Deg + 1 begin
		PP = PP + ArR[J,Deg+2]*(ArT[J] - ArA[J]*ArT[1]/NP);
	end;
	
	
	QQ=ArT[Deg+2]- square(ArT[1])/NP;
	Z=QQ-PP;
	II = NP - Deg-1;
	if QQ <> 0 then J = PP/QQ;
	return minlist(1,J);
end;


once begin
	XMA1Vctr = new vector;
	XMA1Vctr.push_back(34 astype double);
	XMA1Vctr.push_back(65 astype double);
	XMA1Vctr.push_back(29 astype double);
	XMA1Vctr.push_back(25 astype double);
	XMA1Vctr.push_back(17 astype double);
	XMA1Vctr.push_back(35 astype double);
	XMA1Vctr.push_back(19 astype double);
	XMA1Vctr.push_back(21 astype double);
	XMA1Vctr.push_back(19 astype double);
	XMA1Vctr.push_back(50 astype double);
	XMA1Vctr.push_back(20 astype double);
	XMA1Vctr.push_back(85 astype double);
	XMA1Vctr.push_back(84 astype double);
	XMA1Vctr.push_back(78 astype double);
	XMA1Vctr.push_back(44 astype double);
	XMA1Vctr.push_back(60 astype double);
	XMA1Vctr.push_back(41 astype double);
	XMA1Vctr.push_back(17 astype double);
	XMA1Vctr.push_back(24 astype double);
	XMA1Vctr.push_back(45 astype double);
	clearprintlog;
	
	print(PolyRSq(XMA1Vctr):0:5);
end;

Last edited on
If that's "Easylanguage" what does "Hardlanguage" look like?

Why don't you write the lot in C++ ? - it will probably run much faster.
Well, here's polynomial regression in C++. Vector C will contain the polynomial coefficients for least-squares regression of data X and Y.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using vec    = vector<double>;
using matrix = vector<vec>;

bool polynomialRegression( const vec X, const vec Y, int degree, vec &C )
{
   int N = X.size();   assert( Y.size() == N );
   matrix A( N, vec( 1 + degree ) );
   for ( int i = 0; i < N; i++ )
   {
      double xp = 1;
      for ( int j = 0; j <= degree; j++ )
      {
         A[i][j] = xp;
         xp *= X[i];
      }
   }

   matrix AT = transpose( A );
   return GaussElimination( matmul( AT, A ), matmul( AT, Y ), C );
}



Full code below - just put your own data in vectors X and Y in int main() at the bottom.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <algorithm>
#include <cassert>
using namespace std;

const double SMALL = 1.0E-30;          // used to stop divide-by-zero
const double NEARZERO = 1.0e-10;       // helps in printing

using vec    = vector<double>;
using matrix = vector<vec>;

// Function prototypes
void print( const string &title, const matrix &A );
void print( const string &title, const vec    &V );
double poly( const vec C, double x );
matrix transpose( const matrix &A );
matrix matmul( const matrix &A, const matrix &B );
vec    matmul( const matrix &A, const vec    &V );
bool GaussElimination( matrix A, vec B, vec &X );
bool polynomialRegression( const vec X, const vec Y, int degree, vec &C );

//======================================================================

void print( const string &title, const matrix &A )
{
   if ( title != "" ) cout << title << '\n';

   for ( auto &row : A )
   {
      for ( auto x : row )
      {
         if ( abs( x ) < NEARZERO ) x = 0.0;
         cout << setw( 12 ) << x;
      }
      cout << '\n';
   }
}

//======================================================================

void print( const string &title, const vec &A )
{
   if ( title != "" ) cout << title << '\n';

   for ( auto x : A )
   {
      if ( abs( x ) < NEARZERO ) x = 0.0;
      cout << setw( 12 ) << x << '\n';
   }
}

//======================================================================

double poly( const vec C, double x )
{
   double result = 0.0;
   for ( int i = C.size() - 1; i >= 0; i-- ) result = C[i] + result * x;
   return result;
}

//====================================================================== 

matrix transpose( const matrix &A )                        // Transpose a matrix
{
   int m = A.size(),   n = A[0].size();
   matrix AT( n, vec( m ) );
   for ( int i = 0; i < n; i++ )
   {
      for ( int j = 0; j < m; j++ ) AT[i][j] = A[j][i];
   }
   return AT;
}

//======================================================================

matrix matmul( const matrix &A, const matrix &B )          // Matrix times matrix
{
   int rowsA = A.size(),   colsA = A[0].size();
   int rowsB = B.size(),   colsB = B[0].size();
   assert( colsA == rowsB );

   matrix C( rowsA, vec( colsB, 0.0 ) );
   for ( int i = 0; i < rowsA; i++ )
   {
      for ( int j = 0; j < colsB; j++ )
      {
         for ( int k = 0; k < colsA; k++ ) C[i][j] += A[i][k] * B[k][j];
      }
   }
   return C;
}

//======================================================================

vec matmul( const matrix &A, const vec &V )                // Matrix times vector
{
   int rowsA = A.size(),   colsA = A[0].size();
   int rowsV = V.size();
   assert( colsA == rowsV );

   vec C( rowsA, 0.0 );
   for ( int i = 0; i < rowsA; i++ )
   {
      for ( int k = 0; k < colsA; k++ ) C[i] += A[i][k] * V[k];
   }
   return C;
}

//======================================================================

bool GaussElimination( matrix A, vec B, vec &X )
//--------------------------------------
// Solve AX = B by Gaussian elimination
//--------------------------------------
{
   int n = A.size();

   // Row operations for i = 0, ,,,, n - 2 (n-1 not needed)
   for ( int i = 0; i < n - 1; i++ )
   {
      // Pivot: find row r below with largest element in column i
      int r = i;
      double maxA = abs( A[i][i] );
      for ( int k = i + 1; k < n; k++ )
      {
         double val = abs( A[k][i] );
         if ( val > maxA )
         {
            r = k;
            maxA = val;
         }
      }
      if ( r != i )
      {
         for ( int j = i; j < n; j++ ) swap( A[i][j], A[r][j] );
         swap( B[i], B[r] );
      }

      // Row operations to make upper-triangular
      double pivot = A[i][i];
      if ( abs( pivot ) < SMALL ) return false;            // Singular matrix

      for ( int r = i + 1; r < n; r++ )                    // On lower rows
      {
         double multiple = A[r][i] / pivot;                // Multiple of row i to clear element in ith column
         for ( int j = i; j < n; j++ ) A[r][j] -= multiple * A[i][j];
         B[r] -= multiple * B[i];
      }
   }
   if ( abs( A[n-1][n-1] ) < SMALL ) return false;         // Singular matrix

   // Back-substitute
   X = B;
   for ( int i = n - 1; i >= 0; i-- )
   {
      for ( int j = i + 1; j < n; j++ )  X[i] -= A[i][j] * X[j];
      X[i] /= A[i][i];
   }

   return true;
}

//====================================================================== 

bool polynomialRegression( const vec X, const vec Y, int degree, vec &C )
{
   int N = X.size();   assert( Y.size() == N );
   matrix A( N, vec( 1 + degree ) );
   for ( int i = 0; i < N; i++ )
   {
      double xp = 1;
      for ( int j = 0; j <= degree; j++ )
      {
         A[i][j] = xp;
         xp *= X[i];
      }
   }

   matrix AT = transpose( A );
   return GaussElimination( matmul( AT, A ), matmul( AT, Y ), C );
}

//====================================================================== 

int main()
{
   // Some data
   vec X = { 1, 2, 3, 4, 5, 6 };
   vec Y = X;
   for ( int i = 0; i < X.size(); i++ ) Y[i] = 10 + 8 * X[i] + 6 * X[i] * X[i] + 4 * X[i] * X[i] * X[i];

   vec C;
   int degree = 3;
   if ( polynomialRegression( X, Y, degree, C ) )
   {
      print( "Coefficients in C0 + C1.X + C2.X^2 + ... : ", C );
      cout << '\n';
      for ( int i = 0; i < X.size(); i++ ) cout << X[i] << '\t' << Y[i] << '\t' << poly( C, X[i] ) << '\n';
   }
   else
   {
      cout << "Unable to solve\n";
   }
}


Coefficients in C0 + C1.X + C2.X^2 + ... : 
          10
           8
           6
           4

1	28	28
2	82	82
3	196	196
4	394	394
5	700	700
6	1138	1138

Well that is impressive, and I may be able to use that, but my question was about how to pass data from Easylanguage to a C++ dll as a vector. Calling the dll from Easylanguage is done using:

external: "PolyFitCPPDLL.dll", Long, "PolyFitFunction", Vector;

So, if I create my dll and use the above statement to pass a vector, then what do I need in the dll to take that argument and use it in the regression.
Yes, but since I'd never heard about "Easylanguage" until today - and I suspect that is true about many in this c++ forum - you will have to show a lot more about its interface with other programming languages than that.

Show a link where this language is interfaced with c++ or, failing that, any other mainstream language. You aren't showing your function call - you are just showing an External statement telling the linker to look for it somewhere. Where in your code are you calling it?
external: "PolyFitCPPDLL.dll", Long, "PolyFitFunction", Vector;

That is all there is to calling a dll in Easylanguage. The data I want to export is in the form of a vector, but it could be any object. I already know how to use the above in Easylanguage. What I'm trying to learn is what I need to put in the dll to handle the argument I'm sending it (the vector).

Here is a complete example of a Easylanguage document that calls a dll which just adds 1 to whatever you send it:

external: "MyCPPDLL.dll", Long, "TestFunction", Long;
plot1(TestFunction(1));

The plot statement invokes the external function (TestFunction) which returns 2, which is what plots on my chart.

The external statement is: path to dll, the return type for the dll, the name of the function inside the dll, and the type of what is being passed.

That's it!
If you are sending your TestFunction one number and it returns one number then that may be all you need.

However, you are (presumably) trying to least-squares-fit a cubic polynomial to a whole set of data points (x1,y1), (x2,y2), ... , (xn,yn) and return a set of coefficients (c0,c1,c2,c3). I fail to see how your external statement accomplishes that.

I have absolutely no idea how your Easylanguage works, but it looks more like your external statement would be something like
external: "PolyFitCPPDLL.dll", vector, "PolyFitFunction", vector, vector;

i.e. two input vectors and one output vector.

Also, a c++ std::vector is a very c++ entity. I would be very surprised if you could pass it directly to any other language. If I am interfacing C++ to Fortran, which I do occasionally, then I would have to pass simple arrays; there's absolutely no way I could pass a std::vector.


Is this document relevant to what you are doing? It seems to have some examples at the end.
https://uploads.tradestation.com/uploads/EasyLanguage-Extension-SDK.pdf


Last edited on
I only need to pass the dll 1 vector, typically about 20 data points. The dll will return the R squared double value for the data points I send it. The x of the x-y points is just the vector index. If I can't pass a vector, then what type of data structure should I use; array, string?
You should use simple arrays.

The x of the x-y points is just the vector index.

Sorry, I don't understand that. Aren't you passing a set of points (x1,y1), (x2,y2), ... , (xn,yn)?

Are you intending to return the coefficients of the polynomial or just the R2 goodness-of-fit parameter (sum of the squared errors)?
This is the Easylanguage definition of a vector:
Vector Class (Collection)

"The Vector class allows you to create a collection of data elements referenced by an index (zero-based). Data elements may be inserted, read, and deleted from anywhere within the collection.

An element is added to the vector collection several ways: using insert(iIndex, oElement) to add the element in front of the iIndex element. where oElement is the data to be added, or using push_back(oElement) to add the element to the end of the collection."

One of the reasons I want to use vectors instead of arrays is that in Easylanguage an array is not just a single object. Any array definition can be duplicated hundreds or thousands of times, so it is inherently inefficient. The arrays used in the dll would only have one copy of it, and then destroyed on then end of the call.

So, an Easylanguage vector is just a simple 1d array, but its size is indefinite.

I don't need to pass the x value of the points, because it is simply the index of the array or vector.

I don't need the polynomial coefficients. I'm not trying to do any predicting. I just want to know goodness of fit; R squared.
Last edited on
Yes, but an Easylanguage vector class is NOT the same as a C++ vector class. Neither are "just" arrays; both include information about size, etc. The best that you could hope for is that you could send a pointer to the start of their data buffer PLUS an integer giving their size. I know how to do that in c++, but I don't know how that is done in Easylanguage because I'd never heard of this language before yesterday.

Arrays are not inherently inefficient as procedure arguments. You don't usually copy over all the elements: you just send a pointer to the start of the array.

My best interpretation of what you are asking is that you are trying to get the R^2 value for a cubic polynomial fit to the points (0,y0), (1,y1), (2,y2), ... I hope that is right.
Last edited on
To avoid changing existing routines I wrote an interface to them, as below.
I looked at @coder777's link, but I'm not sure of the "extern" line.

Your Easylanguage code must send it a pointer to the start of the array and an int for its size.
1
2
3
4
5
6
7
8
9
10
11
12
13
// Returns the R^2 parameter for a cubic polynomial fit to the points
// (0,Y0), (1,y1), ..., (N-1,yN-1)

extern "C"  __declspec( dllexport ) double __stdcall    // VERY UNSURE ABOUT THIS
PolyFitFunction( double *Y, int N )
{
   vec X( N );   for ( int i = 0; i < N; i++ ) X[i] = i;
   vec F( Y, Y + N );
   vec C;
   double Rsquared;
   if ( polynomialRegression( X, F, 3, C, Rsquared ) ) return Rsquared;
   else                                                return 0.0;
}



Full code. EDIT: I've changed the solution method to Cholesky factorisation (since the matrix is symmetric) and stripped out some debugging routines.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <cassert>
#include <cmath>
using namespace std;

const double SMALL = 1.0E-30;          // used to stop divide-by-zero

using vec    = vector<double>;         // vector
using matrix = vector<vec>;            // matrix

// Function prototypes
double poly( const vec &C, double x );
matrix transpose( const matrix &A );
matrix matmul( const matrix &A, const matrix &B );
vec    matmul( const matrix &A, const vec    &V );
bool solve( const matrix &A, const vec &B, vec &X );
bool polynomialRegression( const vec &X, const vec &Y, int degree, vec &C, double &Rsquared );

//======================================================================

double poly( const vec &C, double x )
{
   double result = 0.0;
   for ( int i = C.size() - 1; i >= 0; i-- ) result = C[i] + result * x;
   return result;
}

//====================================================================== 

matrix transpose( const matrix &A )                        // Transpose a matrix
{
   int m = A.size(),   n = A[0].size();
   matrix AT( n, vec( m ) );
   for ( int i = 0; i < n; i++ )
   {
      for ( int j = 0; j < m; j++ ) AT[i][j] = A[j][i];
   }
   return AT;
}

//======================================================================

matrix matmul( const matrix &A, const matrix &B )          // Matrix times matrix
{
   int rowsA = A.size(),   colsA = A[0].size();
   int rowsB = B.size(),   colsB = B[0].size();
   assert( colsA == rowsB );

   matrix C( rowsA, vec( colsB, 0.0 ) );
   for ( int i = 0; i < rowsA; i++ )
   {
      for ( int j = 0; j < colsB; j++ )
      {
         for ( int k = 0; k < colsA; k++ ) C[i][j] += A[i][k] * B[k][j];
      }
   }
   return C;
}

//======================================================================

vec matmul( const matrix &A, const vec &V )                // Matrix times vector
{
   int rowsA = A.size(),   colsA = A[0].size();
   int rowsV = V.size();
   assert( colsA == rowsV );

   vec C( rowsA, 0.0 );
   for ( int i = 0; i < rowsA; i++ )
   {
      for ( int k = 0; k < colsA; k++ ) C[i] += A[i][k] * V[k];
   }
   return C;
}

//======================================================================

bool solve( const matrix &A, const vec &B, vec &X )
//--------------------------------------
// Solve AX = B by Cholesky factorisation of A (i.e. A = L.LT)
// Requires A to be SYMMETRIC
//--------------------------------------
{
   int n = A.size();

   // Cholesky-factorise A
   matrix L( n, vec( n, 0 ) );
   for ( int i = 0; i < n; i++ )
   {
      // Diagonal value
      L[i][i] = A[i][i];
      for ( int j = 0; j < i; j++ ) L[i][i] -= L[i][j] * L[i][j];
      L[i][i] = sqrt( L[i][i] );
      if ( abs( L[i][i] ) < SMALL ) return false;

      // Rest of the ith column of L
      for ( int k = i + 1; k < n; k++ )
      {
         L[k][i] = A[k][i];
         for ( int j = 0; j < i; j++ ) L[k][i] -= L[i][j] * L[k][j];
         L[k][i] /= L[i][i];
      }
   }

   // Solve LY = B, where L is lower-triangular and Y = LT.X
   vec Y = B;
   for ( int i = 0; i < n; i++ )
   {
      for ( int j = 0; j < i; j++ ) Y[i] -= L[i][j] * Y[j];
      Y[i] /= L[i][i];
   }

   // Solve UX = Y, where U = LT is upper-triangular
   X = Y;
   for ( int i = n - 1; i >= 0; i-- )
   {
      for ( int j = i + 1; j < n; j++ ) X[i] -= L[j][i] * X[j];
      X[i] /= L[i][i];
   }

   return true;
}

//====================================================================== 

bool polynomialRegression( const vec &X, const vec &Y, int degree, vec &C, double &Rsquared )
{
   int N = X.size();   assert( Y.size() == N );
   matrix A( N, vec( 1 + degree ) );
   for ( int i = 0; i < N; i++ )
   {
      double xp = 1;
      for ( int j = 0; j <= degree; j++ )
      {
         A[i][j] = xp;
         xp *= X[i];
      }
   }

   // Solve the least-squares problem for the polynomial coefficients C
   matrix AT = transpose( A );
   if ( !solve( matmul( AT, A ), matmul( AT, Y ), C ) ) return false;

   // Calculate R^2
   vec AC = matmul( A, C );
   double sumYsq = 0, sumACsq = 0, sumY = 0.0;
   for ( int i = 0; i < N; i++ )
   {
      sumY    += Y[i];
      sumYsq  += Y[i] * Y[i];
      sumACsq += AC[i] * AC[i];
   }
   Rsquared = 1.0 - ( sumYsq - sumACsq ) / ( sumYsq - sumY * sumY / N + SMALL );
   return true;
}

//====================================================================== 

// Interface routine that takes a (pointer to) an array Y, of size N,
// and returns the R^2 parameter for a cubic polynomial fit to the points
// (0,Y0), (1,y1), ..., (N-1,yN-1)

// extern "C"  __declspec( dllexport ) double __stdcall PolyFitFunction( double *Y, int N )   // VERY UNSURE ABOUT THIS
double PolyFitFunction( double *Y, int N )
{
   vec X( N );   for ( int i = 0; i < N; i++ ) X[i] = i;
   vec F( Y, Y + N );
   vec C;
   double Rsquared;
   if ( polynomialRegression( X, F, 3, C, Rsquared ) ) return Rsquared;
   else                                                return 0.0;
}

//====================================================================== 

int main()
{
   // Data
   vec X = { 0, 1, 2, 3, 4, 5 };
   int N = X.size();
   vec Y( N );
   // Exact cubic polynomial
   for ( int i = 0; i < N; i++ ) Y[i] = 10 + 8 * X[i] + 6 * X[i] * X[i] + 4 * X[i] * X[i] * X[i];
   // Fudge some values or you'll get perfect agreement
   Y[0] -= 10; Y[N-1] += 20;    // Comment this out and you should get the original cubic


   vec C;
   int degree = 3;
   double Rsquared;
   if ( polynomialRegression( X, Y, degree, C, Rsquared ) )
   {
      cout << "Coefficients in C0 + C1.X + C2.X^2 + ... : ";
      for ( double e : C ) cout << e << "  ";

      cout << "\n\nCheck fit: (Xi, Yi, poly(Xi) )\n";
      for ( int i = 0; i < X.size(); i++ ) cout << X[i] << '\t' << Y[i] << '\t' << poly( C, X[i] ) << '\n';

      cout << "\n\nR^2 = " << Rsquared << '\n';

      // Can we get the same answer via an interface function? (Assumes X is { 0, 1, 2, ... } )
      cout << "\nR^2 (by interface) = " << PolyFitFunction( Y.data(), N ) << '\n';
   }
   else
   {
      cerr << "Unable to solve\n";
   }
   return 0;
}

Last edited on
I feel like I'm wasting your time here, and I appreciate your effort very much. I thought the answer to this question was going to be much simpler. Let me take some time to look more at what you've posted and do some additional study. If I just can't figure it out, I'll come back later.

Thanks for your time and effort.
You are by no means wasting our time. I have plenty of matrix routines but I had never got round to coding up polynomial regression before, so it was an interesting challenge and could well prove useful in the future.

I don't know your language's syntax, I'm afraid. I don't quite know how you would refer to double * pointers, or array addresses in your code. I think it would be more like
external: "PolyFitCPPDLL.dll", double, "PolyFitFunction", double*, int;
and you would call the function by something like
Rsquared = PolyFitFunction( arrayname, N );

You will have to pass a pointer to the start of the array. You can't pass a vector as such, but you might be able to pass a pointer to the start of its data buffer (which I actually did in my example).

Some links to better documentation on your language might help.
EasyLanguage is a proprietary programming language. You might get more direct help with the Tradestation community.
It appears that the answer to the problem is that you cannot pass a vector from Easylanguage to a C++ dll. Instead, one would pass the data which could be put into a vector within the dll itself.
Pass a pointer to the start of the data buffer.
I finally put my question to someone who uses Tradestation Easylanguage and who I know to be knowledgeable in this area. He said you cannot pass an Easylanguage object to a dll, period. Easylanguage is used to process stock and futures market data, so it stores variables and such in what can best be visualized as an array. These specailized arrays or time series data can be passed to a dll using the Tradestation Software Development Kit (SDK). The tskit.dll needs to be imported into the C++ dll to make it all work. I'm just now learning to use this.

Thanks to all for your help.
Pages: 12