Maths in Programing Video Games - c++

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.

Related

Implementing Kalman filter in C++

I'd like to implement an extended Kalman filter in C++ using the eigen library because I'm interested in robotics, this seems like a good exercise to get better at C++ and it seems like a fun project. I was hoping I can post my code to get some feedback on writing classes and what my next steps should be from here. So I got the equations from a class online
what I have so far is below, I've hardcoded a state vector of size 2x1 and an array of measurements as a test but would like to change it so I can declare a state vector of any size, and I'll move the array of measurements to a main.cpp file. I just did this in the beginning so I can simply declare and object of this class and quickly test out the functions, and everything seems to be working so far. What I was thinking of doing next is to make another class that takes measurements from some source and converts it into eigen matrices to pass onto this kalman filter class. The main questions I have are:
Should I have the measurement update and state prediction as two different functions? Does it really matter? I did that in the first place because I thought it was easier to read.
Should I set the size of things like the state vector in the class constructor or is it better to have something like an initializer function for that?
I read that it's better practice to have class members that are matrices actually be pointers to the matrix, because it makes the class lighter. What does this mean? Is that important if I want to run this on a PC vs something like a raspberry pi?
In the measurementUpdate function, should y, S, K be class members? It'll make the class larger, but then I wouldn't be constructing and destroying the Eigen objects when the program is looping? Is that good practice?
Should there be a class member that takes the measurement inputs or is it better to just pass a value to the measurement update function? Does it matter?
Is it even worth it to try and implement a class for this or is it better to just have a single function that implements the filter?
removed this one because it wasn't a question.
I was thinking of implementing some getter functions so I can check the state variable and covariance matrix, is it better to just make those members public and not have the getter functions?
Apologies if this is posted in the wrong place and if these are super basic questions I'm pretty new to this stuff. Thanks for all the help, all advice is appreciated.
header:
#include "eigen3/Eigen/Dense"
#include <iostream>
#include <vector>
class EKF {
public:
EKF();
void filter(Eigen::MatrixXd Z);
private:
void measurementUpdate(Eigen::MatrixXd Z);
void statePrediction();
Eigen::MatrixXd P_; //Initial uncertainty
Eigen::MatrixXd F_; //Linearized state approximation function
Eigen::MatrixXd H_; //Jacobian of linearrized measurement function
Eigen::MatrixXd R_; //Measurement uncertainty
Eigen::MatrixXd I_; //Identity matrix
Eigen::MatrixXd u_; //Mean of state function
Eigen::MatrixXd x_; //Matrix of initial state variables
};
source:
EKF::EKF() {
double meas[5] = {1.0, 2.1, 1.6, 3.1, 2.4};
x_.resize(2, 1);
P_.resize(2, 2);
u_.resize(2, 1);
F_.resize(2, 2);
H_.resize(1, 2);
R_.resize(1, 1);
I_.resize(2, 2);
Eigen::MatrixXd Z(1, 1);
for(int i = 0; i < 5; i++){
Z << meas[i];
measurementUpdate(Z);
//statePrediction();
}
}
void EKF::measurementUpdate(Eigen::MatrixXd Z){
//Calculate measurement residual
Eigen::MatrixXd y = Z - (H_ * x_);
Eigen::MatrixXd S = H_ * P_ * H_.transpose() + R_;
Eigen::MatrixXd K = P_ * H_.transpose() * S.inverse();
//Calculate posterior state vector and covariance matrix
x_ = x_ + (K * y);
P_ = (I_ - (K * H_)) * P_;
}
void EKF::statePrediction(){
//Predict next state vector
x_ = (F_ * x_) + u_;
P_ = F_ * P_ * F_.transpose();
}
void EKF::filter(Eigen::MatrixXd Z){
measurementUpdate(Z);
statePrediction();
}
One thing to consider, which will affect the answers to ypur questions, is how 'generic' a filter you want to make.
There is no restriction in a Kalman filter that the sampling rate of the measurements be constant, nor that you get all the measurements every time. The only restriction is that the measurements appear in increasing time order. If you want to support this, then your measurement function will be passed arrays of variable sizes, and the H and R matrices will also be of variable size, and moreover the F and Q matrices (though of constant shape) will need to know the time update -- in particular you will need a function to compute Q.
As an example of what I mean, consider the example of some sort of survey boat that has a dgps sensor that gives a position every second, a gyro compass that gives the ship's heading twice a second, and a rgps system that gives the range and bearing to a towed buoy every two seconds. In this case we could get measurements like this:
at 0.0 gyro and dgps
at 0.0 gyro
at 1.0 gyro and dgps
at 1.5 gyro
at 2.0 gyro, dgps and rgps
and so on. So we get different numbers of observations at different times.
On a different topic I've always found it useful to have a way of seeing how well the filter is doing. Somewhat surprisingly the state covariance matrix is not a way of seeing this. In the linear (as opposed to extended) filter the state covariance could be computed for all times before you see any data! This is not true for the extended case as the state covariance depends on the states through the measurement Jacobian, but that is a very weak dependence on the observations. I think the most useful quality measures are those based on the measurements. Easy ones to compute are the 'innovations' -- the difference between the measured values and the values calculated using the predicted state -- and the residuals -- the difference between the measured values and the values calculated using the updated state. Each of these, over time, should have mean 0. If you want to get fancier there are the normalised residuals. If ita is the innovations vector, the normalised residuals are
T = inv(S)
u = T*ita
nr[i] = u[i]/sqrt( T[i][i])
The nice thing about the normalised residuals is that each (over time) should have mean 0 but also sd 1 -- if the filter is correctly tuned.

