How can I name fields in an OCaml variant? [closed] - ocaml

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
Variants with lots of fields start to get unwieldy. The role of each field ends up in comments:
type ty =
| FunTy of (*all*) ty list * (*params*) ty list * (*return type*) ty
...
One solution is to have the value of the variant be a record.
type ty =
| FunTy of ft
...
and ft = {
forall : ty list;
p_tys : ty list;
ret_ty : ty
}
However, there's an indirection required to dereference the record fields. It doesn't matter for my purposes, but I can see this performance difference making the refactor above unidiomatic in practice.
To keep this answers objectivish, references to the OCaml docs or a style guide would help.

Since OCaml 4.03 (released in 2016) you can use inline records, which give you the nice interface of the record syntax — plus, you can have mutable fields — with the same memory representation as with the tuple syntax.
type ty =
| FunTy of {
forall : ty list;
p_tys : ty list;
ret_ty : ty
}
...
You have some facility to manipulate the contained record, but (not differently than the argument “tuple” in the tuple syntax) it is not a first-class value (see the documentation linked above for more details).

It's a matter of style, so I will note down my opinion on this.
With this particular example, where we have a choice between specifying the Variant constructor with a tuple or with record, even I think that for too many fields, record should be used.
Pattern-Matching anyway suffices in either case, whether it's tuple or record.
Whether it's tuple or record, all fields will have to be specified when dealing with values.
However the real advantage comes from the record dealing with too many fields, as
Record fields are identifiable via keys, and which is more convenient to manage and fields are treated in an order-insignificant manner, which means better control at the hands of the author.
Tuple fields are order-significant, which means the author will have to be careful while treating tuple data
Though tuples will be lesser on the memory side, but records do have advantages when the fields grow large in number.
This opinion is strictly with respect to tuple or record. Any other combination, may follow a different opinion... from me. :-)

When you see a variant type where a constructor is taking many parameter, you may wish to consider using more indirection in another way. Consider a simple, contrived example of specifying a type to build a triangle. We'd need to store coordinates for each corner in either 2D or 3D space.
type triangle =
Triangle_2d of float * float * (* Point A *)
float * float * (* Point B *)
float * float (* Point C *)
| Triangle_3d of float * float * float * (* Point A *)
float * float * float * (* Point B *)
float * float * float (* Point C *)
Talk about unweildy. So let's use records.
type triangle =
Triangle_2d of { ax : float; ay : float;
bx : float; by : float;
cx : float; cy : float }
| Triangle_3d of { ax : float; ay : float; az : float;
bx : float; by : float; bz : float;
cx : float; cy : float; cz : float }
But when we really think about it, aren't we just specifying coordinates? So maybe we should create a coordinate type.
type coordinate =
Coord_2d of { x : float; y : float }
| Coord_3d of { x : float; y : float; z : float }
And then our triangle type is simply:
type triangle =
Triangle_2d of { a : coord; b : coord }
| Triangle_3d of { a : coord; b : coord; c : coord }
Or even:
type triangle =
Triangle_2d of coord * coord
| Triangle_3d of coord * coord * coord
It's a lot cleaner to look at sure, but also it lets us break down the problem into smaller bites. If I want to calculate the distance between two vertices on the triangle, I don't need to do math with the whole triangle. I can simply define a function to deal with coordinates, and I can deal with the difference between 2D and 3D coordinates at this level. I could even break it down and write functions that project 3D coordinates onto a given axis or plane.

Related

How is a struct of struct's memory arranged by default in C++?

