Code Monkey home page Code Monkey logo

linalg's People

Contributors

ddiakopoulos avatar quinor avatar runningskull avatar sgorsten avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

linalg's Issues

rotation_quat fails in some cases

With rotation matrix {0,-1,0,0,-1,0,0,0,-1}, the function rotation_quat returns {0.7071068,0.7071068,0,0} instead of {-0.7071068,0.7071068,0,0}.

Unit tests

linalg.h is textually short, but very general. Most operations have been generalized over:

  • whether operation acts on vectors or matrices
  • underlying element type
  • size of vector or dimensions of matrix
  • whether one of the arguments is a scalar of the element type
  • if one of the arguments is a scalar, whether it is on the left or the right

Additionally, names have been deliberately chosen to be terse, allowing for the concise expression of complex mathematical formula. This means plenty of potential name collisions with the std:: namespace and the potential for unintended argument-dependent lookup.

We're going to need a good set of unit tests to make sure that all templates are being instantiated across the range of reasonable types, sizes, and argument combinations. We don't need to get super exhaustive, given that most functions are one-liners and many functions share common structure, but we should make sure we're equipped to catch regressions as the library evolves.

User Code Extensions

Hi, I'm currently looking into linalg as a replacement for glm, and so far I like linalg a lot.

However I'd like a little more flexibility; specifically I think it would be useful if linalg directly supported user code extensions to the vec and mat data structures via macros, e.g. in each of the template instantiations there would be a declaration like this:

