It looks to me as though you have sparse solver code written in C and are trying to link that to your Delphi program. I think you have a fundamental problem in the way you have declared your external imports. Rather than answer the question you asked directly, I'll show you what I believe to be the right way to declare and call such external imports.
The first thing I would say is that the large static array types that you have declared are not what you need here. Those array types can sometimes be useful, but only really when you cast another array to PADouble = ^ADouble
. In your situation you don't need those arrays at all and I do suggest that you remove them.
I'm going to assume that you are calling a function called solve
that takes n
, nz
, Ap
, Ai
, Ax
and b
as input parameters and returns x
as an output parameter. The function returns x
such that A*x=b
where A
is the n
dimensional square sparse matrix specified by Ap
, Ai
and Ax
. The nz
parameter specifies the number of non-zero elements. No doubt the actual function will vary in details, but the concepts will be just the same. For example, it's common to infer nz
from Ap[n]
, but those details are for you to resolve.
I suggest that you declare the function to receive the parameters as pointers to the first element. So the function declarations looks like this:
function solve(
n: Integer;
nz: Integer;
Ap: PInteger;
Ai: PInteger;
Ax: PDouble;
b: PDouble;
x: PDouble
): Integer; cdecl; external;
Then you need to populate your sparse matrix arrays. Declare these as dynamic arrays:
var
Ap: TArray<Integer>;
Ai: TArray<Integer>;
Ax: TArray<Double>;
....
SetLength(Ap, n);
Ap[0] := ...;
....
SetLength(Ai, nz);
Ap[0] := ...;
....
SetLength(Ax, nz);
Ax[0] := ...;
....
I expect that you will only know the value of n
, nz
etc. at runtime and that the content of the matrix will be filled out using loops and so on. The code in the question is presumably test code to try and test out the external code. Arnaud's answer gives you sound advice on how to populate a dynamic array.
You will also need to initialise b
and x
:
var
b: TArray<Double>;
x: TArray<Double>;
....
SetLength(b, n);
b[0] := ...;
....
SetLength(x, n);
// no need to initialise values of x[i] since it is the output
Now you can call the function:
var
retval: Integer;
....
retval := solve(n, nz, PInteger(Ap), PInteger(Ai), PDouble(Ax),
PDouble(b), PDouble(x));
One final point, converning the use of generic arrays. Since you are using a modern Delphi I do suggest that you use generic dynamic arrays. So, instead of array of ...
you should use TArray<...>
. The reason for this is that generic types have different type compatibility rules from old-style dynamic arrays. In the code above, for example, b
and x
are assignment compatible. But if they were declared like this:
var
b: array of Double;
x: array of Double;
then they would not be assignment compatible. You can get around that issue by declaring a type, TDoubleArray = array of Double
. However, if you use the generic array then you can use generic container classes such as TList<T>
than return values of type TArray<T>
which you can readily consume.
I know this isn't quite the question that you asked but I have a feeling that it may be useful to you.