If I want to define a Matrix class in C++, for OpenGL rendering for example, the way I like to do it, and which also seems the most convenient, is to first define a Vector class as such :
class vec3 {
double x;
double y;
double z;
[ ... ]
}
class vec4 {
double x;
double y;
double z;
double w;
[ ... ]
}
Now, as far as I understand, the values of x, y, z{, w} are supposed to be contiguous in memory when I create a vec{3|4} (right ???).
If I then create my matrix as such :
class mat3 {
vec3 _m[3];
[ ... ]
}
class mat4 {
vec4 _m[4];
[ ... ]
}
Would the values of x, y, z{, w} of each vector in the matrix class always be next to one another in memory ? If I give the adress of the first element to OpenGL, which reads the next 16 values in memory (for a 4x4 matrix), would it read the 16 values of the matrix in order, or could some other information from elsewhere in the program get in the way ?
Edit (29/Nov./2019) : Fixed a typo
Would the values of x, y, z{, w} of each vector in the matrix class always be next to one another in memory ?
Probably not guaranteed to be so by the language, but probably will be contiguous in practice.
would it read the 16 values of the matrix
The behaviour of indexing over members is undefined in C++. The API probably written in C which may have different rules through.
There is a data structure that you can iterate over and is guaranteed to have 16 adjacent elements: array of 16 doubles.
The robust solution is to start with a double[16]. To the compiler, &vec3::y is just a way to express the offset of y, and you want that to be 1. You can achieve the same by writing
struct vec3 {
double* base;
double& x() { return *base; }
double& y() { return *(base+1); }
double& z() { return *(base+2); }
};
struct mat3 {
double values[9];
vec3 operator[](size_t s) { return vec3{values+3*s}; }
};
It's all inline, so the compiler can still calculate the offsets statically. There won't be a function call at runtime when you use y().
The standard allows arbitrary padding, so technically whether the members are contiguous in memory is implementation-defined. I don't know of any implementation that does something unexpected for your case though, so you should be fine by just adding a static_assert(sizeof(vec3) == 3 * sizeof(double));.
Similarly, accessing a bunch of members as if they were an array (i.e. via pointer arithmetic) in your code is undefined behavior by the standard, as there is no actual array object there. Now, if you give OpenGL this struct which has the values in the right places there should be no problem (because your compiler presumably doesn't touch the OpenGL code and the OpenGL only cares that the bytes are what they should be).
But note that this is only "fine" for the scope of the course I would say. For actual production code, these assumptions are too flimsy and a more robust (but possibly slightly less convenient) approach should be preferred.

Is reading inactive union member of the same type as active one well-defined? [duplicate]

This question already has an answer here:
Accessing same-type inactive member in unions
(1 answer)
Closed 6 years ago.
Consider the following structure:
struct vec4
{
union{float x; float r; float s};
union{float y; float g; float t};
union{float z; float b; float p};
union{float w; float a; float q};
};
Something like this seems to be used in e.g. GLM to provide GLSL-like types like vec4, vec2 etc..
But although the intended usage is like to make this possible
vec4 a(1,2,4,7);
a.x=7;
a.b=a.r;
, it seems to be an undefined behavior, because, as quoted here,
In a union, at most one of the data members can be active at any time, that is, the value of at most one of the data members can be stored in a union at any time.
Wouldn't it be better to e.g. use just define the structure something like the following?
struct vec4
{
float x,y,z,w;
float &r,&g,&b,&a;
float &s,&t,&p,&q;
vec4(float X,float Y,float Z,float W)
:x(X),y(Y),z(Z),w(W),
r(x),g(y),b(z),a(w),
s(x),t(y),p(z),q(w)
{}
vec4()
:r(x),g(y),b(z),a(w),
s(x),t(y),p(z),q(w)
{}
vec4(const vec4& rhs)
:x(rhs.x),y(rhs.y),z(rhs.z),w(rhs.w),
r(x),g(y),b(z),a(w),
s(x),t(y),p(z),q(w)
{}
vec4& operator=(const vec4& rhs)
{
x=rhs.x;
y=rhs.y;
z=rhs.z;
w=rhs.w;
return *this;
}
};
Or am I working around a non-existent issue? Is there maybe some special statement allowing access to identically-typed inactive union members?
I think the quote in which you are referring to is directed at having different types with in the union.
struct foo {
union {
float x,
int y,
double z,
};
};
These are different data, conveniently stored into the same structure, unions are not supposed to be a casting mechanism.
GLM approach uses the same data and uses the union for an alias mechanic.
Your approach might be 'better' C++ but its worse 'Engineering'. Vector math needs to be fast, and the smaller the better in this case.
Your implementation is makes the vector 3 times bigger. sizeof(glm::vec4); // 16 while sizeof(your_vec4); // 48 - ouch If you where processing a large armount of these which is often the case, 3 times as more cache misses with your_vec4.
I think you are right though glm's use of unions as alias's is a bit much, while I'm not sure if its undefined, but this type of thing I've seen a lot without much issue, and glm is widely used.
I don't really see the need to emulate glsl in C++, and struct { float x,y,z,w; } would be better (at least in my mind).

Simple trigonometric algorithm to compute sin() and cos() of fixed-point numbers

As I showed in other questions, i'm currently implementing a C++ metaprogramming library which includes, among other things, a set of types and metafunctions for compile-time arithmetic.
My goal now is to implement the trigonometric functions sin and cos for my fixed point type.
My problem is that every paper I have found about trigonometric algorithms talks about CORDIC or some kind of Taylor series. The problem with CORDIC is that it needs a huge set of precomputed values through a lookup-table, and I couln't provide it easilly with tmp. Also, the point of CORDIC is to compute that trigonometric functions in hardware which has not a multiplier, and i'm perfectly cappable to do multiplications with my library.
So my question is: Is there any other simple alternative to CORDIC and Taylor Series to compute trigonometric functions?
Finally I have implemented the sin metafunction through Taylor series, using series of 10 terms by default (Could be configurable).
I have based my implementation in this interesting article.
My library includes an implementation of a tmp for loop using iterators, and expression templates to allow write complex expressions in a "clear" way (Clear compared to the common template-meta-programming syntax add<mul<sub<1,2>>>...). This allows me to literally copy-paste the C implementation provided by the article:
template<typename T , typename TERMS_COUNT = mpl::uinteger<4>>
struct sin_t;
template<typename T , typename TERMS_COUNT = mpl::uinteger<4>>
using sin = typename sin_t<T,TERMS_COUNT>::result;
/*
* sin() function implementation through Taylor series (Check http://www10.informatik.uni-erlangen.de/~pflaum/pflaum/ProSeminar/meta-art.html)
*
* The C equivalent code is:
*
* // Calculate sin(x) using j terms
* float sine(float x, int j)
* {
* float val = 1;
*
* for (int k = j - 1; k >= 0; --k)
* val = 1 - x*x/(2*k+2)/(2*k+3)*val;
*
* return x * val;
* }
*/
template<mpl::fpbits BITS , mpl::fbcount PRECISION , unsigned int TERMS_COUNT>
struct sin_t<mpl::fixed_point<BITS,PRECISION>,mpl::uinteger<TERMS_COUNT>>
{
private:
using x = mpl::fixed_point<BITS,PRECISION>;
using begin = mpl::make_integer_backward_iterator<TERMS_COUNT-1>;
using end = mpl::make_integer_backward_iterator<-1>;
using one = mpl::decimal<1,0,PRECISION>;
using two = mpl::decimal<2,0,PRECISION>;
using three = mpl::decimal<3,0,PRECISION>;
template<typename K , typename VAL>
struct kernel : public mpl::function<decltype( one() - ( x() * x() )/(two() * K() + two())/(two()*K()+three())*VAL() )> {};
public:
using result = decltype( x() * mpl::for_loop<begin , end , one , kernel>() );
};
Here is the header of the implementation in the project repo.
huge set of precomputed values through a lookup-table
How many is "huge"? Sounds like a one-time effort that would be fast as hell once you were done. My advice? Get a shovel and fill in that table. You'd have it done by the time you get another answer here.

Confusion regarding OpenGL coordinate systems

I'm having trouble understanding the core concept of spaces in OpenGL. I've been reading an online book on modern 3D graphics for a couple weeks now and i often find myself confused with all of the spaces used in a program. To be specific, spaces such as: Model space , World space, Camera space, Clip space. I can't seem to wrap my mind around the order that i should be transforming the matrix from and into, an example from one of my tutorial programs:
//.vert shader of a program
#version 330
layout(location = 0) in vec4 position;
uniform mat4 cameraToClipMatrix;
uniform mat4 worldToCameraMatrix;
uniform mat4 modelToWorldMatrix;
void main()
{
vec4 temp = modelToWorldMatrix * position;
temp = worldToCameraMatrix * temp;
gl_Position = cameraToClipMatrix * temp;
}
cameraToClip , worldToCamera, XtoY, ZtoQ, how can i get an understanding of these spaces in OpenGL, websites? videos? references? Or should i just go back and re-read the information on these spaces in the tutorial until it attatches to my brain.
I really don't know how to explain it any better than I did. Especially when the matrices are named about as clearly as they can be.
Think of a matrix like a function. A function has inputs and it returns a value. You must pass the correct input or your compiler will complain.
Consider these functions:
Float intToFloat(Int i);
Double floatToDouble(Float f);
Real doubleToReal(Double d);
Where Int, Float, Double, and Real are user-defined C++ types.
Let's say I need to write this function:
Real intToReal(Int i);
So all I have is an Int. Of the above functions, there is exactly one function I can call: intToFloat. The name says it all: it takes an int and turns it into a float. Therefore, given an Int, the only thing I can do with it is call intToFloat.
Int i = ...;
Float f = intToFloat(i);
Well, now I have a Float. There is again only one function I can call: floatToDouble.
Double d = floatToDouble(d);
And with that, I can only call doubleToReal. Which means our intToReal function is:
Real intToReal(Int i)
{
Int i = ...;
Float f = intToFloat(i);
Double d = floatToDouble(d);
return doubleToReal(d);
}
Just like the matrix example.
The most important thing that a Vertex Shader does is transform positions from their original space (called model space) to the space that OpenGL defines called clip space. That's job #1 for most vertex shaders.
The matrices are just like those functions, converting the position into intermediate spaces along the way.
There can be no answer to this question until after it is solved. What will teach well enough to some people, for them to grok concepts, will not do the same for everybody. My best advice is to learn to be a 3D modeler before you become a 3D programmer. That's what I did. Once you have good familiarity with visualization of the data, then you can form mental models more easily, and code with them in mind. And when you need further visualizations to help you create algorithms, you'll be able to create them without using code.

Maths in Programing Video Games

I've just finished second year at Uni doing a games course, this is always been bugging me how math and game programming are related. Up until now I've been using Vectors, Matrices, and Quaternions in games, I can under stand how these fit into games.
This is a General Question about the relationship between Maths and Programming for Real Time Graphics, I'm curious on how dynamic the maths is. Is it a case where all the formulas and derivatives are predefined(semi defined)?
Is it even feasible to calculate derivatives/integrals in realtime?
These are some of things I don't see how they fit inside programming/maths As an example.
MacLaurin/Talor Series I can see this is useful, but is it the case that you must pass your function and its derivatives, or can you pass it a single function and have it work out the derivatives for you?
MacLaurin(sin(X)); or MacLaurin(sin(x), cos(x), -sin(x));
Derivatives /Integrals This is related to the first point. Calculating the y' of a function done dynamically at run time or is this something that is statically done perhaps with variables inside a set function.
f = derive(x); or f = derivedX;
Bilnear Patches We learned this as a way to possible generate landscapes in small chunks that could be 'sewen' together, is this something that happens in games? I've never heard of this (granted my knowlages is very limited) being used with procedural methods or otherwise. What I've done so far involves arrays for vertex information being processesed.
Sorry if this is off topic, but the community here seems spot on, on this kinda thing.
Thanks.
Skizz's answer is true when taken literally, but only a small change is required to make it possible to compute the derivative of a C++ function. We modify skizz's function f to
template<class Float> f (Float x)
{
return x * x + Float(4.0f) * x + Float(6.0f); // f(x) = x^2 + 4x + 6
}
It is now possible to write a C++ function to compute the derivative of f with respect to x. Here is a complete self-contained program to compute the derivative of f. It is exact (to machine precision) as it's not using an inaccurate method like finite differences. I explain how it works in a paper I wrote. It generalises to higher derivatives. Note that much of the work is done statically by the compiler. If you turn up optimization, and your compiler inlines decently, it should be as fast as anything you could write by hand for simple functions. (Sometimes faster! In particular, it's quite good at amortising the cost of computing f and f' simultaneously because it makes common subexpression elimination easier for the compiler to spot than if you write separate functions for f and f'.)
using namespace std;
template<class Float>
Float f(Float x)
{
return x * x + Float(4.0f) * x + Float(6.0f);
}
struct D
{
D(float x0, float dx0 = 0) : x(x0), dx(dx0) { }
float x, dx;
};
D operator+(const D &a, const D &b)
{
// The rule for the sum of two functions.
return D(a.x+b.x, a.dx+b.dx);
}
D operator*(const D &a, const D &b)
{
// The usual Leibniz product rule.
return D(a.x*b.x, a.x*b.dx+a.dx*b.x);
}
// Here's the function skizz said you couldn't write.
float d(D (*f)(D), float x) {
return f(D(x, 1.0f)).dx;
}
int main()
{
cout << f(0) << endl;
// We can't just take the address of f. We need to say which instance of the
// template we need. In this case, f<D>.
cout << d(&f<D>, 0.0f) << endl;
}
It prints the results 6 and 4 as you should expect. Try other functions f. A nice exercise is to try working out the rules to allow subtraction, division, trig functions etc.
2) Derivatives and integrals are usually not computed on large data sets in real time, its too expensive. Instead they are precomputed. For example (at the top of my head) to render a single scatter media Bo Sun et al. use their "airlight model" which consists of a lot of algebraic shortcuts to get a precomputed lookup table.
3) Streaming large data sets is a big topic, especially in terrain.
A lot of the maths you will encounter in games is to solve very specific problems, and is usually kept simple. Linear algebra is used far more than any calculus. In Graphics (I like this the most) a lot of the algorithms come from research done in academia, and then they are modified for speed by game programmers: although even academic research makes speed their goal these days.
I recommend the two books Real time collision detection and Real time rendering, which contain the guts of most of the maths and concepts used in game engine programming.
I think there's a fundamental problem with your understanding of the C++ language itself. Functions in C++ are not the same as mathmatical functions. So, in C++, you could define a function (which I will now call methods to avoid confusion) to implement a mathmatical function:
float f (float x)
{
return x * x + 4.0f * x + 6.0f; // f(x) = x^2 + 4x + 6
}
In C++, there is no way to do anything with the method f other than to get the value of f(x) for a given x. The mathmatical function f(x) can be transformed quite easily, f'(x) for example, which in the example above is f'(x) = 2x + 4. To do this in C++ you'd need to define a method df (x):
float df (float x)
{
return 2.0f * x + 4.0f; // f'(x) = 2x + 4
}
you can't do this:
get_derivative (f(x));
and have the method get_derivative transform the method f(x) for you.
Also, you would have to ensure that when you wanted the derivative of f that you call the method df. If you called the method for the derivative of g by accident, your results would be wrong.
We can, however, approximate the derivative of f(x) for a given x:
float d (float (*f) (float x), x) // pass a pointer to the method f and the value x
{
const float epsilon = a small value;
float dy = f(x+epsilon/2.0f) - f(x-epsilon/2.0f);
return epsilon / dy;
}
but this is very unstable and quite inaccurate.
Now, in C++ you can create a class to help here:
class Function
{
public:
virtual float f (float x) = 0; // f(x)
virtual float df (float x) = 0; // f'(x)
virtual float ddf (float x) = 0; // f''(x)
// if you wanted further transformations you'd need to add methods for them
};
and create our specific mathmatical function:
class ExampleFunction : Function
{
float f (float x) { return x * x + 4.0f * x + 6.0f; } // f(x) = x^2 + 4x + 6
float df (float x) { return 2.0f * x + 4.0f; } // f'(x) = 2x + 4
float ddf (float x) { return 2.0f; } // f''(x) = 2
};
and pass an instance of this class to a series expansion routine:
float Series (Function &f, float x)
{
return f.f (x) + f.df (x) + f.ddf (x); // series = f(x) + f'(x) + f''(x)
}
but, we're still having to create a method for the function's derivative ourselves, but at least we're not going to accidentally call the wrong one.
Now, as others have stated, games tend to favour speed, so a lot of the maths is simplified: interpolation, pre-computed tables, etc.
Most of the maths in games is designed to to as cheap to calculate as possible, trading speed over accuracy. For example, much of the number crunching uses integers or single-precision floats rather than doubles.
Not sure about your specific examples, but if you can define a cheap (to calculate) formula for a derivative beforehand, then that is preferable to calculating things on the fly.
In games, performance is paramount. You won't find anything that's done dynamically when it could be done statically, unless it leads to a notable increase in visual fidelity.
You might be interested in compile time symbolic differentiation. This can (in principle) be done with c++ templates. No idea as to whether games do this in practice (symbolic differentiation might be too expensive to program right and such extensive template use might be too expensive in compile time, I have no idea).
However, I thought that you might find the discussion of this topic interesting. Googling "c++ template symbolic derivative" gives a few articles.
There's many great answers if you are interested in symbolic calculation and computation of derivatives.
However, just as a sanity check, this kind of symbolic (analytical) calculus isn't practical to do at real time in the context of games.
In my experience (which is more 3D geometry in computer vision than games), most of the calculus and math in 3D geometry comes in by way of computing things offline ahead of time and then coding to implement this math. It's very seldom that you'll need to symbolically compute things on the fly and then get on-the-fly analytical formulae this way.
Can any game programmers verify?
1), 2)
MacLaurin/Taylor series (1) are constructed from derivatives (2) in any case.
Yes, you are unlikely to need to symbolically compute any of these at run-time - but for sure user207442's answer is great if you need it.
What you do find is that you need to perform a mathematical calculation and that you need to do it in reasonable time, or sometimes very fast. To do this, even if you re-use other's solutions, you will need to understand basic analysis.
If you do have to solve the problem yourself, the upside is that you often only need an approximate answer. This means that, for example, a series type expansion may well allow you to reduce a complex function to a simple linear or quadratic, which will be very fast.
For integrals, the you can often compute the result numerically, but it will always be much slower than an analytic solution. The difference may well be the difference between being practical or not.
In short: Yes, you need to learn the maths, but in order to write the program rather than have the program do it for you.