Nim lang GLM and OpenGL matrix pointer uniform issues - pointers

When I use NIM GLM to create a projection matrix and attempt to pass that to a shader with glUniformMatrix4fv, I get a type mismatch issue. The matrix pointer is of type ptr float64 and I assume that glUniformMatrix4fv needs ptr float32.
I'll be damned if I can figure out how to convert this or ensure the projection matrix starts off at the right level of precision.
Interestingly all other matrcies I have created - such as model and view - pass to the shaders without a hitch.
Here is the code...
var
projection = perspective(PI/2, aspectRatio, 0.1f, 100.0f)
projectionMatrixLocation: int32
#... later in the main loop
projectionMatrixLocation = glGetUniformLocation(shaderProgram,"projection")
#...
while not window.windowShouldClose:
#...
glUniformMatrix4fv(projectionMatrixLocation, 1, false, projection.caddr) #here the error comes
#...
# in the shader
uniform mat4 projection;

perspective will return a Mat4[T], based on the type of its first parameter. you can see this for yourself:
import glm,math
var
proj64 = perspective(PI / 2, 1.33, 0.1, 100)
proj32 = perspective(PI.float32 / 2, 1.33, 0.1, 100)
echo typeof proj32 #Mat4[float32]
echo typeof proj64 #Mat4[float], 64 bit on every architecture
note that the subsequent parameters can be ints and they'll be converted.
DO NOT cast a float64 to a float32, you're just converting it to zero!
echo proj32.caddr[] #0.75
echo proj64.caddr[] #0.7500000000000002
echo cast[ptr float32](proj64.caddr)[] #2.802596928649634e-45

Okay. I have been doing some black magic with my pointers. I'm not sure this is the solution given that I can't see anything rendered on the screen at the moment. It's tricky to debug with my GSL shaders created using in-line in strings, but at least the thing is compiling now.
Replacing...
glUniformMatrix4fv(projectionMatrixLocation, 1, false, projection.caddr)
With...
glUniformMatrix4fv(projectionMatrixLocation, 1, false, cast[ptr float32] (projection.caddr))
Please let me know if this is a dangerous approach!

Related

Explain the meaning of X02AJF(0.D0)

If I have this function in fortran
DOUBLE PRECISION FUNCTION X02AJF()
! RETURNS (1/2)*B**(1-P) IF ROUNDS IS .TRUE.
! RETURNS B**(1-P) OTHERWISE
DOUBLE PRECISION X02CON
DATA X02CON / 2.D-3 /
! .. Executable Statements ..
X02AJF = X02CON
RETURN
END
then what is the value of this variable
EPS = X02AJF(0.D0)
I can't know what mean this
X02AJF(0.D0)???
Is it mean EPS=0 ??
I can't know what mean this
X02AJF(0.D0)???
In strict accordance with the FORTRAN language, this is a wrong function call.
Is it mean EPS=0 ??
No. EPS == 2.D-3, but this is undefined behavior.
Informally, before the OPTIONAL attribute Fortran 90, many often violated the requirement of matching the number of arguments. For example, the System V ABI AMD64 defines a call to the FORTRAN function as similar to a call to the C function. Therefore, in this case, the result of X02AJF(0.D0) will be the same as X02AJF().

How to create ndarray::ArrayView with custom strides?

I am facing a slice of numbers and want to create an ndarray::ArrayView out of this slice (without copying).
In the ArrayView, I want to include 2 numbers, then skip one, and so on. For example:
use ndarray::{ArrayView1, ShapeBuilder};
let numbers = &[0.0, 1.0, 10.0, 2.0, 3.0, 10.0];
let shape = // Some shape
let view = ArrayView1::from_shape(shape, numbers);
// Expected output for `view`:
// [0.0, 1.0, 2.0, 3.0]
Is there any way to set shape reaching the desired output?
Normal strides didn't work because they use a fix step size.
I also tried creating a 2x3 ArrayView2 out of numbers, then splitting the last column, and then flattening the array, but this cannot be done without copying because splitting breaks the memory layout.
I hope that it's possible to accomplish what I am trying to do.
ArrayView1 is a type alias for ArrayBase. The definition for ArrayBase is:
pub struct ArrayBase<S, D>
where
S: RawData,
{
/// Data buffer / ownership information. (If owned, contains the data
/// buffer; if borrowed, contains the lifetime and mutability.)
data: S,
/// A non-null pointer into the buffer held by `data`; may point anywhere
/// in its range. If `S: Data`, this pointer must be aligned.
ptr: std::ptr::NonNull<S::Elem>,
/// The lengths of the axes.
dim: D,
/// The element count stride per axis. To be parsed as `isize`.
strides: D,
}
D is essentially a list, so ArrayBase stores a list of dimensions and a list of strides. For ArrayView1, D basically ends up as [usize; 1], so you can only store a single length and stride.
To answer your question, sadly what you are asking for is not possible with ArrayView1, it lacks the storage space to hold multiple strides.

How to use boost::compute::atan2?