How to use C++ random function in Halide?

My goal is to be able to model signal-dependent Gaussian noise in Halide. I have a model built in OpenCV which I am now porting to Halide. The challenge is that Halide's random number generator is not normally distributed, so I need to use an external function to produce the noise values.
The implementation attempt uses the C++ random number generator to produced normally distributed noise, a Halide Func to produce the signal-depended standard deviations of the noise at each pixel, and then the noise is added to the pixels in renoise. Below I show the layout of the functions.
// Note: This is an implementation of the noise model found in the paper below:
// "Noise measurement for raw-data of digital imaging sensors by
// automatic segmentation of non-uniform targets"
float get_normal_dist_rand( float mean, float std_dev ) {
std::default_random_engine generator;
std::normal_distribution<float> distribution(mean,std_dev);
float out = distribution(generator);
return out;
}
Func make_get_std_dev( Func *in_func ) {
Var x, y, c;
float q = 0.0060;
float p = 0.0500;
// std_dev = q * sqrt(unnoised_pixel - p)
Func get_std_dev("get_std_dev");
get_std_dev(x,y,c) = q * sqrt( (*in_func)(x,y,c) - p );
return get_std_dev;
}
Func make_renoise( Func *in_func, Func *std_dev ) {
Var x, y, c;
// Noise parameters
// noised_pixel = unnoised_pixel +
// gaussian_rand( std_dev = q * sqrt(unnoised_pixel - p) )
// q and p values do not vary between channels
Func renoise("renoise");
renoise(x,y,c) = (*in_func)(x,y,c) +
get_normal_dist_rand(0,(*std_dev)(x,y,c));
return renoise;
}
This makes sense to me, but unfortunately I receive the following error when I try to compile:
../common/pipe_stages.cpp: In function 'Halide::Func make_renoise(Halide::Func*, Halide::Func*)':
../common/pipe_stages.cpp:223:64: error: cannot convert 'std::enable_if<true, Halide::FuncRef>::type {aka Halide::FuncRef}' to 'float' for argument '2' to 'float get_normal_dist_rand(float, float)'
get_normal_dist_rand(0,(*std_dev)(x,y,c));
^
So it seems that the output of a Func cannot be provided to a C++ function. I guess this makes sense as a limitation of Halide, but I don't really see an alternative to implement the signal dependent normally distributed noise. Is there another way to use external C++ functions in Halide? I have seen folks talking about using "extern" but unfortunately documentation on that functionality seems to be quite light, and I am unable to find what I need.
You'll need to use one of our extern mechanisms to bind to C++ code. HalideExtern_* is the easier of the two and will let you make a call to get random numbers one at a time. Alas test/correctness/c_function.cpp is the immediate example for this, which will help, but could be clearer.
I expect you'll want to request a buffer of random numbers at a time for efficiency reasons. This can be done via the define_extern mechanism. The C++ function has to participate in bounds inference so it is a little more involved. The test for this is correctness/extern_producer.cpp.
I'd expect either transforming our random numbers to be appropriately distributed or implementing the random number generation algorithm in Halide is the right way to go for really fast production code, but that is likely more work than you want to do to get this working initially.
You could also use Halide's RNG along with a binomial approximation to the Gaussian:
Expr gaussian_random(Expr sigma) {
return (random_float() + random_float() + random_float() - 1.5f) * 2 * sigma;
}
Add more instances of randomFloat to get closer and closer to a true normal distribution.