template<class T> struct vec<T,2>
{
#ifdef LINALG_VEC2_USER
   LINALG_VEC2_USER
#endif
 // ...

This trivially allows user code to extend these types, for example by adding custom ctors or operator overloads. In my case this would significantly simplify the transition from glm -> linalg by injecting glm behavior:

  • mat * mat operators for matrix-matrix multiplication.
  • mat * vec operators for matrix-vector multiplication.
  • mat3 ctor from the upper 3x3 elements of a mat4 (extract rotation/scale matrix).
  • Per-element scalar ctors for matrix types.

Convert a mat4 to a mat3 and back

Hi,
I am not sure if I am missing something so please correct me if there already is an easier way to do this. Here's what I want to do:

  • Convert a mat4 transformation matrix to a mat3 rotation matrix (essentially dropping the translation part)
  • Convert it back to a mat4 with the translation part set to {0, 0, 0}

This is a pretty common operation for a bunch of 3D rendering related tasks. I have been doing that manually so far (the types are just linalg typedefs):


auto skyboxViewRot = Mat3f { transform.x.xyz(), transform.y.xyz(), transform.z.xyz() };
auto skyboxView = Mat4f { Vec4f { skyboxViewRot.x, 0.0f },
                                        Vec4f { skyboxViewRot.y, 0.0f },
                                        Vec4f { skyboxViewRot.z, 0.0f },
                                        Vec4f { 0.0f, 0.0f, 0.0f, 1.0f } };

I am pretty sure in glm the mat3 and mat4 constructors allow you to do this as one liners. Is there a similar way to achieve this in linalg? Otherwise I think it might be useful to add utilities for these operations (not sure if this is beyond the scope of the library but these seem to be very common operations to me).

Thanks!

Undefined behavior on operator[] overload prevents use in constexpr context

Good time of day.
For start, my applause to this great library.

I've done some experiments with the code and I want to share a few considerations.
An attempt to create a general form of mat and vec is complicated for compat with constexpr semantic in current library form.

	constexpr const T & operator[] (int i) const { return (&x)[i]; }

It isn't really constexpr and that is very sad, becourse we cann't use access in general form's constexpr method.

I intended to offer change declaration

	T x,y;

to

    union { std::array<T,2> a; struct { T x,y; }; };

with

    T & operator[] (int i) { return a[i]; }

for support general constexpr access. But, for some reason of current implementation of constexp in c++, we can not effectively use initialization through x, y, z, and access through an array.

I tried to rewrite the entire library to work through an array. The result is here https://github.com/Mirmik/linalg/blob/master/linalg.h. This is a slightly more ugly solution, but in the context of it we can create a comfortable general form mat and vec (sketch here: https://github.com/Mirmik/linalg/blob/master/linalg_ext.h).

What do you think about it all?

Identity()

I see that the design of linalg is rather minimalistic and this may be seen as a feature creep.
So I don't mind if you just close this issue.
That said, a function to generate an identity matrix is often handy, even if it's trivial to write it manually.

Impossible to create row vectors

mat<T, 1, N> is not defined. transpose(vec<T, 3>()) does not work. I see no way to construct row vectors. But then, how do I multiply something with a row vector specifically?

Doesn't build on MSVC 2017

1>c:\vs_projs\vulkan repo\example\include\linalg.h(305): error C2988: unrecognizable template declaration/definition
1>c:\vs_projs\vulkan repo\example\include\linalg.h(305): error C2059: syntax error: 'const'
1>c:\vs_projs\vulkan repo\example\include\linalg.h(305): error C2059: syntax error: ')'
1>c:\vs_projs\vulkan repo\example\include\linalg.h(305): error C2143: syntax error: missing ';' before '{'
1>c:\vs_projs\vulkan repo\example\include\linalg.h(305): error C2447: '{': missing function header (old-style formal list?)

"Fixed" by commenting out the affected line

`using namespace linalg::ostream_overloads` sometimes does not work.

using namespace linalg::ostream_overloads sometimes does not work as planed.
For example doctest library(https://github.com/onqtam/doctest) does not found operator defined like this.

It might be a good idea to change it in the documentation for this way:

#include "linalg.h"
namespace linalg { using linalg::ostream_overloads::operator <<; }

It works better because c++ adl mechanism lookup function in argument`s namespaces first. So, in other places it can ignore overloaded operator for various reasons.

(In fact, it's not entirely clear to me why the overloads are generally hidden. )

Thanks for your work.

General implementation of `vec<T,M>` and `mat<T,M,N>`

Presently, vec<T,M> is only defined for M equal to 2, 3, or 4, and mat<T,M,N> is only defined for M and N equal to 2, 3, or 4. This is mainly to allow for the presence of member variables x, y, z, and w when appropriate, and to allow for construction using the {x,y,z} syntax.

Should we also provide a general implementation of vec and mat which would handle sizes greater than four? These could simply use a backing array (or perhaps std::array). They would not support element access with .x, .y, etc., but would support access by array index, as well as all other functions and operators.

Future usability wishlist

linalg.h was my first formal introduction to linear algebra, and most of my current game projects depend on it. Thank you. I feel that the library can be further improved for n00b-friendliness. Here is my current usability wishlist, for the next release that has breaking changes.

Change linalg namespace to alg

It's shorter.

Global precision qualifier macro

#define alg::FLOAT float
#define alg::FLOAT double
#define alg::FLOAT long double

Similar to GLSL behavior, i.e. GLSL's precision mediump. Precision qualifiers would only affect the following new types.

GLSL types

alg::mat2 / alg::mat3 / alg::mat4
alg::vec2 / alg::vec3 / alg::vec4
alg::FLOAT

These types are set to the precision specified by alg::FLOAT.

GLM-style matrix multiplication

4x4 matrix multiplication is one of the most common things graphics programmers do. Having to type linalg::mul for each operation is crazy, and Lobster has gone ahead and adapted linalg's syntax to use * multiplication.

Reduction functions for matrices?

I just tried to call argmax() with a matrix as an argument and realized that the reductions here work only for vectors.

So here is a feature request to consider: functions such as sum() and argmax() for matrices.

Fix semantics of operator overloads on matrices.

Based on consistent feedback from many users, I have come to the conclusion that my original design decision of having all non-comparison operator overloads be defined in terms of element-wise application to values of the same dimensions to be in error.

Most users expect the expression matrix * matrix to perform matrix multiplication, and matrix * vector to perform matrix multiplication by interpreting the vector as a single column matrix, matching the semantics of GLSL. Currently, linalg.h has the somewhat surprising behavior of treating matrix * matrix as an element-wise multiplication.

It is my intention to modify the library to match users' expectations by restricting the set of operator overloads on matrices to those operations which are well defined in linear algebra, to more closely match users' expectations. This is a breaking change, and is thus targeted for v3.0.

mul(a,b,c) with visual studio 2017 release candidate

Only hit one snag with visual studio 2017 RC.
With existing projects that worked fine with earlier compiler (20150), I now get the compiler error:

c:\users...\include\linalg.h(301): fatal error C1202: recursive type or function dependency context too complex

which refers to the following line of code:

    template<class T, int M, int N, class... R> auto mul(const mat<T,M,N> & a, R... r) -> decltype(mul(a, mul(r...))) { return mul(a, mul(r...)); }

This routine is typically used in lines of code that multiply 3 matrices together such as:

    float3x3 Iinv = mul(s_orientation_matrix, tensorinv, transpose(s_orientation_matrix));

As a temporary workaround, i just commented out this implementation of mul(...) and replaced it with a specific one takes 3 float3x3s since that's the only use case i need at the moment.

    inline float3x3 mul(const float3x3 &a, const float3x3 &b, const float3x3 &c) { return mul(mul(a, b), c);  }  // VS2017 release candidate failing to compile the multi-arg mul from linalg.h

Sure, that works. However, ideally would rather have a general mul that takes an arbitrary number of matrices of any compatible types. Any ideas? Wait for MS to fix compiler? or is there something that can be reworked within the linalg.h implementation?

note I'm submitting this issue primarily for awareness, this is not an urgent issue for me.

thanks

Initializing a std::array of vecs

I have the following code:

std::array<linalg::aliases::int2,8> offsets = { {0, -1}, {-1, 0}, {1, 0}, {0, 1}, {-1, -1}, {1, -1}, {-1, 1}, {1, 1} };

This does not compile (error: too many initializers for ‘std::array<linalg::vec<int, 2>, 8>’). However, this does compile:

linalg::aliases::int2 offsets[8] = { {0, -1}, {-1, 0}, {1, 0}, {0, 1}, {-1, -1}, {1, -1}, {-1, 1}, {1, 1} };

As does this:

std::vector<linalg::aliases::int2> offsets = { {0, -1}, {-1, 0}, {1, 0}, {0, 1}, {-1, -1}, {1, -1}, {-1, 1}, {1, 1} };

Is it to be expected that initializing a std::array of vecs in this manner does not work, whereas a plain array or std::vector does?

Suggestion: projection_onto() and rejection_from() functions for vectors

For example:

template<class T> struct vec<T,4>
{
    // ...
    vec<T,4>                    projected_onto(vec<T,4> const& v)   { return (dot(*this,v)/dot(v,v)) * v;}
    vec<T,4>                    rejection_from(vec<T,4> const& v)   { return *this - this->projected_onto(v); }
    // ...
}

I feel like projection_onto() at least is common enough to warrant inclusion.

Question about column order.

I want to ask a question that does not give me peace for a long time, and to which I can’t find a definite answer.
Why in general and in this library in particular the column order is used?
What is the advantage of column order over row order and otherwise?
Why did you choose the column order for this library?

`mul()` gives wrong answer?

#include "linalg.h"
#include <iostream>

using namespace linalg::aliases;
using namespace linalg::ostream_overloads;
using namespace std;

int main() {

    float3x3 A = {
        {1.f, 0.f, 3.f},
        {0.f, 1.f, 3.f},
        {0.f, 0.f, 1.f},
    };

    float3x3 B = {
        {2.f, 0.f, 0.f},
        {0.f, 2.f, 0.f},
        {0.f, 0.f, 1.f},
    };

    cout << mul(A, B) << endl;

    /* 
     * the result output by this program is {{2,0,6},{0,2,6},{0,0,1}}, while by Octave:
     *
     * >> a = [ [1 0 3]; [0 1 3]; [0 0 1] ]
     * a =
     * 
     *    1   0   3
     *    0   1   3
     *    0   0   1
     * 
     * >> b = [[2 0 0]; [0 2 0]; [0 0 1]]
     * b =
     * 
     *    2   0   0
     *    0   2   0
     *    0   0   1
     * 
     * >> a * b
     * ans =
     * 
     *    2   0   3
     *    0   2   3
     *    0   0   1
     * */

    return 0;
}

while the document states mul(mat<T,M,N> a, mat<T,N,P> b) -> mat<T,M,P>, the library seems to calculate mul(b, a).

Is something I made wrong? or there is a bug in the library?

avoid GCC -Wshadow warnings?

At first glance it is only about constructors.
Would it be OK to change vec(T x, T y) : x(x), y(y) etc to, say, vec(T x_, T y_) : x(x_), y(y_)?

-Wshadow needs to be enabled explicitely so I guess few people use it. What's your opinion? I could provide PR if it'd be helpful.

../linalg.h: In constructor ‘constexpr linalg::vec<T, 2>::vec(T, T)’:
../linalg.h:69:69: warning: declaration of ‘y’ shadows a member of ‘linalg::vec<T, 2>’ [-Wshadow]
         constexpr                   vec(T x, T y)                   : x(x), y(y) {}
                                                                     ^
../linalg.h:67:39: note: shadowed declaration is here
         T                           x,y;
                                       ^

Mixed-mode arithmetic

The C standard allows for arithmetic operators to act on different data types, for instance, int + short, float * double, or int + float. In these cases, type promotion rules come into effect to determine the resulting type.

We currently allow integer promotion on arithmetic operators, for instance, short2() + short2() == int2().

Should we allow mixed-mode operations, such as short2() + int2(), float3() * double3(), etc? The result of doing so seems fairly well defined, and could make it easier to convert existing scalar algorithms to use linalg vector types.

If so, should we also permit scalars to participate, such as short2() + int(), float3() * double()? This seems a little bit more problematic. In the expression float() * 0.5, 0.5 is treated by the compiler as a floating point constant, but in the expression float3() * 0.5, 0.5 would be treated as a double and cause the result of the expression to be promoted to double3.

Feature request: Disable operator * for matrices?

Hi and thanks for the lib! It's by far one of the least bloated linear algebra libs we have found, and we have had great success with it so far!

Well, except for one aspect. We have had quite a few bugs where people implicitly assumed that the * operator was matrix multiply (and not element-wise multiply). We have become more used to using mul() now, but it's still a problem that pops up every now and then.

So the feature request we have is to be able to disable operator * for matrices (but not for vectors) so that we don't accidentally do element-wise multiplication instead of matrix multiplication.

Have a nice day!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.