I would like to compute the phase of a complex number using boost::compute
here is my attempt, I expect the result to be equal to atan2(0.5f):
namespace bc = boost::compute;
bc::vector<std::complex<float>> vec{ {1.0f, 2.0f} };
bc::vector<float> result(1);
bc::transform(vec.begin(), vec.end(), result.begin(), bc::atan2<float>());
but I get a compilation error claiming "Non-unary function invoked one argument"
boost::compute's atan2 would appear to be a binary function just like std::atan2.
I'm assuming you're trying to obtain the phase angle of your complex number? The standard C++ function for this would be std::arg() - I don't see this one being defined in boost::compute, though I might have missed it.
If arg() is indeed missing, you're quite right it's implemented via atan2 - you'll need to extract the imaginary (boost::compute::imag()) and real (boost::compute::real()) components first though, and pass them as individual arguments to atan2.
I think you can also use Boost.Compute's lambda expressions for this:
bc::vector<float2> input{ {1.0f, 2.0f}, {3.0f, 4.0f}, {5.0f, 6.0f} };
bc::vector<float> output(3);
using boost::compute::lambda::atan2;
using boost::compute::_1;
using boost::compute::lambda::get;
bc::transform(
float2_input.begin(),
float2_input.end(),
float_output.begin(),
atan2(get<1>(_1), get<0>(_1)),
queue
);
float2 is bassically a complex in Boost.Compute. You can also check test_lambda.cpp.
I found a way to make it work.
stage 1: allocate 2 vectors:
bc::vector<std::complex<float>> vec{ {1.0f, 2.0f}, {3.0f, 4.0f}, {5.0f, 6.0f} };
bc::vector<float> result(3);
stage 2: interpret the complex vector as a float buffer iterator
buffer_iterator is quite useful when you have a strongly typed vector and would like to pass it to an algorithm as a different type.
auto beginf = bc::make_buffer_iterator<float>(vec.get_buffer(), 0);
auto endf = bc::make_buffer_iterator<float>(vec.get_buffer(), 6); // note end point to final index + 1
stage 3: define strided iterators so that we can use the same buffer as the argument for tan2. each iterator iterates the buffers in strides of 2 indices, and they supply tan2 with interleaved access to the buffer:
auto begin_a = bc::make_strided_iterator(beginf + 1, 2); // access imaginary part
auto end_a = bc::make_strided_iterator_end(beginf + 1, endf , 2);
auto begin_b = bc::make_strided_iterator(beginf, 2); // access real part
finally, call transform:
bc::transform(begin_a, end_a, begin_b, result.begin(), bc::atan2<float>()); // atan(b/a)
bc::system::default_queue().finish();

How do I represent sparse arrays in Pari/GP?