Calling Stan routines from a C++ program

I read here that it is possible (and I interpreted straightforward) to call Stan routines from a C++ program.
I have some complex log-likelihood functions which I have coded up in C++ and really have no idea how I could code them using the Stan language. Is it possible to call the Monte Carlo routines in Stan using the log-likelihood function I have already coded in C++? If so are there any examples of this?
It seems like quite a natural thing to do but I cannot find any examples or pointers as to how to do this.
Upon further review (you may want to unaccept my previous answer), you could try this: Write a .stan program with a user-defined function in the functions block that has the correct signature (and parses) but basically does nothing. Like this
functions {
real foo_log(real[] y, vector beta, matrix X, real sigma) {
return not_a_number(); // replace this after parsing to C++
}
}
data {
int<lower=1> N;
int<lower=1> K;
matrix[N,K] X;
real y[N];
}
parameters {
vector[K] beta;
real<lower=0> sigma;
}
model {
y ~ foo(beta, X, sigma);
// priors here
}
Then, use CmdStan to compile that model, which will generate a .hpp file as an intermediate step. Edit that .hpp file inside the body of foo_log to call your templated C++ function and also #include the header file(s) where your stuff is defined. Then recompile and execute the binary.
That might actually work for you, but if whatever you are doing is somewhat widely useful, we would love for you to contribute the C++ stuff.
I think your question is a bit different from the one you linked to. He had a complete Stan program and wanted to drive it from C++, whereas you are asking if you could circumvent writing a Stan program by calling an external C++ function to evaluate the log-likelihood. But that would not get you very far because you still have to pass in the data in a form that Stan can handle, declare to Stan what are the unknown parameters (plus their support), etc. So, I don't think you can (or should) evade learning the Stan language.
But it is fairly easy to expose a C++ function to the Stan language, which essentially just involves adding your my_loglikelihood.hpp file in the right place under ${STAN_HOME}/lib/stan_math_${VERSION}/stan/math/, adding an include statement to the math.hpp file in that subdirectory, and editing ${STAN_HOME}/src/stan/lang/function_signatures.h. At that point, your .stan program could look as simple as
data {
// declare data like y, X, etc.
}
parameters {
// declare parameters like theta
}
model {
// call y ~ my_logliklihood_log(theta, X)
}
But I think the real answer to your question is that if you have already written a C++ function to evaluate the log-likelihood, then rewriting it in the Stan language shouldn't take more than a few minutes. The Stan language is very C-like so that it is easier to parse the .stan file into a C++ source file. Here is a Stan function I wrote for the log-likelihood of a conditionally Gaussian outcome in a regression context:
functions {
/**
* Increments the log-posterior with the logarithm of a multivariate normal
* likelihood with a scalar standard deviation for all errors
* Equivalent to y ~ normal(intercept + X * beta, sigma) but faster
* #param beta vector of coefficients (excluding intercept)
* #param b precomputed vector of OLS coefficients (excluding intercept)
* #param middle matrix (excluding ones) typically precomputed as crossprod(X)
* #param intercept scalar (assuming X is centered)
* #param ybar precomputed sample mean of the outcome
* #param SSR positive precomputed value of the sum of squared OLS residuals
* #param sigma positive value for the standard deviation of the errors
* #param N integer equal to the number of observations
*/
void ll_mvn_ols_lp(vector beta, vector b, matrix middle,
real intercept, real ybar,
real SSR, real sigma, int N) {
increment_log_prob( -0.5 * (quad_form_sym(middle, beta - b) +
N * square(intercept - ybar) + SSR) /
square(sigma) - # 0.91... is log(sqrt(2 * pi()))
N * (log(sigma) + 0.91893853320467267) );
}
}
which is basically just me dumping what could otherwise be C-syntax into the body of a function in the Stan language that is then callable in the model block of a .stan program.
So, in short, I think it would probably be easiest for you to rewrite your C++ function as a Stan function. However, it is possible that your log-likelihood involves something exotic for which there is currently no corresponding Stan syntax. In that case, you could fall back to exposing that C++ function to the Stan language and ideally making pull requests to the math and stan repositories on GitHub under stan-dev so that other people could use it (although then you would also have to write unit-tests, documentation, etc.).