I have a function that returns integer values to integer input. The output values are relatively sparse; the function only returns around 2^14 unique outputs for input values 1....2^16. I want to create a dataset that lets me quickly find the inputs that produce any given output.
At present, I'm storing my dataset in a Map of Lists, with each output value serving as the key for a List of input values. This seems slow and appears to use a whole of stack space. Is there a more efficient way to create/store/access my dataset?
Added:
It turns out the time taken by my sparesearray() function varies hugely on the ratio of output values (i.e., keys) to input values (values stored in the lists). Here's the time taken for a function that requires many lists, each with only a few values:
? sparsearray(2^16,x->x\7);
time = 126 ms.
Here's the time taken for a function that requires only a few lists, each with many values:
? sparsearray(2^12,x->x%7);
time = 218 ms.
? sparsearray(2^13,x->x%7);
time = 892 ms.
? sparsearray(2^14,x->x%7);
time = 3,609 ms.
As you can see, the time increases exponentially!
Here's my code:
\\ sparsearray takes two arguments, an integer "n" and a closure "myfun",
\\ and returns a Map() in which each key a number, and each key is associated
\\ with a List() of the input numbers for which the closure produces that output.
\\ E.g.:
\\ ? sparsearray(10,x->x%3)
\\ %1 = Map([0, List([3, 6, 9]); 1, List([1, 4, 7, 10]); 2, List([2, 5, 8])])
sparsearray(n,myfun=(x)->x)=
{
my(m=Map(),output,oldvalue=List());
for(loop=1,n,
output=myfun(loop);
if(!mapisdefined(m,output),
/* then */
oldvalue=List(),
/* else */
oldvalue=mapget(m,output));
listput(oldvalue,loop);
mapput(m,output,oldvalue));
m
}
To some extent, the behavior you are seeing is to be expected. PARI appears to pass lists and maps by value rather than reference except to the special inbuilt functions for manipulating them. This can be seen by creating a wrapper function like mylistput(list,item)=listput(list,item);. When you try to use this function you will discover that it doesn't work because it is operating on a copy of the list. Arguably, this is a bug in PARI, but perhaps they have their reasons. The upshot of this behavior is each time you add an element to one of the lists stored in the map, the entire list is being copied, possibly twice.
The following is a solution that avoids this issue.
sparsearray(n,myfun=(x)->x)=
{
my(vi=vector(n, i, i)); \\ input values
my(vo=vector(n, i, myfun(vi[i]))); \\ output values
my(perm=vecsort(vo,,1)); \\ obtain order of output values as a permutation
my(list=List(), bucket=List(), key);
for(loop=1, #perm,
if(loop==1||vo[perm[loop]]<>key,
if(#bucket, listput(list,[key,Vec(bucket)]);bucket=List()); key=vo[perm[loop]]);
listput(bucket,vi[perm[loop]])
);
if(#bucket, listput(list,[key,Vec(bucket)]));
Mat(Col(list))
}
The output is a matrix in the same format as a map - if you would rather a map then it can be converted with Map(...), but you probably want a matrix for processing since there is no built in function on a map to get the list of keys.
I did a little bit of reworking of the above to try and make something more akin to GroupBy in C#. (a function that could have utility for many things)
VecGroupBy(v, f)={
my(g=vector(#v, i, f(v[i]))); \\ groups
my(perm=vecsort(g,,1));
my(list=List(), bucket=List(), key);
for(loop=1, #perm,
if(loop==1||g[perm[loop]]<>key,
if(#bucket, listput(list,[key,Vec(bucket)]);bucket=List()); key=g[perm[loop]]);
listput(bucket, v[perm[loop]])
);
if(#bucket, listput(list,[key,Vec(bucket)]));
Mat(Col(list))
}
You would use this like VecGroupBy([1..300],i->i%7).
There is no good native GP solution because of the way garbage collection occurs because passing arguments by reference has to be restricted in GP's memory model (from version 2.13 on, it is supported for function arguments using the ~ modifier, but not for map components).
Here is a solution using the libpari function vec_equiv(), which returns the equivalence classes of identical objects in a vector.
install(vec_equiv,G);
sparsearray(n, f=x->x)=
{
my(v = vector(n, x, f(x)), e = vec_equiv(v));
[vector(#e, i, v[e[i][1]]), e];
}
? sparsearray(10, x->x%3)
%1 = [[0, 1, 2], [Vecsmall([3, 6, 9]), Vecsmall([1, 4, 7, 10]), Vecsmall([2, 5, 8])]]
(you have 3 values corresponding to the 3 given sets of indices)
The behaviour is linear as expected
? sparsearray(2^20,x->x%7);
time = 307 ms.
? sparsearray(2^21,x->x%7);
time = 670 ms.
? sparsearray(2^22,x->x%7);
time = 1,353 ms.
Use mapput, mapget and mapisdefined methods on a map created with Map(). If multiple dimensions are required, then use a polynomial or vector key.
I guess that is what you are already doing, and I'm not sure there is a better way. Do you have some code? From personal experience, 2^16 values with 2^14 keys should not be an issue with regards to speed or memory - there may be some unnecessary copying going on in your implementation.

UnsafeMutablePointer<Int8> from String in Swift

I'm using the dgeev algorithm from the LAPACK implementation in the Accelerate framework to calculate eigenvectors and eigenvalues of a matrix. Sadly the LAPACK functions are not described in the Apple Documentation with a mere link to http://netlib.org/lapack/faq.html included.
If you look it up, you will find that the first two arguments in dgeev are characters signifying whether to calculate eigenvectors or not. In Swift, it is asking for UnsafeMutablePointer<Int8>. When I simply use "N", I get an error. The dgeev function and the error are described in the following screenshot
What should I do to solve this?
The "problem" is that the first two parameters are declared as char *
and not as const char *, even if the strings are not modified by the function:
int dgeev_(char *__jobvl, char *__jobvr, ...);
is mapped to Swift as
func dgeev_(__jobvl: UnsafeMutablePointer<Int8>, __jobvr: UnsafeMutablePointer<Int8>, ...) -> Int32;
A possible workaround is
let result = "N".withCString {
dgeev_(UnsafeMutablePointer($0), UnsafeMutablePointer($0), &N, ...)
}
Inside the block, $0 is a pointer to a NUL-terminated array of char with the
UTF-8 representation of the string.
Remark: dgeev_() does not modify the strings pointed to by the first two arguments,
so it "should be" declared as
int dgeev_(const char *__jobvl, const char *__jobvr, ...);
which would be mapped to Swift as
func dgeev_(__jobvl: UnsafePointer<Int8>, __jobvr: UnsafePointer<Int8>, ...) -> Int32;
and in that case you could simply call it as
let result = dgeev_("N", "N", &N, ...)
because Swift strings are converted to UnsafePointer<Int8>) automatically,
as explained in String value to UnsafePointer<UInt8> function parameter behavior.
It is ugly, but you can use:
let unsafePointerOfN = ("N" as NSString).UTF8String
var unsafeMutablePointerOfN: UnsafeMutablePointer<Int8> = UnsafeMutablePointer(unsafePointerOfN)
and use unsafeMutablePointerOfN as a parameter instead of "N".
With Swift 4.2 and 5 you can use this similar approach
let str = "string"
let unsafePointer = UnsafeMutablePointer<Int8>(mutating: (str as NSString).utf8String)
You can get the result from unsafePointer.

Resources