C++: How to compute an integral with interval bounds?

I am both tired, new to C++ and real bad at dealing with polynomials. That's a bad combo for my assignment. Nevertheless I am trying to solve it. Please note that I might have misunderstood certain parts both mathematically and language-wise. Maybe even terminology.
The first task of my assignment was to create a class for storing polynomials. I figured the important parts were coefficiants and the degree of the polynomial. As such I have a polynomial class that (partly) looks like this:
class Polynomial {
private:
double* Coefficients; //Array of coefficients in order of ascending power
int Degree; //The degree of the polynomial
...
The class should have a method for finding the integral of the polynomial within a lower and upper bound. But I really do not know how to work with it.
Since it's bad practise not to show what I've done, this is what I currently have, and it probably does not make a lot of sense, but please, if you can, point me in the right direction?
Polynomial Polynomial::ComputeIntegral(double lower, double upper) {
//Values needed to create new polynomial
//degree will be one more than the original polynomial
int degree = Degree + 1;
double* coefficients = new double[degree + 1];
coefficients[0] = 0;
for (int i = 0; i < degree +1; i++) {
coefficients[i + 1] = Coefficients[i] / (double)(i + 1);
}
Polynomial integral(degree, coefficients);
return integral;
}
That I can see myself, it is messed up because a) I do not use the bounds, and b) I am pretty sure per the assignment description I should end up with a value rather than a new polynomial.
Google tells me there are algorithms to deal with finding integrals (Trapezoid for example), but I can not wrap my head around matching that with my representation of a polynomial.
A few pointers:
Use std::vectors instead of pointers and new. (If you are new to C++, there are very few circumstances when you actually need to use new.)
ComputeIntegral(double, double) will need to return a double, since it is obviously computing a definite integral. (The function you have at the moment would be something like GetPrimitive(), as it returns the primitive of the polynomial, which is another poly.
The definite integral is the difference of the primitive evaluated at the bounds (First Fundamental theorem of calculus).
There are a number of ways you could represent the polynomial as a data structure, but I would suggest a single std::vector<double> coeffs that represents all of the coefficients up to the degree of the poly, then the degree can be calculated at coeffs.size(). In some cases there may be zeroes in that coeffs though.
In the general case, it is possible to use the boost library to compute integrals: https://www.boost.org/doc/libs/1_77_0/libs/math/doc/html/quadrature.html
There is also the library ALGLIB that I have used to compute integrals. Here is an example to compute integrals with ALGLIB: Integrate a public but non static member function with ALGLIB

Function of a letter in C++

I have the following expression:
A = cos(5x),
where x is a letter indicating a generic parameter.
In my program I have to work on A, and after some calculations I must have a result that must still be a function of x , explicitly.
In order to do that, what kind of variable should A (and I guess all the other variables that I use for my calculations) be?
Many thanks to whom will answer
I'm guessing you need precision. In which case, double is probably what you want.
You can also use float if you need to operate on a lot of floating-point numbers (think in the order of thousands or more) and analysis of the algorithm has shown that the reduced range and accuracy don't pose a problem.
If you need more range or accuracy than double, long double can also be used.
To define function A(x) = cos(5 * x)
You may do:
Regular function:
double A(double x) { return std::cos(5 * x); }
Lambda:
auto A = [](double x) { return std::cos(5 * x); };
And then just call it as any callable object.
A(4.); // cos(20.)
It sounds like you're trying to do a symbolic calculation, ie
A = magic(cos(5 x))
B = acos(A)
print B
> 5 x
If so, there isn't a simple datatype that will do this for you, unless you're programming in Mathematica.
The most general answer is "A will be an Expression in some AST representation for which you have a general algebraic solver."
However, if you really want to end up with a C++ function you can call (instead of a symbolic representation you can print as well as evaluating), you can just use function composition. In that case, A would be a
std::function<double (double )>
or something similar.