From ee0ca039e15412fa49417270642876ae252b6501 Mon Sep 17 00:00:00 2001 From: Rachel Hwang Date: Mon, 29 Feb 2016 18:22:46 -0500 Subject: [PATCH 01/23] viewer done --- CMakeLists.txt | 9 +- README.md | 43 ++++- src/.DS_Store | Bin 0 -> 8196 bytes src/camera/camera.cpp | 167 ++++++++++++++++++ src/camera/camera.hpp | 58 ++++++ src/fluidSolver/fluidSolver.cpp | 8 + src/fluidSolver/fluidSolver.hpp | 6 + src/geom/cube.cpp | 89 ++++++++++ src/geom/cube.hpp | 28 +++ src/geom/geom.cpp | 2 + src/geom/geom.hpp | 39 ++++ src/geom/particles.cpp | 77 ++++++++ src/geom/particles.hpp | 42 +++++ src/main.cpp | 3 +- src/main.hpp | 2 + src/scene/.DS_Store | Bin 0 -> 6148 bytes src/scene/scene.cpp | 96 ++++++++++ src/scene/scene.hpp | 21 ++- .../SimpleFragmentShader.fragmentshader | 15 ++ src/viewer/SimpleVertexShader.vertexshader | 22 +++ src/viewer/shader.cpp | 110 ++++++++++++ src/viewer/shader.hpp | 6 + src/viewer/viewer.cpp | 116 ++++++++++++ src/viewer/viewer.hpp | 39 ++++ 24 files changed, 987 insertions(+), 11 deletions(-) create mode 100644 src/.DS_Store create mode 100644 src/geom/cube.cpp create mode 100644 src/geom/cube.hpp create mode 100644 src/geom/particles.cpp create mode 100644 src/geom/particles.hpp create mode 100644 src/scene/.DS_Store create mode 100755 src/viewer/SimpleFragmentShader.fragmentshader create mode 100755 src/viewer/SimpleVertexShader.vertexshader create mode 100755 src/viewer/shader.cpp create mode 100755 src/viewer/shader.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0da15cd6..c794456e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,7 +54,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(COCOA "-framework Cocoa") set(COREVIDEO "-framework CoreVideo") set(IOKIT "-framework IOKit") - set(CORELIBS ${CORELIBS} ${COCOA} ${IOKIT} ${COREVIDEO}) + set(CORE_LIBS ${CORE_LIBS} ${COCOA} ${IOKIT} ${COREVIDEO}) endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") # Linux specific hacks/fixes @@ -84,11 +84,14 @@ endif() set(CORE_SRC src/main.cpp src/camera/camera.cpp + src/viewer/shader.cpp src/viewer/viewer.cpp src/fluidSolver/fluidSolver.cpp src/scene/scene.cpp src/geom/geom.cpp + src/geom/cube.cpp + src/geom/particles.cpp ) -add_executable(Thanda ${CORE_SRC}) -target_link_libraries(Thanda ${CORE_LIBS}) \ No newline at end of file +add_executable(Thanda ${CORE_SRC} src/viewer/SimpleVertexShader.vertexshader src/viewer/SimpleFragmentShader.fragmentshader) +target_link_libraries(Thanda ${CORE_LIBS}) diff --git a/README.md b/README.md index 54283261..39d1b285 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,47 @@ # CIS563-FluidSolver (Credit : CIS565 README) -Fluid Solver Submission guidelines: +Hello! +All required functionality implemented, although I plan to go back and change my collision so that things are deleted properly as opposed to just changing color. -- If you have modified any of the CMakeLists.txt files at all (aside from the list of CORE_SRC), you must test that your project can build. Beware of any build issues. +#Controls -- Open a GitHub pull request so that we can see that you have finished. The title should be "Submission: YOUR NAME". +UP: zoom in +DOWN: zoom out +LEFT: pan left +RIGHT: pan right +W: rotate about the camera right axis, negative direction +S: rotate about the camera right axis, positive direction +A: rotate about the camera up axis, negative direction +D: rotate about the camera up axis, positive direction -- In the body of the pull request, include a link to your repository. +#Organization + +Camera: +Stores all camera operations for matrix computation and movement. + +FluidSolver: +Will eventually be library of functions to act on Particles. + +Scene: +Container for scene geometry. Initializes scene with json. + +Viewer: +Calls all the window operations. Draws geometry with a call from scene. + +Geometry: +Abstract class defining required functionality for the subclasses... basically just the create function for now. + + Particles: + A object storing a list of particle positions and states in a bunch of parallel vectors... I'm considering changing to having a particle object also. Also a particle init function. + + Cube: + Essentially just used for the fluid container. Basic cube drawing. + +#External code + +I used the open gl tutorial code as reference. I changed most of the code, but I'm using the loadShader code in shader.cpp verbatim. This is the code for loading the shader programs, which reads in the fragement and vertex shader code, compiles it, and links it, checking for errors at each step. This essentially just does everything necessary to actually use the shaders. -- Submit on canvas with a direct link to your pull request on GitHub -And you're done! \ No newline at end of file diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..9db3146de98630ba9f669a790a9c0cec38997118 GIT binary patch literal 8196 zcmeHMT}&KR6g~$ioeR`n{>pZdx+x+p*(wwZk}58+K(%d3TwsBs>+H_7OdMu#XLh$r zh!|@$jT$v-;)}8PQ`2bTizfPFG}dTe^r0pt>WgnanWzta^xV0#q%4s5q&A(qx%a#G z+;e8`eD|9f&Hw;7nA5rdLI9vp709cp*`$bhQ8$z_-%>${6c3<7HeGNQ(x#o>;2jtO z1_A~G1_A~G1_B2D4-C*dTNGuB_r9DB+JJ$8ft!*6@qCC-6&UkzS)%vopvFr92t^9u z73xzS;Kf9IjQO}M(F>(x%IpFCQ1nv_l;JcV5$=RBAD1P{a6lOj=${$=3UjzsQ!RbcaE!EJ8txMc6TcL1T3qbzj7GW+b}mIDi+x?)(MV5s z@6r-Kt0>L;4-FijURXM}^3J>Oy?^0@ufCQvp#La=`Vv|$m2zS_`7!xTqs%UHa&?Up zRvn5r43DHZ&pG--x~aNGUXQD;?xgrmhiG~rV_W{}lNsC0&0926n^Db7j-2%Y(@Ypo z>dus_pK(QR#<8>RkmopMP^_?}c%8WV6AP|kTh64ObqE=|SkoBZ)4K1#!QOkX?6_qo zXLYP0nHTh!`b0r6H?2Au-O>!}^bGN7xyC6&&$3#4hK*b5ye^}fLc1CNM48oSImc~H z_-Nits43K+qb!-1>zBs6S&veSQ8tya=jUmKjx_g$4lDdyi2W2)nxSkNsx{eAuSb6VBl zR#&Mg(;{L(({xQ~jqQ_r+ZyYX9WGupyCDkwFak4>0gGh+0=x(>!JDuG7vW?094^5( z@Eu%+@8K$}!cXus{04u(pYRs~GOWTH+<|r2jJM(*ybW*119&HPVi)#e3^iy84DjUy%cAJ6f`d*XzlXkkp8$ouW28b*>lWE|O`unYC=S z^%EpL{fwt2zWs{l9SQFhBI1f1wuRdj(m5~lhO8qT6)NWCa@JF)#`rclOS%+_<`r_b zkC7gaGF~ZX`&rDpi#W(}TR6@Xj+;nsOTnEdxqU`ry9__TkMIlp3ctfOl2|2j+=WdT zCW*D+9oUZhu>+%c2z&4z?8Cz(uwfjg$C-l;B!nJ=GQa?hj gA|~eJvP7~_`PV-L1n+;3_q9JcgZID3$IaIK4W?7x5dZ)H literal 0 HcmV?d00001 diff --git a/src/camera/camera.cpp b/src/camera/camera.cpp index fb246b12..d0998151 100644 --- a/src/camera/camera.cpp +++ b/src/camera/camera.cpp @@ -4,3 +4,170 @@ // #include "camera.hpp" + +static const float PI = 3.14159265358979323846f; +static const float TWO_PI = 2 * PI; +static const float INV_PI = 1.0f / PI; +static const float DEG2RAD = PI / 180.f; +static const float RAD2DEG = 180.f / PI; + +Camera::Camera(): + Camera(400, 300) +{ + look = glm::vec3(0,0,-1); + up = glm::vec3(0,1,0); + right = glm::vec3(1,0,0); +} + +Camera::Camera(unsigned int w, unsigned int h): + Camera(w, h, glm::vec3(0,0,25), glm::vec3(0,0,0), glm::vec3(0,1,0)) +{} + +Camera::Camera(unsigned int w, unsigned int h, const glm::vec3 &e, const glm::vec3 &r, const glm::vec3 &worldUp): + fovy(45.f), + width(w), + height(h), + near_clip(0.1f), + far_clip(1000), + lens_radius(0.f), + focal_distance(-10.f), + eye(e), + ref(r), + world_up(worldUp) +{ + RecomputeAttributes(); +} + +Camera::Camera(const Camera &c): + fovy(c.fovy), + width(c.width), + height(c.height), + near_clip(c.near_clip), + far_clip(c.far_clip), + lens_radius(c.lens_radius), + focal_distance(c.focal_distance), + aspect(c.aspect), + eye(c.eye), + ref(c.ref), + look(c.look), + up(c.up), + right(c.right), + world_up(c.world_up), + V(c.V), + H(c.H) +{} + +void Camera::CopyAttributes(const Camera &c) +{ + fovy = c.fovy; + near_clip = c.near_clip; + far_clip = c.far_clip; + lens_radius = c.lens_radius; + focal_distance = c.focal_distance; + eye = c.eye; + ref = c.ref; + look = c.look; + up = c.up; + right = c.right; + width = c.width; + height = c.height; + aspect = c.aspect; + V = c.V; + H = c.H; +} + +void Camera::RecomputeAttributes() +{ + look = glm::normalize(ref - eye); + right = glm::normalize(glm::cross(look, world_up)); + up = glm::cross(right, look); + + float tan_fovy = tan(fovy/2 * DEG2RAD); + float len = glm::length(ref - eye); + aspect = float(width)/height; + V = up*len*tan_fovy; + H = right*len*aspect*tan_fovy; +} + +glm::mat4 Camera::getViewProj() +{ + return glm::perspective(fovy, width / (float)height, near_clip, far_clip) * glm::lookAt(eye, ref, up); +} + +glm::mat4 Camera::ViewMatrix() +{ + // View matrix = O * T + glm::mat4 orientation_mat = glm::mat4( + right.x, up.x, look.x, 0.f, + right.y, up.y, look.y, 0.f, + right.z, up.z, look.z, 0.f, + 0.f, 0.f, 0.f, 1.f + ); + + glm::mat4 translation_mat = glm::mat4( + 1.f, 0.f, 0.f, 0.f, + 0.f, 1.f, 0.f, 0.f, + 0.f, 0.f, 1.f, 0.f, + -eye.x, -eye.y, -eye.z, 1.f + ); + + return orientation_mat * translation_mat; +} + +glm::mat4 Camera::PerspectiveProjectionMatrix() +{ + // Compute top, bottom, left, right based on near, far, fovy, and aspect + float top = near_clip * glm::tan(glm::radians(fovy) / 2); + float bottom = -top; + float right = top * aspect; + float left = -right; + + // Build mat4 by columns + return glm::mat4( + (2 * near_clip) / (right - left), 0.f, 0.f, 0.f, + 0.f, (2 * near_clip) / (top - bottom), 0.f, 0.f, + -(right + left) / (right - left), - (top + bottom) / (top - bottom), far_clip / (far_clip - near_clip), 1.f, + 0.f, 0.f, - (far_clip * near_clip) / (far_clip - near_clip), 0.f + ); +} + +void Camera::RotateAboutUp(float deg) +{ + deg *= DEG2RAD; + glm::mat4 rotation = glm::rotate(glm::mat4(1.0f), deg, up); + ref = ref - eye; + ref = glm::vec3(rotation * glm::vec4(ref, 1)); + ref = ref + eye; + RecomputeAttributes(); +} +void Camera::RotateAboutRight(float deg) +{ + deg *= DEG2RAD; + glm::mat4 rotation = glm::rotate(glm::mat4(1.0f), deg, right); + ref = ref - eye; + ref = glm::vec3(rotation * glm::vec4(ref, 1)); + ref = ref + eye; + RecomputeAttributes(); +} + +void Camera::TranslateAlongLook(float amt) +{ + glm::vec3 translation = look * amt; + eye += translation; + ref += translation; +} + +void Camera::TranslateAlongRight(float amt) +{ + glm::vec3 translation = right * amt; + eye += translation; + ref += translation; +} +void Camera::TranslateAlongUp(float amt) +{ + glm::vec3 translation = up * amt; + eye += translation; + ref += translation; +} + +GLenum Camera::drawMode(){return GL_LINES;} diff --git a/src/camera/camera.hpp b/src/camera/camera.hpp index 59ad2b12..a4968672 100644 --- a/src/camera/camera.hpp +++ b/src/camera/camera.hpp @@ -6,5 +6,63 @@ #ifndef camera_hpp #define camera_hpp +// Include GLFW +#include + +// Include GLM +#include +#include + +#include + +using namespace glm; + +//A perspective projection camera +//Receives its eye position and reference point from the scene XML file +class Camera +{ +public: + Camera(); + Camera(unsigned int w, unsigned int h); + Camera(unsigned int w, unsigned int h, const glm::vec3 &e, const glm::vec3 &r, const glm::vec3 &worldUp); + Camera(const Camera &c); + + void CopyAttributes(const Camera &c); + + float fovy; + unsigned int width, height; // Screen dimensions + float near_clip; // Near clip plane distance + float far_clip; // Far clip plane distance + float lens_radius; // Len's aperture + float focal_distance; // Focal distance + + //Computed attributes + float aspect; + + glm::vec3 eye, //The position of the camera in world space + ref, //The point in world space towards which the camera is pointing + look, //The normalized vector from eye to ref. Is also known as the camera's "forward" vector. + up, //The normalized vector pointing upwards IN CAMERA SPACE. This vector is perpendicular to LOOK and RIGHT. + right, //The normalized vector pointing rightwards IN CAMERA SPACE. It is perpendicular to UP and LOOK. + world_up, //The normalized vector pointing upwards IN WORLD SPACE. This is primarily used for computing the camera's initial UP vector. + V, //Represents the vertical component of the plane of the viewing frustum that passes through the camera's reference point. Used in Camera::Raycast. + H; //Represents the horizontal component of the plane of the viewing frustum that passes through the camera's reference point. Used in Camera::Raycast. + + glm::mat4 PerspectiveProjectionMatrix(); + glm::mat4 ViewMatrix(); + glm::mat4 getViewProj(); + + void RecomputeAttributes(); + + void RotateAboutUp(float deg); + void RotateAboutRight(float deg); + + void TranslateAlongLook(float amt); + void TranslateAlongRight(float amt); + void TranslateAlongUp(float amt); + + virtual GLenum drawMode(); +}; + #endif /* camera_hpp */ diff --git a/src/fluidSolver/fluidSolver.cpp b/src/fluidSolver/fluidSolver.cpp index 9c9a1663..280cf7ad 100644 --- a/src/fluidSolver/fluidSolver.cpp +++ b/src/fluidSolver/fluidSolver.cpp @@ -4,3 +4,11 @@ #include "fluidSolver.hpp" + +void FluidSolver::updateParticles(Particles *p) { + + for (int i=0; i < p->positions.size(); i++) { + p->positions[i] += p->speed[i]; + } + p->detectCollisions(); +} diff --git a/src/fluidSolver/fluidSolver.hpp b/src/fluidSolver/fluidSolver.hpp index 6429c4e3..72b5f3ee 100644 --- a/src/fluidSolver/fluidSolver.hpp +++ b/src/fluidSolver/fluidSolver.hpp @@ -5,5 +5,11 @@ #ifndef fluidSolver_hpp #define fluidSolver_hpp +#include "../geom/particles.hpp" + +class FluidSolver{ +public: + static void updateParticles(Particles *particles); +}; #endif /* fluidSolver_hpp */ diff --git a/src/geom/cube.cpp b/src/geom/cube.cpp new file mode 100644 index 00000000..1f50df8a --- /dev/null +++ b/src/geom/cube.cpp @@ -0,0 +1,89 @@ +// +// geom.cpp +// Thanda + +#include "cube.hpp" +#include + +void Cube::create() { + // Our vertices. Tree consecutive floats give a 3D vertex; Three consecutive vertices give a triangle. + // A cube has 6 faces with 2 triangles each, so this makes 6*2=12 triangles, and 12*3 vertices + static const GLfloat g_vertex_buffer_data[] = { + // Back face. + -1.0f,-1.0f,-1.0f, + -1.0f,1.0f, -1.0f, + -1.0f,1.0f, -1.0f, + 1.0f,1.0f, -1.0f, + 1.0f,1.0f, -1.0f, + 1.0f,-1.0f,-1.0f, + 1.0f,-1.0f,-1.0f, + -1.0f,-1.0f,-1.0f, + // Front face. + -1.0f,-1.0f,1.0f, + -1.0f,1.0f, 1.0f, + -1.0f,1.0f, 1.0f, + 1.0f,1.0f, 1.0f, + 1.0f,1.0f, 1.0f, + 1.0f,-1.0f,1.0f, + 1.0f,-1.0f,1.0f, + -1.0f,-1.0f,1.0f, + 1.0f,1.0f, 1.0f, + // Connectors. + 1.0f,1.0f, -1.0f, + -1.0f,1.0f, 1.0f, + -1.0f,1.0f, -1.0f, + 1.0f,-1.0f, 1.0f, + 1.0f,-1.0f, -1.0f, + -1.0f,-1.0f, 1.0f, + -1.0f,-1.0f, -1.0f + }; + + // One color for each vertex. They were generated randomly. + static const GLfloat g_color_buffer_data[] = { + 0.583f, 0.771f, 0.014f, + 0.609f, 0.115f, 0.436f, + 0.327f, 0.483f, 0.844f, + 0.822f, 0.569f, 0.201f, + 0.435f, 0.602f, 0.223f, + 0.310f, 0.747f, 0.185f, + 0.597f, 0.770f, 0.761f, + 0.559f, 0.436f, 0.730f, + 0.359f, 0.583f, 0.152f, + 0.483f, 0.596f, 0.789f, + 0.559f, 0.861f, 0.639f, + 0.195f, 0.548f, 0.859f, + 0.014f, 0.184f, 0.576f, + 0.771f, 0.328f, 0.970f, + 0.406f, 0.615f, 0.116f, + 0.676f, 0.977f, 0.133f, + 0.971f, 0.572f, 0.833f, + 0.140f, 0.616f, 0.489f, + 0.997f, 0.513f, 0.064f, + 0.945f, 0.719f, 0.592f, + 0.543f, 0.021f, 0.978f, + 0.279f, 0.317f, 0.505f, + 0.167f, 0.620f, 0.077f, + 0.347f, 0.857f, 0.137f, + 0.055f, 0.953f, 0.042f, + 0.714f, 0.505f, 0.345f, + 0.783f, 0.290f, 0.734f, + 0.722f, 0.645f, 0.174f, + 0.302f, 0.455f, 0.848f, + 0.225f, 0.587f, 0.040f, + 0.517f, 0.713f, 0.338f, + 0.053f, 0.959f, 0.120f, + 0.393f, 0.621f, 0.362f, + 0.673f, 0.211f, 0.457f, + 0.820f, 0.883f, 0.371f, + 0.982f, 0.099f, 0.879f + }; + + glGenBuffers(1, &vertexbuffer); + glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW); + + glGenBuffers(1, &colorbuffer); + glBindBuffer(GL_ARRAY_BUFFER, colorbuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data), g_color_buffer_data, GL_STATIC_DRAW); +} + diff --git a/src/geom/cube.hpp b/src/geom/cube.hpp new file mode 100644 index 00000000..143d7982 --- /dev/null +++ b/src/geom/cube.hpp @@ -0,0 +1,28 @@ +// +// geom.hpp +// Thanda + +#ifndef cube_hpp +#define cube_hpp + +#include "geom.hpp" + +//A cube is assumed to have side lengths of 1 and a center of <0,0,0>. This means all vertices are of the form <+/-0.5, +/-0.5, +/-0.5> +//These attributes can be altered by applying a transformation matrix to the cube. +class Cube : public Geometry +{ +public: + //Constructors/destructors + Cube() { + name ="CUBE"; + draw_type = GL_LINES; + transform = glm::mat4(1.0f); + num_indicies = 36; + } + //Functions + virtual ~Cube(){} + virtual void create(); +}; + + +#endif /* cube_hpp */ diff --git a/src/geom/geom.cpp b/src/geom/geom.cpp index c4438fdc..230c9473 100644 --- a/src/geom/geom.cpp +++ b/src/geom/geom.cpp @@ -3,3 +3,5 @@ // Thanda #include "geom.hpp" + +void Geometry::detectCollisions() {} diff --git a/src/geom/geom.hpp b/src/geom/geom.hpp index 91e658f7..64583236 100644 --- a/src/geom/geom.hpp +++ b/src/geom/geom.hpp @@ -5,5 +5,44 @@ #ifndef geom_hpp #define geom_hpp +#include +#include +#include + +// Include standard headers +#include +#include + +// Include GLEW. Always include it before gl.h and glfw.h, since it's a bit magic. +#include + +// Include GLFW +#include + +// Include GLM +#include +#include + +class Geometry +{ +public: +//Constructors/destructors + Geometry() : name("GEOMETRY") {} +//Functions + virtual ~Geometry(){} + virtual void create() = 0; + virtual void detectCollisions(); + const glm::mat4& getModelMatrix() { return transform; } + void setModelMatrix(const glm::mat4 &trans) { transform = trans; } + +//Member variables + std::string name;//Mainly used for debugging purposes + glm::mat4 transform; + GLuint vertexbuffer; + GLuint colorbuffer; + GLenum draw_type; + int num_indicies; +}; + #endif /* geom_hpp */ diff --git a/src/geom/particles.cpp b/src/geom/particles.cpp new file mode 100644 index 00000000..39317622 --- /dev/null +++ b/src/geom/particles.cpp @@ -0,0 +1,77 @@ +// +// geom.cpp +// Thanda + +#include "particles.hpp" + +#include + +#define FPS 100.f + +void Particles::initParticles(const glm::vec3 &bounds, const glm::vec3 &container_bounds) { + positions.clear(); + + minBoundX = -container_bounds[0]; + minBoundY = -container_bounds[1]; + minBoundZ = -container_bounds[2]; + maxBoundX = container_bounds[0]; + maxBoundY = container_bounds[1]; + maxBoundZ = container_bounds[2]; + + for (float i=0.f; i < bounds[0] ; i += separation) { + for (float j=0.f; j < bounds[1]; j += separation) { + for (float k=0.f; k < bounds[2]; k += separation) { + positions.push_back(glm::vec3(i, j, k)); + speed.push_back(glm::vec3(0.f, -9.8f, 0.f) / FPS); + dead.push_back(0); + std::cout << i << " " << j << " " << k << std::endl; + } + } + } + + num_indicies = positions.size() * 3 + 1; + std::cout << "SIZE" << num_indicies << std::endl; +} + + +void Particles::detectCollisions() { + for (int i=0; i < positions.size(); i++) { + if ((positions[i][0] < minBoundX || positions[i][0] > maxBoundX) + || (positions[i][1] < minBoundY || positions[i][1] > maxBoundY) + || (positions[i][2] < minBoundZ || positions[i][2] > maxBoundZ)) { + dead[i] = 1; + } + } +} + +void Particles::create() { + // Our vertices. Tree consecutive floats give a 3D vertex; Three consecutive vertices give a triangle. + // A cube has 6 faces with 2 triangles each, so this makes 6*2=12 triangles, and 12*3 vertices + std::vector g_vertex_buffer_data; + std::vector g_color_buffer_data; + for (int i=0; i < positions.size(); i++) { + g_vertex_buffer_data.push_back(positions[i][0]); + g_vertex_buffer_data.push_back(positions[i][1]); + g_vertex_buffer_data.push_back(positions[i][2]); + + if (dead[i]) { + g_color_buffer_data.push_back(1.0f); + g_color_buffer_data.push_back(1.0f); + g_color_buffer_data.push_back(1.0f); + } else { + g_color_buffer_data.push_back(0.0f); + g_color_buffer_data.push_back(0.0f); + g_color_buffer_data.push_back(0.5f); + } + } + + glGenBuffers(1, &vertexbuffer); + glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * g_vertex_buffer_data.size(), g_vertex_buffer_data.data(), GL_STATIC_DRAW); + + glGenBuffers(1, &colorbuffer); + glBindBuffer(GL_ARRAY_BUFFER, colorbuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * g_color_buffer_data.size(), g_color_buffer_data.data(), GL_STATIC_DRAW); + +// std::cout << g_vertex_buffer_data.size() << " +#include +#include "geom.hpp" + +class Particles : public Geometry +{ +public: +//Constructors/destructors + Particles() { + name = "PARTICLES"; + draw_type = GL_POINTS; + transform = glm::mat4(1.0f); + } +//Functions + virtual ~Particles(){} + virtual void create(); + void initParticles(const glm::vec3 &bounds, const glm::vec3 &container_bounds); + virtual void detectCollisions(); + + std::vector positions; + std::vector speed; + std::vector colors; + std::vector dead; + + float minBoundX; + float minBoundY; + float minBoundZ; + float maxBoundX; + float maxBoundY; + float maxBoundZ; + + float separation; +}; + +#endif /* particles_hpp */ diff --git a/src/main.cpp b/src/main.cpp index 2a00d1e4..33fd689d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,7 +5,8 @@ using namespace std; int main() { - + Viewer viewer = Viewer(); + //viewer.render(); return 0; } diff --git a/src/main.hpp b/src/main.hpp index fe1f64d5..267de04b 100644 --- a/src/main.hpp +++ b/src/main.hpp @@ -5,5 +5,7 @@ #ifndef main_hpp #define main_hpp +# include "viewer/viewer.hpp" + #endif /* main_hpp */ diff --git a/src/scene/.DS_Store b/src/scene/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 + +void Scene::loadScene(const char *filename) { + + std::string contents; + std::string line; + std::ifstream myfile (filename); + if (myfile.is_open()) + { + while ( std::getline (myfile,line) ) + { + contents += line; + } + myfile.close(); + } + + Json::Value root; // will contains the root value after parsing. + Json::Reader reader; + bool parsingSuccessful = reader.parse( contents, root ); + if ( !parsingSuccessful ) + { + // report to the user the failure and their locations in the document. + std::cout << "Failed to parse configuration\n" + << reader.getFormattedErrorMessages(); + return; + } + + // Get fluid bounding box. + Cube *box = new Cube(); + glm::vec3 container_bounds(root["containerDim"]["scaleX"].asFloat(), + root["containerDim"]["scaleY"].asFloat(), + root["containerDim"]["scaleZ"].asFloat()); + box->setModelMatrix(glm::scale(box->getModelMatrix(), container_bounds)); + objects.push_back(box); + + // Get particle bounds. + Particles *fluid_particles = new Particles(); + glm::vec3 particle_bounds = glm::vec3(root["particleDim"]["boundX"].asFloat(), + root["particleDim"]["boundY"].asFloat(), + root["particleDim"]["boundZ"].asFloat()); + + + fluid_particles->separation = root["particleSeparation"].asFloat(); + fluid_particles->initParticles(particle_bounds, container_bounds); + particles = fluid_particles; + objects.push_back(fluid_particles); +} + +void Scene::drawScene(GLuint &programID, GLuint &MatrixID, Camera &camera) { + // Use our shader + glUseProgram(programID); + + for (Geometry *geom : objects) { + geom->create(); + // Model matrix : an identity matrix (model will be at the origin) + glm::mat4 Model = geom->getModelMatrix(); + // Our ModelViewProjection : multiplication of our 3 matrices + glm::mat4 MVP = camera.getViewProj() * Model; // Remember, matrix multiplication is the other way around + glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]); + + // 1rst attribute buffer : vertices + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, geom->vertexbuffer); + glVertexAttribPointer( + 0, // attribute. No particular reason for 0, but must match the layout in the shader. + 3, // size + GL_FLOAT, // type + GL_FALSE, // normalized? + 0, // stride + (void*)0 // array buffer offset + ); + + // 2nd attribute buffer : colors + glEnableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, geom->colorbuffer); + glVertexAttribPointer( + 1, // attribute. No particular reason for 1, but must match the layout in the shader. + 3, // size + GL_FLOAT, // type + GL_FALSE, // normalized? + 0, // stride + (void*)0 // array buffer offset + ); + + // Draw the triangle ! + glPointSize(1); + glDrawArrays(geom->draw_type, 0, geom->num_indicies); // 12*3 indices starting at 0 -> 12 triangles + + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); + } + + // Update particle positions + FluidSolver::updateParticles(particles); +} diff --git a/src/scene/scene.hpp b/src/scene/scene.hpp index 84022a43..54ac58ba 100644 --- a/src/scene/scene.hpp +++ b/src/scene/scene.hpp @@ -1,3 +1,22 @@ // // scene.hpp -// Thanda \ No newline at end of file +// Thanda + +#include +#include +#include + +#include "../geom/particles.hpp" +#include "../geom/cube.hpp" +#include "../camera/camera.hpp" +#include "../fluidSolver/fluidSolver.hpp" + +class Scene +{ +public: + void loadScene(const char *filepath); + void drawScene(GLuint &programID, GLuint &MatrixID, Camera &camera); + + std::vector objects; + Particles *particles; +}; diff --git a/src/viewer/SimpleFragmentShader.fragmentshader b/src/viewer/SimpleFragmentShader.fragmentshader new file mode 100755 index 00000000..2c1809c0 --- /dev/null +++ b/src/viewer/SimpleFragmentShader.fragmentshader @@ -0,0 +1,15 @@ +#version 330 core + +// Interpolated values from the vertex shaders +in vec3 fragmentColor; + +// Ouput data +out vec3 color; + +void main(){ + + // Output color = color specified in the vertex shader, + // interpolated between all 3 surrounding vertices + color = fragmentColor; + +} diff --git a/src/viewer/SimpleVertexShader.vertexshader b/src/viewer/SimpleVertexShader.vertexshader new file mode 100755 index 00000000..1996c371 --- /dev/null +++ b/src/viewer/SimpleVertexShader.vertexshader @@ -0,0 +1,22 @@ +#version 330 core + +// Input vertex data, different for all executions of this shader. +layout(location = 0) in vec3 vertexPosition_modelspace; +layout(location = 1) in vec3 vertexColor; + +// Output data ; will be interpolated for each fragment. +out vec3 fragmentColor; +// Values that stay constant for the whole mesh. +uniform mat4 MVP; + +void main(){ + + // Output position of the vertex, in clip space : MVP * position + gl_Position = MVP * vec4(vertexPosition_modelspace,1); + + gl_PointSize = 10.0; + + // The color of each vertex will be interpolated + // to produce the color of each fragment + fragmentColor = vertexColor; +} diff --git a/src/viewer/shader.cpp b/src/viewer/shader.cpp new file mode 100755 index 00000000..86d40dc9 --- /dev/null +++ b/src/viewer/shader.cpp @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include +#include +using namespace std; + +#include +#include + +#include + +#include "shader.hpp" + +GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path){ + + // Create the shaders + GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); + GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); + + // Read the Vertex Shader code from the file + std::string VertexShaderCode; + std::ifstream VertexShaderStream(vertex_file_path, std::ios::in); + if(VertexShaderStream.is_open()){ + std::string Line = ""; + while(getline(VertexShaderStream, Line)) + VertexShaderCode += "\n" + Line; + VertexShaderStream.close(); + }else{ + printf("Impossible to open %s. Are you in the right directory ? Don't forget to read the FAQ !\n", vertex_file_path); + getchar(); + return 0; + } + + // Read the Fragment Shader code from the file + std::string FragmentShaderCode; + std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in); + if(FragmentShaderStream.is_open()){ + std::string Line = ""; + while(getline(FragmentShaderStream, Line)) + FragmentShaderCode += "\n" + Line; + FragmentShaderStream.close(); + } + + GLint Result = GL_FALSE; + int InfoLogLength; + + + // Compile Vertex Shader + printf("Compiling shader : %s\n", vertex_file_path); + char const * VertexSourcePointer = VertexShaderCode.c_str(); + glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL); + glCompileShader(VertexShaderID); + + // Check Vertex Shader + glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); + glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); + if ( InfoLogLength > 0 ){ + std::vector VertexShaderErrorMessage(InfoLogLength+1); + glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]); + printf("%s\n", &VertexShaderErrorMessage[0]); + } + + + + // Compile Fragment Shader + printf("Compiling shader : %s\n", fragment_file_path); + char const * FragmentSourcePointer = FragmentShaderCode.c_str(); + glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL); + glCompileShader(FragmentShaderID); + + // Check Fragment Shader + glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); + glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); + if ( InfoLogLength > 0 ){ + std::vector FragmentShaderErrorMessage(InfoLogLength+1); + glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]); + printf("%s\n", &FragmentShaderErrorMessage[0]); + } + + + + // Link the program + printf("Linking program\n"); + GLuint ProgramID = glCreateProgram(); + glAttachShader(ProgramID, VertexShaderID); + glAttachShader(ProgramID, FragmentShaderID); + glLinkProgram(ProgramID); + + // Check the program + glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); + glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); + if ( InfoLogLength > 0 ){ + std::vector ProgramErrorMessage(InfoLogLength+1); + glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]); + printf("%s\n", &ProgramErrorMessage[0]); + } + + + glDetachShader(ProgramID, VertexShaderID); + glDetachShader(ProgramID, FragmentShaderID); + + glDeleteShader(VertexShaderID); + glDeleteShader(FragmentShaderID); + + return ProgramID; +} + + diff --git a/src/viewer/shader.hpp b/src/viewer/shader.hpp new file mode 100755 index 00000000..f55c5cb0 --- /dev/null +++ b/src/viewer/shader.hpp @@ -0,0 +1,6 @@ +#ifndef SHADER_HPP +#define SHADER_HPP + +GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path); + +#endif diff --git a/src/viewer/viewer.cpp b/src/viewer/viewer.cpp index 60d1868a..2cc8ead1 100644 --- a/src/viewer/viewer.cpp +++ b/src/viewer/viewer.cpp @@ -3,3 +3,119 @@ // Thanda #include "viewer.hpp" +#include "../geom/cube.hpp" + +using namespace glm; + +Viewer::Viewer() : width(1024), height(768), camera() { + Init(); +} + +Viewer::Viewer(int w, int h) : width{w}, height{h}, camera() { + Init(); +} + +Viewer::~Viewer() {} + +void Viewer::render() { + do{ + + // Clear the screen + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + if (glfwGetKey(window, GLFW_KEY_UP ) == GLFW_PRESS) { + camera.TranslateAlongLook(.5f); + } else if (glfwGetKey(window, GLFW_KEY_DOWN ) == GLFW_PRESS) { + camera.TranslateAlongLook(-.5f); + } else if (glfwGetKey(window, GLFW_KEY_LEFT ) == GLFW_PRESS) { + camera.TranslateAlongRight(-.5f); + } else if (glfwGetKey(window, GLFW_KEY_RIGHT ) == GLFW_PRESS) { + camera.TranslateAlongRight(.5f); + } else if (glfwGetKey(window, GLFW_KEY_W ) == GLFW_PRESS) { + camera.RotateAboutRight(-10); + } else if (glfwGetKey(window, GLFW_KEY_S ) == GLFW_PRESS) { + camera.RotateAboutRight(10); + } else if (glfwGetKey(window, GLFW_KEY_A ) == GLFW_PRESS) { + camera.RotateAboutUp(-10); + } else if (glfwGetKey(window, GLFW_KEY_D ) == GLFW_PRESS) { + camera.RotateAboutUp(10); + } + + + scene.drawScene(programID, MatrixID, camera); + // Swap buffers + glfwSwapBuffers(window); + glfwPollEvents(); + + } // Check if the ESC key was pressed or the window was closed + while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS && + glfwWindowShouldClose(window) == 0 ); + + // Cleanup VBO and shader + for (Geometry * geom : scene.objects) { + glDeleteBuffers(1, &geom->vertexbuffer); + glDeleteBuffers(1, &geom->colorbuffer); + } + glDeleteProgram(programID); + glDeleteVertexArrays(1, &VertexArrayID); + + // Close OpenGL window and terminate GLFW + glfwTerminate(); +} + +void Viewer::Init() +{ + // Initialise GLFW + if( !glfwInit() ) + { + fprintf( stderr, "Failed to initialize GLFW\n" ); + getchar(); + } + + glfwWindowHint(GLFW_SAMPLES, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + + // Open a window and create its OpenGL context + window = glfwCreateWindow( 1024, 768, "Fluid Simulation", NULL, NULL); + if( window == NULL ){ + fprintf( stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n" ); + getchar(); + glfwTerminate(); + } + glfwMakeContextCurrent(window); + + // Initialize GLEW + glewExperimental = true; // Needed for core profile + if (glewInit() != GLEW_OK) { + fprintf(stderr, "Failed to initialize GLEW\n"); + getchar(); + glfwTerminate(); + } + + // Ensure we can capture the escape key being pressed below + glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE); + + // Background + glClearColor(0.9f, 0.9f, 0.9f, 0.0f); + + // Enable depth test + glEnable(GL_DEPTH_TEST); + // Accept fragment if it closer to the camera than the former one + glDepthFunc(GL_LESS); + + glGenVertexArrays(1, &VertexArrayID); + glBindVertexArray(VertexArrayID); + + // Create and compile our GLSL program from the shaders + programID = LoadShaders( "../CIS563-FluidSolver/src/viewer/SimpleVertexShader.vertexshader", "../CIS563-FluidSolver/src/viewer/SimpleFragmentShader.fragmentshader" ); + + // Get a handle for our "MVP" uniform + MatrixID = glGetUniformLocation(programID, "MVP"); + + scene.loadScene("../CIS563-FluidSolver/src/scene/scene.json"); + + render(); +} diff --git a/src/viewer/viewer.hpp b/src/viewer/viewer.hpp index abb78a17..0cb9c668 100644 --- a/src/viewer/viewer.hpp +++ b/src/viewer/viewer.hpp @@ -5,5 +5,44 @@ #ifndef viewer_hpp #define viewer_hpp +// Include standard headers +#include +#include + +// Include GLEW. Always include it before gl.h and glfw.h, since it's a bit magic. +#include + +// Include GLFW +#include + +// Include GLM +#include +#include + +// Include +#include "shader.hpp" +#include "../camera/camera.hpp" +#include "../scene/scene.hpp" + +using namespace glm; + +class Viewer { +public: + Viewer(); + Viewer(int width, int height); + ~Viewer(); + + void render(); + void Init(); + int width; + int height; + GLFWwindow* window; + GLuint programID; + GLuint MatrixID; + GLuint VertexArrayID; + + Camera camera; + Scene scene; +}; #endif /* viewer_hpp */ From 43d2834449a38f2b6799df3e5b41565e4a149d01 Mon Sep 17 00:00:00 2001 From: Rachel Hwang Date: Wed, 23 Mar 2016 13:19:27 -0400 Subject: [PATCH 02/23] Sprint one, mostly working --- CMakeLists.txt | 1 + src/fluidSolver/.DS_Store | Bin 0 -> 6148 bytes src/fluidSolver/fluidSolver.cpp | 200 +++++++++++++++++++++++++++++++- src/fluidSolver/fluidSolver.hpp | 31 ++++- src/fluidSolver/grid.cpp | 28 +++++ src/fluidSolver/grid.hpp | 50 ++++++++ src/geom/cube.hpp | 4 + src/geom/particles.cpp | 59 +++++----- src/geom/particles.hpp | 39 ++++--- src/scene/scene.cpp | 8 +- src/scene/scene.hpp | 3 +- src/scene/scene.json | 14 +-- 12 files changed, 378 insertions(+), 59 deletions(-) create mode 100644 src/fluidSolver/.DS_Store create mode 100644 src/fluidSolver/grid.cpp create mode 100644 src/fluidSolver/grid.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ebaeac1..d515be34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,6 +87,7 @@ set(CORE_SRC src/viewer/shader.cpp src/viewer/viewer.cpp src/fluidSolver/fluidSolver.cpp + src/fluidSolver/grid.cpp src/scene/scene.cpp src/geom/geom.cpp src/geom/cube.cpp diff --git a/src/fluidSolver/.DS_Store b/src/fluidSolver/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 + +#define FPS 1000.f +#define RES 1 +#define CELL_WIDTH 1.f/RES +#define MATHIF(test, if_true, if_false) (((if_true) * (test)) + ((if_false) * (!test))) + +void FlipSolver::step() { + + // Reset grid values. + clearGrids(); + // Transfer particle velocities to grid. + storeParticleVelocityToGrid(); + // TODO: Apply forces. + // TODO: Enforce boundary collisions. + particle_container->detectCollisions(); + // TODO: Classify voxels. + // TODO: Pressure step. + // Update particle velocities. + //interpolateVelocity(); + // Update particle positions. + for (Particle *p : particle_container->particles) { + p->position += p->velocity / FPS; + } +} + + +void FlipSolver::init() { + + // Get dimensions of the fluid container. + int x = int(ceil(particle_container->x_dim)); + int y = int(ceil(particle_container->y_dim)); + int z = int(ceil(particle_container->z_dim)); + + constructMacGrid(x, y, z); +} + + +void FlipSolver::constructMacGrid(int x, int y, int z) { + // Initialize the macgrid and subgrids. + macgrid = MacGrid(x*RES, y*RES, z*RES); +} + + +void FlipSolver::clearGrids() { + macgrid.u_grid.clear(); + macgrid.v_grid.clear(); + macgrid.w_grid.clear(); +} + + +void FlipSolver::normalizeGrid(Grid &grid) { + int numCells = grid.cells.size(); + for (int i=0; i < numCells; ++i) { + grid.cells[i] /= MATHIF(grid.particleCount[i] > 0, grid.particleCount[i], 1); + //std::cout << grid.particleCount[i] << " "; + } +} + + +void FlipSolver::storeParticleVelocityToGridComponent(Particle *p, Grid &grid, int dim) { + // HACK TO MAKE THIS WIP CODE WORK! + //if (p->dead) { + // return; + //} + // END HACK. + + glm::vec3 curr_idx = getVelocityGridIndex(p->position, dim); + int i = curr_idx[0]; + int j = curr_idx[1]; + int k = curr_idx[2]; + + for (int n=0; n < 2; ++n) { + for (int m=0; m < 2; ++m) { + for (int o=0; o < 2; ++o) { + int I = i+n; + int J = j+m; + int K = j+o; + if (((I >= 0 && I < particle_container->x_dim) + && (J >= 0 && J < particle_container->y_dim)) + && (K >= 0 && K < particle_container->z_dim)) { + grid(I, J, K) += p->velocity[dim]; + grid.incrementParticleCount(I, J, K); + } + } + } + } +} + + +void printGrid(Grid &grid) { + std::cout << "START "; + int numCells = grid.cells.size(); + for (int i=0; i < numCells; ++i) { + std::cout << grid.cells[i] << " "; + } + std::cout << " END "; +} + + +void FlipSolver::storeParticleVelocityToGrid() { + for (Particle *p : particle_container->particles) { + // Do u_grid update. + storeParticleVelocityToGridComponent(p, macgrid.u_grid, 0); + normalizeGrid(macgrid.u_grid); + // Do v_grid update. + storeParticleVelocityToGridComponent(p, macgrid.v_grid, 1); + normalizeGrid(macgrid.v_grid); + printGrid(macgrid.v_grid); + // Do w_grid update. + storeParticleVelocityToGridComponent(p, macgrid.w_grid, 2); + normalizeGrid(macgrid.w_grid); + } +} + + +// Return the three indices for accessing the edge corresponding to the given position. +// Dim specifies which grid. 0 for u_grid, 1 for v_grid, 2 for w_grid. +glm::vec3 FlipSolver::getVelocityGridIndex(const glm::vec3 &pos, int dim) { + glm::vec3 p = pos; + + // Offset two of the dimensions. + p[(dim+1)%3] -= CELL_WIDTH * 0.5; + p[(dim+2)%3] -= CELL_WIDTH * 0.5; + + // Transform to index space by subtracting minimum bounds and dividing by grid resolution. + int i = int(floor((p[0] - particle_container->x_dim) * RES)); + int j = int(floor((p[1] - particle_container->y_dim) * RES)); + int k = int(floor((p[2] - particle_container->z_dim) * RES)); + + // Clamp values. + i = std::min(std::max(i, 0), int(particle_container->x_dim-1)); + j = std::min(std::max(j, 0), int(particle_container->y_dim-1)); + k = std::min(std::max(k, 0), int(particle_container->z_dim-1)); + + return glm::vec3(i, j, k); +} + + +// Return the three indices for accessing the edge corresponding to the given position. +// Use for pressure grid. +glm::vec3 FlipSolver::getPressureGridIndex(const glm::vec3 &pos) { + + // Transform to index space by subtracting minimum bounds and dividing by grid resolution. + int i = int(floor((pos[0] - particle_container->x_dim - (CELL_WIDTH * 0.5)) * RES)); + int j = int(floor((pos[1] - particle_container->y_dim - (CELL_WIDTH * 0.5)) * RES)); + int k = int(floor((pos[2] - particle_container->z_dim - (CELL_WIDTH * 0.5)) * RES)); + + // Clamp values. + i = std::min(std::max(i, 0), int(particle_container->x_dim-1)); + j = std::min(std::max(j, 0), int(particle_container->y_dim-1)); + k = std::min(std::max(k, 0), int(particle_container->z_dim-1)); + + return glm::vec3(i, j, k); +} + + +float lerp(float p1, float p2, float u) { + return p1*u + p2*(1-u); +} + + +float FlipSolver::interpolateVelocityComponent(Particle *p, const Grid &grid, int dim) { + // Get min and max indices. (Imagine a bounding box around particle). + glm::vec3 curr_idx = getVelocityGridIndex(p->position, dim); + glm::vec3 next_idx = getVelocityGridIndex(p->position + CELL_WIDTH, dim); + int i = curr_idx[0]; + int j = curr_idx[1]; + int k = curr_idx[2]; + int ii = next_idx[0]; + int jj = next_idx[1]; + int kk = next_idx[2]; + + // Do x direction. + float x_uVal = (p->position[0] - floor(p->position[0]))/ RES; + float tmp1 = MATHIF(i!=ii, lerp(grid(i, j, k), grid(ii, j, k), x_uVal), grid(i, j, k)); + float tmp2 = MATHIF(i!=ii, lerp(grid(i, jj, k), grid(ii, jj, k), x_uVal), grid(i, jj, k)); + float tmp3 = MATHIF(i!=ii, lerp(grid(i, j, kk), grid(ii, j, kk), x_uVal), grid(i, j, kk)); + float tmp4 = MATHIF(i!=ii, lerp(grid(i, jj, kk), grid(ii, jj, kk), x_uVal), grid(i, jj, kk)); + + // Do y direction. + float y_uVal = (p->position[1] - floor(p->position[1]))/ RES; + float tmp5 = MATHIF(j!=jj, lerp(tmp1, tmp2, y_uVal), tmp1); + float tmp6 = MATHIF(j!=jj, lerp(tmp3, tmp4, y_uVal), tmp3); + + // Do z direction. + float z_uVal = (p->position[2] - floor(p->position[2]))/ RES; + return MATHIF(k!=kk, lerp(tmp5, tmp6, y_uVal), tmp5); +} -void FluidSolver::updateParticles(Particles *p) { +void FlipSolver::interpolateVelocity() { + for (Particle *p : particle_container->particles) { + p->velocity[0] = interpolateVelocityComponent(p, macgrid.u_grid, 0); + p->velocity[1] = interpolateVelocityComponent(p, macgrid.v_grid, 1); + p->velocity[2] = interpolateVelocityComponent(p, macgrid.w_grid, 2); - for (int i=0; i < p->positions.size(); i++) { - p->positions[i] += p->speed[i]; + //std::cout << p->position[0] << " " << p->position[1] << " " << p->position[2]; } - p->detectCollisions(); } diff --git a/src/fluidSolver/fluidSolver.hpp b/src/fluidSolver/fluidSolver.hpp index 72b5f3ee..c1817741 100644 --- a/src/fluidSolver/fluidSolver.hpp +++ b/src/fluidSolver/fluidSolver.hpp @@ -6,10 +6,39 @@ #define fluidSolver_hpp #include "../geom/particles.hpp" +#include "grid.hpp" class FluidSolver{ public: - static void updateParticles(Particles *particles); + FluidSolver() {} + FluidSolver(ParticleContainer *particles) : particle_container(particles) {} + virtual void init() = 0; + + ParticleContainer *particle_container = NULL; +}; + +class FlipSolver : public FluidSolver { +public: + FlipSolver() {} + FlipSolver(ParticleContainer *particles) : FluidSolver(particles) {} + virtual void init(); + + void step(); + + glm::vec3 getVelocityGridIndex(const glm::vec3 &pos, int dim); + glm::vec3 getPressureGridIndex(const glm::vec3 &pos); + + void constructMacGrid(int x, int y, int z); + void storeParticleVelocityToGridComponent(Particle *p, Grid &grid, int dim); + void storeParticleVelocityToGrid(); + + void clearGrids(); + void normalizeGrid(Grid &grid); + + float interpolateVelocityComponent(Particle *p, const Grid &grid, int dim); + void interpolateVelocity(); + + MacGrid macgrid; }; #endif /* fluidSolver_hpp */ diff --git a/src/fluidSolver/grid.cpp b/src/fluidSolver/grid.cpp new file mode 100644 index 00000000..24110662 --- /dev/null +++ b/src/fluidSolver/grid.cpp @@ -0,0 +1,28 @@ +// +// grid.cpp +// Thanda + + +#include "grid.hpp" + +float& Grid::operator() (int i, int j, int k) { + return cells[i*x_dim*y_dim + j*y_dim + k]; +} + +const float& Grid::operator() (int i, int j, int k) const { + return cells[i*x_dim*y_dim + j*y_dim + k]; +} + +int Grid::getParticleCount(int i, int j, int k) { + return particleCount[i*x_dim*y_dim + j*y_dim + k]; +} + +void Grid::incrementParticleCount(int i, int j, int k) { + particleCount[i*x_dim*y_dim + j*y_dim + k]++; +} + +void Grid::clear() { + cells = std::vector(x_dim*y_dim*z_dim, 0.f); + particleCount = std::vector(x_dim*y_dim*z_dim, 0); +} + diff --git a/src/fluidSolver/grid.hpp b/src/fluidSolver/grid.hpp new file mode 100644 index 00000000..8d5f8db5 --- /dev/null +++ b/src/fluidSolver/grid.hpp @@ -0,0 +1,50 @@ +// +// grid.hpp +// Thanda + +#ifndef grid_hpp +#define grid_hpp + +#include "../geom/particles.hpp" + +class Grid{ +private: + int x_dim; + int y_dim; + int z_dim; +public: + Grid() {} + Grid(int x, int y, int z) : x_dim(x), y_dim(y), z_dim(z) { + cells = std::vector(x_dim*y_dim*z_dim, 0.f); + particleCount = std::vector(x_dim*y_dim*z_dim, 0); + } + ~Grid() {} + float& operator() (int i, int j, int k); + const float& operator() (int i, int j, int k) const; + float& operator() (int i); + const float& operator() (int i) const; + int getParticleCount(int i, int j, int k); + void incrementParticleCount(int i, int j, int k); + void clear(); + + std::vector cells; + std::vector particleCount; +}; + +class MacGrid{ +public: + MacGrid() {} + MacGrid(int x, int y, int z) { + u_grid = Grid(x+1, y, z); + v_grid = Grid(x, y+1, z); + w_grid = Grid(x, y, z+1); + p_grid = Grid(x, y, z); + } + + Grid u_grid; + Grid v_grid; + Grid w_grid; + Grid p_grid; +}; + +#endif /* grid_hpp */ diff --git a/src/geom/cube.hpp b/src/geom/cube.hpp index 143d7982..cd89f5b5 100644 --- a/src/geom/cube.hpp +++ b/src/geom/cube.hpp @@ -22,6 +22,10 @@ class Cube : public Geometry //Functions virtual ~Cube(){} virtual void create(); + + float x_dim; + float y_dim; + float z_dim; }; diff --git a/src/geom/particles.cpp b/src/geom/particles.cpp index 39317622..91b9e257 100644 --- a/src/geom/particles.cpp +++ b/src/geom/particles.cpp @@ -6,55 +6,56 @@ #include -#define FPS 100.f +void ParticleContainer::initParticles(const glm::vec3 &bounds, const glm::vec3 &container_bounds) { + particles.clear(); -void Particles::initParticles(const glm::vec3 &bounds, const glm::vec3 &container_bounds) { - positions.clear(); - - minBoundX = -container_bounds[0]; - minBoundY = -container_bounds[1]; - minBoundZ = -container_bounds[2]; - maxBoundX = container_bounds[0]; - maxBoundY = container_bounds[1]; - maxBoundZ = container_bounds[2]; + min_bound_x = -container_bounds[0]; + min_bound_y = -container_bounds[1]; + min_bound_z = -container_bounds[2]; + max_bound_x = container_bounds[0]; + max_bound_y = container_bounds[1]; + max_bound_z = container_bounds[2]; + x_dim = max_bound_x - min_bound_x; + y_dim = max_bound_y - min_bound_y; + z_dim = max_bound_z - min_bound_z; for (float i=0.f; i < bounds[0] ; i += separation) { for (float j=0.f; j < bounds[1]; j += separation) { for (float k=0.f; k < bounds[2]; k += separation) { - positions.push_back(glm::vec3(i, j, k)); - speed.push_back(glm::vec3(0.f, -9.8f, 0.f) / FPS); - dead.push_back(0); - std::cout << i << " " << j << " " << k << std::endl; + glm::vec3 pos(i, j, k); + glm::vec3 vel = glm::vec3(0.f, -9.8f, 0.f); + particles.push_back(new Particle(pos, vel)); + //std::cout << vel[0] << " " << vel[1] << " " << vel[2] << std::endl; } } } - num_indicies = positions.size() * 3 + 1; - std::cout << "SIZE" << num_indicies << std::endl; + num_indicies = particles.size() * 3 + 1; + //std::cout << "SIZE" << num_indicies << std::endl; } -void Particles::detectCollisions() { - for (int i=0; i < positions.size(); i++) { - if ((positions[i][0] < minBoundX || positions[i][0] > maxBoundX) - || (positions[i][1] < minBoundY || positions[i][1] > maxBoundY) - || (positions[i][2] < minBoundZ || positions[i][2] > maxBoundZ)) { - dead[i] = 1; - } +void ParticleContainer::detectCollisions() { + + for (Particle *p : particles) { + p->dead = ((p->position[0] < min_bound_x || p->position[0] > max_bound_x) + || (p->position[1] < min_bound_y || p->position[1] > max_bound_y) + || (p->position[2] < min_bound_z || p->position[2] > max_bound_z)); } } -void Particles::create() { +void ParticleContainer::create() { // Our vertices. Tree consecutive floats give a 3D vertex; Three consecutive vertices give a triangle. // A cube has 6 faces with 2 triangles each, so this makes 6*2=12 triangles, and 12*3 vertices std::vector g_vertex_buffer_data; std::vector g_color_buffer_data; - for (int i=0; i < positions.size(); i++) { - g_vertex_buffer_data.push_back(positions[i][0]); - g_vertex_buffer_data.push_back(positions[i][1]); - g_vertex_buffer_data.push_back(positions[i][2]); - if (dead[i]) { + for (Particle *p : particles) { + g_vertex_buffer_data.push_back(p->position[0]); + g_vertex_buffer_data.push_back(p->position[1]); + g_vertex_buffer_data.push_back(p->position[2]); + + if (p->dead) { g_color_buffer_data.push_back(1.0f); g_color_buffer_data.push_back(1.0f); g_color_buffer_data.push_back(1.0f); diff --git a/src/geom/particles.hpp b/src/geom/particles.hpp index 5ff5799b..ffe7efa3 100644 --- a/src/geom/particles.hpp +++ b/src/geom/particles.hpp @@ -9,32 +9,43 @@ #include #include "geom.hpp" -class Particles : public Geometry +class Particle +{ +public: + Particle(const glm::vec3 &pos, const glm::vec3 &vel) : position(pos), velocity(vel) {} + ~Particle(); + + glm::vec3 position; + glm::vec3 velocity; + int dead; +}; + +class ParticleContainer : public Geometry { public: //Constructors/destructors - Particles() { + ParticleContainer() { name = "PARTICLES"; draw_type = GL_POINTS; transform = glm::mat4(1.0f); } //Functions - virtual ~Particles(){} + virtual ~ParticleContainer(){} virtual void create(); void initParticles(const glm::vec3 &bounds, const glm::vec3 &container_bounds); virtual void detectCollisions(); - std::vector positions; - std::vector speed; - std::vector colors; - std::vector dead; - - float minBoundX; - float minBoundY; - float minBoundZ; - float maxBoundX; - float maxBoundY; - float maxBoundZ; + std::vector particles; + + float min_bound_x; + float min_bound_y; + float x_dim; + float min_bound_z; + float max_bound_x; + float y_dim; + float max_bound_y; + float max_bound_z; + float z_dim; float separation; }; diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index 5dec6aae..ac17d22f 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -40,7 +40,7 @@ void Scene::loadScene(const char *filename) { objects.push_back(box); // Get particle bounds. - Particles *fluid_particles = new Particles(); + ParticleContainer *fluid_particles = new ParticleContainer(); glm::vec3 particle_bounds = glm::vec3(root["particleDim"]["boundX"].asFloat(), root["particleDim"]["boundY"].asFloat(), root["particleDim"]["boundZ"].asFloat()); @@ -50,6 +50,10 @@ void Scene::loadScene(const char *filename) { fluid_particles->initParticles(particle_bounds, container_bounds); particles = fluid_particles; objects.push_back(fluid_particles); + + // Create fluid solver + fluid_solver = FlipSolver(fluid_particles); + fluid_solver.init(); } void Scene::drawScene(GLuint &programID, GLuint &MatrixID, Camera &camera) { @@ -97,5 +101,5 @@ void Scene::drawScene(GLuint &programID, GLuint &MatrixID, Camera &camera) { } // Update particle positions - FluidSolver::updateParticles(particles); + fluid_solver.step(); } diff --git a/src/scene/scene.hpp b/src/scene/scene.hpp index 54ac58ba..8ecfc18a 100644 --- a/src/scene/scene.hpp +++ b/src/scene/scene.hpp @@ -18,5 +18,6 @@ class Scene void drawScene(GLuint &programID, GLuint &MatrixID, Camera &camera); std::vector objects; - Particles *particles; + ParticleContainer *particles; + FlipSolver fluid_solver; }; diff --git a/src/scene/scene.json b/src/scene/scene.json index 789b4a42..04d120aa 100644 --- a/src/scene/scene.json +++ b/src/scene/scene.json @@ -1,13 +1,13 @@ { "containerDim" : { - "scaleX" : 5.0, - "scaleY" : 5.0, - "scaleZ" : 5.0 + "scaleX" : 3.0, + "scaleY" : 3.0, + "scaleZ" : 3.0 }, "particleDim" : { - "boundX" : 3.7, - "boundY" : 3.7, - "boundZ" : 3.7 + "boundX" : 1.0, + "boundY" : 1.0, + "boundZ" : 1.0 }, - "particleSeparation" : 0.1 + "particleSeparation" : 0.2 } \ No newline at end of file From 3979cef84a36329254611c1844f2e308da917c72 Mon Sep 17 00:00:00 2001 From: Rachel Hwang Date: Wed, 23 Mar 2016 13:26:30 -0400 Subject: [PATCH 03/23] Sprint one, mostly working. Remove extraneous print statement --- src/fluidSolver/fluidSolver.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/fluidSolver/fluidSolver.cpp b/src/fluidSolver/fluidSolver.cpp index 3d00100b..02887297 100644 --- a/src/fluidSolver/fluidSolver.cpp +++ b/src/fluidSolver/fluidSolver.cpp @@ -111,7 +111,6 @@ void FlipSolver::storeParticleVelocityToGrid() { // Do v_grid update. storeParticleVelocityToGridComponent(p, macgrid.v_grid, 1); normalizeGrid(macgrid.v_grid); - printGrid(macgrid.v_grid); // Do w_grid update. storeParticleVelocityToGridComponent(p, macgrid.w_grid, 2); normalizeGrid(macgrid.w_grid); From f842feaedee9b672794369ef7698c1f88a0b865f Mon Sep 17 00:00:00 2001 From: rahwang Date: Mon, 28 Mar 2016 01:54:06 -0400 Subject: [PATCH 04/23] fixed velocity transfer to grid. grid to particle still buggy --- src/fluidSolver/fluidSolver.cpp | 135 ++++++++++++++++---------------- src/fluidSolver/fluidSolver.hpp | 9 ++- src/fluidSolver/grid.cpp | 22 ------ src/fluidSolver/grid.hpp | 98 ++++++++++++++++++----- src/geom/particles.cpp | 14 +--- src/scene/scene.json | 2 +- 6 files changed, 154 insertions(+), 126 deletions(-) diff --git a/src/fluidSolver/fluidSolver.cpp b/src/fluidSolver/fluidSolver.cpp index 02887297..fd9acab8 100644 --- a/src/fluidSolver/fluidSolver.cpp +++ b/src/fluidSolver/fluidSolver.cpp @@ -5,33 +5,39 @@ #include "fluidSolver.hpp" #include -#define FPS 1000.f +#define TIME_STEP (1/10000.f) #define RES 1 #define CELL_WIDTH 1.f/RES -#define MATHIF(test, if_true, if_false) (((if_true) * (test)) + ((if_false) * (!test))) - -void FlipSolver::step() { +void FlipSolver::step() +{ // Reset grid values. clearGrids(); - // Transfer particle velocities to grid. + // Transfer particle velocities to grid (Also marks cell types). storeParticleVelocityToGrid(); // TODO: Apply forces. + applyGravity(); // TODO: Enforce boundary collisions. particle_container->detectCollisions(); - // TODO: Classify voxels. // TODO: Pressure step. // Update particle velocities. //interpolateVelocity(); // Update particle positions. - for (Particle *p : particle_container->particles) { - p->position += p->velocity / FPS; - } + updateParticlePositions(); } -void FlipSolver::init() { +// Using RK2 method. +void FlipSolver::updateParticlePositions() { + for (Particle *p : particle_container->particles) + { + p->position += p->velocity * TIME_STEP; + } +} + +void FlipSolver::init() +{ // Get dimensions of the fluid container. int x = int(ceil(particle_container->x_dim)); int y = int(ceil(particle_container->y_dim)); @@ -41,114 +47,101 @@ void FlipSolver::init() { } -void FlipSolver::constructMacGrid(int x, int y, int z) { +void FlipSolver::constructMacGrid(int x, int y, int z) +{ // Initialize the macgrid and subgrids. macgrid = MacGrid(x*RES, y*RES, z*RES); } -void FlipSolver::clearGrids() { +void FlipSolver::clearGrids() +{ macgrid.u_grid.clear(); macgrid.v_grid.clear(); macgrid.w_grid.clear(); + macgrid.cellTypes.clear(); } -void FlipSolver::normalizeGrid(Grid &grid) { - int numCells = grid.cells.size(); - for (int i=0; i < numCells; ++i) { - grid.cells[i] /= MATHIF(grid.particleCount[i] > 0, grid.particleCount[i], 1); - //std::cout << grid.particleCount[i] << " "; - } +void FlipSolver::applyGravity() +{ + macgrid.v_grid.applyToCells(-9.8f); } -void FlipSolver::storeParticleVelocityToGridComponent(Particle *p, Grid &grid, int dim) { - // HACK TO MAKE THIS WIP CODE WORK! - //if (p->dead) { - // return; - //} - // END HACK. - +void FlipSolver::storeParticleVelocityToGridComponent(Particle *p, Grid &grid, int dim) +{ glm::vec3 curr_idx = getVelocityGridIndex(p->position, dim); int i = curr_idx[0]; int j = curr_idx[1]; int k = curr_idx[2]; - for (int n=0; n < 2; ++n) { - for (int m=0; m < 2; ++m) { - for (int o=0; o < 2; ++o) { + for (int n=-1; n < 2; ++n) + { + for (int m=-1; m < 2; ++m) + { + for (int o=-1; o < 2; ++o) + { int I = i+n; int J = j+m; - int K = j+o; + int K = k+o; if (((I >= 0 && I < particle_container->x_dim) && (J >= 0 && J < particle_container->y_dim)) - && (K >= 0 && K < particle_container->z_dim)) { + && (K >= 0 && K < particle_container->z_dim)) + { grid(I, J, K) += p->velocity[dim]; grid.incrementParticleCount(I, J, K); } } } } -} - -void printGrid(Grid &grid) { - std::cout << "START "; - int numCells = grid.cells.size(); - for (int i=0; i < numCells; ++i) { - std::cout << grid.cells[i] << " "; - } - std::cout << " END "; + // Mark cell type + glm::vec3 type_idx = getGridIndex(p->position); + macgrid.cellTypes(type_idx[0], type_idx[1], type_idx[2]) = macgrid.cellTypes.FLUID; } -void FlipSolver::storeParticleVelocityToGrid() { - for (Particle *p : particle_container->particles) { +void FlipSolver::storeParticleVelocityToGrid() +{ + for (Particle *p : particle_container->particles) + { // Do u_grid update. storeParticleVelocityToGridComponent(p, macgrid.u_grid, 0); - normalizeGrid(macgrid.u_grid); // Do v_grid update. storeParticleVelocityToGridComponent(p, macgrid.v_grid, 1); - normalizeGrid(macgrid.v_grid); // Do w_grid update. storeParticleVelocityToGridComponent(p, macgrid.w_grid, 2); - normalizeGrid(macgrid.w_grid); } + macgrid.u_grid.normalizeCells(); + macgrid.v_grid.normalizeCells(); + macgrid.v_grid.printGrid(); + macgrid.w_grid.normalizeCells(); } // Return the three indices for accessing the edge corresponding to the given position. // Dim specifies which grid. 0 for u_grid, 1 for v_grid, 2 for w_grid. -glm::vec3 FlipSolver::getVelocityGridIndex(const glm::vec3 &pos, int dim) { +glm::vec3 FlipSolver::getVelocityGridIndex(const glm::vec3 &pos, int dim) +{ glm::vec3 p = pos; // Offset two of the dimensions. p[(dim+1)%3] -= CELL_WIDTH * 0.5; p[(dim+2)%3] -= CELL_WIDTH * 0.5; - // Transform to index space by subtracting minimum bounds and dividing by grid resolution. - int i = int(floor((p[0] - particle_container->x_dim) * RES)); - int j = int(floor((p[1] - particle_container->y_dim) * RES)); - int k = int(floor((p[2] - particle_container->z_dim) * RES)); - - // Clamp values. - i = std::min(std::max(i, 0), int(particle_container->x_dim-1)); - j = std::min(std::max(j, 0), int(particle_container->y_dim-1)); - k = std::min(std::max(k, 0), int(particle_container->z_dim-1)); - - return glm::vec3(i, j, k); + return getGridIndex(p); } // Return the three indices for accessing the edge corresponding to the given position. // Use for pressure grid. -glm::vec3 FlipSolver::getPressureGridIndex(const glm::vec3 &pos) { - +glm::vec3 FlipSolver::getGridIndex(const glm::vec3 &pos) +{ // Transform to index space by subtracting minimum bounds and dividing by grid resolution. - int i = int(floor((pos[0] - particle_container->x_dim - (CELL_WIDTH * 0.5)) * RES)); - int j = int(floor((pos[1] - particle_container->y_dim - (CELL_WIDTH * 0.5)) * RES)); - int k = int(floor((pos[2] - particle_container->z_dim - (CELL_WIDTH * 0.5)) * RES)); + int i = int(floor((pos[0] - particle_container->min_bound_x) / CELL_WIDTH)); + int j = int(floor((pos[1] - particle_container->min_bound_y) / CELL_WIDTH)); + int k = int(floor((pos[2] - particle_container->min_bound_z) / CELL_WIDTH)); // Clamp values. i = std::min(std::max(i, 0), int(particle_container->x_dim-1)); @@ -159,12 +152,14 @@ glm::vec3 FlipSolver::getPressureGridIndex(const glm::vec3 &pos) { } -float lerp(float p1, float p2, float u) { +float lerp(float p1, float p2, float u) +{ return p1*u + p2*(1-u); } -float FlipSolver::interpolateVelocityComponent(Particle *p, const Grid &grid, int dim) { +float FlipSolver::interpolateVelocityComponent(Particle *p, const Grid &grid, int dim) +{ // Get min and max indices. (Imagine a bounding box around particle). glm::vec3 curr_idx = getVelocityGridIndex(p->position, dim); glm::vec3 next_idx = getVelocityGridIndex(p->position + CELL_WIDTH, dim); @@ -176,24 +171,26 @@ float FlipSolver::interpolateVelocityComponent(Particle *p, const Grid &grid, in int kk = next_idx[2]; // Do x direction. - float x_uVal = (p->position[0] - floor(p->position[0]))/ RES; + float x_uVal = (p->position[0] - ((i * CELL_WIDTH) + particle_container->min_bound_x)) / CELL_WIDTH; float tmp1 = MATHIF(i!=ii, lerp(grid(i, j, k), grid(ii, j, k), x_uVal), grid(i, j, k)); float tmp2 = MATHIF(i!=ii, lerp(grid(i, jj, k), grid(ii, jj, k), x_uVal), grid(i, jj, k)); float tmp3 = MATHIF(i!=ii, lerp(grid(i, j, kk), grid(ii, j, kk), x_uVal), grid(i, j, kk)); float tmp4 = MATHIF(i!=ii, lerp(grid(i, jj, kk), grid(ii, jj, kk), x_uVal), grid(i, jj, kk)); // Do y direction. - float y_uVal = (p->position[1] - floor(p->position[1]))/ RES; + float y_uVal = (p->position[1] - ((j * CELL_WIDTH) + particle_container->min_bound_y)) / CELL_WIDTH; float tmp5 = MATHIF(j!=jj, lerp(tmp1, tmp2, y_uVal), tmp1); float tmp6 = MATHIF(j!=jj, lerp(tmp3, tmp4, y_uVal), tmp3); // Do z direction. - float z_uVal = (p->position[2] - floor(p->position[2]))/ RES; - return MATHIF(k!=kk, lerp(tmp5, tmp6, y_uVal), tmp5); + float z_uVal = (p->position[2] - ((k * CELL_WIDTH) + particle_container->min_bound_z)) / CELL_WIDTH; + return MATHIF(k!=kk, lerp(tmp5, tmp6, z_uVal), tmp5); } -void FlipSolver::interpolateVelocity() { - for (Particle *p : particle_container->particles) { +void FlipSolver::interpolateVelocity() +{ + for (Particle *p : particle_container->particles) + { p->velocity[0] = interpolateVelocityComponent(p, macgrid.u_grid, 0); p->velocity[1] = interpolateVelocityComponent(p, macgrid.v_grid, 1); p->velocity[2] = interpolateVelocityComponent(p, macgrid.w_grid, 2); diff --git a/src/fluidSolver/fluidSolver.hpp b/src/fluidSolver/fluidSolver.hpp index c1817741..1c1b844a 100644 --- a/src/fluidSolver/fluidSolver.hpp +++ b/src/fluidSolver/fluidSolver.hpp @@ -26,17 +26,18 @@ class FlipSolver : public FluidSolver { void step(); glm::vec3 getVelocityGridIndex(const glm::vec3 &pos, int dim); - glm::vec3 getPressureGridIndex(const glm::vec3 &pos); + glm::vec3 getGridIndex(const glm::vec3 &pos); void constructMacGrid(int x, int y, int z); - void storeParticleVelocityToGridComponent(Particle *p, Grid &grid, int dim); + void storeParticleVelocityToGridComponent(Particle *p, Grid &grid, int dim); void storeParticleVelocityToGrid(); void clearGrids(); - void normalizeGrid(Grid &grid); - float interpolateVelocityComponent(Particle *p, const Grid &grid, int dim); + float interpolateVelocityComponent(Particle *p, const Grid &grid, int dim); void interpolateVelocity(); + void applyGravity(); + void updateParticlePositions(); MacGrid macgrid; }; diff --git a/src/fluidSolver/grid.cpp b/src/fluidSolver/grid.cpp index 24110662..10e45acd 100644 --- a/src/fluidSolver/grid.cpp +++ b/src/fluidSolver/grid.cpp @@ -4,25 +4,3 @@ #include "grid.hpp" - -float& Grid::operator() (int i, int j, int k) { - return cells[i*x_dim*y_dim + j*y_dim + k]; -} - -const float& Grid::operator() (int i, int j, int k) const { - return cells[i*x_dim*y_dim + j*y_dim + k]; -} - -int Grid::getParticleCount(int i, int j, int k) { - return particleCount[i*x_dim*y_dim + j*y_dim + k]; -} - -void Grid::incrementParticleCount(int i, int j, int k) { - particleCount[i*x_dim*y_dim + j*y_dim + k]++; -} - -void Grid::clear() { - cells = std::vector(x_dim*y_dim*z_dim, 0.f); - particleCount = std::vector(x_dim*y_dim*z_dim, 0); -} - diff --git a/src/fluidSolver/grid.hpp b/src/fluidSolver/grid.hpp index 8d5f8db5..703bf214 100644 --- a/src/fluidSolver/grid.hpp +++ b/src/fluidSolver/grid.hpp @@ -6,45 +6,103 @@ #define grid_hpp #include "../geom/particles.hpp" +#include -class Grid{ +#define MATHIF(test, if_true, if_false) (((if_true) * (test)) + ((if_false) * (!test))) + +template +class Grid { private: int x_dim; int y_dim; int z_dim; + + // The velocity or pressure quantities stored on the grid. + std::vector cells; + // The number of particles influencing this quanitity. + std::vector particleCount; public: Grid() {} Grid(int x, int y, int z) : x_dim(x), y_dim(y), z_dim(z) { - cells = std::vector(x_dim*y_dim*z_dim, 0.f); + cells = std::vector(x_dim*y_dim*z_dim, 0.f); particleCount = std::vector(x_dim*y_dim*z_dim, 0); } - ~Grid() {} - float& operator() (int i, int j, int k); - const float& operator() (int i, int j, int k) const; - float& operator() (int i); - const float& operator() (int i) const; - int getParticleCount(int i, int j, int k); - void incrementParticleCount(int i, int j, int k); - void clear(); + ~Grid() {} - std::vector cells; - std::vector particleCount; + T& operator() (int i, int j, int k) + { + return cells[i + y_dim * (j + z_dim * k)]; + } + + const T& operator() (int i, int j, int k) const + { + return cells[i + y_dim * (j + z_dim * k)]; + } + + int getParticleCount(int i, int j, int k) + { + return particleCount[i + y_dim * (j + z_dim * k)]; + } + + void incrementParticleCount(int i, int j, int k) + { + particleCount[i + y_dim * (j + z_dim * k)]++; + } + + void clear() + { + cells = std::vector(x_dim*y_dim*z_dim, 0); + particleCount = std::vector(x_dim*y_dim*z_dim, 0); + } + + void printGrid() + { + std::cout << "START "; + int numCells = cells.size(); + for (int i=0; i < numCells; ++i) + { + std::cout << cells[i] << " "; + } + std::cout << " END "; + } + + void applyToCells(float f) + { + int numCells = cells.size(); + for (int i=0; i < numCells; ++i) + { + cells[i] += f; + } + } + + void normalizeCells() + { + int numCells = cells.size(); + for (int i=0; i < numCells; ++i) + { + cells[i] /= MATHIF(particleCount[i] > 0, particleCount[i], 1); + } + } + + enum {AIR = 0, FLUID = 1, SOLID = 2}; }; class MacGrid{ public: MacGrid() {} MacGrid(int x, int y, int z) { - u_grid = Grid(x+1, y, z); - v_grid = Grid(x, y+1, z); - w_grid = Grid(x, y, z+1); - p_grid = Grid(x, y, z); + u_grid = Grid(x+1, y, z); + v_grid = Grid(x, y+1, z); + w_grid = Grid(x, y, z+1); + p_grid = Grid(x, y, z); + cellTypes = Grid(x, y, z); } - Grid u_grid; - Grid v_grid; - Grid w_grid; - Grid p_grid; + Grid u_grid; + Grid v_grid; + Grid w_grid; + Grid p_grid; + Grid cellTypes; }; #endif /* grid_hpp */ diff --git a/src/geom/particles.cpp b/src/geom/particles.cpp index 91b9e257..928e8074 100644 --- a/src/geom/particles.cpp +++ b/src/geom/particles.cpp @@ -23,7 +23,7 @@ void ParticleContainer::initParticles(const glm::vec3 &bounds, const glm::vec3 & for (float j=0.f; j < bounds[1]; j += separation) { for (float k=0.f; k < bounds[2]; k += separation) { glm::vec3 pos(i, j, k); - glm::vec3 vel = glm::vec3(0.f, -9.8f, 0.f); + glm::vec3 vel = glm::vec3(0.f, 0.f, 0.f); particles.push_back(new Particle(pos, vel)); //std::cout << vel[0] << " " << vel[1] << " " << vel[2] << std::endl; } @@ -55,15 +55,9 @@ void ParticleContainer::create() { g_vertex_buffer_data.push_back(p->position[1]); g_vertex_buffer_data.push_back(p->position[2]); - if (p->dead) { - g_color_buffer_data.push_back(1.0f); - g_color_buffer_data.push_back(1.0f); - g_color_buffer_data.push_back(1.0f); - } else { - g_color_buffer_data.push_back(0.0f); - g_color_buffer_data.push_back(0.0f); - g_color_buffer_data.push_back(0.5f); - } + g_color_buffer_data.push_back(0.0f); + g_color_buffer_data.push_back(0.0f); + g_color_buffer_data.push_back(0.5f); } glGenBuffers(1, &vertexbuffer); diff --git a/src/scene/scene.json b/src/scene/scene.json index 04d120aa..89628617 100644 --- a/src/scene/scene.json +++ b/src/scene/scene.json @@ -9,5 +9,5 @@ "boundY" : 1.0, "boundZ" : 1.0 }, - "particleSeparation" : 0.2 + "particleSeparation" : 0.5 } \ No newline at end of file From 8c4ea81a4a4096e28dc82d7c329d8dbbcdaa4950 Mon Sep 17 00:00:00 2001 From: rahwang Date: Wed, 30 Mar 2016 03:49:53 -0400 Subject: [PATCH 05/23] Sprint 2 work in progress --- src/fluidSolver/fluidSolver.cpp | 221 +++++++++++++++++++++++++++----- src/fluidSolver/fluidSolver.hpp | 4 + src/fluidSolver/grid.hpp | 66 +++++++--- src/geom/particles.hpp | 4 +- src/scene/scene.json | 8 +- 5 files changed, 250 insertions(+), 53 deletions(-) diff --git a/src/fluidSolver/fluidSolver.cpp b/src/fluidSolver/fluidSolver.cpp index fd9acab8..6103e66c 100644 --- a/src/fluidSolver/fluidSolver.cpp +++ b/src/fluidSolver/fluidSolver.cpp @@ -5,9 +5,10 @@ #include "fluidSolver.hpp" #include -#define TIME_STEP (1/10000.f) -#define RES 1 -#define CELL_WIDTH 1.f/RES +#define GRAVITY -9.8f +#define TIME_STEP (1.0f/10.f) +#define RES 4 +#define CELL_WIDTH (1.f/RES) void FlipSolver::step() { @@ -15,20 +16,136 @@ void FlipSolver::step() clearGrids(); // Transfer particle velocities to grid (Also marks cell types). storeParticleVelocityToGrid(); - // TODO: Apply forces. + // Zero velocities pointing into solid cells. + enforceBoundaryConditions(); applyGravity(); - // TODO: Enforce boundary collisions. - particle_container->detectCollisions(); // TODO: Pressure step. + // Handle air/fluid boundaries. + //extrapolateVelocities(); // Update particle velocities. - //interpolateVelocity(); - // Update particle positions. + interpolateVelocity(); updateParticlePositions(); + handleCollisions(); } -// Using RK2 method. -void FlipSolver::updateParticlePositions() { +void FlipSolver::extrapolateVelocities() { + for (int i=0; i < particle_container->min_bound_x; ++i) + { + for (int j=0; j < particle_container->min_bound_y; ++j) + { + for (int k=0; k < particle_container->min_bound_z; ++k) + { + if (macgrid.cellTypes(i, j, k) == macgrid.cellTypes.AIR) + { + for (int n=-1; n < 2; ++n) + { + for (int m=-1; m < 2; ++m) + { + for (int o=-1; o < 2; ++o) + { + int I = i+n; + int J = j+m; + int K = k+o; + if (((I >= 0 && I < particle_container->x_dim) + && (J >= 0 && J < particle_container->y_dim)) + && (K >= 0 && K < particle_container->z_dim)) + { + } + } + } + } + } + } + } + } +} + + +void FlipSolver::handleCollisions() +{ + for (Particle *p : particle_container->particles) + { + // Check to see if p is inside bounding volume + if (p->position[0] < particle_container->min_bound_x || p->position[0] > particle_container->max_bound_x) + { + p->position[0] = std::min(std::max(p->position[0], particle_container->min_bound_x), particle_container->max_bound_x); + p->velocity[0] *= -0.5; + } + if (p->position[1] < particle_container->min_bound_y || p->position[1] > particle_container->max_bound_y) + { + p->position[1] = std::min(std::max(p->position[1], particle_container->min_bound_y), particle_container->max_bound_y); + p->velocity[1] *= -0.5f; + } + if (p->position[2] < particle_container->min_bound_z || p->position[2] > particle_container->max_bound_z) + { + p->position[2] = std::min(std::max(p->position[2], particle_container->min_bound_z), particle_container->max_bound_z); + p->velocity[2] *= -0.5; + } + } +} + + +void FlipSolver::enforceBoundaryConditions() +{ + // Iterate through all the grids. + for (int i=0; i < macgrid.p_grid.x_dim; ++i) + { + for (int j=0; j < macgrid.p_grid.y_dim; ++j) + { + for (int k=0; k < macgrid.p_grid.z_dim; ++k) + { + // Check to see if the cell is solid. + if (macgrid.cellTypes(i, j, k) = macgrid.p_grid.SOLID) + { + // For the min faces, zero velocity into cell. + macgrid.u(i, j, k) = std::min(0.f, macgrid.u(i, j, k)); + macgrid.v(i, j, k) = std::min(0.f, macgrid.v(i, j, k)); + macgrid.w(i, j, k) = std::min(0.f, macgrid.w(i, j, k)); + + for (int ii=i; ii < i+1; ++ii) + { + for (int jj=j; jj < j+1; ++jj) + { + for (int kk=k; kk < k+1; ++kk) + { + // For the max faces, zero velocity into cell. + if (ii < macgrid.u.x_dim && jj < macgrid.u.y_dim && kk < macgrid.u.z_dim) + macgrid.u(ii, jj, kk) = std::max(0.f, macgrid.u(i+1, j, k)); + if (jj < macgrid.v.x_dim && jj < macgrid.v.y_dim && kk < macgrid.v.z_dim) + macgrid.v(ii, jj, kk) = std::max(0.f, macgrid.v(i+1, j, k)); + if (kk < macgrid.w.x_dim && jj < macgrid.w.y_dim && kk < macgrid.w.z_dim) + macgrid.w(ii, jj, kk) = std::max(0.f, macgrid.w(i+1, j, k)); + } + } + } + } + + // For the min borders, zero velocity out of fluid bounds. + if (i == 0) + macgrid.u(i, j, k) = std::max(0.f, macgrid.u(i, j, k)); + if (j == 0) + macgrid.v(i, j, k) = std::max(0.f, macgrid.v(i, j, k)); + if (j == 0) + macgrid.w(i, j, k) = std::max(0.f, macgrid.w(i, j, k)); + + // For the max borders, zero velocity out of fluid bounds. + if (i == macgrid.p_grid.x_dim-1) + macgrid.u(i+1, j, k) = std::min(0.f, macgrid.u(i+1, j, k)); + if (j == macgrid.p_grid.y_dim-1) + macgrid.v(i, j+1, k) = std::min(0.f, macgrid.v(i, j+1, k)); + if (k == macgrid.p_grid.z_dim-1) + macgrid.w(i, j, k+1) = std::min(0.f, macgrid.w(i, j, k+1)); + + } + } + } +} + + +// Using forward Euler for now. +void FlipSolver::updateParticlePositions() +{ for (Particle *p : particle_container->particles) { p->position += p->velocity * TIME_STEP; @@ -44,6 +161,7 @@ void FlipSolver::init() int z = int(ceil(particle_container->z_dim)); constructMacGrid(x, y, z); + applyGravity(); } @@ -56,16 +174,20 @@ void FlipSolver::constructMacGrid(int x, int y, int z) void FlipSolver::clearGrids() { - macgrid.u_grid.clear(); - macgrid.v_grid.clear(); - macgrid.w_grid.clear(); + macgrid.u.copyCells(macgrid.u_old); + macgrid.v.copyCells(macgrid.v_old); + macgrid.w.copyCells(macgrid.w_old); + + macgrid.u.clearVelocity(); + macgrid.v.clearVelocity(); + macgrid.w.clearVelocity(); macgrid.cellTypes.clear(); } void FlipSolver::applyGravity() { - macgrid.v_grid.applyToCells(-9.8f); + macgrid.v.applyToCells(GRAVITY * TIME_STEP); } @@ -85,11 +207,18 @@ void FlipSolver::storeParticleVelocityToGridComponent(Particle *p, Grid & int I = i+n; int J = j+m; int K = k+o; - if (((I >= 0 && I < particle_container->x_dim) - && (J >= 0 && J < particle_container->y_dim)) - && (K >= 0 && K < particle_container->z_dim)) + if (((I >= 0 && I < grid.x_dim) + && (J >= 0 && J < grid.y_dim)) + && (K >= 0 && K < grid.z_dim)) { - grid(I, J, K) += p->velocity[dim]; + // Calculate weight based on distance from cell center. + float x = particle_container->min_bound_x + ((I + 0.5f) * CELL_WIDTH); + float y = particle_container->min_bound_y + ((J + 0.5f) * CELL_WIDTH); + float z = particle_container->min_bound_z + ((K + 0.5f) * CELL_WIDTH); + float weight = 1.0f / glm::length(glm::vec3(x, y, z)-p->position); + + // Store velocity contribution and increment particle counter. + grid(I, J, K) += weight * p->velocity[dim]; grid.incrementParticleCount(I, J, K); } } @@ -107,16 +236,16 @@ void FlipSolver::storeParticleVelocityToGrid() for (Particle *p : particle_container->particles) { // Do u_grid update. - storeParticleVelocityToGridComponent(p, macgrid.u_grid, 0); + storeParticleVelocityToGridComponent(p, macgrid.u, 0); // Do v_grid update. - storeParticleVelocityToGridComponent(p, macgrid.v_grid, 1); + storeParticleVelocityToGridComponent(p, macgrid.v, 1); // Do w_grid update. - storeParticleVelocityToGridComponent(p, macgrid.w_grid, 2); + storeParticleVelocityToGridComponent(p, macgrid.w, 2); } - macgrid.u_grid.normalizeCells(); - macgrid.v_grid.normalizeCells(); - macgrid.v_grid.printGrid(); - macgrid.w_grid.normalizeCells(); + macgrid.u.normalizeCells(); + macgrid.v.normalizeCells(); + //macgrid.v_grid.printGrid(); + macgrid.w.normalizeCells(); } @@ -154,7 +283,7 @@ glm::vec3 FlipSolver::getGridIndex(const glm::vec3 &pos) float lerp(float p1, float p2, float u) { - return p1*u + p2*(1-u); + return p2*u + p1*(1.0f-u); } @@ -177,6 +306,8 @@ float FlipSolver::interpolateVelocityComponent(Particle *p, const Grid &g float tmp3 = MATHIF(i!=ii, lerp(grid(i, j, kk), grid(ii, j, kk), x_uVal), grid(i, j, kk)); float tmp4 = MATHIF(i!=ii, lerp(grid(i, jj, kk), grid(ii, jj, kk), x_uVal), grid(i, jj, kk)); + //std::cout << tmp1 << " " << tmp2 << " " << tmp3 << " " << tmp4 << std::endl; + // Do y direction. float y_uVal = (p->position[1] - ((j * CELL_WIDTH) + particle_container->min_bound_y)) / CELL_WIDTH; float tmp5 = MATHIF(j!=jj, lerp(tmp1, tmp2, y_uVal), tmp1); @@ -184,17 +315,43 @@ float FlipSolver::interpolateVelocityComponent(Particle *p, const Grid &g // Do z direction. float z_uVal = (p->position[2] - ((k * CELL_WIDTH) + particle_container->min_bound_z)) / CELL_WIDTH; - return MATHIF(k!=kk, lerp(tmp5, tmp6, z_uVal), tmp5); + float THING = MATHIF(k!=kk, lerp(tmp5, tmp6, z_uVal), tmp5); + return THING; +} + + +void FlipSolver::storeDeltaVelocity(Grid &old_grid, const Grid &grid) +{ + int numCells = old_grid.getNumCells(); + for (int i=0; i < numCells; ++i) + { + old_grid(i) = grid(i) - old_grid(i); + } } + void FlipSolver::interpolateVelocity() { + storeDeltaVelocity(macgrid.u_old, macgrid.u); + storeDeltaVelocity(macgrid.v_old, macgrid.v); + storeDeltaVelocity(macgrid.w_old, macgrid.w); + for (Particle *p : particle_container->particles) { - p->velocity[0] = interpolateVelocityComponent(p, macgrid.u_grid, 0); - p->velocity[1] = interpolateVelocityComponent(p, macgrid.v_grid, 1); - p->velocity[2] = interpolateVelocityComponent(p, macgrid.w_grid, 2); - - //std::cout << p->position[0] << " " << p->position[1] << " " << p->position[2]; + // Get PIC components. + float pic_x = interpolateVelocityComponent(p, macgrid.u, 0); + float pic_y = interpolateVelocityComponent(p, macgrid.v, 1); + float pic_z = interpolateVelocityComponent(p, macgrid.w, 2); + + // Get FLIP components. "old" grids currently contain delta velocity. + float flip_x = p->velocity[0] + interpolateVelocityComponent(p, macgrid.u_old, 0); + float flip_y = p->velocity[1] + interpolateVelocityComponent(p, macgrid.v_old, 1); + float flip_z = p->velocity[2] + interpolateVelocityComponent(p, macgrid.w_old, 2); + + p->velocity[0] = 0.05f * pic_x + 0.95f * flip_x; + p->velocity[1] = 0.05f * pic_y + 0.95f * flip_y; + p->velocity[2] = 0.05f * pic_z + 0.95f * flip_z; + + //std::cout << p->velocity[1] << std::endl; } } diff --git a/src/fluidSolver/fluidSolver.hpp b/src/fluidSolver/fluidSolver.hpp index 1c1b844a..9689d0eb 100644 --- a/src/fluidSolver/fluidSolver.hpp +++ b/src/fluidSolver/fluidSolver.hpp @@ -38,6 +38,10 @@ class FlipSolver : public FluidSolver { void interpolateVelocity(); void applyGravity(); void updateParticlePositions(); + void handleCollisions(); + void enforceBoundaryConditions(); + void extrapolateVelocities(); + void storeDeltaVelocity(Grid &old_grid, const Grid &grid); MacGrid macgrid; }; diff --git a/src/fluidSolver/grid.hpp b/src/fluidSolver/grid.hpp index 703bf214..a6a063b3 100644 --- a/src/fluidSolver/grid.hpp +++ b/src/fluidSolver/grid.hpp @@ -8,20 +8,20 @@ #include "../geom/particles.hpp" #include -#define MATHIF(test, if_true, if_false) (((if_true) * (test)) + ((if_false) * (!test))) +#define MATHIF(test, if_true, if_false) (((if_true) * (test)) + ((if_false) * (1 - (test)))) template class Grid { private: - int x_dim; - int y_dim; - int z_dim; - // The velocity or pressure quantities stored on the grid. std::vector cells; // The number of particles influencing this quanitity. std::vector particleCount; public: + int x_dim; + int y_dim; + int z_dim; + Grid() {} Grid(int x, int y, int z) : x_dim(x), y_dim(y), z_dim(z) { cells = std::vector(x_dim*y_dim*z_dim, 0.f); @@ -38,6 +38,16 @@ class Grid { { return cells[i + y_dim * (j + z_dim * k)]; } + + T& operator() (int i) + { + return cells[i]; + } + + const T& operator() (int i) const + { + return cells[i]; + } int getParticleCount(int i, int j, int k) { @@ -49,11 +59,21 @@ class Grid { particleCount[i + y_dim * (j + z_dim * k)]++; } - void clear() + void clearVelocity() { - cells = std::vector(x_dim*y_dim*z_dim, 0); + cells = std::vector(x_dim*y_dim*z_dim, 0.f); particleCount = std::vector(x_dim*y_dim*z_dim, 0); } + + void copyCells(Grid &dst_grid) + { + dst_grid.cells = cells; + } + + void clear() + { + cells = std::vector(x_dim*y_dim*z_dim, 0.f); + } void printGrid() { @@ -80,9 +100,14 @@ class Grid { int numCells = cells.size(); for (int i=0; i < numCells; ++i) { - cells[i] /= MATHIF(particleCount[i] > 0, particleCount[i], 1); + cells[i] /= MATHIF(particleCount[i] > 0, particleCount[i], 1.0f); } } + + int getNumCells() + { + return cells.size(); + } enum {AIR = 0, FLUID = 1, SOLID = 2}; }; @@ -90,17 +115,28 @@ class Grid { class MacGrid{ public: MacGrid() {} - MacGrid(int x, int y, int z) { - u_grid = Grid(x+1, y, z); - v_grid = Grid(x, y+1, z); - w_grid = Grid(x, y, z+1); + MacGrid(int x, int y, int z) + { + u = Grid(x+1, y, z); + v = Grid(x, y+1, z); + w = Grid(x, y, z+1); + + u_old = Grid(x+1, y, z); + v_old = Grid(x, y+1, z); + w_old = Grid(x, y, z+1); + p_grid = Grid(x, y, z); cellTypes = Grid(x, y, z); } - Grid u_grid; - Grid v_grid; - Grid w_grid; + Grid u; + Grid v; + Grid w; + + Grid u_old; + Grid v_old; + Grid w_old; + Grid p_grid; Grid cellTypes; }; diff --git a/src/geom/particles.hpp b/src/geom/particles.hpp index ffe7efa3..cd93a0b8 100644 --- a/src/geom/particles.hpp +++ b/src/geom/particles.hpp @@ -39,12 +39,12 @@ class ParticleContainer : public Geometry float min_bound_x; float min_bound_y; - float x_dim; float min_bound_z; float max_bound_x; - float y_dim; float max_bound_y; float max_bound_z; + float x_dim; + float y_dim; float z_dim; float separation; diff --git a/src/scene/scene.json b/src/scene/scene.json index 89628617..93a35b30 100644 --- a/src/scene/scene.json +++ b/src/scene/scene.json @@ -1,13 +1,13 @@ { "containerDim" : { - "scaleX" : 3.0, - "scaleY" : 3.0, - "scaleZ" : 3.0 + "scaleX" : 2.0, + "scaleY" : 2.0, + "scaleZ" : 2.0 }, "particleDim" : { "boundX" : 1.0, "boundY" : 1.0, "boundZ" : 1.0 }, - "particleSeparation" : 0.5 + "particleSeparation" : 0.2 } \ No newline at end of file From 312c9a8332a16f267e50f058cf8547843137c81d Mon Sep 17 00:00:00 2001 From: rahwang Date: Wed, 30 Mar 2016 07:45:39 -0400 Subject: [PATCH 06/23] Sprint 2 done --- CMakeLists.txt | 2 +- src/fluidSolver/fluidSolver.cpp | 123 ++++++++++++++++++-------------- src/fluidSolver/fluidSolver.hpp | 4 +- src/fluidSolver/grid.hpp | 25 +++++-- src/geom/particles.cpp | 38 +++++----- src/geom/particles.hpp | 16 ++--- src/scene/scene.json | 12 ++-- 7 files changed, 128 insertions(+), 92 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d515be34..8d045ead 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,7 +64,7 @@ endif() # set compiler flags for c++11 if(${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O3 -m64 -msse2 -w") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O0 -m64 -msse2 -w") elseif(WIN32) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") endif() diff --git a/src/fluidSolver/fluidSolver.cpp b/src/fluidSolver/fluidSolver.cpp index 6103e66c..b2607ae8 100644 --- a/src/fluidSolver/fluidSolver.cpp +++ b/src/fluidSolver/fluidSolver.cpp @@ -9,6 +9,7 @@ #define TIME_STEP (1.0f/10.f) #define RES 4 #define CELL_WIDTH (1.f/RES) +#define DAMPING 1.0f void FlipSolver::step() { @@ -21,39 +22,57 @@ void FlipSolver::step() applyGravity(); // TODO: Pressure step. // Handle air/fluid boundaries. - //extrapolateVelocities(); + extrapolateVelocity(); // Update particle velocities. - interpolateVelocity(); + gridVelocityToParticle(); updateParticlePositions(); handleCollisions(); } -void FlipSolver::extrapolateVelocities() { - for (int i=0; i < particle_container->min_bound_x; ++i) +void FlipSolver::extrapolateVelocity() { + for (int i=0; i < macgrid.p_grid.x_dim; ++i) { - for (int j=0; j < particle_container->min_bound_y; ++j) + for (int j=0; j < macgrid.p_grid.y_dim; ++j) { - for (int k=0; k < particle_container->min_bound_z; ++k) + for (int k=0; k < macgrid.p_grid.z_dim; ++k) { if (macgrid.cellTypes(i, j, k) == macgrid.cellTypes.AIR) { - for (int n=-1; n < 2; ++n) + // X velocity grid check. + if ((i-1 > 0 && macgrid.cellTypes(i-1, j, k) == macgrid.cellTypes.FLUID) + && (i+1 > macgrid.p_grid.x_dim || macgrid.cellTypes(i+1, j, k) != macgrid.cellTypes.FLUID)) { - for (int m=-1; m < 2; ++m) - { - for (int o=-1; o < 2; ++o) - { - int I = i+n; - int J = j+m; - int K = k+o; - if (((I >= 0 && I < particle_container->x_dim) - && (J >= 0 && J < particle_container->y_dim)) - && (K >= 0 && K < particle_container->z_dim)) - { - } - } - } + macgrid.u(i, j, k) = macgrid.u(i-1, j, k); + } + else if ((i+1 <= macgrid.p_grid.x_dim && macgrid.cellTypes(i+1, j, k) == macgrid.cellTypes.FLUID) + && (i-1 < 0 || macgrid.cellTypes(i-1, j, k) != macgrid.cellTypes.FLUID)) + { + macgrid.u(i, j, k) = macgrid.u(i+1, j, k); + } + + // Y velocity grid check. + if ((j-1 > 0 && macgrid.cellTypes(i, j-1, k) == macgrid.cellTypes.FLUID) + && (j+1 > macgrid.p_grid.y_dim || macgrid.cellTypes(i, j+1, k) != macgrid.cellTypes.FLUID)) + { + macgrid.v(i, j, k) = macgrid.v(i, j-1, k); + } + else if ((j+1 <= macgrid.p_grid.y_dim && macgrid.cellTypes(i, j+1, k) == macgrid.cellTypes.FLUID) + && (j-1 < 0 || macgrid.cellTypes(i, j-1, k) != macgrid.cellTypes.FLUID)) + { + macgrid.v(i, j, k) = macgrid.v(i, j+1, k); + } + + // X velocity grid check. + if ((k-1 > 0 && macgrid.cellTypes(i, j, k-1) == macgrid.cellTypes.FLUID) + && (k+1 > macgrid.p_grid.z_dim || macgrid.cellTypes(i, j, k+1) != macgrid.cellTypes.FLUID)) + { + macgrid.u(i, j, k) = macgrid.u(i, j, k-1); + } + else if ((k+1 <= macgrid.p_grid.z_dim && macgrid.cellTypes(i, j, k+1) == macgrid.cellTypes.FLUID) + && (k-1 < 0 || macgrid.cellTypes(i, j, k-1) != macgrid.cellTypes.FLUID)) + { + macgrid.u(i, j, k) = macgrid.u(i, j, k+1); } } } @@ -67,20 +86,20 @@ void FlipSolver::handleCollisions() for (Particle *p : particle_container->particles) { // Check to see if p is inside bounding volume - if (p->position[0] < particle_container->min_bound_x || p->position[0] > particle_container->max_bound_x) + if (p->pos[0] < particle_container->min_x || p->pos[0] > particle_container->max_x) { - p->position[0] = std::min(std::max(p->position[0], particle_container->min_bound_x), particle_container->max_bound_x); - p->velocity[0] *= -0.5; + p->pos[0] = std::min(std::max(p->pos[0], particle_container->min_x), particle_container->max_x); + p->velocity[0] *= -DAMPING; } - if (p->position[1] < particle_container->min_bound_y || p->position[1] > particle_container->max_bound_y) + if (p->pos[1] < particle_container->min_y || p->pos[1] > particle_container->max_y) { - p->position[1] = std::min(std::max(p->position[1], particle_container->min_bound_y), particle_container->max_bound_y); - p->velocity[1] *= -0.5f; + p->pos[1] = std::min(std::max(p->pos[1], particle_container->min_y), particle_container->max_y); + p->velocity[1] *= -DAMPING; } - if (p->position[2] < particle_container->min_bound_z || p->position[2] > particle_container->max_bound_z) + if (p->pos[2] < particle_container->min_z || p->pos[2] > particle_container->max_z) { - p->position[2] = std::min(std::max(p->position[2], particle_container->min_bound_z), particle_container->max_bound_z); - p->velocity[2] *= -0.5; + p->pos[2] = std::min(std::max(p->pos[2], particle_container->min_z), particle_container->max_z); + p->velocity[2] *= -DAMPING; } } } @@ -111,11 +130,11 @@ void FlipSolver::enforceBoundaryConditions() { // For the max faces, zero velocity into cell. if (ii < macgrid.u.x_dim && jj < macgrid.u.y_dim && kk < macgrid.u.z_dim) - macgrid.u(ii, jj, kk) = std::max(0.f, macgrid.u(i+1, j, k)); - if (jj < macgrid.v.x_dim && jj < macgrid.v.y_dim && kk < macgrid.v.z_dim) - macgrid.v(ii, jj, kk) = std::max(0.f, macgrid.v(i+1, j, k)); - if (kk < macgrid.w.x_dim && jj < macgrid.w.y_dim && kk < macgrid.w.z_dim) - macgrid.w(ii, jj, kk) = std::max(0.f, macgrid.w(i+1, j, k)); + macgrid.u(ii, jj, kk) = std::max(0.f, macgrid.u(ii, jj, kk)); + if (ii < macgrid.v.x_dim && jj < macgrid.v.y_dim && kk < macgrid.v.z_dim) + macgrid.v(ii, jj, kk) = std::max(0.f, macgrid.v(ii, jj, kk)); + if (ii < macgrid.w.x_dim && jj < macgrid.w.y_dim && kk < macgrid.w.z_dim) + macgrid.w(ii, jj, kk) = std::max(0.f, macgrid.w(ii, jj, kk)); } } } @@ -136,7 +155,6 @@ void FlipSolver::enforceBoundaryConditions() macgrid.v(i, j+1, k) = std::min(0.f, macgrid.v(i, j+1, k)); if (k == macgrid.p_grid.z_dim-1) macgrid.w(i, j, k+1) = std::min(0.f, macgrid.w(i, j, k+1)); - } } } @@ -148,7 +166,7 @@ void FlipSolver::updateParticlePositions() { for (Particle *p : particle_container->particles) { - p->position += p->velocity * TIME_STEP; + p->pos += p->velocity * TIME_STEP; } } @@ -193,7 +211,7 @@ void FlipSolver::applyGravity() void FlipSolver::storeParticleVelocityToGridComponent(Particle *p, Grid &grid, int dim) { - glm::vec3 curr_idx = getVelocityGridIndex(p->position, dim); + glm::vec3 curr_idx = getVelocityGridIndex(p->pos, dim); int i = curr_idx[0]; int j = curr_idx[1]; int k = curr_idx[2]; @@ -212,10 +230,10 @@ void FlipSolver::storeParticleVelocityToGridComponent(Particle *p, Grid & && (K >= 0 && K < grid.z_dim)) { // Calculate weight based on distance from cell center. - float x = particle_container->min_bound_x + ((I + 0.5f) * CELL_WIDTH); - float y = particle_container->min_bound_y + ((J + 0.5f) * CELL_WIDTH); - float z = particle_container->min_bound_z + ((K + 0.5f) * CELL_WIDTH); - float weight = 1.0f / glm::length(glm::vec3(x, y, z)-p->position); + float x = particle_container->min_x + ((I + 0.5f) * CELL_WIDTH); + float y = particle_container->min_y + ((J + 0.5f) * CELL_WIDTH); + float z = particle_container->min_z + ((K + 0.5f) * CELL_WIDTH); + float weight = 1.0f / glm::length(glm::vec3(x, y, z)-p->pos); // Store velocity contribution and increment particle counter. grid(I, J, K) += weight * p->velocity[dim]; @@ -226,7 +244,7 @@ void FlipSolver::storeParticleVelocityToGridComponent(Particle *p, Grid & } // Mark cell type - glm::vec3 type_idx = getGridIndex(p->position); + glm::vec3 type_idx = getGridIndex(p->pos); macgrid.cellTypes(type_idx[0], type_idx[1], type_idx[2]) = macgrid.cellTypes.FLUID; } @@ -244,7 +262,6 @@ void FlipSolver::storeParticleVelocityToGrid() } macgrid.u.normalizeCells(); macgrid.v.normalizeCells(); - //macgrid.v_grid.printGrid(); macgrid.w.normalizeCells(); } @@ -268,9 +285,9 @@ glm::vec3 FlipSolver::getVelocityGridIndex(const glm::vec3 &pos, int dim) glm::vec3 FlipSolver::getGridIndex(const glm::vec3 &pos) { // Transform to index space by subtracting minimum bounds and dividing by grid resolution. - int i = int(floor((pos[0] - particle_container->min_bound_x) / CELL_WIDTH)); - int j = int(floor((pos[1] - particle_container->min_bound_y) / CELL_WIDTH)); - int k = int(floor((pos[2] - particle_container->min_bound_z) / CELL_WIDTH)); + int i = int(floor((pos[0] - particle_container->min_x) / CELL_WIDTH)); + int j = int(floor((pos[1] - particle_container->min_y) / CELL_WIDTH)); + int k = int(floor((pos[2] - particle_container->min_z) / CELL_WIDTH)); // Clamp values. i = std::min(std::max(i, 0), int(particle_container->x_dim-1)); @@ -290,8 +307,8 @@ float lerp(float p1, float p2, float u) float FlipSolver::interpolateVelocityComponent(Particle *p, const Grid &grid, int dim) { // Get min and max indices. (Imagine a bounding box around particle). - glm::vec3 curr_idx = getVelocityGridIndex(p->position, dim); - glm::vec3 next_idx = getVelocityGridIndex(p->position + CELL_WIDTH, dim); + glm::vec3 curr_idx = getVelocityGridIndex(p->pos, dim); + glm::vec3 next_idx = getVelocityGridIndex(p->pos + CELL_WIDTH, dim); int i = curr_idx[0]; int j = curr_idx[1]; int k = curr_idx[2]; @@ -300,7 +317,7 @@ float FlipSolver::interpolateVelocityComponent(Particle *p, const Grid &g int kk = next_idx[2]; // Do x direction. - float x_uVal = (p->position[0] - ((i * CELL_WIDTH) + particle_container->min_bound_x)) / CELL_WIDTH; + float x_uVal = (p->pos[0] - ((i * CELL_WIDTH) + particle_container->min_x)) / CELL_WIDTH; float tmp1 = MATHIF(i!=ii, lerp(grid(i, j, k), grid(ii, j, k), x_uVal), grid(i, j, k)); float tmp2 = MATHIF(i!=ii, lerp(grid(i, jj, k), grid(ii, jj, k), x_uVal), grid(i, jj, k)); float tmp3 = MATHIF(i!=ii, lerp(grid(i, j, kk), grid(ii, j, kk), x_uVal), grid(i, j, kk)); @@ -309,12 +326,12 @@ float FlipSolver::interpolateVelocityComponent(Particle *p, const Grid &g //std::cout << tmp1 << " " << tmp2 << " " << tmp3 << " " << tmp4 << std::endl; // Do y direction. - float y_uVal = (p->position[1] - ((j * CELL_WIDTH) + particle_container->min_bound_y)) / CELL_WIDTH; + float y_uVal = (p->pos[1] - ((j * CELL_WIDTH) + particle_container->min_y)) / CELL_WIDTH; float tmp5 = MATHIF(j!=jj, lerp(tmp1, tmp2, y_uVal), tmp1); float tmp6 = MATHIF(j!=jj, lerp(tmp3, tmp4, y_uVal), tmp3); // Do z direction. - float z_uVal = (p->position[2] - ((k * CELL_WIDTH) + particle_container->min_bound_z)) / CELL_WIDTH; + float z_uVal = (p->pos[2] - ((k * CELL_WIDTH) + particle_container->min_z)) / CELL_WIDTH; float THING = MATHIF(k!=kk, lerp(tmp5, tmp6, z_uVal), tmp5); return THING; } @@ -330,7 +347,7 @@ void FlipSolver::storeDeltaVelocity(Grid &old_grid, const Grid &gr } -void FlipSolver::interpolateVelocity() +void FlipSolver::gridVelocityToParticle() { storeDeltaVelocity(macgrid.u_old, macgrid.u); storeDeltaVelocity(macgrid.v_old, macgrid.v); diff --git a/src/fluidSolver/fluidSolver.hpp b/src/fluidSolver/fluidSolver.hpp index 9689d0eb..f64b86d7 100644 --- a/src/fluidSolver/fluidSolver.hpp +++ b/src/fluidSolver/fluidSolver.hpp @@ -35,12 +35,12 @@ class FlipSolver : public FluidSolver { void clearGrids(); float interpolateVelocityComponent(Particle *p, const Grid &grid, int dim); - void interpolateVelocity(); + void gridVelocityToParticle(); void applyGravity(); void updateParticlePositions(); void handleCollisions(); void enforceBoundaryConditions(); - void extrapolateVelocities(); + void extrapolateVelocity(); void storeDeltaVelocity(Grid &old_grid, const Grid &grid); MacGrid macgrid; diff --git a/src/fluidSolver/grid.hpp b/src/fluidSolver/grid.hpp index a6a063b3..d8312ad9 100644 --- a/src/fluidSolver/grid.hpp +++ b/src/fluidSolver/grid.hpp @@ -7,6 +7,7 @@ #include "../geom/particles.hpp" #include +#include #define MATHIF(test, if_true, if_false) (((if_true) * (test)) + ((if_false) * (1 - (test)))) @@ -21,46 +22,62 @@ class Grid { int x_dim; int y_dim; int z_dim; + int maxIndex; Grid() {} Grid(int x, int y, int z) : x_dim(x), y_dim(y), z_dim(z) { cells = std::vector(x_dim*y_dim*z_dim, 0.f); particleCount = std::vector(x_dim*y_dim*z_dim, 0); + maxIndex = x_dim*y_dim*z_dim; } ~Grid() {} T& operator() (int i, int j, int k) { - return cells[i + y_dim * (j + z_dim * k)]; +// assert(i >= 0 && j >= 0 && k >= 0); +// assert(i < x_dim && j < y_dim && k < z_dim); +// assert(i + x_dim * (j + y_dim * k) < maxIndex); + return cells[i + x_dim * (j + y_dim * k)]; } const T& operator() (int i, int j, int k) const { - return cells[i + y_dim * (j + z_dim * k)]; +// assert(i >= 0 && j >= 0 && k >= 0); +// assert(i < x_dim && j < y_dim && k < z_dim); +// assert(i + x_dim * (j + y_dim * k) < maxIndex); + return cells[i + x_dim * (j + y_dim * k)]; } T& operator() (int i) { + assert(i >= 0 && i < maxIndex); return cells[i]; } const T& operator() (int i) const { + assert(i >= 0 && i < maxIndex); return cells[i]; } int getParticleCount(int i, int j, int k) { - return particleCount[i + y_dim * (j + z_dim * k)]; + assert(i >= 0 && j >= 0 && k >= 0); + assert(i < x_dim && j < y_dim && k < z_dim); + return particleCount.at(i + x_dim * (j + y_dim * k)); } void incrementParticleCount(int i, int j, int k) { - particleCount[i + y_dim * (j + z_dim * k)]++; + assert(i >= 0 && j >= 0 && k >= 0); + assert(i < x_dim && j < y_dim && k < z_dim); + particleCount.at(i + x_dim * (j + y_dim * k))++; } void clearVelocity() { + cells.clear(); + particleCount.clear(); cells = std::vector(x_dim*y_dim*z_dim, 0.f); particleCount = std::vector(x_dim*y_dim*z_dim, 0); } diff --git a/src/geom/particles.cpp b/src/geom/particles.cpp index 928e8074..3676c065 100644 --- a/src/geom/particles.cpp +++ b/src/geom/particles.cpp @@ -9,19 +9,21 @@ void ParticleContainer::initParticles(const glm::vec3 &bounds, const glm::vec3 &container_bounds) { particles.clear(); - min_bound_x = -container_bounds[0]; - min_bound_y = -container_bounds[1]; - min_bound_z = -container_bounds[2]; - max_bound_x = container_bounds[0]; - max_bound_y = container_bounds[1]; - max_bound_z = container_bounds[2]; - x_dim = max_bound_x - min_bound_x; - y_dim = max_bound_y - min_bound_y; - z_dim = max_bound_z - min_bound_z; + min_x = -container_bounds[0]; + min_y = -container_bounds[1]; + min_z = -container_bounds[2]; + max_x = container_bounds[0]; + max_y = container_bounds[1]; + max_z = container_bounds[2]; + x_dim = max_x - min_x; + y_dim = max_y - min_y; + z_dim = max_z - min_z; - for (float i=0.f; i < bounds[0] ; i += separation) { - for (float j=0.f; j < bounds[1]; j += separation) { - for (float k=0.f; k < bounds[2]; k += separation) { + // Divide by two to center around the origin. + glm::vec3 centered_bounds = bounds / 2.f; + for (float i=-centered_bounds[0]; i < centered_bounds[0]; i += separation) { + for (float j=-centered_bounds[1]; j < centered_bounds[1]; j += separation) { + for (float k=-centered_bounds[2]; k < centered_bounds[2]; k += separation) { glm::vec3 pos(i, j, k); glm::vec3 vel = glm::vec3(0.f, 0.f, 0.f); particles.push_back(new Particle(pos, vel)); @@ -38,9 +40,9 @@ void ParticleContainer::initParticles(const glm::vec3 &bounds, const glm::vec3 & void ParticleContainer::detectCollisions() { for (Particle *p : particles) { - p->dead = ((p->position[0] < min_bound_x || p->position[0] > max_bound_x) - || (p->position[1] < min_bound_y || p->position[1] > max_bound_y) - || (p->position[2] < min_bound_z || p->position[2] > max_bound_z)); + p->dead = ((p->pos[0] < min_x || p->pos[0] > max_x) + || (p->pos[1] < min_y || p->pos[1] > max_y) + || (p->pos[2] < min_z || p->pos[2] > max_z)); } } @@ -51,9 +53,9 @@ void ParticleContainer::create() { std::vector g_color_buffer_data; for (Particle *p : particles) { - g_vertex_buffer_data.push_back(p->position[0]); - g_vertex_buffer_data.push_back(p->position[1]); - g_vertex_buffer_data.push_back(p->position[2]); + g_vertex_buffer_data.push_back(p->pos[0]); + g_vertex_buffer_data.push_back(p->pos[1]); + g_vertex_buffer_data.push_back(p->pos[2]); g_color_buffer_data.push_back(0.0f); g_color_buffer_data.push_back(0.0f); diff --git a/src/geom/particles.hpp b/src/geom/particles.hpp index cd93a0b8..b78eece5 100644 --- a/src/geom/particles.hpp +++ b/src/geom/particles.hpp @@ -12,10 +12,10 @@ class Particle { public: - Particle(const glm::vec3 &pos, const glm::vec3 &vel) : position(pos), velocity(vel) {} + Particle(const glm::vec3 &pos, const glm::vec3 &vel) : pos(pos), velocity(vel) {} ~Particle(); - glm::vec3 position; + glm::vec3 pos; glm::vec3 velocity; int dead; }; @@ -37,12 +37,12 @@ class ParticleContainer : public Geometry std::vector particles; - float min_bound_x; - float min_bound_y; - float min_bound_z; - float max_bound_x; - float max_bound_y; - float max_bound_z; + float min_x; + float min_y; + float min_z; + float max_x; + float max_y; + float max_z; float x_dim; float y_dim; float z_dim; diff --git a/src/scene/scene.json b/src/scene/scene.json index 93a35b30..b9908eb5 100644 --- a/src/scene/scene.json +++ b/src/scene/scene.json @@ -1,13 +1,13 @@ { "containerDim" : { - "scaleX" : 2.0, - "scaleY" : 2.0, - "scaleZ" : 2.0 + "scaleX" : 3.0, + "scaleY" : 3.0, + "scaleZ" : 3.0 }, "particleDim" : { - "boundX" : 1.0, - "boundY" : 1.0, - "boundZ" : 1.0 + "boundX" : 2.0, + "boundY" : 2.0, + "boundZ" : 2.0 }, "particleSeparation" : 0.2 } \ No newline at end of file From 273b0d1178563c269e1e57ae16111ed488d8671f Mon Sep 17 00:00:00 2001 From: rahwang Date: Thu, 31 Mar 2016 00:00:35 -0400 Subject: [PATCH 07/23] Sprint 2 done -- adding TBB (cannot build yet) --- src/fluidSolver/fluidSolver.cpp | 63 +++++++++++++++++++++++++++++++++ src/fluidSolver/grid.hpp | 10 ++++++ 2 files changed, 73 insertions(+) diff --git a/src/fluidSolver/fluidSolver.cpp b/src/fluidSolver/fluidSolver.cpp index b2607ae8..88807ea7 100644 --- a/src/fluidSolver/fluidSolver.cpp +++ b/src/fluidSolver/fluidSolver.cpp @@ -4,6 +4,7 @@ #include "fluidSolver.hpp" #include +#include #define GRAVITY -9.8f #define TIME_STEP (1.0f/10.f) @@ -11,6 +12,8 @@ #define CELL_WIDTH (1.f/RES) #define DAMPING 1.0f +//#define TBB 1 + void FlipSolver::step() { // Reset grid values. @@ -83,6 +86,29 @@ void FlipSolver::extrapolateVelocity() { void FlipSolver::handleCollisions() { +#ifdef TBB + int size = particle_container->particles.size(); + tbb::parallel_for(0, size, 1, [=](int i) + { + Particle *p = particle_container->particles[i]; + // Check to see if p is inside bounding volume + if (p->pos[0] < particle_container->min_x || p->pos[0] > particle_container->max_x) + { + p->pos[0] = std::min(std::max(p->pos[0], particle_container->min_x), particle_container->max_x); + p->velocity[0] *= -DAMPING; + } + if (p->pos[1] < particle_container->min_y || p->pos[1] > particle_container->max_y) + { + p->pos[1] = std::min(std::max(p->pos[1], particle_container->min_y), particle_container->max_y); + p->velocity[1] *= -DAMPING; + } + if (p->pos[2] < particle_container->min_z || p->pos[2] > particle_container->max_z) + { + p->pos[2] = std::min(std::max(p->pos[2], particle_container->min_z), particle_container->max_z); + p->velocity[2] *= -DAMPING; + } + }); +#else for (Particle *p : particle_container->particles) { // Check to see if p is inside bounding volume @@ -102,6 +128,7 @@ void FlipSolver::handleCollisions() p->velocity[2] *= -DAMPING; } } +#endif } @@ -251,6 +278,19 @@ void FlipSolver::storeParticleVelocityToGridComponent(Particle *p, Grid & void FlipSolver::storeParticleVelocityToGrid() { +#ifdef TBB + int size = particle_container->particles.size(); + tbb::parallel_for(0, size, 1, [=](int i) + { + Particle *p = particle_container->particles[i]; + // Do u_grid update. + storeParticleVelocityToGridComponent(p, macgrid.u, 0); + // Do v_grid update. + storeParticleVelocityToGridComponent(p, macgrid.v, 1); + // Do w_grid update. + storeParticleVelocityToGridComponent(p, macgrid.w, 2); + } +#else for (Particle *p : particle_container->particles) { // Do u_grid update. @@ -260,6 +300,7 @@ void FlipSolver::storeParticleVelocityToGrid() // Do w_grid update. storeParticleVelocityToGridComponent(p, macgrid.w, 2); } +#endif macgrid.u.normalizeCells(); macgrid.v.normalizeCells(); macgrid.w.normalizeCells(); @@ -353,6 +394,27 @@ void FlipSolver::gridVelocityToParticle() storeDeltaVelocity(macgrid.v_old, macgrid.v); storeDeltaVelocity(macgrid.w_old, macgrid.w); +#ifdef TBB + int size = particle_container->particles.size(); + tbb::parallel_for(0, size, 1, [=](int i) + { + Particle *p = particle_container->particles[i]; + + // Get PIC components. + float pic_x = interpolateVelocityComponent(p, macgrid.u, 0); + float pic_y = interpolateVelocityComponent(p, macgrid.v, 1); + float pic_z = interpolateVelocityComponent(p, macgrid.w, 2); + + // Get FLIP components. "old" grids currently contain delta velocity. + float flip_x = p->velocity[0] + interpolateVelocityComponent(p, macgrid.u_old, 0); + float flip_y = p->velocity[1] + interpolateVelocityComponent(p, macgrid.v_old, 1); + float flip_z = p->velocity[2] + interpolateVelocityComponent(p, macgrid.w_old, 2); + + p->velocity[0] = 0.05f * pic_x + 0.95f * flip_x; + p->velocity[1] = 0.05f * pic_y + 0.95f * flip_y; + p->velocity[2] = 0.05f * pic_z + 0.95f * flip_z; + }); +#else for (Particle *p : particle_container->particles) { // Get PIC components. @@ -371,4 +433,5 @@ void FlipSolver::gridVelocityToParticle() //std::cout << p->velocity[1] << std::endl; } +#endif } diff --git a/src/fluidSolver/grid.hpp b/src/fluidSolver/grid.hpp index d8312ad9..7d189b93 100644 --- a/src/fluidSolver/grid.hpp +++ b/src/fluidSolver/grid.hpp @@ -11,6 +11,8 @@ #define MATHIF(test, if_true, if_false) (((if_true) * (test)) + ((if_false) * (1 - (test)))) +// #define TBB 1 + template class Grid { private: @@ -114,11 +116,19 @@ class Grid { void normalizeCells() { +#ifdef TBB + int size = cells.size(); + tbb::parallel_for(0, size, 1, [=](int i) + { + cells[i] /= MATHIF(particleCount[i] > 0, particleCount[i], 1.0f); + } +#else int numCells = cells.size(); for (int i=0; i < numCells; ++i) { cells[i] /= MATHIF(particleCount[i] > 0, particleCount[i], 1.0f); } +#endif } int getNumCells() From 31267925db4622aa313152f2ea954072aaab58f8 Mon Sep 17 00:00:00 2001 From: rahwang Date: Fri, 8 Apr 2016 01:25:42 -0400 Subject: [PATCH 08/23] Starting sprint 3, fixing enforceBoundary conditions --- src/fluidSolver/fluidSolver.cpp | 194 ++++++++++++++++++-------------- src/fluidSolver/fluidSolver.hpp | 8 ++ 2 files changed, 120 insertions(+), 82 deletions(-) diff --git a/src/fluidSolver/fluidSolver.cpp b/src/fluidSolver/fluidSolver.cpp index 88807ea7..d6144473 100644 --- a/src/fluidSolver/fluidSolver.cpp +++ b/src/fluidSolver/fluidSolver.cpp @@ -14,6 +14,7 @@ //#define TBB 1 + void FlipSolver::step() { // Reset grid values. @@ -33,50 +34,94 @@ void FlipSolver::step() } -void FlipSolver::extrapolateVelocity() { +void FlipSolver::computePressure() +{ + int n = macgrid.p_grid.getNumCells(); + int m = n*n; + + // To be passed to coefficient matrix. + std::vector coefficients; + + // b vector of divergences + Eigen::VectorXd b(n); + + //buildProblem(coefficients, b, n); + + // The coefficient matrix + SpMat A(m,m); + A.setFromTriplets(coefficients.begin(), coefficients.end()); + + // Solving for pressure + Eigen::SimplicialCholesky chol(A); // performs a Cholesky factorization of A + Eigen::VectorXd x = chol.solve(b); // use factorization to solve for the given right hand side for (int i=0; i < macgrid.p_grid.x_dim; ++i) { for (int j=0; j < macgrid.p_grid.y_dim; ++j) { for (int k=0; k < macgrid.p_grid.z_dim; ++k) { - if (macgrid.cellTypes(i, j, k) == macgrid.cellTypes.AIR) + + } + } + } +} + + +void FlipSolver::setSolidCells() +{ + for (int i=0; i < macgrid.p_grid.x_dim; ++i) + { + for (int j=0; j < macgrid.p_grid.y_dim; ++j) + { + for (int k=0; k < macgrid.p_grid.z_dim; ++k) + { + if (i == 0 || j == 0 || k == 0 || + i == macgrid.p_grid.x_dim-1 || j == macgrid.p_grid.y_dim -1 || k == macgrid.p_grid.z_dim-1) { - // X velocity grid check. - if ((i-1 > 0 && macgrid.cellTypes(i-1, j, k) == macgrid.cellTypes.FLUID) - && (i+1 > macgrid.p_grid.x_dim || macgrid.cellTypes(i+1, j, k) != macgrid.cellTypes.FLUID)) - { - macgrid.u(i, j, k) = macgrid.u(i-1, j, k); - } - else if ((i+1 <= macgrid.p_grid.x_dim && macgrid.cellTypes(i+1, j, k) == macgrid.cellTypes.FLUID) - && (i-1 < 0 || macgrid.cellTypes(i-1, j, k) != macgrid.cellTypes.FLUID)) - { - macgrid.u(i, j, k) = macgrid.u(i+1, j, k); - } - - // Y velocity grid check. - if ((j-1 > 0 && macgrid.cellTypes(i, j-1, k) == macgrid.cellTypes.FLUID) - && (j+1 > macgrid.p_grid.y_dim || macgrid.cellTypes(i, j+1, k) != macgrid.cellTypes.FLUID)) - { - macgrid.v(i, j, k) = macgrid.v(i, j-1, k); - } - else if ((j+1 <= macgrid.p_grid.y_dim && macgrid.cellTypes(i, j+1, k) == macgrid.cellTypes.FLUID) - && (j-1 < 0 || macgrid.cellTypes(i, j-1, k) != macgrid.cellTypes.FLUID)) - { - macgrid.v(i, j, k) = macgrid.v(i, j+1, k); - } - - // X velocity grid check. - if ((k-1 > 0 && macgrid.cellTypes(i, j, k-1) == macgrid.cellTypes.FLUID) - && (k+1 > macgrid.p_grid.z_dim || macgrid.cellTypes(i, j, k+1) != macgrid.cellTypes.FLUID)) - { - macgrid.u(i, j, k) = macgrid.u(i, j, k-1); - } - else if ((k+1 <= macgrid.p_grid.z_dim && macgrid.cellTypes(i, j, k+1) == macgrid.cellTypes.FLUID) - && (k-1 < 0 || macgrid.cellTypes(i, j, k-1) != macgrid.cellTypes.FLUID)) - { - macgrid.u(i, j, k) = macgrid.u(i, j, k+1); - } + macgrid.cellTypes(i, j, k) == macgrid.cellTypes.SOLID; + } + } + } + } +} + + +void FlipSolver::extrapolateVelocity() +{ + // Create temporary grids marking "near fluid" cells as fluid cells. + // These temporary grids will hold {FLUID | AIR} all AIR cells adjacent + // to FLUID cells in the temporary grids need extrapolation. + Grid tmp_u(macgrid.u.x_dim, macgrid.u.y_dim, macgrid.u.z_dim); + Grid tmp_v(macgrid.v.x_dim, macgrid.v.y_dim, macgrid.v.z_dim); + Grid tmp_w(macgrid.w.x_dim, macgrid.w.y_dim, macgrid.w.z_dim); + + tmp_u.clear(); + tmp_v.clear(); + tmp_w.clear(); + + for (int i=1; i < macgrid.p_grid.x_dim; ++i) + { + for (int j=1; j < macgrid.p_grid.y_dim; ++j) + { + for (int k=1; k < macgrid.p_grid.z_dim; ++k) + { + if (macgrid.cellTypes(i, j, k) == macgrid.cellTypes.FLUID) + { + tmp_u(i, j, k) = macgrid.cellTypes.FLUID; + tmp_v(i, j, k) = macgrid.cellTypes.FLUID; + tmp_w(i, j, k) = macgrid.cellTypes.FLUID; + } + else if (macgrid.cellTypes(i-1, j, k) == macgrid.cellTypes.FLUID) + { + tmp_u(i, j, k) = macgrid.cellTypes.FLUID; + } + else if (macgrid.cellTypes(i, j-1, k) == macgrid.cellTypes.FLUID) + { + tmp_u(i, j, k) = macgrid.cellTypes.FLUID; + } + else if (macgrid.cellTypes(i, j, k-1) == macgrid.cellTypes.FLUID) + { + tmp_u(i, j, k) = macgrid.cellTypes.FLUID; } } } @@ -134,60 +179,45 @@ void FlipSolver::handleCollisions() void FlipSolver::enforceBoundaryConditions() { - // Iterate through all the grids. + // Enforce for u velocity. + for (int j=0; j < macgrid.p_grid.y_dim; ++j) + { + for (int k=0; k < macgrid.p_grid.z_dim; ++k) + { + macgrid.u(0, j, k) = 0.f; + macgrid.u(1, j, k) = 0.f; + macgrid.u(macgrid.u.x_dim-2, j, k) = 0.f; + macgrid.u(macgrid.u.x_dim-1, j, k) = 0.f; + } + } + + // Enforce for v velocity. + for (int i=0; i < macgrid.p_grid.x_dim; ++i) + { + for (int k=0; k < macgrid.p_grid.z_dim; ++k) + { + macgrid.v(i, 0, k) = 0.f; + macgrid.v(i, 1, k) = 0.f; + macgrid.v(i, macgrid.v.y_dim-2, k) = 0.f; + macgrid.v(i, macgrid.v.y_dim-1, k) = 0.f; + } + } + + // Enforce for w velocity. for (int i=0; i < macgrid.p_grid.x_dim; ++i) { for (int j=0; j < macgrid.p_grid.y_dim; ++j) { - for (int k=0; k < macgrid.p_grid.z_dim; ++k) - { - // Check to see if the cell is solid. - if (macgrid.cellTypes(i, j, k) = macgrid.p_grid.SOLID) - { - // For the min faces, zero velocity into cell. - macgrid.u(i, j, k) = std::min(0.f, macgrid.u(i, j, k)); - macgrid.v(i, j, k) = std::min(0.f, macgrid.v(i, j, k)); - macgrid.w(i, j, k) = std::min(0.f, macgrid.w(i, j, k)); - - for (int ii=i; ii < i+1; ++ii) - { - for (int jj=j; jj < j+1; ++jj) - { - for (int kk=k; kk < k+1; ++kk) - { - // For the max faces, zero velocity into cell. - if (ii < macgrid.u.x_dim && jj < macgrid.u.y_dim && kk < macgrid.u.z_dim) - macgrid.u(ii, jj, kk) = std::max(0.f, macgrid.u(ii, jj, kk)); - if (ii < macgrid.v.x_dim && jj < macgrid.v.y_dim && kk < macgrid.v.z_dim) - macgrid.v(ii, jj, kk) = std::max(0.f, macgrid.v(ii, jj, kk)); - if (ii < macgrid.w.x_dim && jj < macgrid.w.y_dim && kk < macgrid.w.z_dim) - macgrid.w(ii, jj, kk) = std::max(0.f, macgrid.w(ii, jj, kk)); - } - } - } - } - - // For the min borders, zero velocity out of fluid bounds. - if (i == 0) - macgrid.u(i, j, k) = std::max(0.f, macgrid.u(i, j, k)); - if (j == 0) - macgrid.v(i, j, k) = std::max(0.f, macgrid.v(i, j, k)); - if (j == 0) - macgrid.w(i, j, k) = std::max(0.f, macgrid.w(i, j, k)); - - // For the max borders, zero velocity out of fluid bounds. - if (i == macgrid.p_grid.x_dim-1) - macgrid.u(i+1, j, k) = std::min(0.f, macgrid.u(i+1, j, k)); - if (j == macgrid.p_grid.y_dim-1) - macgrid.v(i, j+1, k) = std::min(0.f, macgrid.v(i, j+1, k)); - if (k == macgrid.p_grid.z_dim-1) - macgrid.w(i, j, k+1) = std::min(0.f, macgrid.w(i, j, k+1)); - } + macgrid.w(i, j, 0) = 0.f; + macgrid.w(i, j, 1) = 0.f; + macgrid.w(i, j, macgrid.w.z_dim-2) = 0.f; + macgrid.w(i, j, macgrid.w.z_dim-1) = 0.f; } } } + // Using forward Euler for now. void FlipSolver::updateParticlePositions() { diff --git a/src/fluidSolver/fluidSolver.hpp b/src/fluidSolver/fluidSolver.hpp index f64b86d7..1af8c1ab 100644 --- a/src/fluidSolver/fluidSolver.hpp +++ b/src/fluidSolver/fluidSolver.hpp @@ -7,6 +7,11 @@ #include "../geom/particles.hpp" #include "grid.hpp" +#include +#include + +typedef Eigen::SparseMatrix SpMat; // declares a column-major sparse matrix type of double +typedef Eigen::Triplet T; class FluidSolver{ public: @@ -42,6 +47,9 @@ class FlipSolver : public FluidSolver { void enforceBoundaryConditions(); void extrapolateVelocity(); void storeDeltaVelocity(Grid &old_grid, const Grid &grid); + void setSolidCells(); + void computePressure(); + MacGrid macgrid; }; From dbe07471dc91d33d58329db8da7b05237688166c Mon Sep 17 00:00:00 2001 From: rahwang Date: Fri, 8 Apr 2016 01:53:59 -0400 Subject: [PATCH 09/23] bug fix --- CMakeLists.txt | 24 +++++++++++++++++++++--- src/fluidSolver/fluidSolver.cpp | 2 +- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d045ead..95ae29cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,14 @@ find_package(OPENGL REQUIRED) find_package(GLEW) find_library(GLFW_LIBRARY "glfw3" HINTS ${GLFW_LIBRARY_DIR}) find_library(JSONCPP "jsoncpp") +find_library(TBB "tbb") + + +# For open VDB +find_library(OPENVDB "openvdb") +find_library(LIBZ "z") +find_library(HALF "half") + add_definitions( -DTW_STATIC @@ -46,7 +54,9 @@ add_definitions( -D_CRT_SECURE_NO_WARNINGS ) -set(CORE_LIBS ${GLFW_LIBRARY} ${GLUT_LIBRARY} ${GLEW_LIBRARY} ${JSONCPP} ${OPENGL_LIBRARY} ) + +set(CORE_LIBS ${GLFW_LIBRARY} ${GLUT_LIBRARY} ${GLEW_LIBRARY} ${JSONCPP} ${OPENGL_LIBRARY} ${TBB} ${OPENVDB} ${LIBZ} ${HALF}) + # OSX-specific hacks/fixes if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") @@ -57,11 +67,13 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(CORE_LIBS ${CORE_LIBS} ${COCOA} ${IOKIT} ${COREVIDEO}) endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + # Linux specific hacks/fixes if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lX11 -lXxf86vm -lXrandr -lpthread -lXi") endif() + # set compiler flags for c++11 if(${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O0 -m64 -msse2 -w") @@ -69,17 +81,19 @@ elseif(WIN32) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") endif() + if(MSVC) - set(COMPILER_FLAGS + set(COMPILER_FLAGS CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE - CMAKE_C_FLAGS + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE ) endif() + # Add source files you want to compile (.cpp) set(CORE_SRC src/main.cpp @@ -94,6 +108,10 @@ set(CORE_SRC src/geom/particles.cpp ) + add_executable(Thanda ${CORE_SRC} src/viewer/SimpleVertexShader.vertexshader src/viewer/SimpleFragmentShader.fragmentshader) + target_link_libraries(Thanda ${CORE_LIBS}) + + diff --git a/src/fluidSolver/fluidSolver.cpp b/src/fluidSolver/fluidSolver.cpp index d6144473..0fe333e4 100644 --- a/src/fluidSolver/fluidSolver.cpp +++ b/src/fluidSolver/fluidSolver.cpp @@ -319,7 +319,7 @@ void FlipSolver::storeParticleVelocityToGrid() storeParticleVelocityToGridComponent(p, macgrid.v, 1); // Do w_grid update. storeParticleVelocityToGridComponent(p, macgrid.w, 2); - } + }); #else for (Particle *p : particle_container->particles) { From da452ea73c4282f6cfd38dd5cbfda30701856d02 Mon Sep 17 00:00:00 2001 From: rahwang Date: Fri, 8 Apr 2016 19:25:07 -0400 Subject: [PATCH 10/23] Adding some pressure computation code --- src/fluidSolver/fluidSolver.cpp | 258 +++++++++++++++++++++++++++----- src/fluidSolver/fluidSolver.hpp | 3 +- src/fluidSolver/grid.hpp | 13 +- 3 files changed, 228 insertions(+), 46 deletions(-) diff --git a/src/fluidSolver/fluidSolver.cpp b/src/fluidSolver/fluidSolver.cpp index 0fe333e4..777a1ff0 100644 --- a/src/fluidSolver/fluidSolver.cpp +++ b/src/fluidSolver/fluidSolver.cpp @@ -25,6 +25,7 @@ void FlipSolver::step() enforceBoundaryConditions(); applyGravity(); // TODO: Pressure step. + enforceBoundaryConditions(); // Handle air/fluid boundaries. extrapolateVelocity(); // Update particle velocities. @@ -34,18 +35,105 @@ void FlipSolver::step() } +void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficients) +{ + // Index between 1 and dim-1 because we know the wells of our tank are solid. + for (int i=1; i < macgrid.marker.x_dim-1; ++i) + { + for (int j=1; j < macgrid.marker.y_dim-1; ++j) + { + for (int k=1; k < macgrid.marker.z_dim-1; ++k) + { + if (macgrid.marker(i, j, k) == macgrid.marker.FLUID) + { + // This is a count of the EMPTY | FLUID neighboring cells. + if (macgrid.marker(i, j, k) == macgrid.marker.FLUID) { + int count = 0; + // RIGHT + if (macgrid.marker(i+1, j, k) != macgrid.marker.SOLID) + { + coefficients.push_back(T(macgrid.marker.flatIdx(i, j, k), + macgrid.marker.flatIdx(i+1, j, k), + -1)); + count++; + } + // LEFT + if (macgrid.marker(i-1, j, k) != macgrid.marker.SOLID) + { + coefficients.push_back(T(macgrid.marker.flatIdx(i, j, k), + macgrid.marker.flatIdx(i-1, j, k), + -1)); + count++; + } + // UP + if (macgrid.marker(i, j+1, k) != macgrid.marker.SOLID) + { + coefficients.push_back(T(macgrid.marker.flatIdx(i, j, k), + macgrid.marker.flatIdx(i, j+1, k), + -1)); + count++; + } + // DOWN + if (macgrid.marker(i, j-1, k) != macgrid.marker.SOLID) + { + coefficients.push_back(T(macgrid.marker.flatIdx(i, j, k), + macgrid.marker.flatIdx(i, j-1, k), + -1)); + count++; + } + // FRONT + if (macgrid.marker(i, j, k+1) != macgrid.marker.SOLID) + { + coefficients.push_back(T(macgrid.marker.flatIdx(i, j, k), + macgrid.marker.flatIdx(i, j, k+1), + -1)); + count++; + } + // BEHIND + if (macgrid.marker(i, j, k-1) != macgrid.marker.SOLID) + { + coefficients.push_back(T(macgrid.marker.flatIdx(i, j, k), + macgrid.marker.flatIdx(i, j, k-1), + -1)); + count++; + } + coefficients.push_back(T(macgrid.marker.flatIdx(i, j, k), + macgrid.marker.flatIdx(i, j, k), + count)); + } + } + } + } + } +} + + + void FlipSolver::computePressure() { - int n = macgrid.p_grid.getNumCells(); + int n = macgrid.p.getNumCells(); int m = n*n; - // To be passed to coefficient matrix. - std::vector coefficients; - - // b vector of divergences + // Build b vector of divergences Eigen::VectorXd b(n); + int idx = 0; + for (int i=0; i < macgrid.p.x_dim; ++i) + { + for (int j=0; j < macgrid.p.y_dim; ++j) + { + for (int k=0; k < macgrid.p.z_dim; ++k) + { + float u_div = macgrid.u(i+1, j, k) - macgrid.u(i, j, k); + float v_div = macgrid.v(i, j+1, k) - macgrid.v(i, j, k); + float w_div = macgrid.w(i, j, k+1) - macgrid.w(i, j, k); + b[idx++] = u_div+v_div+w_div; + } + } + } - //buildProblem(coefficients, b, n); + // Assemble coeff vector to be passed to coefficient matrix. + std::vector coefficients; + assemblePressureSolveCoefficients(coefficients); // The coefficient matrix SpMat A(m,m); @@ -54,31 +142,80 @@ void FlipSolver::computePressure() // Solving for pressure Eigen::SimplicialCholesky chol(A); // performs a Cholesky factorization of A Eigen::VectorXd x = chol.solve(b); // use factorization to solve for the given right hand side - for (int i=0; i < macgrid.p_grid.x_dim; ++i) + +} + + +void FlipSolver::setSolidCells() +{ + for (int i=0; i < macgrid.p.x_dim; ++i) { - for (int j=0; j < macgrid.p_grid.y_dim; ++j) + for (int j=0; j < macgrid.p.y_dim; ++j) { - for (int k=0; k < macgrid.p_grid.z_dim; ++k) + for (int k=0; k < macgrid.p.z_dim; ++k) { - + if (i == 0 || j == 0 || k == 0 || + i == macgrid.p.x_dim-1 || j == macgrid.p.y_dim -1 || k == macgrid.p.z_dim-1) + { + macgrid.marker(i, j, k) == macgrid.marker.SOLID; + } } } } } -void FlipSolver::setSolidCells() +void FlipSolver::extrapolateVelocityComponent(const Grid& tmp, Grid& grid) { - for (int i=0; i < macgrid.p_grid.x_dim; ++i) + for (int i=0; i < grid.x_dim; ++i) { - for (int j=0; j < macgrid.p_grid.y_dim; ++j) + for (int j=0; j < grid.y_dim; ++j) { - for (int k=0; k < macgrid.p_grid.z_dim; ++k) + for (int k=0; k < grid.z_dim; ++k) { - if (i == 0 || j == 0 || k == 0 || - i == macgrid.p_grid.x_dim-1 || j == macgrid.p_grid.y_dim -1 || k == macgrid.p_grid.z_dim-1) + float accum = 0.f; + int count = 0; + if (tmp(i, j, k) != macgrid.marker.FLUID) { - macgrid.cellTypes(i, j, k) == macgrid.cellTypes.SOLID; + // RIGHT + if (i+1 < grid.x_dim && tmp(i+1, j, k) == macgrid.marker.FLUID) + { + accum += grid(i+1, j, k); + count++; + } + // LEFT + if (i-1 >= 0 && tmp(i-1, j, k) == macgrid.marker.FLUID) + { + accum += grid(i-1, j, k); + count++; + } + // UP + if (j+1 < grid.y_dim && tmp(i, j+1, k) == macgrid.marker.FLUID) + { + accum += grid(i, j+1, k); + count++; + } + // DOWN + if (j-1 >= 0 && tmp(i, j-1, k) == macgrid.marker.FLUID) + { + accum += grid(i, j-1, k); + count++; + } + // FRONT + if (k+1 < grid.z_dim && tmp(i, j, k+1) == macgrid.marker.FLUID) + { + accum += grid(i, j, k+1); + count++; + } + // BEHIND + if (k-1 >= 0 && tmp(i, j, k-1) == macgrid.marker.FLUID) + { + accum += grid(i, j, k-1); + count++; + } + // Store extrapolated velocity. + if (count > 0) + grid(i, j, k) = accum / count; } } } @@ -91,41 +228,75 @@ void FlipSolver::extrapolateVelocity() // Create temporary grids marking "near fluid" cells as fluid cells. // These temporary grids will hold {FLUID | AIR} all AIR cells adjacent // to FLUID cells in the temporary grids need extrapolation. - Grid tmp_u(macgrid.u.x_dim, macgrid.u.y_dim, macgrid.u.z_dim); - Grid tmp_v(macgrid.v.x_dim, macgrid.v.y_dim, macgrid.v.z_dim); - Grid tmp_w(macgrid.w.x_dim, macgrid.w.y_dim, macgrid.w.z_dim); + Grid tmp_u(macgrid.u.x_dim, macgrid.u.y_dim, macgrid.u.z_dim); + Grid tmp_v(macgrid.v.x_dim, macgrid.v.y_dim, macgrid.v.z_dim); + Grid tmp_w(macgrid.w.x_dim, macgrid.w.y_dim, macgrid.w.z_dim); tmp_u.clear(); tmp_v.clear(); tmp_w.clear(); - for (int i=1; i < macgrid.p_grid.x_dim; ++i) + // Populate u temp grid. + for (int i=1; i < macgrid.u.x_dim; ++i) + { + for (int j=1; j < macgrid.u.y_dim; ++j) + { + for (int k=1; k < macgrid.u.z_dim; ++k) + { + if (macgrid.marker(i, j, k) == macgrid.marker.FLUID) + { + tmp_u(i, j, k) = macgrid.marker.FLUID; + } + else if (macgrid.marker(i-1, j, k) == macgrid.marker.FLUID) + { + tmp_u(i, j, k) = macgrid.marker.FLUID; + } + } + } + } + + // Populate v temp grid. + for (int i=1; i < macgrid.v.x_dim; ++i) { - for (int j=1; j < macgrid.p_grid.y_dim; ++j) + for (int j=1; j < macgrid.v.y_dim; ++j) { - for (int k=1; k < macgrid.p_grid.z_dim; ++k) + for (int k=1; k < macgrid.v.z_dim; ++k) { - if (macgrid.cellTypes(i, j, k) == macgrid.cellTypes.FLUID) + if (macgrid.marker(i, j, k) == macgrid.marker.FLUID) { - tmp_u(i, j, k) = macgrid.cellTypes.FLUID; - tmp_v(i, j, k) = macgrid.cellTypes.FLUID; - tmp_w(i, j, k) = macgrid.cellTypes.FLUID; + tmp_v(i, j, k) = macgrid.marker.FLUID; } - else if (macgrid.cellTypes(i-1, j, k) == macgrid.cellTypes.FLUID) + else if (macgrid.marker(i, j-1, k) == macgrid.marker.FLUID) { - tmp_u(i, j, k) = macgrid.cellTypes.FLUID; + tmp_v(i, j, k) = macgrid.marker.FLUID; } - else if (macgrid.cellTypes(i, j-1, k) == macgrid.cellTypes.FLUID) + } + } + } + + // Populate w temp grid. + for (int i=1; i < macgrid.w.x_dim; ++i) + { + for (int j=1; j < macgrid.w.y_dim; ++j) + { + for (int k=1; k < macgrid.w.z_dim; ++k) + { + if (macgrid.marker(i, j, k) == macgrid.marker.FLUID) { - tmp_u(i, j, k) = macgrid.cellTypes.FLUID; + tmp_w(i, j, k) = macgrid.marker.FLUID; } - else if (macgrid.cellTypes(i, j, k-1) == macgrid.cellTypes.FLUID) + else if (macgrid.marker(i, j, k-1) == macgrid.marker.FLUID) { - tmp_u(i, j, k) = macgrid.cellTypes.FLUID; + tmp_w(i, j, k) = macgrid.marker.FLUID; } } } } + + // Now for all non-fluid cells that border fluid in the tmp grids, extrapolate. + extrapolateVelocityComponent(tmp_u, macgrid.u); + extrapolateVelocityComponent(tmp_v, macgrid.v); + extrapolateVelocityComponent(tmp_w, macgrid.w); } @@ -180,9 +351,9 @@ void FlipSolver::handleCollisions() void FlipSolver::enforceBoundaryConditions() { // Enforce for u velocity. - for (int j=0; j < macgrid.p_grid.y_dim; ++j) + for (int j=0; j < macgrid.p.y_dim; ++j) { - for (int k=0; k < macgrid.p_grid.z_dim; ++k) + for (int k=0; k < macgrid.p.z_dim; ++k) { macgrid.u(0, j, k) = 0.f; macgrid.u(1, j, k) = 0.f; @@ -192,9 +363,9 @@ void FlipSolver::enforceBoundaryConditions() } // Enforce for v velocity. - for (int i=0; i < macgrid.p_grid.x_dim; ++i) + for (int i=0; i < macgrid.p.x_dim; ++i) { - for (int k=0; k < macgrid.p_grid.z_dim; ++k) + for (int k=0; k < macgrid.p.z_dim; ++k) { macgrid.v(i, 0, k) = 0.f; macgrid.v(i, 1, k) = 0.f; @@ -204,9 +375,9 @@ void FlipSolver::enforceBoundaryConditions() } // Enforce for w velocity. - for (int i=0; i < macgrid.p_grid.x_dim; ++i) + for (int i=0; i < macgrid.p.x_dim; ++i) { - for (int j=0; j < macgrid.p_grid.y_dim; ++j) + for (int j=0; j < macgrid.p.y_dim; ++j) { macgrid.w(i, j, 0) = 0.f; macgrid.w(i, j, 1) = 0.f; @@ -256,7 +427,7 @@ void FlipSolver::clearGrids() macgrid.u.clearVelocity(); macgrid.v.clearVelocity(); macgrid.w.clearVelocity(); - macgrid.cellTypes.clear(); + macgrid.marker.clear(); } @@ -273,6 +444,11 @@ void FlipSolver::storeParticleVelocityToGridComponent(Particle *p, Grid & int j = curr_idx[1]; int k = curr_idx[2]; + if (macgrid.marker(i, j, k) == macgrid.marker.SOLID) + { + return; + } + for (int n=-1; n < 2; ++n) { for (int m=-1; m < 2; ++m) @@ -302,7 +478,7 @@ void FlipSolver::storeParticleVelocityToGridComponent(Particle *p, Grid & // Mark cell type glm::vec3 type_idx = getGridIndex(p->pos); - macgrid.cellTypes(type_idx[0], type_idx[1], type_idx[2]) = macgrid.cellTypes.FLUID; + macgrid.marker(type_idx[0], type_idx[1], type_idx[2]) = macgrid.marker.FLUID; } diff --git a/src/fluidSolver/fluidSolver.hpp b/src/fluidSolver/fluidSolver.hpp index 1af8c1ab..5a7760f0 100644 --- a/src/fluidSolver/fluidSolver.hpp +++ b/src/fluidSolver/fluidSolver.hpp @@ -45,11 +45,12 @@ class FlipSolver : public FluidSolver { void updateParticlePositions(); void handleCollisions(); void enforceBoundaryConditions(); + void extrapolateVelocityComponent(const Grid& tmp, Grid& grid); void extrapolateVelocity(); void storeDeltaVelocity(Grid &old_grid, const Grid &grid); void setSolidCells(); void computePressure(); - + void assemblePressureSolveCoefficients(std::vector &coefficients); MacGrid macgrid; }; diff --git a/src/fluidSolver/grid.hpp b/src/fluidSolver/grid.hpp index 7d189b93..4f7a9a17 100644 --- a/src/fluidSolver/grid.hpp +++ b/src/fluidSolver/grid.hpp @@ -76,6 +76,11 @@ class Grid { particleCount.at(i + x_dim * (j + y_dim * k))++; } + int flatIdx(int i, int j, int k) + { + return i + x_dim * (j + y_dim * k); + } + void clearVelocity() { cells.clear(); @@ -152,8 +157,8 @@ class MacGrid{ v_old = Grid(x, y+1, z); w_old = Grid(x, y, z+1); - p_grid = Grid(x, y, z); - cellTypes = Grid(x, y, z); + p = Grid(x, y, z); + marker = Grid(x, y, z); } Grid u; @@ -164,8 +169,8 @@ class MacGrid{ Grid v_old; Grid w_old; - Grid p_grid; - Grid cellTypes; + Grid p; + Grid marker; }; #endif /* grid_hpp */ From 7a16d8dc1cf9d593e188c08b9b65b29ba791fd9e Mon Sep 17 00:00:00 2001 From: rahwang Date: Sat, 9 Apr 2016 13:36:28 -0400 Subject: [PATCH 11/23] adding cmpute pressure step --- src/fluidSolver/fluidSolver.cpp | 43 ++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/src/fluidSolver/fluidSolver.cpp b/src/fluidSolver/fluidSolver.cpp index 777a1ff0..7210cb0c 100644 --- a/src/fluidSolver/fluidSolver.cpp +++ b/src/fluidSolver/fluidSolver.cpp @@ -11,6 +11,7 @@ #define RES 4 #define CELL_WIDTH (1.f/RES) #define DAMPING 1.0f +#define DENSITY 1.f //#define TBB 1 @@ -24,6 +25,7 @@ void FlipSolver::step() // Zero velocities pointing into solid cells. enforceBoundaryConditions(); applyGravity(); + //computePressure(); // TODO: Pressure step. enforceBoundaryConditions(); // Handle air/fluid boundaries. @@ -37,6 +39,7 @@ void FlipSolver::step() void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficients) { + float scale = TIME_STEP / (DENSITY * CELL_WIDTH * CELL_WIDTH); // Index between 1 and dim-1 because we know the wells of our tank are solid. for (int i=1; i < macgrid.marker.x_dim-1; ++i) { @@ -54,7 +57,7 @@ void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficients) { coefficients.push_back(T(macgrid.marker.flatIdx(i, j, k), macgrid.marker.flatIdx(i+1, j, k), - -1)); + -scale)); count++; } // LEFT @@ -62,7 +65,7 @@ void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficients) { coefficients.push_back(T(macgrid.marker.flatIdx(i, j, k), macgrid.marker.flatIdx(i-1, j, k), - -1)); + -scale)); count++; } // UP @@ -70,7 +73,7 @@ void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficients) { coefficients.push_back(T(macgrid.marker.flatIdx(i, j, k), macgrid.marker.flatIdx(i, j+1, k), - -1)); + -scale)); count++; } // DOWN @@ -78,7 +81,7 @@ void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficients) { coefficients.push_back(T(macgrid.marker.flatIdx(i, j, k), macgrid.marker.flatIdx(i, j-1, k), - -1)); + -scale)); count++; } // FRONT @@ -86,7 +89,7 @@ void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficients) { coefficients.push_back(T(macgrid.marker.flatIdx(i, j, k), macgrid.marker.flatIdx(i, j, k+1), - -1)); + -scale)); count++; } // BEHIND @@ -94,12 +97,12 @@ void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficients) { coefficients.push_back(T(macgrid.marker.flatIdx(i, j, k), macgrid.marker.flatIdx(i, j, k-1), - -1)); + -scale)); count++; } coefficients.push_back(T(macgrid.marker.flatIdx(i, j, k), macgrid.marker.flatIdx(i, j, k), - count)); + count * scale)); } } } @@ -115,8 +118,7 @@ void FlipSolver::computePressure() int m = n*n; // Build b vector of divergences - Eigen::VectorXd b(n); - int idx = 0; + Eigen::VectorXd b(m); for (int i=0; i < macgrid.p.x_dim; ++i) { for (int j=0; j < macgrid.p.y_dim; ++j) @@ -126,7 +128,7 @@ void FlipSolver::computePressure() float u_div = macgrid.u(i+1, j, k) - macgrid.u(i, j, k); float v_div = macgrid.v(i, j+1, k) - macgrid.v(i, j, k); float w_div = macgrid.w(i, j, k+1) - macgrid.w(i, j, k); - b[idx++] = u_div+v_div+w_div; + b[macgrid.p.flatIdx(i, j, k)] = -(u_div+v_div+w_div) / CELL_WIDTH; } } } @@ -140,9 +142,26 @@ void FlipSolver::computePressure() A.setFromTriplets(coefficients.begin(), coefficients.end()); // Solving for pressure - Eigen::SimplicialCholesky chol(A); // performs a Cholesky factorization of A - Eigen::VectorXd x = chol.solve(b); // use factorization to solve for the given right hand side + Eigen::ConjugateGradient chol(A); + Eigen::VectorXd pressures = chol.solve(b); // use factorization to solve for the given right hand side + // Update velocities + float scale = (DENSITY * CELL_WIDTH) / TIME_STEP; + for (int i=1; i < macgrid.p.x_dim-1; ++i) + { + for (int j=1; j < macgrid.p.y_dim-1; ++j) + { + for (int k=1; k < macgrid.p.z_dim-1; ++k) + { + macgrid.u(i, j, k) -= scale * (pressures[macgrid.p.flatIdx(i+1, j, k)] + - pressures[macgrid.p.flatIdx(i, j, k)]); + macgrid.v(i, j, k) -= scale * (pressures[macgrid.p.flatIdx(i, j+1, k)] + - pressures[macgrid.p.flatIdx(i, j, k)]); + macgrid.w(i, j, k) -= scale * (pressures[macgrid.p.flatIdx(i, j, k+1)] + - pressures[macgrid.p.flatIdx(i, j, k)]); + } + } + } } From 232393fd2816dd82f5aa494abf73c7b55b1f458e Mon Sep 17 00:00:00 2001 From: rahwang Date: Sat, 9 Apr 2016 19:16:01 -0400 Subject: [PATCH 12/23] numerous bug fixes --- src/fluidSolver/fluidSolver.cpp | 80 +++++++++++++++++++-------------- src/fluidSolver/grid.hpp | 16 +++---- src/geom/particles.cpp | 4 +- src/scene/scene.cpp | 5 ++- src/scene/scene.json | 14 +++--- 5 files changed, 68 insertions(+), 51 deletions(-) diff --git a/src/fluidSolver/fluidSolver.cpp b/src/fluidSolver/fluidSolver.cpp index 7210cb0c..6f536974 100644 --- a/src/fluidSolver/fluidSolver.cpp +++ b/src/fluidSolver/fluidSolver.cpp @@ -8,7 +8,7 @@ #define GRAVITY -9.8f #define TIME_STEP (1.0f/10.f) -#define RES 4 +#define RES 2 #define CELL_WIDTH (1.f/RES) #define DAMPING 1.0f #define DENSITY 1.f @@ -20,12 +20,13 @@ void FlipSolver::step() { // Reset grid values. clearGrids(); + setSolidCells(); // Transfer particle velocities to grid (Also marks cell types). storeParticleVelocityToGrid(); // Zero velocities pointing into solid cells. - enforceBoundaryConditions(); applyGravity(); - //computePressure(); + enforceBoundaryConditions(); + computePressure(); // TODO: Pressure step. enforceBoundaryConditions(); // Handle air/fluid boundaries. @@ -40,7 +41,7 @@ void FlipSolver::step() void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficients) { float scale = TIME_STEP / (DENSITY * CELL_WIDTH * CELL_WIDTH); - // Index between 1 and dim-1 because we know the wells of our tank are solid. + // Index between 1 and dim-1 because we know the walls of our tank are solid. for (int i=1; i < macgrid.marker.x_dim-1; ++i) { for (int j=1; j < macgrid.marker.y_dim-1; ++j) @@ -119,16 +120,23 @@ void FlipSolver::computePressure() // Build b vector of divergences Eigen::VectorXd b(m); - for (int i=0; i < macgrid.p.x_dim; ++i) + b.setZero(); + + for (int i=1; i < macgrid.p.x_dim-1; ++i) { - for (int j=0; j < macgrid.p.y_dim; ++j) + for (int j=1; j < macgrid.p.y_dim-1; ++j) { - for (int k=0; k < macgrid.p.z_dim; ++k) + for (int k=1; k < macgrid.p.z_dim-1; ++k) { - float u_div = macgrid.u(i+1, j, k) - macgrid.u(i, j, k); - float v_div = macgrid.v(i, j+1, k) - macgrid.v(i, j, k); - float w_div = macgrid.w(i, j, k+1) - macgrid.w(i, j, k); - b[macgrid.p.flatIdx(i, j, k)] = -(u_div+v_div+w_div) / CELL_WIDTH; + if (macgrid.marker(i, j, k) == macgrid.marker.FLUID) + { + float u_div = macgrid.u(i+1, j, k) - macgrid.u(i, j, k); + float v_div = macgrid.v(i, j+1, k) - macgrid.v(i, j, k); + float w_div = macgrid.w(i, j, k+1) - macgrid.w(i, j, k); + b[macgrid.p.flatIdx(i, j, k)] = -(u_div+v_div+w_div) / CELL_WIDTH; + float tmp = -(u_div+v_div+w_div) / CELL_WIDTH; + std::cout << i << " " << j << " " << k << " " << tmp << std::endl; + } } } } @@ -139,11 +147,12 @@ void FlipSolver::computePressure() // The coefficient matrix SpMat A(m,m); + A.setZero(); A.setFromTriplets(coefficients.begin(), coefficients.end()); // Solving for pressure - Eigen::ConjugateGradient chol(A); - Eigen::VectorXd pressures = chol.solve(b); // use factorization to solve for the given right hand side + Eigen::ConjugateGradient con(A); + Eigen::VectorXd pressures = con.solve(b); // use factorization to solve for the given right hand side // Update velocities float scale = (DENSITY * CELL_WIDTH) / TIME_STEP; @@ -468,28 +477,28 @@ void FlipSolver::storeParticleVelocityToGridComponent(Particle *p, Grid & return; } - for (int n=-1; n < 2; ++n) + for (int n=0; n < 2; ++n) { - for (int m=-1; m < 2; ++m) + for (int m=0; m < 2; ++m) { - for (int o=-1; o < 2; ++o) + for (int o=0; o < 2; ++o) { int I = i+n; int J = j+m; int K = k+o; - if (((I >= 0 && I < grid.x_dim) - && (J >= 0 && J < grid.y_dim)) - && (K >= 0 && K < grid.z_dim)) + if ((I < grid.x_dim) && (J < grid.y_dim) && (K < grid.z_dim)) { // Calculate weight based on distance from cell center. - float x = particle_container->min_x + ((I + 0.5f) * CELL_WIDTH); - float y = particle_container->min_y + ((J + 0.5f) * CELL_WIDTH); - float z = particle_container->min_z + ((K + 0.5f) * CELL_WIDTH); - float weight = 1.0f / glm::length(glm::vec3(x, y, z)-p->pos); + glm::vec3 face_pos(particle_container->min_x + I * CELL_WIDTH, + particle_container->min_y + J * CELL_WIDTH, + particle_container->min_z + K * CELL_WIDTH); + face_pos[(dim + 1) % 3] += 0.5f * CELL_WIDTH; + face_pos[(dim + 2) % 3] += 0.5f * CELL_WIDTH; + float weight = 1.f / glm::length(face_pos-p->pos); // Store velocity contribution and increment particle counter. grid(I, J, K) += weight * p->velocity[dim]; - grid.incrementParticleCount(I, J, K); + grid.incrementTotalWeight(I, J, K, weight); } } } @@ -556,9 +565,9 @@ glm::vec3 FlipSolver::getGridIndex(const glm::vec3 &pos) int k = int(floor((pos[2] - particle_container->min_z) / CELL_WIDTH)); // Clamp values. - i = std::min(std::max(i, 0), int(particle_container->x_dim-1)); - j = std::min(std::max(j, 0), int(particle_container->y_dim-1)); - k = std::min(std::max(k, 0), int(particle_container->z_dim-1)); + i = std::min(std::max(i, 0), int(particle_container->x_dim * RES -1)); + j = std::min(std::max(j, 0), int(particle_container->y_dim * RES -1)); + k = std::min(std::max(k, 0), int(particle_container->z_dim * RES -1)); return glm::vec3(i, j, k); } @@ -648,13 +657,18 @@ void FlipSolver::gridVelocityToParticle() float pic_z = interpolateVelocityComponent(p, macgrid.w, 2); // Get FLIP components. "old" grids currently contain delta velocity. - float flip_x = p->velocity[0] + interpolateVelocityComponent(p, macgrid.u_old, 0); - float flip_y = p->velocity[1] + interpolateVelocityComponent(p, macgrid.v_old, 1); - float flip_z = p->velocity[2] + interpolateVelocityComponent(p, macgrid.w_old, 2); +// float flip_x = p->velocity[0] + interpolateVelocityComponent(p, macgrid.u_old, 0); +// float flip_y = p->velocity[1] + interpolateVelocityComponent(p, macgrid.v_old, 1); +// float flip_z = p->velocity[2] + interpolateVelocityComponent(p, macgrid.w_old, 2); - p->velocity[0] = 0.05f * pic_x + 0.95f * flip_x; - p->velocity[1] = 0.05f * pic_y + 0.95f * flip_y; - p->velocity[2] = 0.05f * pic_z + 0.95f * flip_z; +// p->velocity[0] = 0.05f * pic_x + 0.95f * flip_x; +// p->velocity[1] = 0.05f * pic_y + 0.95f * flip_y; +// p->velocity[2] = 0.05f * pic_z + 0.95f * flip_z; + + p->velocity[0] = pic_x; + p->velocity[1] = pic_y; + p->velocity[2] = pic_z; + //std::cout << p->velocity[1] << std::endl; } diff --git a/src/fluidSolver/grid.hpp b/src/fluidSolver/grid.hpp index 4f7a9a17..0207acb4 100644 --- a/src/fluidSolver/grid.hpp +++ b/src/fluidSolver/grid.hpp @@ -19,7 +19,7 @@ class Grid { // The velocity or pressure quantities stored on the grid. std::vector cells; // The number of particles influencing this quanitity. - std::vector particleCount; + std::vector totalWeight; public: int x_dim; int y_dim; @@ -29,7 +29,7 @@ class Grid { Grid() {} Grid(int x, int y, int z) : x_dim(x), y_dim(y), z_dim(z) { cells = std::vector(x_dim*y_dim*z_dim, 0.f); - particleCount = std::vector(x_dim*y_dim*z_dim, 0); + totalWeight = std::vector(x_dim*y_dim*z_dim, 0.f); maxIndex = x_dim*y_dim*z_dim; } ~Grid() {} @@ -66,14 +66,14 @@ class Grid { { assert(i >= 0 && j >= 0 && k >= 0); assert(i < x_dim && j < y_dim && k < z_dim); - return particleCount.at(i + x_dim * (j + y_dim * k)); + return totalWeight.at(i + x_dim * (j + y_dim * k)); } - void incrementParticleCount(int i, int j, int k) + void incrementTotalWeight(int i, int j, int k, float val) { assert(i >= 0 && j >= 0 && k >= 0); assert(i < x_dim && j < y_dim && k < z_dim); - particleCount.at(i + x_dim * (j + y_dim * k))++; + totalWeight.at(i + x_dim * (j + y_dim * k)) += val; } int flatIdx(int i, int j, int k) @@ -84,9 +84,9 @@ class Grid { void clearVelocity() { cells.clear(); - particleCount.clear(); + totalWeight.clear(); cells = std::vector(x_dim*y_dim*z_dim, 0.f); - particleCount = std::vector(x_dim*y_dim*z_dim, 0); + totalWeight = std::vector(x_dim*y_dim*z_dim, 0.f); } void copyCells(Grid &dst_grid) @@ -131,7 +131,7 @@ class Grid { int numCells = cells.size(); for (int i=0; i < numCells; ++i) { - cells[i] /= MATHIF(particleCount[i] > 0, particleCount[i], 1.0f); + cells[i] /= MATHIF(totalWeight[i] > 0, totalWeight[i], 1.0f); } #endif } diff --git a/src/geom/particles.cpp b/src/geom/particles.cpp index 3676c065..d164c204 100644 --- a/src/geom/particles.cpp +++ b/src/geom/particles.cpp @@ -24,7 +24,7 @@ void ParticleContainer::initParticles(const glm::vec3 &bounds, const glm::vec3 & for (float i=-centered_bounds[0]; i < centered_bounds[0]; i += separation) { for (float j=-centered_bounds[1]; j < centered_bounds[1]; j += separation) { for (float k=-centered_bounds[2]; k < centered_bounds[2]; k += separation) { - glm::vec3 pos(i, j, k); + glm::vec3 pos(i+0.25, j+0.25, k+0.25); glm::vec3 vel = glm::vec3(0.f, 0.f, 0.f); particles.push_back(new Particle(pos, vel)); //std::cout << vel[0] << " " << vel[1] << " " << vel[2] << std::endl; @@ -32,7 +32,7 @@ void ParticleContainer::initParticles(const glm::vec3 &bounds, const glm::vec3 & } } - num_indicies = particles.size() * 3 + 1; + num_indicies = particles.size(); //std::cout << "SIZE" << num_indicies << std::endl; } diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index ac17d22f..8817ea07 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -60,6 +60,9 @@ void Scene::drawScene(GLuint &programID, GLuint &MatrixID, Camera &camera) { // Use our shader glUseProgram(programID); + + + Geometry * geom = objects[1]; for (Geometry *geom : objects) { geom->create(); // Model matrix : an identity matrix (model will be at the origin) @@ -93,7 +96,7 @@ void Scene::drawScene(GLuint &programID, GLuint &MatrixID, Camera &camera) { ); // Draw the triangle ! - glPointSize(1); + glPointSize(3); glDrawArrays(geom->draw_type, 0, geom->num_indicies); // 12*3 indices starting at 0 -> 12 triangles glDisableVertexAttribArray(0); diff --git a/src/scene/scene.json b/src/scene/scene.json index b9908eb5..8fc288a7 100644 --- a/src/scene/scene.json +++ b/src/scene/scene.json @@ -1,13 +1,13 @@ { "containerDim" : { - "scaleX" : 3.0, - "scaleY" : 3.0, - "scaleZ" : 3.0 + "scaleX" : 1.0, + "scaleY" : 1.0, + "scaleZ" : 1.0 }, "particleDim" : { - "boundX" : 2.0, - "boundY" : 2.0, - "boundZ" : 2.0 + "boundX" : 1.0, + "boundY" : 1.0, + "boundZ" : 1.0 }, - "particleSeparation" : 0.2 + "particleSeparation" : 0.5 } \ No newline at end of file From f70dccea425e5496e797362c0995e8e6e8d783d6 Mon Sep 17 00:00:00 2001 From: rahwang Date: Sun, 10 Apr 2016 04:10:34 -0400 Subject: [PATCH 13/23] yet more bug fixes --- src/fluidSolver/fluidSolver.cpp | 173 +++++++++++++++++++++----------- src/fluidSolver/fluidSolver.hpp | 7 +- src/scene/scene.json | 14 +-- 3 files changed, 127 insertions(+), 67 deletions(-) diff --git a/src/fluidSolver/fluidSolver.cpp b/src/fluidSolver/fluidSolver.cpp index 6f536974..5b0e30b5 100644 --- a/src/fluidSolver/fluidSolver.cpp +++ b/src/fluidSolver/fluidSolver.cpp @@ -38,7 +38,7 @@ void FlipSolver::step() } -void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficients) +void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficients) { float scale = TIME_STEP / (DENSITY * CELL_WIDTH * CELL_WIDTH); // Index between 1 and dim-1 because we know the walls of our tank are solid. @@ -48,63 +48,78 @@ void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficients) { for (int k=1; k < macgrid.marker.z_dim-1; ++k) { - if (macgrid.marker(i, j, k) == macgrid.marker.FLUID) - { - // This is a count of the EMPTY | FLUID neighboring cells. - if (macgrid.marker(i, j, k) == macgrid.marker.FLUID) { - int count = 0; - // RIGHT - if (macgrid.marker(i+1, j, k) != macgrid.marker.SOLID) + // This is a count of the EMPTY | FLUID neighboring cells. + if (macgrid.marker(i, j, k) == macgrid.marker.FLUID) { + int count = 0; + int curr_idx = macgrid.marker.flatIdx(i, j, k); + + // RIGHT + if (macgrid.marker(i+1, j, k) != macgrid.marker.SOLID) + { + count++; + if (macgrid.marker(i+1, j, k) == macgrid.marker.FLUID) { - coefficients.push_back(T(macgrid.marker.flatIdx(i, j, k), + coefficients.push_back(Tri(curr_idx, macgrid.marker.flatIdx(i+1, j, k), -scale)); - count++; } - // LEFT - if (macgrid.marker(i-1, j, k) != macgrid.marker.SOLID) + } + // LEFT + if (macgrid.marker(i-1, j, k) != macgrid.marker.SOLID) + { + count++; + if (macgrid.marker(i-1, j, k) == macgrid.marker.FLUID) { - coefficients.push_back(T(macgrid.marker.flatIdx(i, j, k), + coefficients.push_back(Tri(curr_idx, macgrid.marker.flatIdx(i-1, j, k), -scale)); - count++; } - // UP - if (macgrid.marker(i, j+1, k) != macgrid.marker.SOLID) + } + // UP + if (macgrid.marker(i, j+1, k) != macgrid.marker.SOLID) + { + count++; + if (macgrid.marker(i, j+1, k) == macgrid.marker.FLUID) { - coefficients.push_back(T(macgrid.marker.flatIdx(i, j, k), + coefficients.push_back(Tri(curr_idx, macgrid.marker.flatIdx(i, j+1, k), -scale)); - count++; } - // DOWN - if (macgrid.marker(i, j-1, k) != macgrid.marker.SOLID) + } + // DOWN + if (macgrid.marker(i, j-1, k) != macgrid.marker.SOLID) + { + count++; + if (macgrid.marker(i, j-1, k) == macgrid.marker.FLUID) { - coefficients.push_back(T(macgrid.marker.flatIdx(i, j, k), + coefficients.push_back(Tri(curr_idx, macgrid.marker.flatIdx(i, j-1, k), -scale)); - count++; } - // FRONT - if (macgrid.marker(i, j, k+1) != macgrid.marker.SOLID) + } + // FRONT + if (macgrid.marker(i, j, k+1) != macgrid.marker.SOLID) + { + count++; + if (macgrid.marker(i, j, k+1) == macgrid.marker.FLUID) { - coefficients.push_back(T(macgrid.marker.flatIdx(i, j, k), - macgrid.marker.flatIdx(i, j, k+1), - -scale)); - count++; + coefficients.push_back(Tri(curr_idx, + macgrid.marker.flatIdx(i, j, k+1), + -scale)); } - // BEHIND - if (macgrid.marker(i, j, k-1) != macgrid.marker.SOLID) + } + // BEHIND + if (macgrid.marker(i, j, k-1) != macgrid.marker.SOLID) + { + count++; + if (macgrid.marker(i, j, k-1) == macgrid.marker.FLUID) { - coefficients.push_back(T(macgrid.marker.flatIdx(i, j, k), - macgrid.marker.flatIdx(i, j, k-1), - -scale)); - count++; + coefficients.push_back(Tri(curr_idx, + macgrid.marker.flatIdx(i, j, k-1), + -scale)); } - coefficients.push_back(T(macgrid.marker.flatIdx(i, j, k), - macgrid.marker.flatIdx(i, j, k), - count * scale)); } + coefficients.push_back(Tri(curr_idx, curr_idx, count * scale)); } } } @@ -116,12 +131,15 @@ void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficients) void FlipSolver::computePressure() { int n = macgrid.p.getNumCells(); - int m = n*n; - // Build b vector of divergences - Eigen::VectorXd b(m); + SpMat A(n,n); + Eigen::VectorXd p(n); + Eigen::VectorXd b(n); + A.setZero(); + p.setZero(); b.setZero(); - + + // Build b vector of divergences for (int i=1; i < macgrid.p.x_dim-1; ++i) { for (int j=1; j < macgrid.p.y_dim-1; ++j) @@ -133,44 +151,83 @@ void FlipSolver::computePressure() float u_div = macgrid.u(i+1, j, k) - macgrid.u(i, j, k); float v_div = macgrid.v(i, j+1, k) - macgrid.v(i, j, k); float w_div = macgrid.w(i, j, k+1) - macgrid.w(i, j, k); - b[macgrid.p.flatIdx(i, j, k)] = -(u_div+v_div+w_div) / CELL_WIDTH; - float tmp = -(u_div+v_div+w_div) / CELL_WIDTH; - std::cout << i << " " << j << " " << k << " " << tmp << std::endl; + b[macgrid.p.flatIdx(i, j, k)] = -1 * (u_div+v_div+w_div) / CELL_WIDTH; + float tmp = -1 * (u_div+v_div+w_div) / CELL_WIDTH; } } } } // Assemble coeff vector to be passed to coefficient matrix. - std::vector coefficients; + std::vector coefficients; assemblePressureSolveCoefficients(coefficients); - // The coefficient matrix - SpMat A(m,m); - A.setZero(); + // Set the coefficient matrix A.setFromTriplets(coefficients.begin(), coefficients.end()); - + // Solving for pressure - Eigen::ConjugateGradient con(A); - Eigen::VectorXd pressures = con.solve(b); // use factorization to solve for the given right hand side + Eigen::ConjugateGradient> con; + con.compute(A); + p = con.solve(b); // use factorization to solve for the given right hand side + + std::cout << "Divergece" << std::endl; + std::cout << b << std::endl; + + std::cout << "Coefficients" << std::endl; + std::cout << A << std::endl; + + std::cout << "Pressure" << std::endl; + std::cout << p << std::endl; // Update velocities - float scale = (DENSITY * CELL_WIDTH) / TIME_STEP; + float scale = TIME_STEP / (DENSITY * CELL_WIDTH); + for (int i=1; i < macgrid.p.x_dim; ++i) + { + for (int j=1; j < macgrid.p.y_dim; ++j) + { + for (int k=1; k < macgrid.p.z_dim; ++k) + { + if (macgrid.marker(i-1, j, k) == macgrid.marker.FLUID || macgrid.marker(i, j, k) == macgrid.marker.FLUID) + { + macgrid.u(i, j, k) -= scale * (p[macgrid.p.flatIdx(i, j, k)] + - p[macgrid.p.flatIdx(i-1, j, k)]); + } + if (macgrid.marker(i, j-1, k) == macgrid.marker.FLUID || macgrid.marker(i, j, k) == macgrid.marker.FLUID) + { + macgrid.v(i, j, k) -= scale * (p[macgrid.p.flatIdx(i, j, k)] + - p[macgrid.p.flatIdx(i, j-1, k)]); + } + if (macgrid.marker(i, j, k-1) == macgrid.marker.FLUID || macgrid.marker(i, j, k) == macgrid.marker.FLUID) + { + macgrid.w(i, j, k) -= scale * (p[macgrid.p.flatIdx(i, j, k)] + - p[macgrid.p.flatIdx(i, j, k-1)]); + } + } + } + } + + // Check resulting divergences. for (int i=1; i < macgrid.p.x_dim-1; ++i) { for (int j=1; j < macgrid.p.y_dim-1; ++j) { for (int k=1; k < macgrid.p.z_dim-1; ++k) { - macgrid.u(i, j, k) -= scale * (pressures[macgrid.p.flatIdx(i+1, j, k)] - - pressures[macgrid.p.flatIdx(i, j, k)]); - macgrid.v(i, j, k) -= scale * (pressures[macgrid.p.flatIdx(i, j+1, k)] - - pressures[macgrid.p.flatIdx(i, j, k)]); - macgrid.w(i, j, k) -= scale * (pressures[macgrid.p.flatIdx(i, j, k+1)] - - pressures[macgrid.p.flatIdx(i, j, k)]); + if (macgrid.marker(i, j, k) == macgrid.marker.FLUID) + { + float u_div = macgrid.u(i+1, j, k) - macgrid.u(i, j, k); + float v_div = macgrid.v(i, j+1, k) - macgrid.v(i, j, k); + float w_div = macgrid.w(i, j, k+1) - macgrid.w(i, j, k); + b[macgrid.p.flatIdx(i, j, k)] = -1 * (u_div+v_div+w_div) / CELL_WIDTH; + float tmp = -1 * (u_div+v_div+w_div) / CELL_WIDTH; + } } } } + + std::cout << "Divergece" << std::endl; + std::cout << b << std::endl; + } diff --git a/src/fluidSolver/fluidSolver.hpp b/src/fluidSolver/fluidSolver.hpp index 5a7760f0..9961e250 100644 --- a/src/fluidSolver/fluidSolver.hpp +++ b/src/fluidSolver/fluidSolver.hpp @@ -8,10 +8,13 @@ #include "../geom/particles.hpp" #include "grid.hpp" #include +#include +#include +#include #include typedef Eigen::SparseMatrix SpMat; // declares a column-major sparse matrix type of double -typedef Eigen::Triplet T; +typedef Eigen::Triplet Tri; class FluidSolver{ public: @@ -50,7 +53,7 @@ class FlipSolver : public FluidSolver { void storeDeltaVelocity(Grid &old_grid, const Grid &grid); void setSolidCells(); void computePressure(); - void assemblePressureSolveCoefficients(std::vector &coefficients); + void assemblePressureSolveCoefficients(std::vector &coefficients); MacGrid macgrid; }; diff --git a/src/scene/scene.json b/src/scene/scene.json index 8fc288a7..b9164c3f 100644 --- a/src/scene/scene.json +++ b/src/scene/scene.json @@ -1,13 +1,13 @@ { "containerDim" : { - "scaleX" : 1.0, - "scaleY" : 1.0, - "scaleZ" : 1.0 + "scaleX" : 2.0, + "scaleY" : 2.0, + "scaleZ" : 2.0 }, "particleDim" : { - "boundX" : 1.0, - "boundY" : 1.0, - "boundZ" : 1.0 + "boundX" : 0.5, + "boundY" : 0.5, + "boundZ" : 0.5 }, - "particleSeparation" : 0.5 + "particleSeparation" : 0.2 } \ No newline at end of file From 80092901caacdb444ce31b928ddedf0c358ec1f2 Mon Sep 17 00:00:00 2001 From: rahwang Date: Sun, 10 Apr 2016 16:48:55 -0400 Subject: [PATCH 14/23] Goop stage of life, continuing too debug --- src/fluidSolver/fluidSolver.cpp | 99 +++++++++++++++++++-------------- src/scene/scene.json | 14 ++--- 2 files changed, 65 insertions(+), 48 deletions(-) diff --git a/src/fluidSolver/fluidSolver.cpp b/src/fluidSolver/fluidSolver.cpp index 5b0e30b5..88c72f3e 100644 --- a/src/fluidSolver/fluidSolver.cpp +++ b/src/fluidSolver/fluidSolver.cpp @@ -7,7 +7,7 @@ #include #define GRAVITY -9.8f -#define TIME_STEP (1.0f/10.f) +#define TIME_STEP (1.0f/20.f) #define RES 2 #define CELL_WIDTH (1.f/RES) #define DAMPING 1.0f @@ -54,70 +54,81 @@ void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficient int curr_idx = macgrid.marker.flatIdx(i, j, k); // RIGHT - if (macgrid.marker(i+1, j, k) != macgrid.marker.SOLID) + if (macgrid.marker(i+1, j, k) == macgrid.marker.AIR) + { + count++; + } + else if (macgrid.marker(i+1, j, k) == macgrid.marker.FLUID) { count++; - if (macgrid.marker(i+1, j, k) == macgrid.marker.FLUID) - { coefficients.push_back(Tri(curr_idx, macgrid.marker.flatIdx(i+1, j, k), -scale)); - } } + // LEFT - if (macgrid.marker(i-1, j, k) != macgrid.marker.SOLID) + if (macgrid.marker(i-1, j, k) == macgrid.marker.AIR) + { + count++; + } + else if (macgrid.marker(i-1, j, k) == macgrid.marker.FLUID) { count++; - if (macgrid.marker(i-1, j, k) == macgrid.marker.FLUID) - { coefficients.push_back(Tri(curr_idx, macgrid.marker.flatIdx(i-1, j, k), -scale)); - } } + // UP - if (macgrid.marker(i, j+1, k) != macgrid.marker.SOLID) + if (macgrid.marker(i, j+1, k) == macgrid.marker.AIR) + { + count++; + } + else if (macgrid.marker(i, j+1, k) == macgrid.marker.FLUID) { count++; - if (macgrid.marker(i, j+1, k) == macgrid.marker.FLUID) - { coefficients.push_back(Tri(curr_idx, macgrid.marker.flatIdx(i, j+1, k), -scale)); - } } + // DOWN - if (macgrid.marker(i, j-1, k) != macgrid.marker.SOLID) + if (macgrid.marker(i, j-1, k) == macgrid.marker.AIR) + { + count++; + } + else if (macgrid.marker(i, j-1, k) == macgrid.marker.FLUID) { count++; - if (macgrid.marker(i, j-1, k) == macgrid.marker.FLUID) - { coefficients.push_back(Tri(curr_idx, macgrid.marker.flatIdx(i, j-1, k), -scale)); - } } + // FRONT - if (macgrid.marker(i, j, k+1) != macgrid.marker.SOLID) + if (macgrid.marker(i, j, k+1) == macgrid.marker.AIR) { count++; - if (macgrid.marker(i, j, k+1) == macgrid.marker.FLUID) - { - coefficients.push_back(Tri(curr_idx, - macgrid.marker.flatIdx(i, j, k+1), - -scale)); - } } + else if (macgrid.marker(i, j, k+1) == macgrid.marker.FLUID) + { + count++; + coefficients.push_back(Tri(curr_idx, + macgrid.marker.flatIdx(i, j, k+1), + -scale)); + } + // BEHIND - if (macgrid.marker(i, j, k-1) != macgrid.marker.SOLID) + if (macgrid.marker(i, j, k-1) == macgrid.marker.AIR) { count++; - if (macgrid.marker(i, j, k-1) == macgrid.marker.FLUID) - { - coefficients.push_back(Tri(curr_idx, - macgrid.marker.flatIdx(i, j, k-1), - -scale)); - } + } + else if (macgrid.marker(i, j, k-1) == macgrid.marker.FLUID) + { + count++; + coefficients.push_back(Tri(curr_idx, + macgrid.marker.flatIdx(i, j, k-1), + -scale)); } coefficients.push_back(Tri(curr_idx, curr_idx, count * scale)); } @@ -170,14 +181,14 @@ void FlipSolver::computePressure() con.compute(A); p = con.solve(b); // use factorization to solve for the given right hand side - std::cout << "Divergece" << std::endl; - std::cout << b << std::endl; - - std::cout << "Coefficients" << std::endl; - std::cout << A << std::endl; - - std::cout << "Pressure" << std::endl; - std::cout << p << std::endl; +// std::cout << "Divergece" << std::endl; +// std::cout << b << std::endl; +// +// std::cout << "Coefficients" << std::endl; +// std::cout << A << std::endl; +// +// std::cout << "Pressure" << std::endl; +// std::cout << p << std::endl; // Update velocities float scale = TIME_STEP / (DENSITY * CELL_WIDTH); @@ -206,6 +217,7 @@ void FlipSolver::computePressure() } } + float div = 0.f; // Check resulting divergences. for (int i=1; i < macgrid.p.x_dim-1; ++i) { @@ -220,13 +232,18 @@ void FlipSolver::computePressure() float w_div = macgrid.w(i, j, k+1) - macgrid.w(i, j, k); b[macgrid.p.flatIdx(i, j, k)] = -1 * (u_div+v_div+w_div) / CELL_WIDTH; float tmp = -1 * (u_div+v_div+w_div) / CELL_WIDTH; + div += tmp; } } } } - std::cout << "Divergece" << std::endl; - std::cout << b << std::endl; + //std::cout << "Divergece" << std::endl; + //std::cout << b << std::endl; + if (abs(div) > 0.1) + { + std::cout << "LIES DIVERGENCE IS HERE : " << div << std::endl; + } } diff --git a/src/scene/scene.json b/src/scene/scene.json index b9164c3f..24d39c7b 100644 --- a/src/scene/scene.json +++ b/src/scene/scene.json @@ -1,13 +1,13 @@ { "containerDim" : { - "scaleX" : 2.0, - "scaleY" : 2.0, - "scaleZ" : 2.0 + "scaleX" : 4.0, + "scaleY" : 4.0, + "scaleZ" : 4.0 }, "particleDim" : { - "boundX" : 0.5, - "boundY" : 0.5, - "boundZ" : 0.5 + "boundX" : 3.0, + "boundY" : 3.0, + "boundZ" : 3.0 }, - "particleSeparation" : 0.2 + "particleSeparation" : 0.1 } \ No newline at end of file From 041bf981650af694e883a8148f60ae0994b25a2d Mon Sep 17 00:00:00 2001 From: rahwang Date: Sun, 10 Apr 2016 19:48:36 -0400 Subject: [PATCH 15/23] still debugging, but progress --- src/fluidSolver/fluidSolver.cpp | 159 +++++++++++++++++++++----------- src/fluidSolver/fluidSolver.hpp | 1 + src/geom/particles.cpp | 2 +- src/scene/scene.cpp | 2 +- src/scene/scene.json | 6 +- 5 files changed, 113 insertions(+), 57 deletions(-) diff --git a/src/fluidSolver/fluidSolver.cpp b/src/fluidSolver/fluidSolver.cpp index 88c72f3e..ab7e13e3 100644 --- a/src/fluidSolver/fluidSolver.cpp +++ b/src/fluidSolver/fluidSolver.cpp @@ -7,14 +7,15 @@ #include #define GRAVITY -9.8f -#define TIME_STEP (1.0f/20.f) -#define RES 2 +#define TIME_STEP (1.0f/50.f) +#define RES 4 #define CELL_WIDTH (1.f/RES) #define DAMPING 1.0f #define DENSITY 1.f //#define TBB 1 +int iter = 0; void FlipSolver::step() { @@ -35,8 +36,28 @@ void FlipSolver::step() gridVelocityToParticle(); updateParticlePositions(); handleCollisions(); + iter++; + if (iter > 100) + { + std::cout << "iteration: " << iter << std::endl; + checkTypes(); + } } +void FlipSolver::checkTypes() +{ + for (int i=0; i < macgrid.marker.x_dim; ++i) + { + for (int j=0; j < macgrid.marker.y_dim; ++j) + { + for (int k=0; k < macgrid.marker.z_dim; ++k) + { + if (macgrid.marker(i, j, k) == macgrid.marker.FLUID) + std::cout << i << " " << j << " " << k << std::endl; + } + } + } +} void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficients) { @@ -53,12 +74,20 @@ void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficient int count = 0; int curr_idx = macgrid.marker.flatIdx(i, j, k); + int right_mark = macgrid.marker(i+1, j, k); + int left_mark = macgrid.marker(i-1, j, k); + int up_mark = macgrid.marker(i, j+1, k); + int down_mark = macgrid.marker(i, j-1, k); + int front_mark = macgrid.marker(i, j, k+1); + int behind_mark = macgrid.marker(i, j, k-1); + + // RIGHT - if (macgrid.marker(i+1, j, k) == macgrid.marker.AIR) + if (right_mark == macgrid.marker.AIR) { count++; } - else if (macgrid.marker(i+1, j, k) == macgrid.marker.FLUID) + else if (right_mark == macgrid.marker.FLUID) { count++; coefficients.push_back(Tri(curr_idx, @@ -67,11 +96,11 @@ void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficient } // LEFT - if (macgrid.marker(i-1, j, k) == macgrid.marker.AIR) + if (left_mark == macgrid.marker.AIR) { count++; } - else if (macgrid.marker(i-1, j, k) == macgrid.marker.FLUID) + else if (left_mark == macgrid.marker.FLUID) { count++; coefficients.push_back(Tri(curr_idx, @@ -80,11 +109,11 @@ void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficient } // UP - if (macgrid.marker(i, j+1, k) == macgrid.marker.AIR) + if (up_mark == macgrid.marker.AIR) { count++; } - else if (macgrid.marker(i, j+1, k) == macgrid.marker.FLUID) + else if (up_mark == macgrid.marker.FLUID) { count++; coefficients.push_back(Tri(curr_idx, @@ -93,11 +122,11 @@ void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficient } // DOWN - if (macgrid.marker(i, j-1, k) == macgrid.marker.AIR) + if (down_mark == macgrid.marker.AIR) { count++; } - else if (macgrid.marker(i, j-1, k) == macgrid.marker.FLUID) + else if (down_mark == macgrid.marker.FLUID) { count++; coefficients.push_back(Tri(curr_idx, @@ -106,11 +135,11 @@ void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficient } // FRONT - if (macgrid.marker(i, j, k+1) == macgrid.marker.AIR) + if (front_mark == macgrid.marker.AIR) { count++; } - else if (macgrid.marker(i, j, k+1) == macgrid.marker.FLUID) + else if (front_mark == macgrid.marker.FLUID) { count++; coefficients.push_back(Tri(curr_idx, @@ -119,11 +148,11 @@ void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficient } // BEHIND - if (macgrid.marker(i, j, k-1) == macgrid.marker.AIR) + if (behind_mark == macgrid.marker.AIR) { count++; } - else if (macgrid.marker(i, j, k-1) == macgrid.marker.FLUID) + else if (behind_mark == macgrid.marker.FLUID) { count++; coefficients.push_back(Tri(curr_idx, @@ -151,6 +180,7 @@ void FlipSolver::computePressure() b.setZero(); // Build b vector of divergences + float scale = 1.f / CELL_WIDTH; for (int i=1; i < macgrid.p.x_dim-1; ++i) { for (int j=1; j < macgrid.p.y_dim-1; ++j) @@ -162,8 +192,7 @@ void FlipSolver::computePressure() float u_div = macgrid.u(i+1, j, k) - macgrid.u(i, j, k); float v_div = macgrid.v(i, j+1, k) - macgrid.v(i, j, k); float w_div = macgrid.w(i, j, k+1) - macgrid.w(i, j, k); - b[macgrid.p.flatIdx(i, j, k)] = -1 * (u_div+v_div+w_div) / CELL_WIDTH; - float tmp = -1 * (u_div+v_div+w_div) / CELL_WIDTH; + b[macgrid.p.flatIdx(i, j, k)] = -scale * (u_div+v_div+w_div); } } } @@ -183,41 +212,64 @@ void FlipSolver::computePressure() // std::cout << "Divergece" << std::endl; // std::cout << b << std::endl; -// -// std::cout << "Coefficients" << std::endl; -// std::cout << A << std::endl; +// // // std::cout << "Pressure" << std::endl; // std::cout << p << std::endl; // Update velocities - float scale = TIME_STEP / (DENSITY * CELL_WIDTH); + scale = TIME_STEP / (DENSITY * CELL_WIDTH); for (int i=1; i < macgrid.p.x_dim; ++i) { for (int j=1; j < macgrid.p.y_dim; ++j) { for (int k=1; k < macgrid.p.z_dim; ++k) { + // Update u if (macgrid.marker(i-1, j, k) == macgrid.marker.FLUID || macgrid.marker(i, j, k) == macgrid.marker.FLUID) { - macgrid.u(i, j, k) -= scale * (p[macgrid.p.flatIdx(i, j, k)] - - p[macgrid.p.flatIdx(i-1, j, k)]); + if (macgrid.marker(i-1, j, k) == macgrid.marker.SOLID || macgrid.marker(i, j, k) == macgrid.marker.SOLID) + { + macgrid.u(i, j, k) = 0.f; + } + else + { + macgrid.u(i, j, k) -= scale * (p[macgrid.p.flatIdx(i, j, k)] + - p[macgrid.p.flatIdx(i-1, j, k)]); + } } + + // Update v if (macgrid.marker(i, j-1, k) == macgrid.marker.FLUID || macgrid.marker(i, j, k) == macgrid.marker.FLUID) { - macgrid.v(i, j, k) -= scale * (p[macgrid.p.flatIdx(i, j, k)] - - p[macgrid.p.flatIdx(i, j-1, k)]); + if (macgrid.marker(i, j-1, k) == macgrid.marker.SOLID || macgrid.marker(i, j, k) == macgrid.marker.SOLID) + { + macgrid.v(i, j, k) = 0.f; + } + else + { + macgrid.v(i, j, k) -= scale * (p[macgrid.p.flatIdx(i, j, k)] + - p[macgrid.p.flatIdx(i, j-1, k)]); + } } + + // Update w if (macgrid.marker(i, j, k-1) == macgrid.marker.FLUID || macgrid.marker(i, j, k) == macgrid.marker.FLUID) { - macgrid.w(i, j, k) -= scale * (p[macgrid.p.flatIdx(i, j, k)] - - p[macgrid.p.flatIdx(i, j, k-1)]); + if (macgrid.marker(i, j, k-1) == macgrid.marker.SOLID || macgrid.marker(i, j, k) == macgrid.marker.SOLID) + { + macgrid.w(i, j, k) = 0.f; + } + else + { + macgrid.w(i, j, k) -= scale * (p[macgrid.p.flatIdx(i, j, k)] + - p[macgrid.p.flatIdx(i, j, k-1)]); + } } } } } - float div = 0.f; // Check resulting divergences. for (int i=1; i < macgrid.p.x_dim-1; ++i) { @@ -227,23 +279,24 @@ void FlipSolver::computePressure() { if (macgrid.marker(i, j, k) == macgrid.marker.FLUID) { + float div = 0.f; float u_div = macgrid.u(i+1, j, k) - macgrid.u(i, j, k); float v_div = macgrid.v(i, j+1, k) - macgrid.v(i, j, k); float w_div = macgrid.w(i, j, k+1) - macgrid.w(i, j, k); b[macgrid.p.flatIdx(i, j, k)] = -1 * (u_div+v_div+w_div) / CELL_WIDTH; float tmp = -1 * (u_div+v_div+w_div) / CELL_WIDTH; div += tmp; + if (abs(div) > 0.1) + { + std::cout << "LIES DIVERGENCE IS HERE : " << i << " "<< j<< " "< 0.1) - { - std::cout << "LIES DIVERGENCE IS HERE : " << div << std::endl; - } + int a =1; } @@ -408,42 +461,44 @@ void FlipSolver::handleCollisions() int size = particle_container->particles.size(); tbb::parallel_for(0, size, 1, [=](int i) { + float OFFSET_CELL_WIDTH = CELL_WIDTH + .01; Particle *p = particle_container->particles[i]; // Check to see if p is inside bounding volume - if (p->pos[0] < particle_container->min_x || p->pos[0] > particle_container->max_x) + if (p->pos[0] < (particle_container->min_x + CELL_WIDTH) + || p->pos[0] > (particle_container->max_x - CELL_WIDTH)) { - p->pos[0] = std::min(std::max(p->pos[0], particle_container->min_x), particle_container->max_x); - p->velocity[0] *= -DAMPING; + p->pos[0] = std::min(std::max(p->pos[0], particle_container->min_x + OFFSET_CELL_WIDTH), particle_container->max_x - OFFSET_CELL_WIDTH); } - if (p->pos[1] < particle_container->min_y || p->pos[1] > particle_container->max_y) + if (p->pos[1] < (particle_container->min_y + CELL_WIDTH) + || p->pos[1] > (particle_container->max_y - CELL_WIDTH)) { - p->pos[1] = std::min(std::max(p->pos[1], particle_container->min_y), particle_container->max_y); - p->velocity[1] *= -DAMPING; + p->pos[1] = std::min(std::max(p->pos[1], particle_container->min_y + OFFSET_CELL_WIDTH), particle_container->max_y - OFFSET_CELL_WIDTH); } - if (p->pos[2] < particle_container->min_z || p->pos[2] > particle_container->max_z) + if (p->pos[2] < (particle_container->min_z + CELL_WIDTH) + || p->pos[2] > (particle_container->max_z - CELL_WIDTH)) { - p->pos[2] = std::min(std::max(p->pos[2], particle_container->min_z), particle_container->max_z); - p->velocity[2] *= -DAMPING; + p->pos[2] = std::min(std::max(p->pos[2], particle_container->min_z + OFFSET_CELL_WIDTH), particle_container->max_z - OFFSET_CELL_WIDTH); } }); #else for (Particle *p : particle_container->particles) { + float OFFSET_CELL_WIDTH = CELL_WIDTH + .01; // Check to see if p is inside bounding volume - if (p->pos[0] < particle_container->min_x || p->pos[0] > particle_container->max_x) + if (p->pos[0] < (particle_container->min_x + CELL_WIDTH) + || p->pos[0] > (particle_container->max_x - CELL_WIDTH)) { - p->pos[0] = std::min(std::max(p->pos[0], particle_container->min_x), particle_container->max_x); - p->velocity[0] *= -DAMPING; + p->pos[0] = std::min(std::max(p->pos[0], particle_container->min_x + OFFSET_CELL_WIDTH), particle_container->max_x - OFFSET_CELL_WIDTH); } - if (p->pos[1] < particle_container->min_y || p->pos[1] > particle_container->max_y) + if (p->pos[1] < (particle_container->min_y + CELL_WIDTH) + || p->pos[1] > (particle_container->max_y - CELL_WIDTH)) { - p->pos[1] = std::min(std::max(p->pos[1], particle_container->min_y), particle_container->max_y); - p->velocity[1] *= -DAMPING; + p->pos[1] = std::min(std::max(p->pos[1], particle_container->min_y + OFFSET_CELL_WIDTH), particle_container->max_y - OFFSET_CELL_WIDTH); } - if (p->pos[2] < particle_container->min_z || p->pos[2] > particle_container->max_z) + if (p->pos[2] < (particle_container->min_z + CELL_WIDTH) + || p->pos[2] > (particle_container->max_z - CELL_WIDTH)) { - p->pos[2] = std::min(std::max(p->pos[2], particle_container->min_z), particle_container->max_z); - p->velocity[2] *= -DAMPING; + p->pos[2] = std::min(std::max(p->pos[2], particle_container->min_z + OFFSET_CELL_WIDTH), particle_container->max_z - OFFSET_CELL_WIDTH); } } #endif diff --git a/src/fluidSolver/fluidSolver.hpp b/src/fluidSolver/fluidSolver.hpp index 9961e250..9221af13 100644 --- a/src/fluidSolver/fluidSolver.hpp +++ b/src/fluidSolver/fluidSolver.hpp @@ -54,6 +54,7 @@ class FlipSolver : public FluidSolver { void setSolidCells(); void computePressure(); void assemblePressureSolveCoefficients(std::vector &coefficients); + void checkTypes(); MacGrid macgrid; }; diff --git a/src/geom/particles.cpp b/src/geom/particles.cpp index d164c204..953faf48 100644 --- a/src/geom/particles.cpp +++ b/src/geom/particles.cpp @@ -24,7 +24,7 @@ void ParticleContainer::initParticles(const glm::vec3 &bounds, const glm::vec3 & for (float i=-centered_bounds[0]; i < centered_bounds[0]; i += separation) { for (float j=-centered_bounds[1]; j < centered_bounds[1]; j += separation) { for (float k=-centered_bounds[2]; k < centered_bounds[2]; k += separation) { - glm::vec3 pos(i+0.25, j+0.25, k+0.25); + glm::vec3 pos(i, j, k); glm::vec3 vel = glm::vec3(0.f, 0.f, 0.f); particles.push_back(new Particle(pos, vel)); //std::cout << vel[0] << " " << vel[1] << " " << vel[2] << std::endl; diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index 8817ea07..9bb222d6 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -102,7 +102,7 @@ void Scene::drawScene(GLuint &programID, GLuint &MatrixID, Camera &camera) { glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); } - + // Update particle positions fluid_solver.step(); } diff --git a/src/scene/scene.json b/src/scene/scene.json index 24d39c7b..f7d6079d 100644 --- a/src/scene/scene.json +++ b/src/scene/scene.json @@ -5,9 +5,9 @@ "scaleZ" : 4.0 }, "particleDim" : { - "boundX" : 3.0, - "boundY" : 3.0, - "boundZ" : 3.0 + "boundX" : 2.0, + "boundY" : 2.0, + "boundZ" : 2.0 }, "particleSeparation" : 0.1 } \ No newline at end of file From f24a00f6426c9e0765ef9fdcc31285872cbee17f Mon Sep 17 00:00:00 2001 From: rahwang Date: Mon, 11 Apr 2016 09:52:41 -0400 Subject: [PATCH 16/23] still debugging, slow progress --- src/fluidSolver/fluidSolver.cpp | 357 +++++++++++++++++++------------- src/fluidSolver/fluidSolver.hpp | 6 +- src/fluidSolver/grid.hpp | 2 +- src/geom/particles.cpp | 16 +- src/geom/particles.hpp | 11 +- src/scene/scene.cpp | 3 - src/scene/scene.json | 12 +- 7 files changed, 242 insertions(+), 165 deletions(-) diff --git a/src/fluidSolver/fluidSolver.cpp b/src/fluidSolver/fluidSolver.cpp index ab7e13e3..2eca14ee 100644 --- a/src/fluidSolver/fluidSolver.cpp +++ b/src/fluidSolver/fluidSolver.cpp @@ -5,15 +5,18 @@ #include "fluidSolver.hpp" #include #include +#include #define GRAVITY -9.8f -#define TIME_STEP (1.0f/50.f) +#define TIME_STEP (1.0f/100.f) #define RES 4 #define CELL_WIDTH (1.f/RES) #define DAMPING 1.0f #define DENSITY 1.f +#define PARTICLES_PER_CELL 1 //#define TBB 1 +//#define RANDOM_SEED 1 int iter = 0; @@ -37,10 +40,14 @@ void FlipSolver::step() updateParticlePositions(); handleCollisions(); iter++; - if (iter > 100) - { - std::cout << "iteration: " << iter << std::endl; - checkTypes(); +// if (iter > 100) +// { +// std::cout << "iteration: " << iter << std::endl; +// checkTypes(); +// } + std::cout << "ITER: " << iter << std::endl; + if (iter == 44) { + int a = 1; } } @@ -52,7 +59,7 @@ void FlipSolver::checkTypes() { for (int k=0; k < macgrid.marker.z_dim; ++k) { - if (macgrid.marker(i, j, k) == macgrid.marker.FLUID) + if (macgrid.marker(i, j, k) == macgrid.marker.SOLID) std::cout << i << " " << j << " " << k << std::endl; } } @@ -74,6 +81,10 @@ void FlipSolver::assemblePressureSolveCoefficients(std::vector &coefficient int count = 0; int curr_idx = macgrid.marker.flatIdx(i, j, k); + if (curr_idx == 1558) { + int a = 1; + } + int right_mark = macgrid.marker(i+1, j, k); int left_mark = macgrid.marker(i-1, j, k); int up_mark = macgrid.marker(i, j+1, k); @@ -172,14 +183,15 @@ void FlipSolver::computePressure() { int n = macgrid.p.getNumCells(); - SpMat A(n,n); - Eigen::VectorXd p(n); - Eigen::VectorXd b(n); + Eigen::SparseMatrix A(n, n); + Eigen::VectorXf b(n); + Eigen::VectorXf p(n); A.setZero(); p.setZero(); b.setZero(); // Build b vector of divergences + std::vector divs; float scale = 1.f / CELL_WIDTH; for (int i=1; i < macgrid.p.x_dim-1; ++i) { @@ -192,7 +204,8 @@ void FlipSolver::computePressure() float u_div = macgrid.u(i+1, j, k) - macgrid.u(i, j, k); float v_div = macgrid.v(i, j+1, k) - macgrid.v(i, j, k); float w_div = macgrid.w(i, j, k+1) - macgrid.w(i, j, k); - b[macgrid.p.flatIdx(i, j, k)] = -scale * (u_div+v_div+w_div); + float div = -scale * (u_div+v_div+w_div); + b[macgrid.p.flatIdx(i, j, k)] = div; } } } @@ -206,8 +219,8 @@ void FlipSolver::computePressure() A.setFromTriplets(coefficients.begin(), coefficients.end()); // Solving for pressure - Eigen::ConjugateGradient> con; - con.compute(A); + Eigen::ConjugateGradient> con(A); +// con.compute(A); p = con.solve(b); // use factorization to solve for the given right hand side // std::cout << "Divergece" << std::endl; @@ -226,50 +239,74 @@ void FlipSolver::computePressure() for (int k=1; k < macgrid.p.z_dim; ++k) { // Update u - if (macgrid.marker(i-1, j, k) == macgrid.marker.FLUID || macgrid.marker(i, j, k) == macgrid.marker.FLUID) + if (macgrid.marker(i-1, j, k) == macgrid.marker.FLUID + || macgrid.marker(i, j, k) == macgrid.marker.FLUID) { - if (macgrid.marker(i-1, j, k) == macgrid.marker.SOLID || macgrid.marker(i, j, k) == macgrid.marker.SOLID) - { - macgrid.u(i, j, k) = 0.f; - } - else - { - macgrid.u(i, j, k) -= scale * (p[macgrid.p.flatIdx(i, j, k)] - - p[macgrid.p.flatIdx(i-1, j, k)]); - } +// if (macgrid.marker(i-1, j, k) == macgrid.marker.SOLID +// || macgrid.marker(i, j, k) == macgrid.marker.SOLID) +// { +// macgrid.u(i, j, k) = 0.f; +// } +// else +// { +// macgrid.u(i, j, k) -= scale * (p[macgrid.p.flatIdx(i, j, k)] +// - p[macgrid.p.flatIdx(i-1, j, k)]); +// } + macgrid.u(i, j, k) -= scale * (p[macgrid.p.flatIdx(i, j, k)] + - p[macgrid.p.flatIdx(i-1, j, k)]); + } // Update v - if (macgrid.marker(i, j-1, k) == macgrid.marker.FLUID || macgrid.marker(i, j, k) == macgrid.marker.FLUID) + if (macgrid.marker(i, j-1, k) == macgrid.marker.FLUID + || macgrid.marker(i, j, k) == macgrid.marker.FLUID) { - if (macgrid.marker(i, j-1, k) == macgrid.marker.SOLID || macgrid.marker(i, j, k) == macgrid.marker.SOLID) - { - macgrid.v(i, j, k) = 0.f; - } - else - { - macgrid.v(i, j, k) -= scale * (p[macgrid.p.flatIdx(i, j, k)] - - p[macgrid.p.flatIdx(i, j-1, k)]); - } +// if (macgrid.marker(i, j-1, k) == macgrid.marker.SOLID +// || macgrid.marker(i, j, k) == macgrid.marker.SOLID) +// { +// macgrid.v(i, j, k) = 0.f; +// } +// else +// { +// macgrid.v(i, j, k) -= scale * (p[macgrid.p.flatIdx(i, j, k)] +// - p[macgrid.p.flatIdx(i, j-1, k)]); +// } + macgrid.v(i, j, k) -= scale * (p[macgrid.p.flatIdx(i, j, k)] + - p[macgrid.p.flatIdx(i, j-1, k)]); + } // Update w - if (macgrid.marker(i, j, k-1) == macgrid.marker.FLUID || macgrid.marker(i, j, k) == macgrid.marker.FLUID) + if (macgrid.marker(i, j, k-1) == macgrid.marker.FLUID + || macgrid.marker(i, j, k) == macgrid.marker.FLUID) { - if (macgrid.marker(i, j, k-1) == macgrid.marker.SOLID || macgrid.marker(i, j, k) == macgrid.marker.SOLID) - { - macgrid.w(i, j, k) = 0.f; - } - else - { - macgrid.w(i, j, k) -= scale * (p[macgrid.p.flatIdx(i, j, k)] - - p[macgrid.p.flatIdx(i, j, k-1)]); - } +// if (macgrid.marker(i, j, k-1) == macgrid.marker.SOLID +// || macgrid.marker(i, j, k) == macgrid.marker.SOLID) +// { +// macgrid.w(i, j, k) = 0.f; +// } +// else +// { +// macgrid.w(i, j, k) -= scale * (p[macgrid.p.flatIdx(i, j, k)] +// - p[macgrid.p.flatIdx(i, j, k-1)]); +// } + macgrid.w(i, j, k) -= scale * (p[macgrid.p.flatIdx(i, j, k)] + - p[macgrid.p.flatIdx(i, j, k-1)]); + } } } } + + // Color particles + for (Particle *pt : box->particles) + { + glm::vec3 idx = getGridIndex(pt->pos); + pt->color[2] = p[macgrid.p.flatIdx(idx[0], idx[1], idx[2])] - 1.f; + } + + // Check resulting divergences. for (int i=1; i < macgrid.p.x_dim-1; ++i) { @@ -280,39 +317,41 @@ void FlipSolver::computePressure() if (macgrid.marker(i, j, k) == macgrid.marker.FLUID) { float div = 0.f; + int u_idx = macgrid.u.flatIdx(i, j, k); + int v_idx = macgrid.v.flatIdx(i, j, k); + int w_idx = macgrid.w.flatIdx(i, j, k); + float u_div = macgrid.u(i+1, j, k) - macgrid.u(i, j, k); float v_div = macgrid.v(i, j+1, k) - macgrid.v(i, j, k); float w_div = macgrid.w(i, j, k+1) - macgrid.w(i, j, k); - b[macgrid.p.flatIdx(i, j, k)] = -1 * (u_div+v_div+w_div) / CELL_WIDTH; float tmp = -1 * (u_div+v_div+w_div) / CELL_WIDTH; div += tmp; if (abs(div) > 0.1) { + int idx = macgrid.p.flatIdx(i, j, k); + std::cout << u_idx << " "<< v_idx << " "<< w_idx << " " << idx <& tmp, Grid& grid) { - for (int i=0; i < grid.x_dim; ++i) + for (int i=0; i < tmp.x_dim; ++i) { - for (int j=0; j < grid.y_dim; ++j) + for (int j=0; j < tmp.y_dim; ++j) { - for (int k=0; k < grid.z_dim; ++k) + for (int k=0; k < tmp.z_dim; ++k) { + if (grid.flatIdx(i, j, k) == 1451) { + int x =1; + } float accum = 0.f; int count = 0; if (tmp(i, j, k) != macgrid.marker.FLUID) { // RIGHT - if (i+1 < grid.x_dim && tmp(i+1, j, k) == macgrid.marker.FLUID) + if (i+1 < tmp.x_dim && tmp(i+1, j, k) == macgrid.marker.FLUID) { accum += grid(i+1, j, k); count++; @@ -345,7 +387,7 @@ void FlipSolver::extrapolateVelocityComponent(const Grid& tmp, Grid& count++; } // UP - if (j+1 < grid.y_dim && tmp(i, j+1, k) == macgrid.marker.FLUID) + if (j+1 < tmp.y_dim && tmp(i, j+1, k) == macgrid.marker.FLUID) { accum += grid(i, j+1, k); count++; @@ -357,7 +399,7 @@ void FlipSolver::extrapolateVelocityComponent(const Grid& tmp, Grid& count++; } // FRONT - if (k+1 < grid.z_dim && tmp(i, j, k+1) == macgrid.marker.FLUID) + if (k+1 < tmp.z_dim && tmp(i, j, k+1) == macgrid.marker.FLUID) { accum += grid(i, j, k+1); count++; @@ -383,64 +425,35 @@ void FlipSolver::extrapolateVelocity() // Create temporary grids marking "near fluid" cells as fluid cells. // These temporary grids will hold {FLUID | AIR} all AIR cells adjacent // to FLUID cells in the temporary grids need extrapolation. - Grid tmp_u(macgrid.u.x_dim, macgrid.u.y_dim, macgrid.u.z_dim); - Grid tmp_v(macgrid.v.x_dim, macgrid.v.y_dim, macgrid.v.z_dim); - Grid tmp_w(macgrid.w.x_dim, macgrid.w.y_dim, macgrid.w.z_dim); + Grid tmp_u(macgrid.marker.x_dim, macgrid.marker.y_dim, macgrid.marker.z_dim); + Grid tmp_v(macgrid.marker.x_dim, macgrid.marker.y_dim, macgrid.marker.z_dim); + Grid tmp_w(macgrid.marker.x_dim, macgrid.marker.y_dim, macgrid.marker.z_dim); tmp_u.clear(); tmp_v.clear(); tmp_w.clear(); - // Populate u temp grid. - for (int i=1; i < macgrid.u.x_dim; ++i) + for (int i=1; i < macgrid.marker.x_dim; ++i) { - for (int j=1; j < macgrid.u.y_dim; ++j) + for (int j=1; j < macgrid.marker.y_dim; ++j) { - for (int k=1; k < macgrid.u.z_dim; ++k) + for (int k=1; k < macgrid.marker.z_dim; ++k) { if (macgrid.marker(i, j, k) == macgrid.marker.FLUID) { tmp_u(i, j, k) = macgrid.marker.FLUID; + tmp_v(i, j, k) = macgrid.marker.FLUID; + tmp_w(i, j, k) = macgrid.marker.FLUID; } - else if (macgrid.marker(i-1, j, k) == macgrid.marker.FLUID) + if (macgrid.marker(i-1, j, k) == macgrid.marker.FLUID) { tmp_u(i, j, k) = macgrid.marker.FLUID; } - } - } - } - - // Populate v temp grid. - for (int i=1; i < macgrid.v.x_dim; ++i) - { - for (int j=1; j < macgrid.v.y_dim; ++j) - { - for (int k=1; k < macgrid.v.z_dim; ++k) - { - if (macgrid.marker(i, j, k) == macgrid.marker.FLUID) + if (macgrid.marker(i, j-1, k) == macgrid.marker.FLUID) { tmp_v(i, j, k) = macgrid.marker.FLUID; } - else if (macgrid.marker(i, j-1, k) == macgrid.marker.FLUID) - { - tmp_v(i, j, k) = macgrid.marker.FLUID; - } - } - } - } - - // Populate w temp grid. - for (int i=1; i < macgrid.w.x_dim; ++i) - { - for (int j=1; j < macgrid.w.y_dim; ++j) - { - for (int k=1; k < macgrid.w.z_dim; ++k) - { - if (macgrid.marker(i, j, k) == macgrid.marker.FLUID) - { - tmp_w(i, j, k) = macgrid.marker.FLUID; - } - else if (macgrid.marker(i, j, k-1) == macgrid.marker.FLUID) + if (macgrid.marker(i, j, k-1) == macgrid.marker.FLUID) { tmp_w(i, j, k) = macgrid.marker.FLUID; } @@ -458,47 +471,47 @@ void FlipSolver::extrapolateVelocity() void FlipSolver::handleCollisions() { #ifdef TBB - int size = particle_container->particles.size(); + int size = box->particles.size(); tbb::parallel_for(0, size, 1, [=](int i) { float OFFSET_CELL_WIDTH = CELL_WIDTH + .01; - Particle *p = particle_container->particles[i]; + Particle *p = box->particles[i]; // Check to see if p is inside bounding volume - if (p->pos[0] < (particle_container->min_x + CELL_WIDTH) - || p->pos[0] > (particle_container->max_x - CELL_WIDTH)) + if (p->pos[0] < (box->min_x + CELL_WIDTH) + || p->pos[0] > (box->max_x - CELL_WIDTH)) { - p->pos[0] = std::min(std::max(p->pos[0], particle_container->min_x + OFFSET_CELL_WIDTH), particle_container->max_x - OFFSET_CELL_WIDTH); + p->pos[0] = std::min(std::max(p->pos[0], box->min_x + OFFSET_CELL_WIDTH), box->max_x - OFFSET_CELL_WIDTH); } - if (p->pos[1] < (particle_container->min_y + CELL_WIDTH) - || p->pos[1] > (particle_container->max_y - CELL_WIDTH)) + if (p->pos[1] < (box->min_y + CELL_WIDTH) + || p->pos[1] > (box->max_y - CELL_WIDTH)) { - p->pos[1] = std::min(std::max(p->pos[1], particle_container->min_y + OFFSET_CELL_WIDTH), particle_container->max_y - OFFSET_CELL_WIDTH); + p->pos[1] = std::min(std::max(p->pos[1], box->min_y + OFFSET_CELL_WIDTH), box->max_y - OFFSET_CELL_WIDTH); } - if (p->pos[2] < (particle_container->min_z + CELL_WIDTH) - || p->pos[2] > (particle_container->max_z - CELL_WIDTH)) + if (p->pos[2] < (box->min_z + CELL_WIDTH) + || p->pos[2] > (box->max_z - CELL_WIDTH)) { - p->pos[2] = std::min(std::max(p->pos[2], particle_container->min_z + OFFSET_CELL_WIDTH), particle_container->max_z - OFFSET_CELL_WIDTH); + p->pos[2] = std::min(std::max(p->pos[2], box->min_z + OFFSET_CELL_WIDTH), box->max_z - OFFSET_CELL_WIDTH); } }); #else - for (Particle *p : particle_container->particles) + for (Particle *p : box->particles) { float OFFSET_CELL_WIDTH = CELL_WIDTH + .01; // Check to see if p is inside bounding volume - if (p->pos[0] < (particle_container->min_x + CELL_WIDTH) - || p->pos[0] > (particle_container->max_x - CELL_WIDTH)) + if (p->pos[0] < (box->min_x + CELL_WIDTH) + || p->pos[0] > (box->max_x - CELL_WIDTH)) { - p->pos[0] = std::min(std::max(p->pos[0], particle_container->min_x + OFFSET_CELL_WIDTH), particle_container->max_x - OFFSET_CELL_WIDTH); + p->pos[0] = std::min(std::max(p->pos[0], box->min_x + OFFSET_CELL_WIDTH), box->max_x - OFFSET_CELL_WIDTH); } - if (p->pos[1] < (particle_container->min_y + CELL_WIDTH) - || p->pos[1] > (particle_container->max_y - CELL_WIDTH)) + if (p->pos[1] < (box->min_y + CELL_WIDTH) + || p->pos[1] > (box->max_y - CELL_WIDTH)) { - p->pos[1] = std::min(std::max(p->pos[1], particle_container->min_y + OFFSET_CELL_WIDTH), particle_container->max_y - OFFSET_CELL_WIDTH); + p->pos[1] = std::min(std::max(p->pos[1], box->min_y + OFFSET_CELL_WIDTH), box->max_y - OFFSET_CELL_WIDTH); } - if (p->pos[2] < (particle_container->min_z + CELL_WIDTH) - || p->pos[2] > (particle_container->max_z - CELL_WIDTH)) + if (p->pos[2] < (box->min_z + CELL_WIDTH) + || p->pos[2] > (box->max_z - CELL_WIDTH)) { - p->pos[2] = std::min(std::max(p->pos[2], particle_container->min_z + OFFSET_CELL_WIDTH), particle_container->max_z - OFFSET_CELL_WIDTH); + p->pos[2] = std::min(std::max(p->pos[2], box->min_z + OFFSET_CELL_WIDTH), box->max_z - OFFSET_CELL_WIDTH); } } #endif @@ -549,21 +562,72 @@ void FlipSolver::enforceBoundaryConditions() // Using forward Euler for now. void FlipSolver::updateParticlePositions() { - for (Particle *p : particle_container->particles) + for (Particle *p : box->particles) { p->pos += p->velocity * TIME_STEP; } } +float randomBetween(float a, float b) { + float random = ((float) rand()) / (float) RAND_MAX; + float diff = b - a; + float r = random * diff; + return a + r; +} + + void FlipSolver::init() { // Get dimensions of the fluid container. - int x = int(ceil(particle_container->x_dim)); - int y = int(ceil(particle_container->y_dim)); - int z = int(ceil(particle_container->z_dim)); + int x = int(ceil(box->x_dim)); + int y = int(ceil(box->y_dim)); + int z = int(ceil(box->z_dim)); constructMacGrid(x, y, z); + +//#ifdef RANDOM_SEED +// // Init particles +// float min = box->min_x + CELL_WIDTH; +// +// int num_cells = (box->max_x - box->min_x) / CELL_WIDTH; +// +// for (float i=0; i < num_cells; i++) +// { +// for (float j=0; j < num_cells; j++) +// { +// for (float k=0; k < num_cells; k++) +// { +// for (int n=0; n < PARTICLES_PER_CELL; n++) +// { +// float x_min = box->min_x + (CELL_WIDTH * i); +// float y_min = box->min_y + (CELL_WIDTH * j); +// float z_min = box->min_z + (CELL_WIDTH * k); +// +// float x = randomBetween(x_min, x_min + CELL_WIDTH); +// float y = randomBetween(y_min, y_min + CELL_WIDTH); +// float z = randomBetween(z_min, z_min + CELL_WIDTH); +// +// glm::vec3 pos(x, y, z); +// glm::vec3 vel = glm::vec3(0.f, 0.f, 0.f); +// box->particles.push_back(new Particle(pos, vel)); +// } +// } +// } +// } +//#else +// for (float i=box->init_min_x; i < box->init_max_x; i += box->separation) { +// for (float j=box->init_min_y; j < box->init_max_y; j += box->separation) { +// for (float k=box->init_min_z; k < box->init_max_z; k += box->separation) { +// glm::vec3 pos(i, j, k); +// glm::vec3 vel = glm::vec3(0.f, 0.f, 0.f); +// box->particles.push_back(new Particle(pos, vel)); +// //std::cout << vel[0] << " " << vel[1] << " " << vel[2] << std::endl; +// } +// } +// } +//#endif + applyGravity(); } @@ -606,6 +670,7 @@ void FlipSolver::storeParticleVelocityToGridComponent(Particle *p, Grid & return; } + for (int n=0; n < 2; ++n) { for (int m=0; m < 2; ++m) @@ -618,12 +683,12 @@ void FlipSolver::storeParticleVelocityToGridComponent(Particle *p, Grid & if ((I < grid.x_dim) && (J < grid.y_dim) && (K < grid.z_dim)) { // Calculate weight based on distance from cell center. - glm::vec3 face_pos(particle_container->min_x + I * CELL_WIDTH, - particle_container->min_y + J * CELL_WIDTH, - particle_container->min_z + K * CELL_WIDTH); + glm::vec3 face_pos(box->min_x + I * CELL_WIDTH, + box->min_y + J * CELL_WIDTH, + box->min_z + K * CELL_WIDTH); face_pos[(dim + 1) % 3] += 0.5f * CELL_WIDTH; face_pos[(dim + 2) % 3] += 0.5f * CELL_WIDTH; - float weight = 1.f / glm::length(face_pos-p->pos); + float weight = glm::length(face_pos-p->pos) / (CELL_WIDTH * CELL_WIDTH); // Store velocity contribution and increment particle counter. grid(I, J, K) += weight * p->velocity[dim]; @@ -642,10 +707,10 @@ void FlipSolver::storeParticleVelocityToGridComponent(Particle *p, Grid & void FlipSolver::storeParticleVelocityToGrid() { #ifdef TBB - int size = particle_container->particles.size(); + int size = box->particles.size(); tbb::parallel_for(0, size, 1, [=](int i) { - Particle *p = particle_container->particles[i]; + Particle *p = box->particles[i]; // Do u_grid update. storeParticleVelocityToGridComponent(p, macgrid.u, 0); // Do v_grid update. @@ -654,7 +719,7 @@ void FlipSolver::storeParticleVelocityToGrid() storeParticleVelocityToGridComponent(p, macgrid.w, 2); }); #else - for (Particle *p : particle_container->particles) + for (Particle *p : box->particles) { // Do u_grid update. storeParticleVelocityToGridComponent(p, macgrid.u, 0); @@ -689,14 +754,14 @@ glm::vec3 FlipSolver::getVelocityGridIndex(const glm::vec3 &pos, int dim) glm::vec3 FlipSolver::getGridIndex(const glm::vec3 &pos) { // Transform to index space by subtracting minimum bounds and dividing by grid resolution. - int i = int(floor((pos[0] - particle_container->min_x) / CELL_WIDTH)); - int j = int(floor((pos[1] - particle_container->min_y) / CELL_WIDTH)); - int k = int(floor((pos[2] - particle_container->min_z) / CELL_WIDTH)); + int i = int(floor((pos[0] - box->min_x) / CELL_WIDTH)); + int j = int(floor((pos[1] - box->min_y) / CELL_WIDTH)); + int k = int(floor((pos[2] - box->min_z) / CELL_WIDTH)); // Clamp values. - i = std::min(std::max(i, 0), int(particle_container->x_dim * RES -1)); - j = std::min(std::max(j, 0), int(particle_container->y_dim * RES -1)); - k = std::min(std::max(k, 0), int(particle_container->z_dim * RES -1)); + i = std::min(std::max(i, 0), int(box->x_dim * RES -1)); + j = std::min(std::max(j, 0), int(box->y_dim * RES -1)); + k = std::min(std::max(k, 0), int(box->z_dim * RES -1)); return glm::vec3(i, j, k); } @@ -721,7 +786,7 @@ float FlipSolver::interpolateVelocityComponent(Particle *p, const Grid &g int kk = next_idx[2]; // Do x direction. - float x_uVal = (p->pos[0] - ((i * CELL_WIDTH) + particle_container->min_x)) / CELL_WIDTH; + float x_uVal = (p->pos[0] - ((i * CELL_WIDTH) + box->min_x)) / CELL_WIDTH; float tmp1 = MATHIF(i!=ii, lerp(grid(i, j, k), grid(ii, j, k), x_uVal), grid(i, j, k)); float tmp2 = MATHIF(i!=ii, lerp(grid(i, jj, k), grid(ii, jj, k), x_uVal), grid(i, jj, k)); float tmp3 = MATHIF(i!=ii, lerp(grid(i, j, kk), grid(ii, j, kk), x_uVal), grid(i, j, kk)); @@ -730,12 +795,12 @@ float FlipSolver::interpolateVelocityComponent(Particle *p, const Grid &g //std::cout << tmp1 << " " << tmp2 << " " << tmp3 << " " << tmp4 << std::endl; // Do y direction. - float y_uVal = (p->pos[1] - ((j * CELL_WIDTH) + particle_container->min_y)) / CELL_WIDTH; + float y_uVal = (p->pos[1] - ((j * CELL_WIDTH) + box->min_y)) / CELL_WIDTH; float tmp5 = MATHIF(j!=jj, lerp(tmp1, tmp2, y_uVal), tmp1); float tmp6 = MATHIF(j!=jj, lerp(tmp3, tmp4, y_uVal), tmp3); // Do z direction. - float z_uVal = (p->pos[2] - ((k * CELL_WIDTH) + particle_container->min_z)) / CELL_WIDTH; + float z_uVal = (p->pos[2] - ((k * CELL_WIDTH) + box->min_z)) / CELL_WIDTH; float THING = MATHIF(k!=kk, lerp(tmp5, tmp6, z_uVal), tmp5); return THING; } @@ -758,10 +823,10 @@ void FlipSolver::gridVelocityToParticle() storeDeltaVelocity(macgrid.w_old, macgrid.w); #ifdef TBB - int size = particle_container->particles.size(); + int size = box->particles.size(); tbb::parallel_for(0, size, 1, [=](int i) { - Particle *p = particle_container->particles[i]; + Particle *p = box->particles[i]; // Get PIC components. float pic_x = interpolateVelocityComponent(p, macgrid.u, 0); @@ -778,7 +843,7 @@ void FlipSolver::gridVelocityToParticle() p->velocity[2] = 0.05f * pic_z + 0.95f * flip_z; }); #else - for (Particle *p : particle_container->particles) + for (Particle *p : box->particles) { // Get PIC components. float pic_x = interpolateVelocityComponent(p, macgrid.u, 0); @@ -786,14 +851,14 @@ void FlipSolver::gridVelocityToParticle() float pic_z = interpolateVelocityComponent(p, macgrid.w, 2); // Get FLIP components. "old" grids currently contain delta velocity. -// float flip_x = p->velocity[0] + interpolateVelocityComponent(p, macgrid.u_old, 0); -// float flip_y = p->velocity[1] + interpolateVelocityComponent(p, macgrid.v_old, 1); -// float flip_z = p->velocity[2] + interpolateVelocityComponent(p, macgrid.w_old, 2); + float flip_x = p->velocity[0] + interpolateVelocityComponent(p, macgrid.u_old, 0); + float flip_y = p->velocity[1] + interpolateVelocityComponent(p, macgrid.v_old, 1); + float flip_z = p->velocity[2] + interpolateVelocityComponent(p, macgrid.w_old, 2); // p->velocity[0] = 0.05f * pic_x + 0.95f * flip_x; // p->velocity[1] = 0.05f * pic_y + 0.95f * flip_y; // p->velocity[2] = 0.05f * pic_z + 0.95f * flip_z; - +// p->velocity[0] = pic_x; p->velocity[1] = pic_y; p->velocity[2] = pic_z; diff --git a/src/fluidSolver/fluidSolver.hpp b/src/fluidSolver/fluidSolver.hpp index 9221af13..62a7c234 100644 --- a/src/fluidSolver/fluidSolver.hpp +++ b/src/fluidSolver/fluidSolver.hpp @@ -14,15 +14,15 @@ #include typedef Eigen::SparseMatrix SpMat; // declares a column-major sparse matrix type of double -typedef Eigen::Triplet Tri; +typedef Eigen::Triplet Tri; class FluidSolver{ public: FluidSolver() {} - FluidSolver(ParticleContainer *particles) : particle_container(particles) {} + FluidSolver(ParticleContainer *particles) : box(particles) {} virtual void init() = 0; - ParticleContainer *particle_container = NULL; + ParticleContainer *box = NULL; }; class FlipSolver : public FluidSolver { diff --git a/src/fluidSolver/grid.hpp b/src/fluidSolver/grid.hpp index 0207acb4..55376760 100644 --- a/src/fluidSolver/grid.hpp +++ b/src/fluidSolver/grid.hpp @@ -96,7 +96,7 @@ class Grid { void clear() { - cells = std::vector(x_dim*y_dim*z_dim, 0.f); + cells = std::vector(x_dim*y_dim*z_dim, 0); } void printGrid() diff --git a/src/geom/particles.cpp b/src/geom/particles.cpp index 953faf48..858c7bf9 100644 --- a/src/geom/particles.cpp +++ b/src/geom/particles.cpp @@ -18,8 +18,14 @@ void ParticleContainer::initParticles(const glm::vec3 &bounds, const glm::vec3 & x_dim = max_x - min_x; y_dim = max_y - min_y; z_dim = max_z - min_z; + + init_min_x = -bounds[0]; + init_min_y = -bounds[1]; + init_min_z = -bounds[2]; + init_max_x = bounds[0]; + init_max_y = bounds[1]; + init_max_z = bounds[2]; - // Divide by two to center around the origin. glm::vec3 centered_bounds = bounds / 2.f; for (float i=-centered_bounds[0]; i < centered_bounds[0]; i += separation) { for (float j=-centered_bounds[1]; j < centered_bounds[1]; j += separation) { @@ -31,7 +37,7 @@ void ParticleContainer::initParticles(const glm::vec3 &bounds, const glm::vec3 & } } } - + num_indicies = particles.size(); //std::cout << "SIZE" << num_indicies << std::endl; } @@ -57,9 +63,9 @@ void ParticleContainer::create() { g_vertex_buffer_data.push_back(p->pos[1]); g_vertex_buffer_data.push_back(p->pos[2]); - g_color_buffer_data.push_back(0.0f); - g_color_buffer_data.push_back(0.0f); - g_color_buffer_data.push_back(0.5f); + g_color_buffer_data.push_back(p->color[0]); + g_color_buffer_data.push_back(p->color[1]); + g_color_buffer_data.push_back(p->color[2]); } glGenBuffers(1, &vertexbuffer); diff --git a/src/geom/particles.hpp b/src/geom/particles.hpp index b78eece5..86f13938 100644 --- a/src/geom/particles.hpp +++ b/src/geom/particles.hpp @@ -12,11 +12,12 @@ class Particle { public: - Particle(const glm::vec3 &pos, const glm::vec3 &vel) : pos(pos), velocity(vel) {} + Particle(const glm::vec3 &pos, const glm::vec3 &vel) : pos(pos), velocity(vel), color(0.f) {} ~Particle(); glm::vec3 pos; glm::vec3 velocity; + glm::vec3 color; int dead; }; @@ -43,6 +44,14 @@ class ParticleContainer : public Geometry float max_x; float max_y; float max_z; + + float init_min_x; + float init_min_y; + float init_min_z; + float init_max_x; + float init_max_y; + float init_max_z; + float x_dim; float y_dim; float z_dim; diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index 9bb222d6..9b3d5c52 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -60,9 +60,6 @@ void Scene::drawScene(GLuint &programID, GLuint &MatrixID, Camera &camera) { // Use our shader glUseProgram(programID); - - - Geometry * geom = objects[1]; for (Geometry *geom : objects) { geom->create(); // Model matrix : an identity matrix (model will be at the origin) diff --git a/src/scene/scene.json b/src/scene/scene.json index f7d6079d..6b233ea0 100644 --- a/src/scene/scene.json +++ b/src/scene/scene.json @@ -1,13 +1,13 @@ { "containerDim" : { - "scaleX" : 4.0, - "scaleY" : 4.0, - "scaleZ" : 4.0 + "scaleX" : 2.0, + "scaleY" : 2.0, + "scaleZ" : 2.0 }, "particleDim" : { - "boundX" : 2.0, - "boundY" : 2.0, - "boundZ" : 2.0 + "boundX" : 1.0, + "boundY" : 1.0, + "boundZ" : 1.0 }, "particleSeparation" : 0.1 } \ No newline at end of file From fd38cf8612f12aa248f409541b454b8f379aad69 Mon Sep 17 00:00:00 2001 From: rahwang Date: Mon, 11 Apr 2016 12:45:42 -0400 Subject: [PATCH 17/23] More bug fixes --- .DS_Store | Bin 0 -> 6148 bytes Debug/Thanda | Bin 0 -> 1604620 bytes Release/Thanda | Bin 0 -> 1208052 bytes nuparu/include/Eigen/Array | 11 - nuparu/include/Eigen/COPYING.BSD | 26 - nuparu/include/Eigen/COPYING.GPL | 674 ----- nuparu/include/Eigen/COPYING.LGPL | 502 ---- nuparu/include/Eigen/COPYING.MINPACK | 52 - nuparu/include/Eigen/COPYING.MPL2 | 373 --- nuparu/include/Eigen/COPYING.README | 18 - nuparu/include/Eigen/Cholesky | 14 +- nuparu/include/Eigen/CholmodSupport | 11 +- nuparu/include/Eigen/Core | 201 +- nuparu/include/Eigen/Eigen | 2 +- nuparu/include/Eigen/Eigen2Support | 82 - nuparu/include/Eigen/Eigenvalues | 7 + nuparu/include/Eigen/Geometry | 49 +- nuparu/include/Eigen/Householder | 7 + nuparu/include/Eigen/IterativeLinearSolvers | 24 +- nuparu/include/Eigen/Jacobi | 7 + nuparu/include/Eigen/LU | 18 +- nuparu/include/Eigen/LeastSquares | 32 - nuparu/include/Eigen/MetisSupport | 7 + nuparu/include/Eigen/OrderingMethods | 7 + nuparu/include/Eigen/PaStiXSupport | 11 +- nuparu/include/Eigen/PardisoSupport | 9 +- nuparu/include/Eigen/QR | 20 +- nuparu/include/Eigen/QtAlignedMalloc | 6 + nuparu/include/Eigen/SPQRSupport | 9 +- nuparu/include/Eigen/SVD | 22 +- nuparu/include/Eigen/Sparse | 13 +- nuparu/include/Eigen/SparseCholesky | 2 - nuparu/include/Eigen/SparseCore | 35 +- nuparu/include/Eigen/SparseLU | 3 - nuparu/include/Eigen/SparseQR | 10 +- nuparu/include/Eigen/StdDeque | 2 +- nuparu/include/Eigen/StdList | 2 +- nuparu/include/Eigen/StdVector | 2 +- nuparu/include/Eigen/SuperLUSupport | 13 +- nuparu/include/Eigen/UmfPackSupport | 10 +- nuparu/include/Eigen/src/Cholesky/LDLT.h | 233 +- nuparu/include/Eigen/src/Cholesky/LLT.h | 106 +- nuparu/include/Eigen/src/Cholesky/LLT_MKL.h | 12 +- .../Eigen/src/CholmodSupport/CholmodSupport.h | 149 +- nuparu/include/Eigen/src/Core/Array.h | 127 +- nuparu/include/Eigen/src/Core/ArrayBase.h | 70 +- nuparu/include/Eigen/src/Core/ArrayWrapper.h | 57 +- nuparu/include/Eigen/src/Core/Assign.h | 533 +--- .../include/Eigen/src/Core/AssignEvaluator.h | 810 ++++++ nuparu/include/Eigen/src/Core/Assign_MKL.h | 254 +- nuparu/include/Eigen/src/Core/BandMatrix.h | 37 +- nuparu/include/Eigen/src/Core/Block.h | 125 +- nuparu/include/Eigen/src/Core/BooleanRedux.h | 50 +- nuparu/include/Eigen/src/Core/CMakeLists.txt | 1 + .../include/Eigen/src/Core/CommaInitializer.h | 24 +- .../include/Eigen/src/Core/CoreEvaluators.h | 1376 ++++++++++ nuparu/include/Eigen/src/Core/CoreIterators.h | 140 +- nuparu/include/Eigen/src/Core/CwiseBinaryOp.h | 121 +- .../include/Eigen/src/Core/CwiseNullaryOp.h | 125 +- nuparu/include/Eigen/src/Core/CwiseUnaryOp.h | 57 +- .../include/Eigen/src/Core/CwiseUnaryView.h | 47 +- nuparu/include/Eigen/src/Core/DenseBase.h | 359 ++- .../include/Eigen/src/Core/DenseCoeffsBase.h | 243 +- nuparu/include/Eigen/src/Core/DenseStorage.h | 470 +++- nuparu/include/Eigen/src/Core/Diagonal.h | 58 +- .../include/Eigen/src/Core/DiagonalMatrix.h | 133 +- .../include/Eigen/src/Core/DiagonalProduct.h | 106 +- nuparu/include/Eigen/src/Core/Dot.h | 60 +- nuparu/include/Eigen/src/Core/EigenBase.h | 76 +- nuparu/include/Eigen/src/Core/Flagged.h | 140 - .../Eigen/src/Core/ForceAlignedAccess.h | 24 +- nuparu/include/Eigen/src/Core/Functors.h | 985 ------- nuparu/include/Eigen/src/Core/Fuzzy.h | 13 +- .../include/Eigen/src/Core/GeneralProduct.h | 436 +--- .../Eigen/src/Core/GenericPacketMath.h | 329 ++- .../include/Eigen/src/Core/GlobalFunctions.h | 67 +- nuparu/include/Eigen/src/Core/IO.h | 16 +- nuparu/include/Eigen/src/Core/Inverse.h | 117 + nuparu/include/Eigen/src/Core/Map.h | 69 +- nuparu/include/Eigen/src/Core/MapBase.h | 61 +- nuparu/include/Eigen/src/Core/MathFunctions.h | 517 +++- nuparu/include/Eigen/src/Core/Matrix.h | 204 +- nuparu/include/Eigen/src/Core/MatrixBase.h | 362 +-- nuparu/include/Eigen/src/Core/NestByValue.h | 20 +- nuparu/include/Eigen/src/Core/NoAlias.h | 60 +- nuparu/include/Eigen/src/Core/NumTraits.h | 45 +- .../Eigen/src/Core/PermutationMatrix.h | 328 +-- .../include/Eigen/src/Core/PlainObjectBase.h | 366 ++- nuparu/include/Eigen/src/Core/Product.h | 222 ++ nuparu/include/Eigen/src/Core/ProductBase.h | 278 -- .../Eigen/src/Core/ProductEvaluators.h | 1061 ++++++++ nuparu/include/Eigen/src/Core/Random.h | 55 +- nuparu/include/Eigen/src/Core/Redux.h | 178 +- nuparu/include/Eigen/src/Core/Ref.h | 95 +- nuparu/include/Eigen/src/Core/Replicate.h | 66 +- nuparu/include/Eigen/src/Core/ReturnByValue.h | 38 +- nuparu/include/Eigen/src/Core/Reverse.h | 181 +- nuparu/include/Eigen/src/Core/Select.h | 22 +- .../include/Eigen/src/Core/SelfAdjointView.h | 212 +- .../Eigen/src/Core/SelfCwiseBinaryOp.h | 176 +- nuparu/include/Eigen/src/Core/Solve.h | 173 ++ .../include/Eigen/src/Core/SolveTriangular.h | 70 +- nuparu/include/Eigen/src/Core/SolverBase.h | 130 + .../include/Eigen/src/Core/SpecialFunctions.h | 160 ++ nuparu/include/Eigen/src/Core/StableNorm.h | 75 +- nuparu/include/Eigen/src/Core/Stride.h | 21 +- nuparu/include/Eigen/src/Core/Swap.h | 149 +- nuparu/include/Eigen/src/Core/Transpose.h | 146 +- .../include/Eigen/src/Core/Transpositions.h | 185 +- .../include/Eigen/src/Core/TriangularMatrix.h | 1060 ++++---- nuparu/include/Eigen/src/Core/VectorBlock.h | 2 + nuparu/include/Eigen/src/Core/VectorwiseOp.h | 315 ++- nuparu/include/Eigen/src/Core/Visitor.h | 62 +- .../Eigen/src/Core/arch/AVX/CMakeLists.txt | 6 + .../include/Eigen/src/Core/arch/AVX/Complex.h | 463 ++++ .../Eigen/src/Core/arch/AVX/MathFunctions.h | 441 ++++ .../Eigen/src/Core/arch/AVX/PacketMath.h | 607 +++++ .../Eigen/src/Core/arch/AVX/TypeCasting.h | 51 + .../Eigen/src/Core/arch/AltiVec/Complex.h | 249 +- .../src/Core/arch/AltiVec/MathFunctions.h | 290 +++ .../Eigen/src/Core/arch/AltiVec/PacketMath.h | 548 +++- .../Eigen/src/Core/arch/CMakeLists.txt | 9 +- .../Eigen/src/Core/arch/CUDA/CMakeLists.txt | 6 + .../Eigen/src/Core/arch/CUDA/MathFunctions.h | 112 + .../Eigen/src/Core/arch/CUDA/PacketMath.h | 309 +++ .../Eigen/src/Core/arch/NEON/Complex.h | 223 +- .../Eigen/src/Core/arch/NEON/MathFunctions.h | 91 + .../Eigen/src/Core/arch/NEON/PacketMath.h | 353 ++- .../include/Eigen/src/Core/arch/SSE/Complex.h | 75 +- .../Eigen/src/Core/arch/SSE/MathFunctions.h | 79 +- .../Eigen/src/Core/arch/SSE/PacketMath.h | 372 ++- .../Eigen/src/Core/arch/SSE/TypeCasting.h | 77 + .../src/Core/functors/AssignmentFunctors.h | 166 ++ .../Eigen/src/Core/functors/BinaryFunctors.h | 523 ++++ .../Eigen/src/Core/functors/CMakeLists.txt | 6 + .../Eigen/src/Core/functors/NullaryFunctors.h | 150 ++ .../Eigen/src/Core/functors/StlFunctors.h | 132 + .../Eigen/src/Core/functors/UnaryFunctors.h | 778 ++++++ .../src/Core/products/CoeffBasedProduct.h | 441 ---- .../Core/products/GeneralBlockPanelKernel.h | 2306 ++++++++++++----- .../src/Core/products/GeneralMatrixMatrix.h | 365 +-- .../products/GeneralMatrixMatrixTriangular.h | 80 +- .../Core/products/GeneralMatrixMatrix_MKL.h | 2 + .../src/Core/products/GeneralMatrixVector.h | 310 ++- .../Core/products/GeneralMatrixVector_MKL.h | 25 +- .../Eigen/src/Core/products/Parallelizer.h | 68 +- .../Core/products/SelfadjointMatrixMatrix.h | 297 ++- .../Core/products/SelfadjointMatrixVector.h | 119 +- .../products/SelfadjointMatrixVector_MKL.h | 13 +- .../src/Core/products/SelfadjointProduct.h | 2 - .../Core/products/SelfadjointRank2Update.h | 8 +- .../Core/products/TriangularMatrixMatrix.h | 126 +- .../products/TriangularMatrixMatrix_MKL.h | 8 +- .../Core/products/TriangularMatrixVector.h | 168 +- .../products/TriangularMatrixVector_MKL.h | 2 - .../Core/products/TriangularSolverMatrix.h | 77 +- .../Core/products/TriangularSolverVector.h | 24 +- nuparu/include/Eigen/src/Core/util/BlasUtil.h | 157 +- .../include/Eigen/src/Core/util/Constants.h | 138 +- .../src/Core/util/DisableStupidWarnings.h | 7 +- .../Eigen/src/Core/util/ForwardDeclarations.h | 106 +- .../include/Eigen/src/Core/util/MKL_support.h | 51 +- nuparu/include/Eigen/src/Core/util/Macros.h | 673 ++++- nuparu/include/Eigen/src/Core/util/Memory.h | 485 ++-- nuparu/include/Eigen/src/Core/util/Meta.h | 195 +- .../Eigen/src/Core/util/StaticAssert.h | 30 +- .../include/Eigen/src/Core/util/XprHelper.h | 431 ++- .../include/Eigen/src/Eigen2Support/Block.h | 126 - .../Eigen/src/Eigen2Support/CMakeLists.txt | 8 - .../include/Eigen/src/Eigen2Support/Cwise.h | 192 -- .../Eigen/src/Eigen2Support/CwiseOperators.h | 298 --- .../src/Eigen2Support/Geometry/AlignedBox.h | 159 -- .../Eigen/src/Eigen2Support/Geometry/All.h | 115 - .../src/Eigen2Support/Geometry/AngleAxis.h | 214 -- .../src/Eigen2Support/Geometry/CMakeLists.txt | 6 - .../src/Eigen2Support/Geometry/Hyperplane.h | 254 -- .../Eigen2Support/Geometry/ParametrizedLine.h | 141 - .../src/Eigen2Support/Geometry/Quaternion.h | 495 ---- .../src/Eigen2Support/Geometry/Rotation2D.h | 145 -- .../src/Eigen2Support/Geometry/RotationBase.h | 123 - .../src/Eigen2Support/Geometry/Scaling.h | 167 -- .../src/Eigen2Support/Geometry/Transform.h | 786 ------ .../src/Eigen2Support/Geometry/Translation.h | 184 -- nuparu/include/Eigen/src/Eigen2Support/LU.h | 120 - nuparu/include/Eigen/src/Eigen2Support/Lazy.h | 71 - .../Eigen/src/Eigen2Support/LeastSquares.h | 170 -- .../include/Eigen/src/Eigen2Support/Macros.h | 20 - .../Eigen/src/Eigen2Support/MathFunctions.h | 57 - .../include/Eigen/src/Eigen2Support/Memory.h | 45 - nuparu/include/Eigen/src/Eigen2Support/Meta.h | 75 - .../include/Eigen/src/Eigen2Support/Minor.h | 117 - nuparu/include/Eigen/src/Eigen2Support/QR.h | 67 - nuparu/include/Eigen/src/Eigen2Support/SVD.h | 638 ----- .../src/Eigen2Support/TriangularSolver.h | 42 - .../Eigen/src/Eigen2Support/VectorBlock.h | 94 - .../src/Eigenvalues/ComplexEigenSolver.h | 27 +- .../Eigen/src/Eigenvalues/ComplexSchur.h | 19 +- .../Eigen/src/Eigenvalues/ComplexSchur_MKL.h | 9 +- .../Eigen/src/Eigenvalues/EigenSolver.h | 88 +- .../src/Eigenvalues/GeneralizedEigenSolver.h | 13 +- .../GeneralizedSelfAdjointEigenSolver.h | 3 +- .../src/Eigenvalues/HessenbergDecomposition.h | 15 +- nuparu/include/Eigen/src/Eigenvalues/RealQZ.h | 28 +- .../include/Eigen/src/Eigenvalues/RealSchur.h | 29 +- .../Eigen/src/Eigenvalues/RealSchur_MKL.h | 10 +- .../src/Eigenvalues/SelfAdjointEigenSolver.h | 421 +-- .../Eigenvalues/SelfAdjointEigenSolver_MKL.h | 8 +- .../src/Eigenvalues/Tridiagonalization.h | 35 +- .../include/Eigen/src/Geometry/AlignedBox.h | 91 +- nuparu/include/Eigen/src/Geometry/AngleAxis.h | 37 +- .../include/Eigen/src/Geometry/EulerAngles.h | 6 +- .../include/Eigen/src/Geometry/Homogeneous.h | 200 +- .../include/Eigen/src/Geometry/Hyperplane.h | 14 +- .../include/Eigen/src/Geometry/OrthoMethods.h | 31 +- .../Eigen/src/Geometry/ParametrizedLine.h | 2 +- .../include/Eigen/src/Geometry/Quaternion.h | 118 +- .../include/Eigen/src/Geometry/Rotation2D.h | 54 +- nuparu/include/Eigen/src/Geometry/Scaling.h | 8 +- nuparu/include/Eigen/src/Geometry/Transform.h | 124 +- nuparu/include/Eigen/src/Geometry/Umeyama.h | 11 +- .../Eigen/src/Geometry/arch/Geometry_SSE.h | 56 +- .../Eigen/src/Householder/BlockHouseholder.h | 74 +- .../Eigen/src/Householder/Householder.h | 3 +- .../src/Householder/HouseholderSequence.h | 48 +- .../BasicPreconditioners.h | 118 +- .../src/IterativeLinearSolvers/BiCGSTAB.h | 119 +- .../ConjugateGradient.h | 162 +- .../IncompleteCholesky.h | 368 +++ .../IterativeLinearSolvers/IncompleteLUT.h | 153 +- .../IterativeSolverBase.h | 308 ++- .../LeastSquareConjugateGradient.h | 216 ++ .../IterativeLinearSolvers/SolveWithGuess.h | 109 + nuparu/include/Eigen/src/Jacobi/Jacobi.h | 29 +- nuparu/include/Eigen/src/LU/Determinant.h | 2 +- nuparu/include/Eigen/src/LU/FullPivLU.h | 285 +- .../Eigen/src/LU/{Inverse.h => InverseImpl.h} | 75 +- nuparu/include/Eigen/src/LU/PartialPivLU.h | 182 +- .../include/Eigen/src/LU/arch/Inverse_SSE.h | 19 +- .../Eigen/src/MetisSupport/MetisSupport.h | 18 +- .../include/Eigen/src/OrderingMethods/Amd.h | 95 +- .../Eigen/src/OrderingMethods/Eigen_Colamd.h | 390 +-- .../Eigen/src/OrderingMethods/Ordering.h | 52 +- .../Eigen/src/PaStiXSupport/PaStiXSupport.h | 139 +- .../Eigen/src/PardisoSupport/PardisoSupport.h | 222 +- .../Eigen/src/QR/ColPivHouseholderQR.h | 171 +- .../Eigen/src/QR/ColPivHouseholderQR_MKL.h | 7 +- .../Eigen/src/QR/FullPivHouseholderQR.h | 225 +- nuparu/include/Eigen/src/QR/HouseholderQR.h | 172 +- .../include/Eigen/src/QR/HouseholderQR_MKL.h | 25 +- .../src/SPQRSupport/SuiteSparseQRSupport.h | 174 +- nuparu/include/Eigen/src/SVD/BDCSVD.h | 1208 +++++++++ nuparu/include/Eigen/src/SVD/JacobiSVD.h | 246 +- nuparu/include/Eigen/src/SVD/JacobiSVD_MKL.h | 4 +- nuparu/include/Eigen/src/SVD/SVDBase.h | 314 +++ .../Eigen/src/SVD/UpperBidiagonalization.h | 326 ++- .../src/SparseCholesky/SimplicialCholesky.h | 294 ++- .../SparseCholesky/SimplicialCholesky_impl.h | 34 +- .../include/Eigen/src/SparseCore/AmbiVector.h | 98 +- .../Eigen/src/SparseCore/CompressedStorage.h | 138 +- .../ConservativeSparseSparseProduct.h | 220 +- .../Eigen/src/SparseCore/MappedSparseMatrix.h | 164 +- .../Eigen/src/SparseCore/SparseAssign.h | 205 ++ .../Eigen/src/SparseCore/SparseBlock.h | 991 ++++--- .../Eigen/src/SparseCore/SparseColEtree.h | 48 +- .../src/SparseCore/SparseCompressedBase.h | 277 ++ .../src/SparseCore/SparseCwiseBinaryOp.h | 375 ++- .../Eigen/src/SparseCore/SparseCwiseUnaryOp.h | 199 +- .../Eigen/src/SparseCore/SparseDenseProduct.h | 403 +-- .../src/SparseCore/SparseDiagonalProduct.h | 224 +- .../include/Eigen/src/SparseCore/SparseDot.h | 17 +- .../Eigen/src/SparseCore/SparseFuzzy.h | 29 +- .../include/Eigen/src/SparseCore/SparseMap.h | 254 ++ .../Eigen/src/SparseCore/SparseMatrix.h | 595 +++-- .../Eigen/src/SparseCore/SparseMatrixBase.h | 263 +- .../Eigen/src/SparseCore/SparsePermutation.h | 170 +- .../Eigen/src/SparseCore/SparseProduct.h | 285 +- .../Eigen/src/SparseCore/SparseRedux.h | 5 +- .../include/Eigen/src/SparseCore/SparseRef.h | 367 +++ .../src/SparseCore/SparseSelfAdjointView.h | 500 ++-- .../Eigen/src/SparseCore/SparseSolverBase.h | 110 + .../SparseSparseProductWithPruning.h | 91 +- .../Eigen/src/SparseCore/SparseTranspose.h | 111 +- .../src/SparseCore/SparseTriangularView.h | 194 +- .../include/Eigen/src/SparseCore/SparseUtil.h | 111 +- .../Eigen/src/SparseCore/SparseVector.h | 166 +- .../include/Eigen/src/SparseCore/SparseView.h | 205 +- .../Eigen/src/SparseCore/TriangularSolver.h | 114 +- nuparu/include/Eigen/src/SparseLU/SparseLU.h | 303 ++- .../include/Eigen/src/SparseLU/SparseLUImpl.h | 12 +- .../Eigen/src/SparseLU/SparseLU_Memory.h | 60 +- .../Eigen/src/SparseLU/SparseLU_Structs.h | 3 +- .../src/SparseLU/SparseLU_SupernodalMatrix.h | 75 +- .../Eigen/src/SparseLU/SparseLU_Utils.h | 10 +- .../Eigen/src/SparseLU/SparseLU_column_bmod.h | 11 +- .../Eigen/src/SparseLU/SparseLU_column_dfs.h | 38 +- .../src/SparseLU/SparseLU_copy_to_ucol.h | 7 +- .../Eigen/src/SparseLU/SparseLU_gemm_kernel.h | 8 +- .../src/SparseLU/SparseLU_heap_relax_snode.h | 21 +- .../Eigen/src/SparseLU/SparseLU_kernel_bmod.h | 29 +- .../Eigen/src/SparseLU/SparseLU_panel_bmod.h | 14 +- .../Eigen/src/SparseLU/SparseLU_panel_dfs.h | 44 +- .../Eigen/src/SparseLU/SparseLU_pivotL.h | 25 +- .../Eigen/src/SparseLU/SparseLU_pruneL.h | 7 +- .../Eigen/src/SparseLU/SparseLU_relax_snode.h | 12 +- nuparu/include/Eigen/src/SparseQR/SparseQR.h | 361 ++- .../include/Eigen/src/StlSupport/StdDeque.h | 6 +- nuparu/include/Eigen/src/StlSupport/StdList.h | 8 +- .../include/Eigen/src/StlSupport/StdVector.h | 7 +- nuparu/include/Eigen/src/StlSupport/details.h | 2 +- .../Eigen/src/SuperLUSupport/SuperLUSupport.h | 176 +- .../Eigen/src/UmfPackSupport/UmfPackSupport.h | 263 +- nuparu/include/Eigen/src/misc/Image.h | 2 - nuparu/include/Eigen/src/misc/Kernel.h | 4 +- nuparu/include/Eigen/src/misc/Solve.h | 76 - nuparu/include/Eigen/src/misc/SparseSolve.h | 128 - .../Eigen/src/plugins/ArrayCwiseBinaryOps.h | 91 +- .../Eigen/src/plugins/ArrayCwiseUnaryOps.h | 392 ++- .../include/Eigen/src/plugins/BlockMethods.h | 300 ++- .../Eigen/src/plugins/CommonCwiseBinaryOps.h | 1 + .../Eigen/src/plugins/CommonCwiseUnaryOps.h | 51 +- .../Eigen/src/plugins/MatrixCwiseBinaryOps.h | 30 +- .../Eigen/src/plugins/MatrixCwiseUnaryOps.h | 56 +- src/.DS_Store | Bin 8196 -> 8196 bytes src/fluidSolver/fluidSolver.cpp | 132 +- src/scene/scene.json | 12 +- 325 files changed, 31322 insertions(+), 21529 deletions(-) create mode 100644 .DS_Store create mode 100755 Debug/Thanda create mode 100755 Release/Thanda delete mode 100644 nuparu/include/Eigen/Array delete mode 100644 nuparu/include/Eigen/COPYING.BSD delete mode 100644 nuparu/include/Eigen/COPYING.GPL delete mode 100644 nuparu/include/Eigen/COPYING.LGPL delete mode 100644 nuparu/include/Eigen/COPYING.MINPACK delete mode 100644 nuparu/include/Eigen/COPYING.MPL2 delete mode 100644 nuparu/include/Eigen/COPYING.README delete mode 100644 nuparu/include/Eigen/Eigen2Support delete mode 100644 nuparu/include/Eigen/LeastSquares mode change 100644 => 100755 nuparu/include/Eigen/PardisoSupport create mode 100755 nuparu/include/Eigen/src/Core/AssignEvaluator.h mode change 100644 => 100755 nuparu/include/Eigen/src/Core/Assign_MKL.h create mode 100644 nuparu/include/Eigen/src/Core/CoreEvaluators.h delete mode 100644 nuparu/include/Eigen/src/Core/Flagged.h delete mode 100644 nuparu/include/Eigen/src/Core/Functors.h create mode 100644 nuparu/include/Eigen/src/Core/Inverse.h create mode 100644 nuparu/include/Eigen/src/Core/Product.h delete mode 100644 nuparu/include/Eigen/src/Core/ProductBase.h create mode 100755 nuparu/include/Eigen/src/Core/ProductEvaluators.h create mode 100644 nuparu/include/Eigen/src/Core/Solve.h create mode 100644 nuparu/include/Eigen/src/Core/SolverBase.h create mode 100644 nuparu/include/Eigen/src/Core/SpecialFunctions.h mode change 100644 => 100755 nuparu/include/Eigen/src/Core/VectorwiseOp.h create mode 100644 nuparu/include/Eigen/src/Core/arch/AVX/CMakeLists.txt create mode 100644 nuparu/include/Eigen/src/Core/arch/AVX/Complex.h create mode 100644 nuparu/include/Eigen/src/Core/arch/AVX/MathFunctions.h create mode 100644 nuparu/include/Eigen/src/Core/arch/AVX/PacketMath.h create mode 100644 nuparu/include/Eigen/src/Core/arch/AVX/TypeCasting.h create mode 100644 nuparu/include/Eigen/src/Core/arch/AltiVec/MathFunctions.h mode change 100644 => 100755 nuparu/include/Eigen/src/Core/arch/AltiVec/PacketMath.h create mode 100644 nuparu/include/Eigen/src/Core/arch/CUDA/CMakeLists.txt create mode 100644 nuparu/include/Eigen/src/Core/arch/CUDA/MathFunctions.h create mode 100644 nuparu/include/Eigen/src/Core/arch/CUDA/PacketMath.h create mode 100644 nuparu/include/Eigen/src/Core/arch/NEON/MathFunctions.h mode change 100644 => 100755 nuparu/include/Eigen/src/Core/arch/SSE/PacketMath.h create mode 100644 nuparu/include/Eigen/src/Core/arch/SSE/TypeCasting.h create mode 100644 nuparu/include/Eigen/src/Core/functors/AssignmentFunctors.h create mode 100644 nuparu/include/Eigen/src/Core/functors/BinaryFunctors.h create mode 100644 nuparu/include/Eigen/src/Core/functors/CMakeLists.txt create mode 100644 nuparu/include/Eigen/src/Core/functors/NullaryFunctors.h create mode 100644 nuparu/include/Eigen/src/Core/functors/StlFunctors.h create mode 100644 nuparu/include/Eigen/src/Core/functors/UnaryFunctors.h delete mode 100644 nuparu/include/Eigen/src/Core/products/CoeffBasedProduct.h mode change 100644 => 100755 nuparu/include/Eigen/src/Core/products/GeneralMatrixVector_MKL.h mode change 100644 => 100755 nuparu/include/Eigen/src/Core/products/SelfadjointMatrixVector_MKL.h mode change 100644 => 100755 nuparu/include/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h mode change 100644 => 100755 nuparu/include/Eigen/src/Core/util/BlasUtil.h mode change 100644 => 100755 nuparu/include/Eigen/src/Core/util/DisableStupidWarnings.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/Block.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/CMakeLists.txt delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/Cwise.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/CwiseOperators.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/Geometry/AlignedBox.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/Geometry/All.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/Geometry/AngleAxis.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/Geometry/CMakeLists.txt delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/Geometry/Hyperplane.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/Geometry/ParametrizedLine.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/Geometry/Quaternion.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/Geometry/Rotation2D.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/Geometry/RotationBase.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/Geometry/Scaling.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/Geometry/Transform.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/Geometry/Translation.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/LU.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/Lazy.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/LeastSquares.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/Macros.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/MathFunctions.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/Memory.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/Meta.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/Minor.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/QR.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/SVD.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/TriangularSolver.h delete mode 100644 nuparu/include/Eigen/src/Eigen2Support/VectorBlock.h mode change 100644 => 100755 nuparu/include/Eigen/src/Eigenvalues/ComplexSchur_MKL.h mode change 100644 => 100755 nuparu/include/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h mode change 100644 => 100755 nuparu/include/Eigen/src/Eigenvalues/RealQZ.h mode change 100644 => 100755 nuparu/include/Eigen/src/Eigenvalues/RealSchur_MKL.h mode change 100644 => 100755 nuparu/include/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_MKL.h create mode 100644 nuparu/include/Eigen/src/IterativeLinearSolvers/IncompleteCholesky.h create mode 100644 nuparu/include/Eigen/src/IterativeLinearSolvers/LeastSquareConjugateGradient.h create mode 100644 nuparu/include/Eigen/src/IterativeLinearSolvers/SolveWithGuess.h rename nuparu/include/Eigen/src/LU/{Inverse.h => InverseImpl.h} (87%) mode change 100644 => 100755 nuparu/include/Eigen/src/PardisoSupport/PardisoSupport.h mode change 100644 => 100755 nuparu/include/Eigen/src/QR/ColPivHouseholderQR_MKL.h create mode 100644 nuparu/include/Eigen/src/SVD/BDCSVD.h mode change 100644 => 100755 nuparu/include/Eigen/src/SVD/JacobiSVD.h create mode 100644 nuparu/include/Eigen/src/SVD/SVDBase.h create mode 100644 nuparu/include/Eigen/src/SparseCore/SparseAssign.h create mode 100644 nuparu/include/Eigen/src/SparseCore/SparseCompressedBase.h create mode 100644 nuparu/include/Eigen/src/SparseCore/SparseMap.h create mode 100644 nuparu/include/Eigen/src/SparseCore/SparseRef.h create mode 100644 nuparu/include/Eigen/src/SparseCore/SparseSolverBase.h mode change 100644 => 100755 nuparu/include/Eigen/src/SparseLU/SparseLU.h delete mode 100644 nuparu/include/Eigen/src/misc/Solve.h delete mode 100644 nuparu/include/Eigen/src/misc/SparseSolve.h diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..9d3830ba8cbca9b9417fc40435bcd0677db1a627 GIT binary patch literal 6148 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 z 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 z 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%0A2?IC2nC z%iA=4)vvl$|FY5c!zbi%N=CbWPRSn`@`pmsnt|#|o!u>Dq+yp6c14%!qszpR0*3vB zu$K`dor9-Iie|4%8}f;f?8n(n;s;cJrsQM}!H>;|THZE74)Z!XNcG_jwj+atJyhB7 z`VD1wGVJ!k&XKsYtyv_tqY1pp``^ofG-|OgVAx#YV{s^wcEH2e8l^oy@{J5~5 z{n$;2^jgRwMN130v({EUN7!FsZQVCMrtC3>oha-+!VYaA@3>XZG~_x$uBT+Qkna|Y z*Do4!Ss@q9Ky}t2)in+K@~7;`jdhOd;mSVAAvkgrQOkSaU3Mf?^>Ru!{dHiC?Z8pOkt@=en{yvWV zNL?#_K=leG@8J;q*nz0!J=TH!2vfa|((w`1Cs*5!3=?*|veB;JRd#p7?kwzK!VdMi zlcITR9BjzNg#5fq^%F{tG~}E@E|Y=k+(D`f8TP*6?8u=t;s{iyd@WwD<`5iNj;Q55 z)1Dm(RlSvx@nO|_R@r`hAmn~ZhS#4cxuqe$Bjiy+4)eN)qQ&d(hW(hZ^SM-)R`$Qc zP#~!Odo`}NR*@|_w=Sy8Ae#|rE*+Txg9s3ccdN-xxBdS-gv>j<9 z?01z7ug5Dp*05^}+b`@;uRl~Yd)?BIvkE!8OLdHruMM^R_-z&YQ6&S_1%p)oyTVqz zfB~MxSX+C(e-?@(6AXK-urIY`M?zH}q-1 zVL!rDAER`9MD+y2t|IIjF4f;J5U-0Hb`fDu6LzTA!xhb5S2E>_1zxBcZC#QZhcQ`cp%GLCED@ zsy#}6!jSU_d9IMdydI@!@w&KSfA%2|Lv5v5ID| zpD^TYAG063mWdxweR00{@im9w$5)72-ewu7t`ekr;}YAEj>7J$Y4&48^X?- zzUn|rR|{!x$T@_Z%cZ)Bl5Y({fuQ=vQdYf!5b2Hik`ygoXEW?24DhVP+S>Cys_ZF- zJxSPYgdOU2O}FZ=7u$X`7IJeX!|Pr1#Ov1#`Bfo5nt|%;E!-{SEyMn6AlKu)C64OB z%Kn8zaO6isE$=#Fq;pg-UD4b^Zhd2`o+0Efl?>HUN=`K7cp<+hn_z-=ZYhx4ZEbUbBC&yN!;7bT`lA_L%uYC{kXE&Juf$3*@roZJN$Oh+H8eR;^O%S zqo2t=8PjsP={Kh3^eqi@2t^Hor{zw5ZM!o}@`;xqPvSl~OG?mPbMbjPBWiiuNoH^d zAerELUG+;d9Ad!51^j}7vGE+ADd5}&>=ke>yA;81X}HL+tsZzuf~|`d?Awea0uib zh+5u99mzqrv|exGR(coSZrGiLy^a{^G?(d$X4QiYxtNfjr*)m? z(n#64lx=yt+fZ#TZ9hYEd7G-Te&)ZZZ6xlZchgw6>sfyXW=($ZAkkBk7NGQaCw&yB zzd-5Qw$?6Sr?_oho^Ka*(uZv0R0=wRI!+ZMhj0*W>*vN&$|TR3v5>NB9Ow6(li!n^ z-)4%EjxtXAgCyviFX`o-^h=aZOID(kM9(M+Yk9uo zA0)`Fw$2n$zLP^}0^1O!`-7zb!L2re5}j6ia-MC1?KCe5C#jxtNfjS2Fgydp;M*k%pX8$O%Gr?RTY{?xtwzrVAPNzTRxdq51Br9Io`0 z97I*VYzwwurt_#DHTs9t(B>VcWyMTF&0QPAHJa?Cm*MnNl$l!%X%wW0z4@Bx?gmw5t44c$%>@Lmp~ z>USYZ=K%y9+ONE-Xs)5NU)qvK2su&7sG+S&?q$f`g`Cxqto@4A(4_`$)k6)tgs@A~ z+Rn!IkfEI48tUOg4K<*8qW0flyQ!hM6Hr5MQB=3_qjT90-o_s`*)H$J zX04&1lkNCPV%Jm-qG7~nwn?6Qqmf^#)cn0rR2*9S;K|v_LvG@e|x`$~$J;1?nL=_m&_x3|_qbbi)@co`BEt>M(ISk%GjG)d&%vzvmHY>uA z*YoP0Ewrvv?+ukbN7YF&6mly^a?p69dXVaohFwnB6@4vEs)s5$nM3enGoqGv4I#9H4N^T-(c<;t z8MY&XggsQ*XqeH;?qt~Qh225epe2u8(-9(I_%}K6&n5}4TA<5HiKe`FImy+SNU&&1j zxq*BZj<+SNE)^ zb)8Nim$IiT+w$(EwPl|pJ?6c5bOJw&q*Q;k*Eg9?p!^tg0zXld((#l_9k%7;^u3bq zT0Rq}ub_0@MU_J#sKdY^PN!+Mw_Z`1CrD+TF;Z{0yNCmp_jy&B9K^1! zgiX}m`wfyj`WZZ~fkf7I3OZmkj48tf;$zLP2y9ox_fze{#7nMLP_7@3mg2l`a@`Os zRD$qLlu=lYWxZCrElvCw(iYe?sZH z1znwrjARQcVpJaJ#DzahK}Y4_L@EAi4x+i_Q{NCdHayt19apkx2 zbK8|xl3)9v{C*uJ`PDZ0Eq`5HN%CwQ4nKU7AD&UF75w8U_%VZ`s9+s~<>z!MdWoyPf*Qj|dk z++V=gVx&ao?WxlJ9;0M@cq{f9az!CmrgfcanWyY$lug&2+ECq!#}0#8ZKW}+UT4f& zF%o9=p(q)%*-4+u=`F+3<0ze$JV;9>da6=bP46b@Cpo>ClipC$Q#n1ClU`ZUf8zAN zh8j*`N>B7$q6Ac)jtT31&h^8SdvQs&$IrjZl~+!JTzSLe#pApjLgnQ~lAp zgh+nZklPCRuUbZO(CF%WN_SL$XxL8)yO2xuLS;W>*ja=^BMB?_Uy-= zB=G~P+bel7hv3ITL@jT_3{*!2sop%%cH})_cULwxlxLOQz_9TQXJX&4$&Q4o{)Lk9 zVb$*%@}okIbg4e~sd#<69SQ{1e@tTXH$n~@U45o#X(108_A&-|R%30Q{+*`mFARIK zu$!f?x~g0C;t94NO@-W2$?&?Rl4}@pRUvyaP@NX-ZXpc}`)*sV$A4)W*H#^=>RCdbN9#JB(#|+>J5kw|x04OkPAStT=#=&irmXzc z(pH&H>FH0=37r4f?4jNi$vnmzZgMRpxt0yewe@hxHIK>lb`2>?l4m>-M?cd-@|))5 zw>S>@^`j{1nCYZX;`BCQ>4Q1_b=GGl!WT?HHZp`bH_mn@p$&UJT7uk3l^-Swdvge$ z_e7NDl|*Q8Csmaa@sTDt!hlN)xPpSQ;ando;3p0EF#%^&2h1Ku4olLiyEdFshJ3U& zOFlK8%fl1lE0w&3Ly)`yQOmoM5Y$YO|XozJ<7JcxoxO6!MK5F5~xb5`lBmM6P!8>O`;P;u^&1q zcWCe=wN~-nv38lhY{h;pzznv|Np2e~HR0zF{IU?G{m^U1FSHdohKr*_r;2AAa9shv zrC^x#v4SfaaCrgO6|iHLRB>5F^Y;3>AzyFFl5c$`lF`e&q~x<4g5;BkTHe2^8Og!> zAxd{t|K_*tm?-Qi%7*I8pNJhp4f|tZ&lPs4>O@7e>T!l#S;()sRDY@D=M1@!kQ-*8 zIx0wYMZ^A~1v~P~SaAfZn<{%Rhv3LAL}@=%l^qFH{R<`I!>Z4YvHch!qnK` z%aFSZ`5Pg-HYb_?{Y=raISn=J62dM`Ydej8>&N1Dq|z;KYg@2A|2w8XT7827R1SZ& z%S%nGpF0?>{sW4lLw3@AoZg($UB^so{jfngyvshjxRaW*ky9ne$4s9L5<$Z_1S3B| zluO3fE>1GoYJ#mvD>@~8Rl&s-Yqd017jnhILZ#UJk;rdNxrFtN$Sk%R#M(iraFrF|73<7*?L5!RfU*JwK(RpnAo~2b8H@ z(0Pe=LF>5YJW9kzx{Nms_*N4x>Rp1I3X8sBIv#;He=6va8S99)S$dN+MOY1srWmfjxM)vl+=jj)bhS2*$10dOiLuq zc9H>C6L3uh!>m>cE@{Be3HWN1mdiFv??0que7M=ZYRKmsa{UG{^Gh29n(b3cKExr^ z?|wur?=&Gpa?n_4n4(4XkMXu0ql7(1*-(A1x7hKaVfPYto%B_gcB_szf$E>*q zTu;Ca70g{{R{_6bz%L27pMV{+bo)^>n^o74|9F!n|23S;!yWzH~vqNBRkSkh0-*T4(XPonf~U_PH|bNT}-Vl#CCn z?qkRWgj~?2da05KB9CzVEU?` za;x6-iS0)xA$Lzj2@AgI1R zm{pGxcBt3=70q6I40$Q9?pcL(bY2}wDx&e z5_dewSyFBih}9**(Pd%N^ybCP)$$`wU}XQs5BQSCl`n> zrDz33G-*+gmK!(Fwz0D0`dUz~)iu{5Cf9#UNjc~Yc?THSP4c@t-Q>5qD-4`LQ5dN6 z5SIo?o;XAPw8?XKZEg|!CCK~t586vPmvaa$VlkqY*Do1k^MrVr-0nw-_{g@obAVl# zo&xTpVDu;@72M2#8wMPWsAYwKpnd4&9=lF_4_Zzq!P*Rt#U?m(9OTS@lH z)uYI^d5F>-)n3D1%K*HVGbGn~Fv(i5EY?VP@V(p`pM z`A9UP=@&K{_eZlc-${@S&#Ma8a0pF*1)`RBe{m3k`;L{Ah7TLQzn@+7zJeV{D>_Z+ zP-`iAYX#GD2W_Gneya@(m_f#p$o*4|0XI6qfKwDz!wYI*(04R3x!$kAg~4-eom@+5 zuD@~+)tpCjP4Xmgeq|)TAx?h7IlrzHCH^ocy(_0TbaZ^)AC^cTcCfEq`u?KhV+uMt z#3H@6cay_JP%r<-1DU(i#Yk+>4>FaaOilZzM{ENMj7&tuW|D@ z-$?%9_hC4agXV7kF6vf&rjKpMr@|gZYdclYOX)q7Zh2E^b(xK< zojnyV4t}^5YW^E?oZNlub5j%lc0kSl){@g3IO)G~`Y}m=(@8%>=}JiStf8=W9cy{{ z`IMk7=pv?xwZ#@N@^@BaYxYvmk>9wv*uI#9*m5FOev+p#5$XMpq@HrUGTG>Uo%4H{ z^D`}|kLHOM^i^-$vbQDACKBWpWHpl`s2$=$(8rY1JGLkn6$QTO<# zH+#Y(;-^j4yQ{Ea`z6RVk=Rr+Ud|yN{~&64qnu))8OiwP>7X+0>}C7aQ^0)`jBPnq z!OaY~v4AfWV!uLbVjm^r!!^;(kn;%nNhPBuB9(mqRg?yj?|#6NCkQ!g{PU5br3dmF z_F4vbHqqKnO&o3_hRjmB<*j84w$H;vH$zSQM2=HUJT}SH#EWfF6VFl9wL5MDZT9%* zecP}ql64IU^6vO(W68L2*21T3C7oN~a||(vpduf)v)yDZixm zYL-uH&72{ee%47p;!fY`q;HV)cwT<7lRih%M{qiB!c{#Mr6+n4 zD8aSKtbX6AsI(q-MNO#0j(#pd-eguZl!_X{A+$d{3zlqs@ma2@;N4$-O2kJR-#7!V zEa2A^%##obe$Idk3Haw{7#zCE?4e|Qc$0bAkbioGC12>t<>B4mi%Q><06Wt51Il<6S@ zUdC&CR%2B?L-dq_zcAp*0v;gX(3)tiXs(IH-E6m-3c00{(Rm%OFOq8*a#bN0b0h~% z&gKYG-N3N#MsY3wOD6$r)uWYtfkUX}R75TBk*C;>P}OTG86Q@CyQ{5wmXPK7t#S^r zu98O^@<<^M6SAxQ$d00;qQ&bk47--FV_mAVD7&m-KQHVT(pMenR$ar8(<-tb*Sd)x z@Oo=K@%lK2;KyM^>G+Qtnl_IhueYE9(nnNZ=wdtK7xn~YV_O}p?16^ePuK~<4)wab zqS@=whWwI{E4frxR`RokTtLV#WuW@WAk}3J`_xP9$hofK2vpyCQykgBAvm%XQOo;N zes&~O^)5=rhgBc%Z2K`p$e$`1UawGcS3~Y3WWSKZT1X#7i`N4UyRfi}yHtOm?3{+3 zUD%b=SN*J8^|OYY@*?|ju#5Ns)g_d?l0)!gDWaD5Qa<)0O!Wau$46A}c+YmEhp>Aq z8(#nThIsvsVK)-?L}7<|Jy6l?byq{qE#xO$s*{v_uL24L)pt6x>gWtq7YkCI)3Dbt zz_Sr+YtPqC*|QCMy0EW4$&Q4oK1#{>uRuHKPb=jn9Zg7WL@$4Hx9v(UomrRdF!OFy0lyMy^gl(`9l60>*_?fU&-SPd5n<% ze1iROsg}vMGn9^xsGe=ub%p&Ft?leNW0d})(&;{b!8*hK)Oy%+e)tyU=CAhWXtU?s z-57h$ofHjDU&85&Dcv=;Io*j%#Cue)k+ilP8@Wk>JhoZ*x)?c!Lojj%qI8_>6ql^g z!-4yG-DO?VG@fsuwVT&n-AL6o?T+#wnfNk7x_F$2K+IL=7F5niyf3 z8Yn&*0!+{Yd>(Y{S1qpIZT&gV@KWU2fm=tUA<7^m;<}7pMHVu_@TYn z0oCJ`y^}+*V;iEDH&NK3s^3>Mt3J`z_G74!M<^MpYbm*#A-^Z&mordZAV~Ef!!9E1 z5-!!ZYKS9V!_Fb>Uvje}p{i3T86Q?%(2(~&&whN1Nnq{Vzf$rl4#AIQh+5upLUwf> zdj3bz(z)+!V>{AQ*nN}@ubU~mnPE2;cGdJ%7j~=eX2^Mj{G>~D4kh0&g#tnKT}<#= z-rpkGk1*ATC>7j*pX1xCny;oR(-#ft@G+81%Pnn3CJB2g*47r1N7=&+`x9Z$ z6LzTAmZI6~@rL}WkgF>hE#yEo@w%8H7Z!4(Fx4{DdO1jSlwto^oEdv(6sFHgaau*>lCq#M& z+LIJ5?d_BQL)Te{OI3AYoEku6=#r4`MjEa(k{{h5f*{>UBaIA~3rY%7(%nc(cc*~T z-6<{j?X}*u*EtjS{GrdY7U#F$_3m}{IkV@^jIuL`?sUTAQz9Fk_1#-}}UCB>%d}VKBfaec7TdwW2 z!k(+_Szsp!t@>pgSBI>xZ~gchbu#Vhoz>c&BJFr7)xK;mG&#GR;r+b#uxw85<6!HWmj{`YHB&z@Y#N8otm0b<& zTEeCdNh<6j%KifEJ%$mYLlz5~JEXFbpQq=(eqG;DeY_C7zQif&kPDPGzYhs=P>0m_ zQ~ju}b!0Nw^xdAeLxu}`h_VNQ{ds8B(cP*iD7hraWn8Mu3puNjGlG01Hv18zdXgyL@z>((4ZbDg~H&p6IG*l3&eo~uNU-hsffvWeK zFdeMgqvREQx@Rq&D=Xh3Ax~BEB#_5~9OQL(LBs3CHLWAH!EPXI^17k0!<1bN?BbzS zr**5Yq2xEIc@{s^a#SZ3@(oUrA6F>r^WKfYegvsLV&Zf_^@|!-^>na*6E>+nksn_F zsO({2PXs&A>%M|!ucs=xEXZHEREG;Wx017iTs9KbS^QLoDf@ORcH}`#I6|sR2>T?b z$dRLz^?4shXGa26pEhASSoMwnSwF^r{Iig$ukYuBAH9{_1LWx-2YEeM(D3?4W#T*oZnx^(O8zq?`|)=T_v?UK!rsnFdL8gSnph!QRK1GO%YZ1w zOf({_NH2XEQ0Gf}8PLdN>9Jn^^!Nt@Hx~^*)~~H@{c4JlTOi4A@Bfnvetjk5hI`6U z*5@5=hj;yXV@DIyX=tig53q6k3i?C9k3YjA;PV!@L@8)NVJawZQ7&l6_gc`DR#2dt{9qi(=!x%iVjpYnL) z%_JC33TM1qC1||I1$De6uJJ1Cc+Zn_m9MM0tMtlve{+(mtfAvgH^k9tGGM&DJ+!{> zdAvb9UVQs2uCoo+cK6vTw#FYY<}f6=8RBF|h3#a-a8GN>`n;F_Gl{@v*lU7LGYn90 zW`J`Dn3~~0Hh>c-I4-~u06Wcqjn?jh=4QyCrV~}U9{!t%Q9}NmQ?xX$p{#kG z?MU|9Xie*S3F97W0h zR$^eqay-&G5(R+I{DWU^F{ zd>*&Af!l(XePs)(hmjj2$rnoH%qXa|j2rGLNm-xw<-c4I%^!iV-+a*o>A>XGQSiTs zxumE9rk0B%;5(e6cD_-G!SetPY&oBxx#iwgw36q5ypYb7XTbxRAUQ(GK9FlWlKn1} z!hWh}D7zxqRfSEe2MasDvU7v|@x7hj^099?Q+&gO>0s66l>9Ie`|<26_Y@Zu_E}ES z6tA{Wnc|6gX^NAXsWd&Cri)H-yTUZZy-k*;SbouZqJi5fK3Ku})g2@EMv|xaeFpf| zOvVlOG@`7zFJpNBDNZjHVT!vd_%nb%7ciN%PQWn~90lNe?*h!iT6oNa)vRPn-ky-n z+EdY);!Z+d!YOK=1(fx9r-1BQRnVCI1r61k%Ue6X1-q@VNp)sn|4-Rfz%CbBbvC!^ zZFk4v?%9)I%;WlM~^?9RWVE+s7?rV2b zJSk&~`32w^0;X1uC*WZU9t7|z!w9iwH%ZVuIg^z9CCKH3Os}Snrh??`O3n=O*C4xE z85dw#Kh?#Qecj7;+$jq?NcBizALSI;agefRpF6bbC$C(~#+B06k5M2;2$@uu6><+H zcL8~$LC8~|-<@H)pm6~XQ+6(}^Se~PPYFkoD?2gRt-ubvpH+6N&aUKBaoLY^W#9*? z-XP>ZI7NPJqOAG6P$a5fy>xfT(NfltUSRhZHhJAu*e#UZ4D4-&5u!up3Yt5lhmuo+ zoZh86mylyAIXcK4K@RGWntrO2D|^SM?8x5IPKVt33|=qg6gjexvgZ4cL#zJqkE=ue z_|p3E9mpMoOkV#c?1Ei zcF1ZIrh_}AmXhCn!n63_myYUiA>ZN@`EiZ1K5svegF57ELBs2pC9Ue2V9ymcsV*;U zpRz}Qoh7vDPu;42RdRWd@%@f?uR4m5^C~$f$Y-91?vRZpP6t$%Quf{0?8u`qI6|s7 zC5P9iIYo{fr>xoM20O4rS__)JzE#5dF&5+rLZ-g{UdVlw{5{BdB2k^lPqk0k1;8%i zQk_TGX_WmL*nd3>*&*9am=0E*SIOsNu^*R8IvsL98T{DIDe_}GWzFCJfE?5z9R&@q zPZzh23;=tGu*vJW!fvDNZ^14YTJ>jc)qRzm0pzSM)y;+MRq`hwUw<09L-v_C9Z;P{ z+52L$BZo^k9g;%Wt2srEET^o`I~MG~4(TCi_Ih_Q>qkeBy9t>(U4gp+bBB$*hyWgBZU3lLj{rQ*Tq@&-6tVC~OHBgB{o*Lj=uU|EAJYr>8YO6WJxE4H+x5?ASJ&(_IFkLIzCZUX{(V6*8&5>4hIYC6564@qKL%@fux!%Eak_>Z!^u3pRZ} zqSN)0g`QLB=5x@%I$I5oQ&ZP>_}r8e5q7DmcKx=D)b%G#)<3?0iqk$9G`3A zuC0kpX4l_dC65bO8>ajh!+7VRHw?&N`jNWwabd$yPLaVsP}Y2}_C4Dc#KCs#6%(U_ zdt!=WO9NZMoai_ZMZnnwY(D>NiLy2EG!+@pJ`ER|)hXzY3}nD*lQjlpbmH?lzSYEC zdw3^k+gg?bk1AU6kqcdmBrgY>ZZ{Nxn{d*FJB5kb^F) z=7NUmSNW{!Szynjvt>DW_X+G6t?ZFtXAP}7u3PnVC078sijYb5E+OYraxRe1-eEsn zs&Qd$GI2Vfy0o(I{mYI#Hk-LlTMZQYDNfRk*GOQU3v1eE)K`hnKhYZNh1EJ8_0>R= zl`XG{v`uWLoVL6U=Cx*Z$FRNqhHW1kb~VvqlgqG^JUMy1IVlY+B5X+`9q(mY8ZVy7 zn)q@jeu?9+Q*eB<6W`16t0qqUZE*C-*{AuSk+#S(tHxvR*_zWxa(@?y35A02tGr#2wYil)e2O+p))N@7w_FA61kI|q z=C*#c2D!bENp(IU*Hm&fkaL6V>Tj$i2?dS*{zloKfE~}J`c4dZ{m)w}h*UqNom=zy z)|>1|pz3WVOb4ruspOS>x@R4oYp!=vJzdDtlsp;aA3+XM-9gY$y(E`)qz>2(g-sn& zL)c#`yExcifE}nhg`in=O(nm5!?XC2_Krn$3?bj-6!~$LvgY@hZ-nlUy(UfvRR5FH zs-6M%9AT5{jnU!tC}j@^I|A%L)!hZns;4Qr9LSYis=Et0kCJnMTms}EuhR+|s=rkB zo!9KhL$jxD`#PtvPjQMIIYwFY`PSkRL;f;hI#~6tY}Sts zAa@lqbx3I;*H?0FkmrKzQjI(NkAjBk@01-M>?G!F=g$5r3Osr950ylB_PW42clJFA z>CRp>u_-4aYCRqN$Nc97Pw3lhEQs&ySwCRJE1aSU{hP8rZ+Q$%wwudAo?LU9ARX}hc@|sDuK>>$ zF!lGve*qq;;GqD&xE!)m&YLhD+$p~(xeUk^g-o3?LCCq3oDJmPKz4Ns?vWz|4b>%; zed{^faX%~UAk`IweS%YD#}Ufy*k)2KGX*1J{xTz56LUav-zQA&Z2)f>Y$k63Uv-LxUaYb!oTi9T}}3?Lh70Eh=I{y}4&s6d>kiP}l)z?_Jzw%SPB7=3L0oYB=+0KGER_LXL?(-(Gg6#%hg1EG9 z5B3^K=G&;M>$-h95v_|aKIM2rC%%Q_7ZIoLo|kWVn#=LMCQh%AYA5A&^jJo&ls5#U ztJGzWxh+;Bi4DQ$uwe?P$lwW-HGe1em$sa zfKve+*l$q;%`;b1$!{OA+>GGppyMwAuTs?NA*AHtm+wH z&k;7MKKKlFj8gV+u)ha8P<3NLv+8L|E(dZYm+DbM&ZFcUAZLt3bu2&CUn={~Lw4jL z?F`GlMOk5=;uJY@jIuuO@$(_Cl659b2dloB*7^|v@^~Th>M!IzO702rK#*Nm3GP`f z1dSDGl(O@KUD&01`%`$GTG=VU&K_EIJh$pRN5#rc-o+{MV;g0C-gD?7jEdkwfM^0^1?K340Z%$dP4~HT(X5hU}1CCQJvb-eo?)g5Oo@0CHC$ zQ-?GWa(yM&200w$pbqIGXn6gdvg3oD#HBisu;1OIf=Kl%+8OqFi-cC4+O0aSlGpR; zp3QWwto}zH!|T~fo(}S@v!OfWpo!A~)vHolM;d|swXmr}h6}sAvP*;gGuVM0(o4|n zb$uoOcb8`|hD&uRA>Zc|`Ei>zip}p_N1{5TpXzt1tm?U7FQT($4SDqlj*L~d`HVQR zADjuTQk z2(L3J`*W~ofgRW(!v)P=7gX}4+w8}6+SHZ49xvnroFYH=P}aN-h(vXMKh@_yvyKb_ zd!(?bud4{Vqq5tA{q|JI4!LZ?bg=3ll$;ghTrSlfAtzFDJdhWH9MmDT$nhgl{o=U0L#inI#dV&?H_082Bl=XSH7)FQ=nJsAU zkf-KzCQv;Ut;oEziaB^aBdx)1 zFKp_N9nwPPgC|}u+JS1*&$m^m=0FGETQ$I9>|S_OdXO~$fcEB666se2X#n0 zLBs2s%6@x^=kX(LAB*afx8U_nPLU&5DeLp*53M?xTlK31R`o29=LwnnTF9f7JQCz9 zheCJAZWE^is;4Qt9N3jys%r^5kFs-s9S(M2hjbM*dtF+|_b##@k7-+9?&yhye1=ox z#|g^%yu~6>oyJe~&G^=l2(ZTsoBI0nO?cf$**(F&bueUy95P`#SoLTne*tn)m+DDE z{#?l^L7o6|P>1vuG`!BE>~nv!BNr1m9a2ZwyEsLTY@@7sofKMiCb#M{@vI*MK^`h( z?rR~pRdOqk9~}tYAtz0o4yf*WBzSX#O%+c3ks+_-J-$>zb^*Q}&G^o2!xEDVr46n)M}yE$26E zj7u0cs}6f(AAFkRiN@n~#(3M!-@VFsJO8EeZoOn3yPWu9jvqt(fD`}O#Es(PCNj#i z%A|$Um;e226L9@e+&tQVHrnYOw+o+I?L*IV6a9!J|504li%{N)Q#2jzC~JO)M+%te z{=A-v=`0UbY))YFnG>D8@@szsoJ7Fp^Ll%wb#~x~8y@{b6H(9DV?-u*3SIP`j5%Sl zCZ58H|HSc4CQgN3@bZ@U7PH@O3w;{L7CQAD7djJ3-V$$r9(smziV7V}S)aESWKrJ{ z2pgV7O^^;W-4q3v2DpNN=~Brk;G7E13UCx#um6_=-`e9cF-*y~|76Jz=$!z$1zbD_ z$tO8Ql8;i>=UrhCp&ow63mU4gePZnx4fZ%;lj^C${$APLz-|n7;IdT8t@=kL=L5Nr zOLYSwr&4lqkYh)p`r&T3*EyAa<}5pMAr2fN)m~w5=M*`zg|a^HI>QL@@@T4{d09Fc z+xpQD+^0kh)^9eThQo`?Xj#QZNcs&Z1Vc)SvXQh*)_m! z3wB_KRClXxt>kzhCw8e`Amq2FsUTAQGB&GD7K!S2JKY`fiL%!)z_WqQmdD6e!k(e* zsbKFij1V2NP|(~VD`Q$e8iGvUrDm_jOhPWFiVg!qwIfA@jOO#slIdu zUfZoqjZ#`D^9FP~%xw3}*D&z&0d#N^23wt$FrD@>Q97xj#K2vY08@KFONiZY(Ld^VpvCh z0(+9MN%gkV@VdXUdxL#qd&mx1Z^Cr2>Ifwl2DyYwbuS^OS8^JVe*ihCLs|+NS7Ux< z|8;^Lx#EE%q&mB>_i~CH*-2S*pAM}$zFYOV=+=+HAde6-t$bHb!H*6~ZUgf9ZJ|44 ztBKPA)%}&73GD1H)#HU7U)i66Jsj-74rwQ7_L@FMgUyOV$JvkLF`N#mB;@s+B0pAB z*8Gl9B&w77sorZokpgySuzLubyncTYjx=m)$gOT>Mp=ZlvsJV8?Q)K6(OPKRRk1xfhKc84q?~hx8USd;OpJ z$O%+0;?q6L>0DX)h6#CslE;BuIug~H{8Z0Xb~UhT37a~ku&|3L`wOriZVA~TCry|R zR$W=i&yR3lzmDptes~;yT;ddU$OX#!ywgAq>X07<4X+>l7egGG4EC?WCe^cqJw(|9 z!LArubxybH2}&*rav7KEdP2^slAOstfq39-{0VVCQwI?j!7^ z%1#LOyGS)X?i$Uz-4M$qv3@CWNi zPq6z6o4kH}6pl1kb`!Ac2CBxVq>8y!cT;jokm)%z6k8G~*=wX>PlXbn-#-ZFgl@-@H4l<8e0C_xd5}%f#d9hc`3GnDh#~fsPpk zV|tL}7pB(^V8jOpNDj^CoeyRNpZCoM9+>9S%)PuYy<&oNU@||xx5X^vvpvh`RJkF{ z5%72gj|F%kz=0Re7(sIj&Qo%AkZTK>E}V8kE~?~$AlGvw`~9s}F+bInl>KZ!Pr<8y z9o4yneUVdS$9c+{@4pGH`u6Xx3+M4W>&Fz3rwf@>-`)?Shbs98kXIT+s258U1P!mp zE4u{PrCq9L2|J6jGl1O$>_D$eyHyue^0j^J$L;sNNC-lxj_jxy))A@Ch-7l+lgRaUIH%-{=mu1nek9wcFKCj7| zcw#4h?;gcdAfDWbpEPmvFEg9SD9^j=x_`Ba|NVUvplu!bzOtL|NCoz;?boElY0TNcOvWO8BXcqwKW|@NA^B<(h9S?3v1* z26pt&s_(9KT|KK_TR$3s{I!rtbuuBBS8{2PR~v-?)q_5qBxqbcb(Q^LH&0?TbGFlm zhj+v6+nl6jwE$?+O~6MuNzOF1M7eFQy+X!#udxB8okG94O~y<% zSyOHqCtiu;gG`(X?Hi5vQG1v{?FF~!r7g4;6xBzPFSx8bQD{lg6YeQWS@Zt$Y9a(& zaH~v^4m3dx1;5$JrG9wDqw;rET-gEe4NlROe1)>+d+q@ayx^J%noWH9kCi+Vl-huBV)k+S=h9=EfRKbW%mF(SD?j0K5u*xUZtUn%zKA6(+g z=k5~w2>1dgsl>hJY+gjg@cn;Lp($Z3{iK2z-su_{zQkl*OWQ97ZkM*BPi;ZHFmit+ zd1=eL1qHQ`al<{$DC_h755xOEi5HTJaJltVa2kL!2$(Lnr<(zet>72{e^@4U`M*VU z-GsF}Q!07)RyOOvGp>ghiB&>g!6|C`C6x7fmx3I$NQ@ISRBwA??PvoweP@<^mgp?( z+RFYP*bPFfF6ma?O37Z36S-997xJ4eR1m5D=P9f9M56lMQWyf&v6a1=0iNIKY)L0<9L`q2R7rsiDd+FL8^(!%z6TUn?yX5RDEm_sg@ zp(4WQ*A}EP&s?U)Ok}bqKF*16<@oz^9G~LE=b5B`ca~BEXXcMhd=>0Mk}urM8!+dKI7R(5 zkFq}R(ZxgvcqUnAf^?vnwmh`pRsgpXFkQG;eh0XQf~x{N0N}v8dkaBxGqq519FXG+ zneOfrg#2=&y#$^;V#zri$?{Bs$LV-}sy)hH!2r)%bGFl{)rCGq=sxe?i`WV0aeDk& z>eO?_anomI&0ph7hvm3PGx5F2ns^l_o`~aLBmO@p{_bz?fO;k}%2V2;g>xP8`W(;h z#1A1}ljDh;_!`7(bNu}o7ZM?$W9FEk(=k2;7XY}3fT?4O3pkB}KLfZuz=0i8L(tqY zd6j(rcb0tV0oTJz{gbtjyqi-bc{^pz_nbPC{hng~UEo%I+I(&Wd*uVb9wKZ~JxADW zl>IH(dkn*G(Zm<~EEY7Y?yKYsAZK-{{#wXhC4T~PcaU8-DD-)KKhC4`a`?Wx z&yxv#B`4`gA)^&+w=dS5qCS6e+SFmbV#$1_K>D-n1?rzkCQJPzD^4dvxBWBct~IPG zhOUVu_s_A_n2f?QaJZ)cWzBteJ{#u$s4(6Ho&KQ@(_ki^uj88V{ZshHzHtJ+#3`EP z3-=h@7~sJEDJ5v0i6?g~`4^C9(7Ez@qK1%%DR~gcu^q{NE6&4tZq@W*8mKM_b{TWF zv*IKYdS;>fyqnDF+&Xq9vY(`xXl)!fGqE+f&cw!ZG!t=6*2K3s@!1@Id4gt$pOTN$ z&ak<<=_xse%2~daO{DLda^$32h54DxNotG&B4?6kt|5+2a|z=$cgD-dn&_vke_f7oU$3TesiqgVxu#`v zsPF)@CYYdORvZPd<+D8-=~TP_CE%F~o(6CefE}~2kd+oRo3-kuHLDTGUkjOT*r|kE zUdg3F{=|{&xBNc(&8@nwvOlciDURk+eQp`-xXUTB;lTp19tpC)o9FrX2TFx zU0%tLRjY)Z_hHSXf8@WRdeFqwt$SB(MdN{; zVor1_nl0e|0ye)BVu`ZmjXXpJ(Z?c8K}!>ALGihub|xEpcl_b4@FJx+G;={+bmSBm zIgJ!VYu>DdC@8uX^xriuC>@6PZ>?BT5hf{_g10YYr}ogPvgUmw;3b?QrxpNwe1>(( z?^_wynXsC*^@=sCHOTFSOlw{`A=gxLHIN5_9MoDZ1P#^SDEkwz1>$)Ow2GrI#AOX1s4LixPa**e>D%_bP7%laBF}A?>`3;z`@H_ut@_VP){a474;MD6?kw!~ z%Ki@Q?S>KJ?lVu&ta^ZwGlQJNr8azz%8XR-Hh}oA`9kHab`C^vQ%gPsy`EP9LNiw*ilz z>UDoxN1B1%(wyyFt4HR*?TSM8c~4DcGn@^D+I#7m9J$Yg&3A*w)hqVGVY*@qnJlfQ zPJAcFKR0pLjr!q5u86N;`Y;V%aU5F6(|;UEzJ~Mv20`mNMbp2UvOaHF=<>gYvzwrE z4IeO{N&&bVz`X=aeRY2}z)cn05a4IOkTkmQ_^qaYnlK%FHFQ>Ta*$ICnfpq}(Uko0 zZdwOQ{=}s%KE(HKz8*HR?{AWhS#UgSx5SVJy_V(^+SaHow8ekT_UvVbZ*ssl$;*q zEH2f>gdA7Nu|d8!iTwytebmJ1fa=uB-aD5aIdmS5km{$?;m9gZkt53}>+?@Pa(yM&2Dx02YFw*X{ZxOa?D$|OF=sp1YBQm~nL{PfwffIQ zHp5v>W9^`8wdhV0HmhbVy;j5b(Y1PiJFZpP_Wb=Ed%~;cgR{1*iA?uQMUt=8&C_7m zAQ?E^)1R_F?*NSNf31FNg3e5gS8xe{OADB0qNjkfC^!SaIc;J7t7Za0^Gp;~^0nW1 zj&J|T_3)EVJ|Q3B6wUDg%9`&9ofh_lKZL7qU__d*^x76{rX4f8#zh+b8|eK z;q=deKd67+Y%}4AuubgrzLb%i`e$)i9%_%r>Z;Qm=|;*RR+%B}!*6=9R=n8MDd>|9`f4|ZVxG!`_g zF014RGue-)rybRsC&TDJIYoY)qO94Ui$rxSKh?KST1Uo#JyF=Cx}&iBDZ3Zg$A4l+ z0#&awVLDj#7$p}1xwuPpIw7Z1a%zwVf*iEgw-7Ye`h3d1FoPYT?;4_cB-N)T!I3?j zB1d*m*5}P0T6H|P>OW6dKL&w3T*$Q6|0v}4O8ySybK}?#mug(ATTGk|sP3oij9_Oo zXFF?sQK82by7|2-V4Z6<&1Sk*t8Fo(MT9*ypO%nob=D5LR->3KU8}e7D)-Py_Jr5^ z|BlcIAzgAk7tF~W8F0^P;d=^>ta-%iHrg+ zuHeD|Z#Rq(PssBG&HYnN$uECp$?r~ZJ-pUm7!S!;IYp8$Qr73~1hQ);Zix7 z9aF)cDQxPWpM*VJ*@MCUEVSy65w5PEtmIN4mv^bIEaV(Y&I0m&g9x?4EEP2Rr?|3j zOk+px9)}~O`oqs~ctG;^F`r!k4tdObe{}6IdC3gimeI%+q zeyWEnJ2%(`T&nvBJB6~7fPHifI})gRjS17i9g;)Ir>C+X=a0b;Qe9BU+c-sjY^JRF zoe+?NI;6Rv;q|d2){)*|4-htaefuYP-BQ_KgPk={HTJXPx>fg7avG2`m~)*~V5+cV z3ft%XD_pGDf&J{yey2s?s|_Y<{*3iw47&(S+e(YTzw5CG#7@RrU3-tRCA`VuEzQtltz|1>hP2CbK3AxR8SL1Dwd# z<$uF|J=!(JUn%+N6qfw*2-m}l!2g8&H>XJQIm-IHI}9S!yV5f&IX%cJBT@a)=k~ggvM*0&M{XR3 zBcytiun%&I9N9}*pLd^OgjjHw3YssczYkhJhJ)-AGF?v9gxp2R9YF30a?s_}&`LV?AYk-eaTKk08}+ zOx)?~g9of5-NEiHZ1VaSVK-BDBe45{9oQkw1iR{QuI$Iu&;s|>or^u1HV4wMs9SKyu$%N@()tmNPKU#v^M#$v#(UI`F zx{@n{JQU<0ufG#CuEu7{jtTasF4d!i{cHjiM5_7wcFg+#p;ae#tB$VZWqi74^#RB0 z3PPTu6FmXDddf`6nNKLTo37a}3im*#4y9n5$zz+1flc3q_>Pmh! zo@ep>en<8C5%BsNr^t^>l=XQFN1{5VpXz6Ot?FrD&k{DN?kVgM${qst^%3kypz8f5 zOb4r;qU6#bS8%B=EaaR@&I;8gfuX8H-%unpcg}v~DRF@R;c21EWTPSOOA0rag+5A)=-)$Y~1NJ~+lh+@H z!Rv38-5l(v!`P8P)n`qZ4p#lWl0OGIqf7NpA%CJ|56Ck?4)S`apyBmr%HB1O9ofGJ zj*#j;!d}iPa%3@OecmdeRp)i9-oDHF(H7)RLME>Z2)T}uYk>S_DEkql`l5-`0oC6s zJ1*D>U8)}ph1ajgQbDBp#cozT59~m%eS&7MKT+};KHal{&Xw(s`9hwdWcm&q<45gC zR2TMBy?m#2q(0b9giT(5E$lMN4g>q+5OyR`^$ioIgH_j2^1l&0i&0&wQwaGEr^t^R zyIA!ykb}JbNzm~6^$x3gHrVs&Y`Hg{90ISymHi{w4MVFAbE}@ASu)9ObDEs~xcI3%UM|F8&pXC%ea+0z>?;67h@ys_x(Cqb{?beTSu#o9g<(ke}%IjS9ZV; zQr%6+dpSjZ?4+#uysANjdQ~t}(CCn}+pHr$fIUpu)YmzL-A>u9!Tt{Hz`m~PR^4C8 znLy6&Qhjp}ypFHrPeD!+iRw2$xH}}RvJZ@AM~-fXBcytUu-9^m99c!Fr8H<4b>mESk(&{z&rbP<$F62 zj{L0b2(XV0U`GN~uQg#^ujeYc8pyTiT=9Cnkc%k!3y=qZ9HjaiK|}Rd%6|GI_w~!I zV3XHfg#9_?F5%_dF< zRR65(;$W8&HmSZd0A6QSc6zXff*q*3ji6a|5hY(8$$s40;&?qz$cH&ae(a~L&zleA zAk|3(4b^{dvW^S~+b3*N-AveBl-&XBi~ZPm;xPRi_d(t3JHZ`q2~QzCtF| zqlMgD$xT4M*_ZtYQhmV0>454k%1!|`?d;pDv7E4@EBn7qtokRg166-7XjYw6$=imr zAG_&Xxf(zAgCC1IMSjc&`Ad+4RA&%0RBzf~9cc-68)1{zzYDv%vMYmqzYjYSsQS1G z)4{5nD>*jEULlj$-GuyN7!^dSpKN45egQd1^#DObb#!GfV}NHhoh{FNIfXq%*%QDn z4|bsH?1E<1i+{I%)CReMkV*BOzVJFs$;Ci^-kbe!sm7Z{f0{TQP+eWwuZHqGzBe1b z&NlHZp#t^Ls1DN*~A51peMcP3HPL- ztk3)Ldm`{#&5nt;Opp#VMnMH%8qB3$H#`33AM-nIjRbsvQ*^29p{)7c5P%&M@u`OK zf@Tx{T5BZ_19_B?sh#5rxwDengWLpUS36_sO9>jPe^7Q-uyYBUrhaQ@*pW!t@xYD+ zcA)BqJzY~zAEUuvh8-QmewMm-Bj5P!EOO|pz4Z(X0JOdIXTFwg-oiicY+_$l>BimtBwzHkk>DIxH}|~vbX%e zj_jbbr9-9(djY4&kvU**F^mu|24)MIRc~Bv{b&L5cS0uB^@Lna$(2BE2Xc_=>Vk&X zO_l8dJC3l)Yp<}M4y1xe^}{vnNK&u^y?)o-)gjT8yp&J(tfF(}mUy5eyq>J&@gVOu zh)^A}P|#4lV3l>G2H16lO{xbAySTCogWUz}K-F~x&0bei^2-4{i|;OlGD|;~52fMK&fvQ)SFdeLVvXV=ITwci3 zA+v>?L&^NTDn4&-kb_h=5j0d6SN4tm?8x0!aD-Gh6814pkt2sFYyJ)f>_FAA196WJsXoviUZ+rY60iq?9jLmc zpjmYeC7JwVu`I=`@6D*J1& z&vju(0#$D{VLDiKPbH@TIfIZ%^__O`Bes%bfII@^Al2;z4b}8v8r%zZ_GL%*t$-t> zdYZ78af%#SL|OB@Az%lpP9|tpy=|E#w*k4MkV$n-A=g&&|3JRdnf(Y-z1zg;fa;dY z{uJy4!Y0+xh5f1z6-26^FK5-^UsqQUksD8D?s-6Y*JUUzMjn~@1khmT{2dmDf zd8IaXO&-b7k-E$&MUZ3`a=y1Yxh?6gjej zvOe!ZumimwBWU(|&qC`*Cy=`fnY{i=$PJZT7vy?Ds_`PXn4jvl%1#J&GIO@`vh7tX zc=E0Xl|(PwVp_rWlPU>*rq^x7$D48@!rEWZ*KH9~=yltRpYZx@4E`c=<0AHiU*tYo zV9T1!bkDCy^6Rq(Eimv9893ZCkg`7S*mgt+czyQ02|6<|QNdvVmlZJ0L_z^)Q*b7L z!vGGPi420~nJBL08{K)1?=Iwe_>Z9ue*?+KI7M@Oh_dGQTidE+zfYMxz@@r?kW(l*3CI;9QJvjSbv9+6?8c7# zxd4uk>f6oX$W~5~BO58}^FC|Cjs&Xy(}d|@)yL*pKYD{aK*-efGlbky$zOv!3*?|{ zb(o-Wt#(&-DzMYJRM!!9Ol3y{yJ~3F`P`~gD0ydB_G90C_(7`U2zeQ&$d5&o^?BcZ z$9}j}<66CB;&edu*16V^)?l|cXFJ#G_OIdg|Ag-IE&NTuhlX-^!+Ye){}WCi#{zqp(zGF%PA`BBxTL_csOO5 z8@y~tedbrw-8r_Vp8=jMVCtW$0v@2?J^){9&3*;;&ps2TgZpQ!l8b;`QphwD(S@8r z$)AHf4rJF%U@xVIpfM8#l>K*Sw&Utt*g>i{Hh~@cI7N2sqO8wbBDCssZq?_1vwjQ# zd8Cj@byp#GRB~I8@3mq-f>a+haXO%SfU+}#ox`O%v#=8=J1*Fhzz+1fpP=-REs;1=}aDUw)+3e8(s=sQK}=6S|rw9!slvf0H%w zWKR5j1jSn+p2~^eFmdxQGn&XKPeqfKyTW0_zu_B)<>v4V_G1iF$M-)$wNoN_8z9wew zbZccbj9Cjwev+J34)4b^*h7Ww^ZsC=JMbBV-$syG zyNxNvfKA8LtYl+ol82itnI+$qRtB>9R^CfTPK%Ky@lOP*`2^%0Cu42a6z-`VM@*ga(zJSB1bk**5{29TJ^0at|j8=6zfMXkoyan zx_*U_TPV31$SVvY)SD*b1&t2rrtFkpr*)}rD{POlqk`QS>_D$exm71u@{VuWkG;RZ z4^o{;$V)jzek`P{&l@`u)ejrHJ7mjb>qslG+XDo=suZEkSmzFt~|S^i%Co_6i1g*3#MXDA+{UQJI^4d- zNm>^>0qeZjj5>(c#q@*CXc1xM59qqsa|Er6H-EsoDBm?U%h2gAOtnC z-##sL^Drtjw|_ymCOQSB)RA{L=YkF($pt;HjDl8hiV9jnS)aFw9o|(?ITO>F+dba; z)DhTj=0vBUH3F_DV4pXkB}zg422eqhjc_wVUZVS=_ppUl{id#~&^97Bi^`CK8^$f7*2%A)A5cVi#4+pyw*nv0S+HTd;lw1zvN-ot`D!}VJO3ndt zsz_A-SI6BUUn=`f6L#dG+1e*ZNcC)CpW+lba*VP*?|#Dw(ILwO%^h-cto0)To5z3*JvcZzXi|J2SvKH{Wr+ zX~mn@$BY&cc5bIG;jahM3e(+WU9Y7xKsn!h8|ctcFtkU?qL+u8%c86YjqE~jhxU@q z^P5u^-Q3XiPinbq`Z&hcw2;sCETdDUe})Noyn=a?+UMP17=HbO8~b!YbN|d!a&?ev z8?xh8WnmWf%8c6a(p)oW^LmX^}uGz`n)e{a!u3&j#+=1pwj>+!>w8U03IY@y4aQrxV3^? z06Yiaz$M~GL9R8$5P7ry#LlQ9xtj!*Y&qI2ceS6#@nl>95mF(OfY_kZpV zS?RNmGz7buu&G003cH-LOM$)0F#Ikj{1NITL9^HOl>D(C&ti0!>K!HE^*v6}EZ!Q; zetZpbkk@7XRKFc%RnGx?A)PIYKwn`;DBA~ioY1PDRCjgAEG1V0xw??4L%tC57fQ|x z@&lmE0HPM3Ja|Rn6TY5y~zMb_tj2Z-kv**=fMuW*8wlWUipOL%vY*#X9WAHQIxg zzD_CR{hT5{c2m}T?-0?qGEm7` zK+fq>9UP~3Du`6Sr_E-c_ed3X zBvAEg6V~-Qp^`WA>7MO$u5?HbAr+yuq!LO z0@ztXtNzrjx`~owfc%L|_3a|?<4H~H#{=5(^?A=!W

dZ!~c_p!&aIR`ntVc$U-I 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 z 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%0DDQmTR?zD6opPoI?R^SoC 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 literal 0 HcmV?d00001 diff --git a/Release/Thanda b/Release/Thanda new file mode 100755 index 0000000000000000000000000000000000000000..679bb9f8885b007c6f217517e502bb49e15a0c39 GIT binary patch literal 1208052 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 #=Bn7TnZI_FhL1d3h?8 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 z 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 )_D~ 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

BW2B&NY*Z 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�jeglLrfJX>l3=bkd2p&c5hoi_(fX9$u1P>v< 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%0D^!_& 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 z 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 literal 0 HcmV?d00001 diff --git a/nuparu/include/Eigen/Array b/nuparu/include/Eigen/Array deleted file mode 100644 index 3d004fb6..00000000 --- a/nuparu/include/Eigen/Array +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef EIGEN_ARRAY_MODULE_H -#define EIGEN_ARRAY_MODULE_H - -// include Core first to handle Eigen2 support macros -#include "Core" - -#ifndef EIGEN2_SUPPORT - #error The Eigen/Array header does no longer exist in Eigen3. All that functionality has moved to Eigen/Core. -#endif - -#endif // EIGEN_ARRAY_MODULE_H diff --git a/nuparu/include/Eigen/COPYING.BSD b/nuparu/include/Eigen/COPYING.BSD deleted file mode 100644 index 11971ffe..00000000 --- a/nuparu/include/Eigen/COPYING.BSD +++ /dev/null @@ -1,26 +0,0 @@ -/* - Copyright (c) 2011, Intel Corporation. All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, - are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of Intel Corporation nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ \ No newline at end of file diff --git a/nuparu/include/Eigen/COPYING.GPL b/nuparu/include/Eigen/COPYING.GPL deleted file mode 100644 index 94a9ed02..00000000 --- a/nuparu/include/Eigen/COPYING.GPL +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/nuparu/include/Eigen/COPYING.LGPL b/nuparu/include/Eigen/COPYING.LGPL deleted file mode 100644 index 4362b491..00000000 --- a/nuparu/include/Eigen/COPYING.LGPL +++ /dev/null @@ -1,502 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/nuparu/include/Eigen/COPYING.MINPACK b/nuparu/include/Eigen/COPYING.MINPACK deleted file mode 100644 index ae7984da..00000000 --- a/nuparu/include/Eigen/COPYING.MINPACK +++ /dev/null @@ -1,52 +0,0 @@ -Minpack Copyright Notice (1999) University of Chicago. All rights reserved - -Redistribution and use in source and binary forms, with or -without modification, are permitted provided that the -following conditions are met: - -1. Redistributions of source code must retain the above -copyright notice, this list of conditions and the following -disclaimer. - -2. Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following -disclaimer in the documentation and/or other materials -provided with the distribution. - -3. The end-user documentation included with the -redistribution, if any, must include the following -acknowledgment: - - "This product includes software developed by the - University of Chicago, as Operator of Argonne National - Laboratory. - -Alternately, this acknowledgment may appear in the software -itself, if and wherever such third-party acknowledgments -normally appear. - -4. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" -WITHOUT WARRANTY OF ANY KIND. THE COPYRIGHT HOLDER, THE -UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND -THEIR EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE -OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY -OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR -USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF -THE SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4) -DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION -UNINTERRUPTED, THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL -BE CORRECTED. - -5. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT -HOLDER, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF -ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT, -INCIDENTAL, CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF -ANY KIND OR NATURE, INCLUDING BUT NOT LIMITED TO LOSS OF -PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, WHETHER -SUCH LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT -(INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE, -EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE -POSSIBILITY OF SUCH LOSS OR DAMAGES. - diff --git a/nuparu/include/Eigen/COPYING.MPL2 b/nuparu/include/Eigen/COPYING.MPL2 deleted file mode 100644 index 14e2f777..00000000 --- a/nuparu/include/Eigen/COPYING.MPL2 +++ /dev/null @@ -1,373 +0,0 @@ -Mozilla Public License Version 2.0 -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. diff --git a/nuparu/include/Eigen/COPYING.README b/nuparu/include/Eigen/COPYING.README deleted file mode 100644 index de5b6321..00000000 --- a/nuparu/include/Eigen/COPYING.README +++ /dev/null @@ -1,18 +0,0 @@ -Eigen is primarily MPL2 licensed. See COPYING.MPL2 and these links: - http://www.mozilla.org/MPL/2.0/ - http://www.mozilla.org/MPL/2.0/FAQ.html - -Some files contain third-party code under BSD or LGPL licenses, whence the other -COPYING.* files here. - -All the LGPL code is either LGPL 2.1-only, or LGPL 2.1-or-later. -For this reason, the COPYING.LGPL file contains the LGPL 2.1 text. - -If you want to guarantee that the Eigen code that you are #including is licensed -under the MPL2 and possibly more permissive licenses (like BSD), #define this -preprocessor symbol: - EIGEN_MPL2_ONLY -For example, with most compilers, you could add this to your project CXXFLAGS: - -DEIGEN_MPL2_ONLY -This will cause a compilation error to be generated if you #include any code that is -LGPL licensed. diff --git a/nuparu/include/Eigen/Cholesky b/nuparu/include/Eigen/Cholesky index f727f5d8..705a04cc 100644 --- a/nuparu/include/Eigen/Cholesky +++ b/nuparu/include/Eigen/Cholesky @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_CHOLESKY_MODULE_H #define EIGEN_CHOLESKY_MODULE_H @@ -10,16 +17,17 @@ * * * This module provides two variants of the Cholesky decomposition for selfadjoint (hermitian) matrices. - * Those decompositions are accessible via the following MatrixBase methods: - * - MatrixBase::llt(), + * Those decompositions are also accessible via the following methods: + * - MatrixBase::llt() * - MatrixBase::ldlt() + * - SelfAdjointView::llt() + * - SelfAdjointView::ldlt() * * \code * #include * \endcode */ -#include "src/misc/Solve.h" #include "src/Cholesky/LLT.h" #include "src/Cholesky/LDLT.h" #ifdef EIGEN_USE_LAPACKE diff --git a/nuparu/include/Eigen/CholmodSupport b/nuparu/include/Eigen/CholmodSupport index 745b884e..83e2c1da 100644 --- a/nuparu/include/Eigen/CholmodSupport +++ b/nuparu/include/Eigen/CholmodSupport @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_CHOLMODSUPPORT_MODULE_H #define EIGEN_CHOLMODSUPPORT_MODULE_H @@ -33,12 +40,8 @@ extern "C" { * */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - #include "src/CholmodSupport/CholmodSupport.h" - #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_CHOLMODSUPPORT_MODULE_H diff --git a/nuparu/include/Eigen/Core b/nuparu/include/Eigen/Core index 9131cc3f..63602f4c 100644 --- a/nuparu/include/Eigen/Core +++ b/nuparu/include/Eigen/Core @@ -14,6 +14,48 @@ // first thing Eigen does: stop the compiler from committing suicide #include "src/Core/util/DisableStupidWarnings.h" +// Handle NVCC/CUDA +#ifdef __CUDACC__ + // Do not try asserts on CUDA! + #ifndef EIGEN_NO_DEBUG + #define EIGEN_NO_DEBUG + #endif + + #ifdef EIGEN_INTERNAL_DEBUGGING + #undef EIGEN_INTERNAL_DEBUGGING + #endif + + // Do not try to vectorize on CUDA! + #ifndef EIGEN_DONT_VECTORIZE + #define EIGEN_DONT_VECTORIZE + #endif + + #ifdef EIGEN_EXCEPTIONS + #undef EIGEN_EXCEPTIONS + #endif + + // All functions callable from CUDA code must be qualified with __device__ + #define EIGEN_DEVICE_FUNC __host__ __device__ + +#else + #define EIGEN_DEVICE_FUNC + +#endif + +#if defined(__CUDA_ARCH__) + #define EIGEN_USING_STD_MATH(FUNC) using ::FUNC; +#else + #define EIGEN_USING_STD_MATH(FUNC) using std::FUNC; +#endif + +#if (defined(_CPPUNWIND) || defined(__EXCEPTIONS)) && !defined(__CUDA_ARCH__) && !defined(EIGEN_EXCEPTIONS) + #define EIGEN_EXCEPTIONS +#endif + +#ifdef EIGEN_EXCEPTIONS + #include +#endif + // then include this file where all our macros are defined. It's really important to do it first because // it's where we do all the alignment settings (platform detection and honoring the user's will if he // defined e.g. EIGEN_DONT_ALIGN) so it needs to be done before we do anything with vectorization. @@ -21,7 +63,7 @@ // Disable the ipa-cp-clone optimization flag with MinGW 6.x or newer (enabled by default with -O3) // See http://eigen.tuxfamily.org/bz/show_bug.cgi?id=556 for details. -#if defined(__MINGW32__) && EIGEN_GNUC_AT_LEAST(4,6) +#if EIGEN_COMP_MINGW && EIGEN_GNUC_AT_LEAST(4,6) #pragma GCC optimize ("-fno-ipa-cp-clone") #endif @@ -31,26 +73,26 @@ // and inclusion of their respective header files #include "src/Core/util/MKL_support.h" -// if alignment is disabled, then disable vectorization. Note: EIGEN_ALIGN is the proper check, it takes into -// account both the user's will (EIGEN_DONT_ALIGN) and our own platform checks -#if !EIGEN_ALIGN +// if alignment is disabled, then disable vectorization. Note: EIGEN_MAX_ALIGN_BYTES is the proper check, it takes into +// account both the user's will (EIGEN_MAX_ALIGN_BYTES,EIGEN_DONT_ALIGN) and our own platform checks +#if EIGEN_MAX_ALIGN_BYTES==0 #ifndef EIGEN_DONT_VECTORIZE #define EIGEN_DONT_VECTORIZE #endif #endif -#ifdef _MSC_VER +#if EIGEN_COMP_MSVC #include // for _aligned_malloc -- need it regardless of whether vectorization is enabled - #if (_MSC_VER >= 1500) // 2008 or later + #if (EIGEN_COMP_MSVC >= 1500) // 2008 or later // Remember that usage of defined() in a #define is undefined by the standard. // a user reported that in 64-bit mode, MSVC doesn't care to define _M_IX86_FP. - #if (defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) || defined(_M_X64) + #if (defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) || EIGEN_ARCH_x86_64 #define EIGEN_SSE2_ON_MSVC_2008_OR_LATER #endif #endif #else // Remember that usage of defined() in a #define is undefined by the standard - #if (defined __SSE2__) && ( (!defined __GNUC__) || (defined __INTEL_COMPILER) || EIGEN_GNUC_AT_LEAST(4,2) ) + #if (defined __SSE2__) && ( (!EIGEN_COMP_GNUC) || EIGEN_COMP_ICC || EIGEN_GNUC_AT_LEAST(4,2) ) #define EIGEN_SSE2_ON_NON_MSVC_BUT_NOT_OLD_GCC #endif #endif @@ -82,6 +124,19 @@ #ifdef __SSE4_2__ #define EIGEN_VECTORIZE_SSE4_2 #endif + #ifdef __AVX__ + #define EIGEN_VECTORIZE_AVX + #define EIGEN_VECTORIZE_SSE3 + #define EIGEN_VECTORIZE_SSSE3 + #define EIGEN_VECTORIZE_SSE4_1 + #define EIGEN_VECTORIZE_SSE4_2 + #endif + #ifdef __AVX2__ + #define EIGEN_VECTORIZE_AVX2 + #endif + #ifdef __FMA__ + #define EIGEN_VECTORIZE_FMA + #endif // include files @@ -95,7 +150,7 @@ extern "C" { // In theory we should only include immintrin.h and not the other *mmintrin.h header files directly. // Doing so triggers some issues with ICC. However old gcc versions seems to not have this file, thus: - #ifdef __INTEL_COMPILER + #if EIGEN_COMP_ICC >= 1110 #include #else #include @@ -112,8 +167,20 @@ #ifdef EIGEN_VECTORIZE_SSE4_2 #include #endif + #ifdef EIGEN_VECTORIZE_AVX + #include + #endif #endif } // end extern "C" + #elif defined __VSX__ + #define EIGEN_VECTORIZE + #define EIGEN_VECTORIZE_VSX + #include + // We need to #undef all these ugly tokens defined in + // => use __vector instead of vector + #undef bool + #undef vector + #undef pixel #elif defined __ALTIVEC__ #define EIGEN_VECTORIZE #define EIGEN_VECTORIZE_ALTIVEC @@ -123,13 +190,18 @@ #undef bool #undef vector #undef pixel - #elif defined __ARM_NEON__ + #elif (defined __ARM_NEON) || (defined __ARM_NEON__) #define EIGEN_VECTORIZE #define EIGEN_VECTORIZE_NEON #include #endif #endif +#if defined __CUDACC__ + #define EIGEN_VECTORIZE_CUDA + #include +#endif + #if (defined _OPENMP) && (!defined EIGEN_DONT_PARALLELIZE) #define EIGEN_HAS_OPENMP #endif @@ -139,7 +211,7 @@ #endif // MSVC for windows mobile does not have the errno.h file -#if !(defined(_MSC_VER) && defined(_WIN32_WCE)) && !defined(__ARMCC_VERSION) +#if !(EIGEN_COMP_MSVC && EIGEN_OS_WINCE) && !EIGEN_COMP_ARM #define EIGEN_HAS_ERRNO #endif @@ -165,23 +237,17 @@ #endif // required for __cpuid, needs to be included after cmath -#if defined(_MSC_VER) && (defined(_M_IX86)||defined(_M_X64)) +#if EIGEN_COMP_MSVC && EIGEN_ARCH_i386_OR_x86_64 && !EIGEN_OS_WINCE #include #endif -#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) - #define EIGEN_EXCEPTIONS -#endif - -#ifdef EIGEN_EXCEPTIONS - #include -#endif - /** \brief Namespace containing all symbols from the %Eigen library. */ namespace Eigen { inline static const char *SimdInstructionSetsInUse(void) { -#if defined(EIGEN_VECTORIZE_SSE4_2) +#if defined(EIGEN_VECTORIZE_AVX) + return "AVX SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2"; +#elif defined(EIGEN_VECTORIZE_SSE4_2) return "SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2"; #elif defined(EIGEN_VECTORIZE_SSE4_1) return "SSE, SSE2, SSE3, SSSE3, SSE4.1"; @@ -193,6 +259,8 @@ inline static const char *SimdInstructionSetsInUse(void) { return "SSE, SSE2"; #elif defined(EIGEN_VECTORIZE_ALTIVEC) return "AltiVec"; +#elif defined(EIGEN_VECTORIZE_VSX) + return "VSX"; #elif defined(EIGEN_VECTORIZE_NEON) return "ARM NEON"; #else @@ -202,34 +270,9 @@ inline static const char *SimdInstructionSetsInUse(void) { } // end namespace Eigen -#define STAGE10_FULL_EIGEN2_API 10 -#define STAGE20_RESOLVE_API_CONFLICTS 20 -#define STAGE30_FULL_EIGEN3_API 30 -#define STAGE40_FULL_EIGEN3_STRICTNESS 40 -#define STAGE99_NO_EIGEN2_SUPPORT 99 - -#if defined EIGEN2_SUPPORT_STAGE40_FULL_EIGEN3_STRICTNESS - #define EIGEN2_SUPPORT - #define EIGEN2_SUPPORT_STAGE STAGE40_FULL_EIGEN3_STRICTNESS -#elif defined EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API - #define EIGEN2_SUPPORT - #define EIGEN2_SUPPORT_STAGE STAGE30_FULL_EIGEN3_API -#elif defined EIGEN2_SUPPORT_STAGE20_RESOLVE_API_CONFLICTS - #define EIGEN2_SUPPORT - #define EIGEN2_SUPPORT_STAGE STAGE20_RESOLVE_API_CONFLICTS -#elif defined EIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API - #define EIGEN2_SUPPORT - #define EIGEN2_SUPPORT_STAGE STAGE10_FULL_EIGEN2_API -#elif defined EIGEN2_SUPPORT - // default to stage 3, that's what it's always meant - #define EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API - #define EIGEN2_SUPPORT_STAGE STAGE30_FULL_EIGEN3_API -#else - #define EIGEN2_SUPPORT_STAGE STAGE99_NO_EIGEN2_SUPPORT -#endif - -#ifdef EIGEN2_SUPPORT -#undef minor +#if defined EIGEN2_SUPPORT_STAGE40_FULL_EIGEN3_STRICTNESS || defined EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API || defined EIGEN2_SUPPORT_STAGE20_RESOLVE_API_CONFLICTS || defined EIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API || defined EIGEN2_SUPPORT +// This will generate an error message: +#error Eigen2-support is only available up to version 3.2. Please go to "http://eigen.tuxfamily.org/index.php?title=Eigen2" for further information #endif // we use size_t frequently and we'll never remember to prepend it with std:: everytime just to @@ -249,45 +292,75 @@ using std::ptrdiff_t; */ #include "src/Core/util/Constants.h" -#include "src/Core/util/ForwardDeclarations.h" #include "src/Core/util/Meta.h" +#include "src/Core/util/ForwardDeclarations.h" #include "src/Core/util/StaticAssert.h" #include "src/Core/util/XprHelper.h" #include "src/Core/util/Memory.h" #include "src/Core/NumTraits.h" #include "src/Core/MathFunctions.h" +#include "src/Core/SpecialFunctions.h" #include "src/Core/GenericPacketMath.h" -#if defined EIGEN_VECTORIZE_SSE +#if defined EIGEN_VECTORIZE_AVX + // Use AVX for floats and doubles, SSE for integers + #include "src/Core/arch/SSE/PacketMath.h" + #include "src/Core/arch/SSE/Complex.h" + #include "src/Core/arch/SSE/MathFunctions.h" + #include "src/Core/arch/AVX/PacketMath.h" + #include "src/Core/arch/AVX/MathFunctions.h" + #include "src/Core/arch/AVX/Complex.h" + #include "src/Core/arch/AVX/TypeCasting.h" +#elif defined EIGEN_VECTORIZE_SSE #include "src/Core/arch/SSE/PacketMath.h" #include "src/Core/arch/SSE/MathFunctions.h" #include "src/Core/arch/SSE/Complex.h" -#elif defined EIGEN_VECTORIZE_ALTIVEC + #include "src/Core/arch/SSE/TypeCasting.h" +#elif defined(EIGEN_VECTORIZE_ALTIVEC) || defined(EIGEN_VECTORIZE_VSX) #include "src/Core/arch/AltiVec/PacketMath.h" + #include "src/Core/arch/AltiVec/MathFunctions.h" #include "src/Core/arch/AltiVec/Complex.h" #elif defined EIGEN_VECTORIZE_NEON #include "src/Core/arch/NEON/PacketMath.h" + #include "src/Core/arch/NEON/MathFunctions.h" #include "src/Core/arch/NEON/Complex.h" #endif +#if defined EIGEN_VECTORIZE_CUDA + #include "src/Core/arch/CUDA/PacketMath.h" + #include "src/Core/arch/CUDA/MathFunctions.h" +#endif + #include "src/Core/arch/Default/Settings.h" -#include "src/Core/Functors.h" +#include "src/Core/functors/BinaryFunctors.h" +#include "src/Core/functors/UnaryFunctors.h" +#include "src/Core/functors/NullaryFunctors.h" +#include "src/Core/functors/StlFunctors.h" +#include "src/Core/functors/AssignmentFunctors.h" + #include "src/Core/DenseCoeffsBase.h" #include "src/Core/DenseBase.h" #include "src/Core/MatrixBase.h" #include "src/Core/EigenBase.h" +#include "src/Core/Product.h" +#include "src/Core/CoreEvaluators.h" +#include "src/Core/AssignEvaluator.h" + #ifndef EIGEN_PARSED_BY_DOXYGEN // work around Doxygen bug triggered by Assign.h r814874 // at least confirmed with Doxygen 1.5.5 and 1.5.6 #include "src/Core/Assign.h" #endif +#include "src/Core/ArrayBase.h" #include "src/Core/util/BlasUtil.h" #include "src/Core/DenseStorage.h" #include "src/Core/NestByValue.h" -#include "src/Core/ForceAlignedAccess.h" + +// #include "src/Core/ForceAlignedAccess.h" + #include "src/Core/ReturnByValue.h" #include "src/Core/NoAlias.h" #include "src/Core/PlainObjectBase.h" @@ -300,32 +373,33 @@ using std::ptrdiff_t; #include "src/Core/SelfCwiseBinaryOp.h" #include "src/Core/Dot.h" #include "src/Core/StableNorm.h" -#include "src/Core/MapBase.h" #include "src/Core/Stride.h" +#include "src/Core/MapBase.h" #include "src/Core/Map.h" +#include "src/Core/Ref.h" #include "src/Core/Block.h" #include "src/Core/VectorBlock.h" -#include "src/Core/Ref.h" #include "src/Core/Transpose.h" #include "src/Core/DiagonalMatrix.h" #include "src/Core/Diagonal.h" #include "src/Core/DiagonalProduct.h" -#include "src/Core/PermutationMatrix.h" -#include "src/Core/Transpositions.h" #include "src/Core/Redux.h" #include "src/Core/Visitor.h" #include "src/Core/Fuzzy.h" #include "src/Core/IO.h" #include "src/Core/Swap.h" #include "src/Core/CommaInitializer.h" -#include "src/Core/Flagged.h" -#include "src/Core/ProductBase.h" #include "src/Core/GeneralProduct.h" +#include "src/Core/Solve.h" +#include "src/Core/Inverse.h" +#include "src/Core/SolverBase.h" +#include "src/Core/PermutationMatrix.h" +#include "src/Core/Transpositions.h" #include "src/Core/TriangularMatrix.h" #include "src/Core/SelfAdjointView.h" #include "src/Core/products/GeneralBlockPanelKernel.h" #include "src/Core/products/Parallelizer.h" -#include "src/Core/products/CoeffBasedProduct.h" +#include "src/Core/ProductEvaluators.h" #include "src/Core/products/GeneralMatrixVector.h" #include "src/Core/products/GeneralMatrixMatrix.h" #include "src/Core/SolveTriangular.h" @@ -347,7 +421,6 @@ using std::ptrdiff_t; #include "src/Core/Random.h" #include "src/Core/Replicate.h" #include "src/Core/Reverse.h" -#include "src/Core/ArrayBase.h" #include "src/Core/ArrayWrapper.h" #ifdef EIGEN_USE_BLAS @@ -369,8 +442,4 @@ using std::ptrdiff_t; #include "src/Core/util/ReenableStupidWarnings.h" -#ifdef EIGEN2_SUPPORT -#include "Eigen2Support" -#endif - #endif // EIGEN_CORE_H diff --git a/nuparu/include/Eigen/Eigen b/nuparu/include/Eigen/Eigen index 19b40ea4..654c8dc6 100644 --- a/nuparu/include/Eigen/Eigen +++ b/nuparu/include/Eigen/Eigen @@ -1,2 +1,2 @@ #include "Dense" -//#include "Sparse" +#include "Sparse" diff --git a/nuparu/include/Eigen/Eigen2Support b/nuparu/include/Eigen/Eigen2Support deleted file mode 100644 index 36156d29..00000000 --- a/nuparu/include/Eigen/Eigen2Support +++ /dev/null @@ -1,82 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN2SUPPORT_H -#define EIGEN2SUPPORT_H - -#if (!defined(EIGEN2_SUPPORT)) || (!defined(EIGEN_CORE_H)) -#error Eigen2 support must be enabled by defining EIGEN2_SUPPORT before including any Eigen header -#endif - -#include "src/Core/util/DisableStupidWarnings.h" - -/** \ingroup Support_modules - * \defgroup Eigen2Support_Module Eigen2 support module - * This module provides a couple of deprecated functions improving the compatibility with Eigen2. - * - * To use it, define EIGEN2_SUPPORT before including any Eigen header - * \code - * #define EIGEN2_SUPPORT - * \endcode - * - */ - -#include "src/Eigen2Support/Macros.h" -#include "src/Eigen2Support/Memory.h" -#include "src/Eigen2Support/Meta.h" -#include "src/Eigen2Support/Lazy.h" -#include "src/Eigen2Support/Cwise.h" -#include "src/Eigen2Support/CwiseOperators.h" -#include "src/Eigen2Support/TriangularSolver.h" -#include "src/Eigen2Support/Block.h" -#include "src/Eigen2Support/VectorBlock.h" -#include "src/Eigen2Support/Minor.h" -#include "src/Eigen2Support/MathFunctions.h" - - -#include "src/Core/util/ReenableStupidWarnings.h" - -// Eigen2 used to include iostream -#include - -#define EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, SizeSuffix) \ -using Eigen::Matrix##SizeSuffix##TypeSuffix; \ -using Eigen::Vector##SizeSuffix##TypeSuffix; \ -using Eigen::RowVector##SizeSuffix##TypeSuffix; - -#define EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(TypeSuffix) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 2) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 3) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 4) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, X) \ - -#define EIGEN_USING_MATRIX_TYPEDEFS \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(i) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(f) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(d) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(cf) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(cd) - -#define USING_PART_OF_NAMESPACE_EIGEN \ -EIGEN_USING_MATRIX_TYPEDEFS \ -using Eigen::Matrix; \ -using Eigen::MatrixBase; \ -using Eigen::ei_random; \ -using Eigen::ei_real; \ -using Eigen::ei_imag; \ -using Eigen::ei_conj; \ -using Eigen::ei_abs; \ -using Eigen::ei_abs2; \ -using Eigen::ei_sqrt; \ -using Eigen::ei_exp; \ -using Eigen::ei_log; \ -using Eigen::ei_sin; \ -using Eigen::ei_cos; - -#endif // EIGEN2SUPPORT_H diff --git a/nuparu/include/Eigen/Eigenvalues b/nuparu/include/Eigen/Eigenvalues index 53c5a73a..ea93eb30 100644 --- a/nuparu/include/Eigen/Eigenvalues +++ b/nuparu/include/Eigen/Eigenvalues @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_EIGENVALUES_MODULE_H #define EIGEN_EIGENVALUES_MODULE_H diff --git a/nuparu/include/Eigen/Geometry b/nuparu/include/Eigen/Geometry index efd9d450..06b736e3 100644 --- a/nuparu/include/Eigen/Geometry +++ b/nuparu/include/Eigen/Geometry @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_GEOMETRY_MODULE_H #define EIGEN_GEOMETRY_MODULE_H @@ -9,10 +16,6 @@ #include "LU" #include -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - /** \defgroup Geometry_Module Geometry module * * @@ -33,27 +36,23 @@ #include "src/Geometry/OrthoMethods.h" #include "src/Geometry/EulerAngles.h" -#if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS - #include "src/Geometry/Homogeneous.h" - #include "src/Geometry/RotationBase.h" - #include "src/Geometry/Rotation2D.h" - #include "src/Geometry/Quaternion.h" - #include "src/Geometry/AngleAxis.h" - #include "src/Geometry/Transform.h" - #include "src/Geometry/Translation.h" - #include "src/Geometry/Scaling.h" - #include "src/Geometry/Hyperplane.h" - #include "src/Geometry/ParametrizedLine.h" - #include "src/Geometry/AlignedBox.h" - #include "src/Geometry/Umeyama.h" - - #if defined EIGEN_VECTORIZE_SSE - #include "src/Geometry/arch/Geometry_SSE.h" - #endif -#endif - -#ifdef EIGEN2_SUPPORT -#include "src/Eigen2Support/Geometry/All.h" +#include "src/Geometry/Homogeneous.h" +#include "src/Geometry/RotationBase.h" +#include "src/Geometry/Rotation2D.h" +#include "src/Geometry/Quaternion.h" +#include "src/Geometry/AngleAxis.h" +#include "src/Geometry/Transform.h" +#include "src/Geometry/Translation.h" +#include "src/Geometry/Scaling.h" +#include "src/Geometry/Hyperplane.h" +#include "src/Geometry/ParametrizedLine.h" +#include "src/Geometry/AlignedBox.h" +#include "src/Geometry/Umeyama.h" + +// Use the SSE optimized version whenever possible. At the moment the +// SSE version doesn't compile when AVX is enabled +#if defined EIGEN_VECTORIZE_SSE && !defined EIGEN_VECTORIZE_AVX +#include "src/Geometry/arch/Geometry_SSE.h" #endif #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/nuparu/include/Eigen/Householder b/nuparu/include/Eigen/Householder index 6e348db5..89cd81b1 100644 --- a/nuparu/include/Eigen/Householder +++ b/nuparu/include/Eigen/Householder @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_HOUSEHOLDER_MODULE_H #define EIGEN_HOUSEHOLDER_MODULE_H diff --git a/nuparu/include/Eigen/IterativeLinearSolvers b/nuparu/include/Eigen/IterativeLinearSolvers index 0f4159dc..957d5750 100644 --- a/nuparu/include/Eigen/IterativeLinearSolvers +++ b/nuparu/include/Eigen/IterativeLinearSolvers @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_ITERATIVELINEARSOLVERS_MODULE_H #define EIGEN_ITERATIVELINEARSOLVERS_MODULE_H @@ -12,28 +19,29 @@ * This module currently provides iterative methods to solve problems of the form \c A \c x = \c b, where \c A is a squared matrix, usually very large and sparse. * Those solvers are accessible via the following classes: * - ConjugateGradient for selfadjoint (hermitian) matrices, + * - LeastSquaresConjugateGradient for rectangular least-square problems, * - BiCGSTAB for general square matrices. * * These iterative solvers are associated with some preconditioners: * - IdentityPreconditioner - not really useful - * - DiagonalPreconditioner - also called JAcobi preconditioner, work very well on diagonal dominant matrices. - * - IncompleteILUT - incomplete LU factorization with dual thresholding + * - DiagonalPreconditioner - also called Jacobi preconditioner, work very well on diagonal dominant matrices. + * - IncompleteLUT - incomplete LU factorization with dual thresholding * * Such problems can also be solved using the direct sparse decomposition modules: SparseCholesky, CholmodSupport, UmfPackSupport, SuperLUSupport. * - * \code - * #include - * \endcode + \code + #include + \endcode */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - +#include "src/IterativeLinearSolvers/SolveWithGuess.h" #include "src/IterativeLinearSolvers/IterativeSolverBase.h" #include "src/IterativeLinearSolvers/BasicPreconditioners.h" #include "src/IterativeLinearSolvers/ConjugateGradient.h" +#include "src/IterativeLinearSolvers/LeastSquareConjugateGradient.h" #include "src/IterativeLinearSolvers/BiCGSTAB.h" #include "src/IterativeLinearSolvers/IncompleteLUT.h" +#include "src/IterativeLinearSolvers/IncompleteCholesky.h" #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/nuparu/include/Eigen/Jacobi b/nuparu/include/Eigen/Jacobi index ba8a4dc3..17c1d785 100644 --- a/nuparu/include/Eigen/Jacobi +++ b/nuparu/include/Eigen/Jacobi @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_JACOBI_MODULE_H #define EIGEN_JACOBI_MODULE_H diff --git a/nuparu/include/Eigen/LU b/nuparu/include/Eigen/LU index db579550..2d70c92d 100644 --- a/nuparu/include/Eigen/LU +++ b/nuparu/include/Eigen/LU @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_LU_MODULE_H #define EIGEN_LU_MODULE_H @@ -16,7 +23,6 @@ * \endcode */ -#include "src/misc/Solve.h" #include "src/misc/Kernel.h" #include "src/misc/Image.h" #include "src/LU/FullPivLU.h" @@ -25,16 +31,14 @@ #include "src/LU/PartialPivLU_MKL.h" #endif #include "src/LU/Determinant.h" -#include "src/LU/Inverse.h" +#include "src/LU/InverseImpl.h" -#if defined EIGEN_VECTORIZE_SSE +// Use the SSE optimized version whenever possible. At the moment the +// SSE version doesn't compile when AVX is enabled +#if defined EIGEN_VECTORIZE_SSE && !defined EIGEN_VECTORIZE_AVX #include "src/LU/arch/Inverse_SSE.h" #endif -#ifdef EIGEN2_SUPPORT - #include "src/Eigen2Support/LU.h" -#endif - #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_LU_MODULE_H diff --git a/nuparu/include/Eigen/LeastSquares b/nuparu/include/Eigen/LeastSquares deleted file mode 100644 index 35137c25..00000000 --- a/nuparu/include/Eigen/LeastSquares +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef EIGEN_REGRESSION_MODULE_H -#define EIGEN_REGRESSION_MODULE_H - -#ifndef EIGEN2_SUPPORT -#error LeastSquares is only available in Eigen2 support mode (define EIGEN2_SUPPORT) -#endif - -// exclude from normal eigen3-only documentation -#ifdef EIGEN2_SUPPORT - -#include "Core" - -#include "src/Core/util/DisableStupidWarnings.h" - -#include "Eigenvalues" -#include "Geometry" - -/** \defgroup LeastSquares_Module LeastSquares module - * This module provides linear regression and related features. - * - * \code - * #include - * \endcode - */ - -#include "src/Eigen2Support/LeastSquares.h" - -#include "src/Core/util/ReenableStupidWarnings.h" - -#endif // EIGEN2_SUPPORT - -#endif // EIGEN_REGRESSION_MODULE_H diff --git a/nuparu/include/Eigen/MetisSupport b/nuparu/include/Eigen/MetisSupport index 6a113f7a..85c41bf3 100644 --- a/nuparu/include/Eigen/MetisSupport +++ b/nuparu/include/Eigen/MetisSupport @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_METISSUPPORT_MODULE_H #define EIGEN_METISSUPPORT_MODULE_H diff --git a/nuparu/include/Eigen/OrderingMethods b/nuparu/include/Eigen/OrderingMethods index 7c0f1fff..d8ea3619 100644 --- a/nuparu/include/Eigen/OrderingMethods +++ b/nuparu/include/Eigen/OrderingMethods @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_ORDERINGMETHODS_MODULE_H #define EIGEN_ORDERINGMETHODS_MODULE_H diff --git a/nuparu/include/Eigen/PaStiXSupport b/nuparu/include/Eigen/PaStiXSupport index 7c616ee5..3411dfac 100644 --- a/nuparu/include/Eigen/PaStiXSupport +++ b/nuparu/include/Eigen/PaStiXSupport @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_PASTIXSUPPORT_MODULE_H #define EIGEN_PASTIXSUPPORT_MODULE_H @@ -35,12 +42,8 @@ extern "C" { * */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - #include "src/PaStiXSupport/PaStiXSupport.h" - #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_PASTIXSUPPORT_MODULE_H diff --git a/nuparu/include/Eigen/PardisoSupport b/nuparu/include/Eigen/PardisoSupport old mode 100644 new mode 100755 index 99330ce7..340edf51 --- a/nuparu/include/Eigen/PardisoSupport +++ b/nuparu/include/Eigen/PardisoSupport @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_PARDISOSUPPORT_MODULE_H #define EIGEN_PARDISOSUPPORT_MODULE_H @@ -7,8 +14,6 @@ #include -#include - /** \ingroup Support_modules * \defgroup PardisoSupport_Module PardisoSupport module * diff --git a/nuparu/include/Eigen/QR b/nuparu/include/Eigen/QR index ac5b0269..f74f365f 100644 --- a/nuparu/include/Eigen/QR +++ b/nuparu/include/Eigen/QR @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_QR_MODULE_H #define EIGEN_QR_MODULE_H @@ -15,14 +22,15 @@ * * This module provides various QR decompositions * This module also provides some MatrixBase methods, including: - * - MatrixBase::qr(), + * - MatrixBase::householderQr() + * - MatrixBase::colPivHouseholderQr() + * - MatrixBase::fullPivHouseholderQr() * * \code * #include * \endcode */ -#include "src/misc/Solve.h" #include "src/QR/HouseholderQR.h" #include "src/QR/FullPivHouseholderQR.h" #include "src/QR/ColPivHouseholderQR.h" @@ -31,15 +39,7 @@ #include "src/QR/ColPivHouseholderQR_MKL.h" #endif -#ifdef EIGEN2_SUPPORT -#include "src/Eigen2Support/QR.h" -#endif - #include "src/Core/util/ReenableStupidWarnings.h" -#ifdef EIGEN2_SUPPORT -#include "Eigenvalues" -#endif - #endif // EIGEN_QR_MODULE_H /* vim: set filetype=cpp et sw=2 ts=2 ai: */ diff --git a/nuparu/include/Eigen/QtAlignedMalloc b/nuparu/include/Eigen/QtAlignedMalloc index 46f7d83b..4044d5ac 100644 --- a/nuparu/include/Eigen/QtAlignedMalloc +++ b/nuparu/include/Eigen/QtAlignedMalloc @@ -1,3 +1,9 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_QTMALLOC_MODULE_H #define EIGEN_QTMALLOC_MODULE_H diff --git a/nuparu/include/Eigen/SPQRSupport b/nuparu/include/Eigen/SPQRSupport index 77016442..f9489dcd 100644 --- a/nuparu/include/Eigen/SPQRSupport +++ b/nuparu/include/Eigen/SPQRSupport @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_SPQRSUPPORT_MODULE_H #define EIGEN_SPQRSUPPORT_MODULE_H @@ -21,8 +28,6 @@ * */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" #include "src/CholmodSupport/CholmodSupport.h" #include "src/SPQRSupport/SuiteSparseQRSupport.h" diff --git a/nuparu/include/Eigen/SVD b/nuparu/include/Eigen/SVD index fd310017..b353f3f5 100644 --- a/nuparu/include/Eigen/SVD +++ b/nuparu/include/Eigen/SVD @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_SVD_MODULE_H #define EIGEN_SVD_MODULE_H @@ -12,24 +19,25 @@ * * * This module provides SVD decomposition for matrices (both real and complex). - * This decomposition is accessible via the following MatrixBase method: + * Two decomposition algorithms are provided: + * - JacobiSVD implementing two-sided Jacobi iterations is numerically very accurate, fast for small matrices, but very slow for larger ones. + * - BDCSVD implementing a recursive divide & conquer strategy on top of an upper-bidiagonalization which remains fast for large problems. + * These decompositions are accessible via the respective classes and following MatrixBase methods: * - MatrixBase::jacobiSvd() + * - MatrixBase::bdcSvd() * * \code * #include * \endcode */ -#include "src/misc/Solve.h" +#include "src/SVD/UpperBidiagonalization.h" +#include "src/SVD/SVDBase.h" #include "src/SVD/JacobiSVD.h" +#include "src/SVD/BDCSVD.h" #if defined(EIGEN_USE_LAPACKE) && !defined(EIGEN_USE_LAPACKE_STRICT) #include "src/SVD/JacobiSVD_MKL.h" #endif -#include "src/SVD/UpperBidiagonalization.h" - -#ifdef EIGEN2_SUPPORT -#include "src/Eigen2Support/SVD.h" -#endif #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/nuparu/include/Eigen/Sparse b/nuparu/include/Eigen/Sparse index 7cc9c091..a2ef7a66 100644 --- a/nuparu/include/Eigen/Sparse +++ b/nuparu/include/Eigen/Sparse @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_SPARSE_MODULE_H #define EIGEN_SPARSE_MODULE_H @@ -11,9 +18,9 @@ * - \ref SparseQR_Module * - \ref IterativeLinearSolvers_Module * - * \code - * #include - * \endcode + \code + #include + \endcode */ #include "SparseCore" diff --git a/nuparu/include/Eigen/SparseCholesky b/nuparu/include/Eigen/SparseCholesky index 9f5056aa..b6a320c4 100644 --- a/nuparu/include/Eigen/SparseCholesky +++ b/nuparu/include/Eigen/SparseCholesky @@ -34,8 +34,6 @@ #error The SparseCholesky module has nothing to offer in MPL2 only mode #endif -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" #include "src/SparseCholesky/SimplicialCholesky.h" #ifndef EIGEN_MPL2_ONLY diff --git a/nuparu/include/Eigen/SparseCore b/nuparu/include/Eigen/SparseCore index 9b5be5e1..76966c4c 100644 --- a/nuparu/include/Eigen/SparseCore +++ b/nuparu/include/Eigen/SparseCore @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_SPARSECORE_MODULE_H #define EIGEN_SPARSECORE_MODULE_H @@ -14,7 +21,7 @@ /** * \defgroup SparseCore_Module SparseCore module * - * This module provides a sparse matrix representation, and basic associatd matrix manipulations + * This module provides a sparse matrix representation, and basic associated matrix manipulations * and operations. * * See the \ref TutorialSparse "Sparse tutorial" @@ -26,37 +33,35 @@ * This module depends on: Core. */ -namespace Eigen { - -/** The type used to identify a general sparse storage. */ -struct Sparse {}; - -} - #include "src/SparseCore/SparseUtil.h" #include "src/SparseCore/SparseMatrixBase.h" +#include "src/SparseCore/SparseAssign.h" #include "src/SparseCore/CompressedStorage.h" #include "src/SparseCore/AmbiVector.h" +#include "src/SparseCore/SparseCompressedBase.h" #include "src/SparseCore/SparseMatrix.h" +#include "src/SparseCore/SparseMap.h" #include "src/SparseCore/MappedSparseMatrix.h" #include "src/SparseCore/SparseVector.h" -#include "src/SparseCore/SparseBlock.h" -#include "src/SparseCore/SparseTranspose.h" +#include "src/SparseCore/SparseRef.h" #include "src/SparseCore/SparseCwiseUnaryOp.h" #include "src/SparseCore/SparseCwiseBinaryOp.h" +#include "src/SparseCore/SparseTranspose.h" +#include "src/SparseCore/SparseBlock.h" #include "src/SparseCore/SparseDot.h" -#include "src/SparseCore/SparsePermutation.h" #include "src/SparseCore/SparseRedux.h" -#include "src/SparseCore/SparseFuzzy.h" +#include "src/SparseCore/SparseView.h" +#include "src/SparseCore/SparseDiagonalProduct.h" #include "src/SparseCore/ConservativeSparseSparseProduct.h" #include "src/SparseCore/SparseSparseProductWithPruning.h" #include "src/SparseCore/SparseProduct.h" #include "src/SparseCore/SparseDenseProduct.h" -#include "src/SparseCore/SparseDiagonalProduct.h" -#include "src/SparseCore/SparseTriangularView.h" #include "src/SparseCore/SparseSelfAdjointView.h" +#include "src/SparseCore/SparseTriangularView.h" #include "src/SparseCore/TriangularSolver.h" -#include "src/SparseCore/SparseView.h" +#include "src/SparseCore/SparsePermutation.h" +#include "src/SparseCore/SparseFuzzy.h" +#include "src/SparseCore/SparseSolverBase.h" #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/nuparu/include/Eigen/SparseLU b/nuparu/include/Eigen/SparseLU index 8527a49b..38b38b53 100644 --- a/nuparu/include/Eigen/SparseLU +++ b/nuparu/include/Eigen/SparseLU @@ -20,9 +20,6 @@ * Please, see the documentation of the SparseLU class for more details. */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - // Ordering interface #include "OrderingMethods" diff --git a/nuparu/include/Eigen/SparseQR b/nuparu/include/Eigen/SparseQR index 4ee42065..a6f3b7f7 100644 --- a/nuparu/include/Eigen/SparseQR +++ b/nuparu/include/Eigen/SparseQR @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_SPARSEQR_MODULE_H #define EIGEN_SPARSEQR_MODULE_H @@ -21,9 +28,6 @@ * */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - #include "OrderingMethods" #include "src/SparseCore/SparseColEtree.h" #include "src/SparseQR/SparseQR.h" diff --git a/nuparu/include/Eigen/StdDeque b/nuparu/include/Eigen/StdDeque index f2723477..be3a7f82 100644 --- a/nuparu/include/Eigen/StdDeque +++ b/nuparu/include/Eigen/StdDeque @@ -14,7 +14,7 @@ #include "Core" #include -#if (defined(_MSC_VER) && defined(_WIN64)) /* MSVC auto aligns in 64 bit builds */ +#if EIGEN_COMP_MSVC && EIGEN_OS_WIN64 /* MSVC auto aligns in 64 bit builds */ #define EIGEN_DEFINE_STL_DEQUE_SPECIALIZATION(...) diff --git a/nuparu/include/Eigen/StdList b/nuparu/include/Eigen/StdList index 225c1e18..07ba1297 100644 --- a/nuparu/include/Eigen/StdList +++ b/nuparu/include/Eigen/StdList @@ -13,7 +13,7 @@ #include "Core" #include -#if (defined(_MSC_VER) && defined(_WIN64)) /* MSVC auto aligns in 64 bit builds */ +#if EIGEN_COMP_MSVC && EIGEN_OS_WIN64 /* MSVC auto aligns in 64 bit builds */ #define EIGEN_DEFINE_STL_LIST_SPECIALIZATION(...) diff --git a/nuparu/include/Eigen/StdVector b/nuparu/include/Eigen/StdVector index 6b22627f..fdfc3776 100644 --- a/nuparu/include/Eigen/StdVector +++ b/nuparu/include/Eigen/StdVector @@ -14,7 +14,7 @@ #include "Core" #include -#if (defined(_MSC_VER) && defined(_WIN64)) /* MSVC auto aligns in 64 bit builds */ +#if EIGEN_COMP_MSVC && EIGEN_OS_WIN64 /* MSVC auto aligns in 64 bit builds */ #define EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(...) diff --git a/nuparu/include/Eigen/SuperLUSupport b/nuparu/include/Eigen/SuperLUSupport index 575e14fb..113f58ee 100644 --- a/nuparu/include/Eigen/SuperLUSupport +++ b/nuparu/include/Eigen/SuperLUSupport @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_SUPERLUSUPPORT_MODULE_H #define EIGEN_SUPERLUSUPPORT_MODULE_H @@ -36,6 +43,8 @@ namespace Eigen { struct SluMatrix; } * - class SuperLU: a supernodal sequential LU factorization. * - class SuperILU: a supernodal sequential incomplete LU factorization (to be used as a preconditioner for iterative methods). * + * \warning This wrapper is only for the 4.x versions of SuperLU. The 3.x and 5.x versions are not supported. + * * \warning When including this module, you have to use SUPERLU_EMPTY instead of EMPTY which is no longer defined because it is too polluting. * * \code @@ -48,12 +57,8 @@ namespace Eigen { struct SluMatrix; } * */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - #include "src/SuperLUSupport/SuperLUSupport.h" - #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_SUPERLUSUPPORT_MODULE_H diff --git a/nuparu/include/Eigen/UmfPackSupport b/nuparu/include/Eigen/UmfPackSupport index 984f64a8..4a9f46a1 100644 --- a/nuparu/include/Eigen/UmfPackSupport +++ b/nuparu/include/Eigen/UmfPackSupport @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_UMFPACKSUPPORT_MODULE_H #define EIGEN_UMFPACKSUPPORT_MODULE_H @@ -26,9 +33,6 @@ extern "C" { * */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - #include "src/UmfPackSupport/UmfPackSupport.h" #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/nuparu/include/Eigen/src/Cholesky/LDLT.h b/nuparu/include/Eigen/src/Cholesky/LDLT.h index d19cb396..6fcae01f 100644 --- a/nuparu/include/Eigen/src/Cholesky/LDLT.h +++ b/nuparu/include/Eigen/src/Cholesky/LDLT.h @@ -16,7 +16,10 @@ namespace Eigen { namespace internal { -template struct LDLT_Traits; + template struct LDLT_Traits; + + // PositiveSemiDef means positive semi-definite and non-zero; same for NegativeSemiDef + enum SignMatrix { PositiveSemiDef, NegativeSemiDef, ZeroSign, Indefinite }; } /** \ingroup Cholesky_Module @@ -40,7 +43,7 @@ template struct LDLT_Traits; * Remember that Cholesky decompositions are not rank-revealing. Also, do not use a Cholesky * decomposition to determine whether a system of equations has a solution. * - * \sa MatrixBase::ldlt(), class LLT + * \sa MatrixBase::ldlt(), SelfAdjointView::ldlt(), class LLT */ template class LDLT { @@ -56,7 +59,8 @@ template class LDLT }; typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; - typedef typename MatrixType::Index Index; + typedef Eigen::Index Index; ///< \deprecated since Eigen 3.3 + typedef typename MatrixType::StorageIndex StorageIndex; typedef Matrix TmpMatrixType; typedef Transpositions TranspositionType; @@ -69,7 +73,12 @@ template class LDLT * The default constructor is useful in cases in which the user intends to * perform decompositions via LDLT::compute(const MatrixType&). */ - LDLT() : m_matrix(), m_transpositions(), m_isInitialized(false) {} + LDLT() + : m_matrix(), + m_transpositions(), + m_sign(internal::ZeroSign), + m_isInitialized(false) + {} /** \brief Default Constructor with memory preallocation * @@ -77,10 +86,11 @@ template class LDLT * according to the specified problem \a size. * \sa LDLT() */ - LDLT(Index size) + explicit LDLT(Index size) : m_matrix(size, size), m_transpositions(size), m_temporary(size), + m_sign(internal::ZeroSign), m_isInitialized(false) {} @@ -89,13 +99,15 @@ template class LDLT * This calculates the decomposition for the input \a matrix. * \sa LDLT(Index size) */ - LDLT(const MatrixType& matrix) + template + explicit LDLT(const EigenBase& matrix) : m_matrix(matrix.rows(), matrix.cols()), m_transpositions(matrix.rows()), m_temporary(matrix.rows()), + m_sign(internal::ZeroSign), m_isInitialized(false) { - compute(matrix); + compute(matrix.derived()); } /** Clear any existing decomposition @@ -139,21 +151,14 @@ template class LDLT inline bool isPositive() const { eigen_assert(m_isInitialized && "LDLT is not initialized."); - return m_sign == 1; - } - - #ifdef EIGEN2_SUPPORT - inline bool isPositiveDefinite() const - { - return isPositive(); + return m_sign == internal::PositiveSemiDef || m_sign == internal::ZeroSign; } - #endif /** \returns true if the matrix is negative (semidefinite) */ inline bool isNegative(void) const { eigen_assert(m_isInitialized && "LDLT is not initialized."); - return m_sign == -1; + return m_sign == internal::NegativeSemiDef || m_sign == internal::ZeroSign; } /** \returns a solution x of \f$ A x = b \f$ using the current decomposition of A. @@ -169,31 +174,23 @@ template class LDLT * least-square solution of \f$ D y_3 = y_2 \f$ is computed. This does not mean that this function * computes the least-square solution of \f$ A x = b \f$ is \f$ A \f$ is singular. * - * \sa MatrixBase::ldlt() + * \sa MatrixBase::ldlt(), SelfAdjointView::ldlt() */ template - inline const internal::solve_retval + inline const Solve solve(const MatrixBase& b) const { eigen_assert(m_isInitialized && "LDLT is not initialized."); eigen_assert(m_matrix.rows()==b.rows() && "LDLT::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); + return Solve(*this, b.derived()); } - #ifdef EIGEN2_SUPPORT - template - bool solve(const MatrixBase& b, ResultType *result) const - { - *result = this->solve(b); - return true; - } - #endif - template bool solveInPlace(MatrixBase &bAndX) const; - LDLT& compute(const MatrixType& matrix); + template + LDLT& compute(const EigenBase& matrix); template LDLT& rankUpdate(const MatrixBase& w, const RealScalar& alpha=1); @@ -223,8 +220,19 @@ template class LDLT eigen_assert(m_isInitialized && "LDLT is not initialized."); return Success; } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_DEVICE_FUNC + void _solve_impl(const RhsType &rhs, DstType &dst) const; + #endif protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } /** \internal * Used to compute and store the Cholesky decomposition A = L D L^* = U^* D U. @@ -235,7 +243,7 @@ template class LDLT MatrixType m_matrix; TranspositionType m_transpositions; TmpMatrixType m_temporary; - int m_sign; + internal::SignMatrix m_sign; bool m_isInitialized; }; @@ -246,49 +254,32 @@ template struct ldlt_inplace; template<> struct ldlt_inplace { template - static bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, int* sign=0) + static bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, SignMatrix& sign) { using std::abs; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; - typedef typename MatrixType::Index Index; + typedef typename TranspositionType::StorageIndex IndexType; eigen_assert(mat.rows()==mat.cols()); const Index size = mat.rows(); if (size <= 1) { transpositions.setIdentity(); - if(sign) - *sign = numext::real(mat.coeff(0,0))>0 ? 1:-1; + if (numext::real(mat.coeff(0,0)) > 0) sign = PositiveSemiDef; + else if (numext::real(mat.coeff(0,0)) < 0) sign = NegativeSemiDef; + else sign = ZeroSign; return true; } - RealScalar cutoff(0), biggest_in_corner; - for (Index k = 0; k < size; ++k) { // Find largest diagonal element Index index_of_biggest_in_corner; - biggest_in_corner = mat.diagonal().tail(size-k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner); + mat.diagonal().tail(size-k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner); index_of_biggest_in_corner += k; - if(k == 0) - { - // The biggest overall is the point of reference to which further diagonals - // are compared; if any diagonal is negligible compared - // to the largest overall, the algorithm bails. - cutoff = abs(NumTraits::epsilon() * biggest_in_corner); - } - - // Finish early if the matrix is not full rank. - if(biggest_in_corner < cutoff) - { - for(Index i = k; i < size; i++) transpositions.coeffRef(i) = i; - if(sign) *sign = 0; - break; - } - - transpositions.coeffRef(k) = index_of_biggest_in_corner; + transpositions.coeffRef(k) = IndexType(index_of_biggest_in_corner); if(k != index_of_biggest_in_corner) { // apply the transposition while taking care to consider only @@ -297,7 +288,7 @@ template<> struct ldlt_inplace mat.row(k).head(k).swap(mat.row(index_of_biggest_in_corner).head(k)); mat.col(k).tail(s).swap(mat.col(index_of_biggest_in_corner).tail(s)); std::swap(mat.coeffRef(k,k),mat.coeffRef(index_of_biggest_in_corner,index_of_biggest_in_corner)); - for(int i=k+1;i struct ldlt_inplace if(k>0) { - temp.head(k) = mat.diagonal().head(k).asDiagonal() * A10.adjoint(); + temp.head(k) = mat.diagonal().real().head(k).asDiagonal() * A10.adjoint(); mat.coeffRef(k,k) -= (A10 * temp.head(k)).value(); if(rs>0) A21.noalias() -= A20 * temp.head(k); } - if((rs>0) && (abs(mat.coeffRef(k,k)) > cutoff)) - A21 /= mat.coeffRef(k,k); - if(sign) - { - // LDLT is not guaranteed to work for indefinite matrices, but let's try to get the sign right - int newSign = numext::real(mat.diagonal().coeff(index_of_biggest_in_corner)) > 0; - if(k == 0) - *sign = newSign; - else if(*sign != newSign) - *sign = 0; + // In some previous versions of Eigen (e.g., 3.2.1), the scaling was omitted if the pivot + // was smaller than the cutoff value. However, since LDLT is not rank-revealing + // we should only make sure that we do not introduce INF or NaN values. + // Remark that LAPACK also uses 0 as the cutoff value. + RealScalar realAkk = numext::real(mat.coeffRef(k,k)); + if((rs>0) && (abs(realAkk) > RealScalar(0))) + A21 /= realAkk; + + if (sign == PositiveSemiDef) { + if (realAkk < 0) sign = Indefinite; + } else if (sign == NegativeSemiDef) { + if (realAkk > 0) sign = Indefinite; + } else if (sign == ZeroSign) { + if (realAkk > 0) sign = PositiveSemiDef; + else if (realAkk < 0) sign = NegativeSemiDef; } } @@ -353,7 +349,6 @@ template<> struct ldlt_inplace using numext::isfinite; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; - typedef typename MatrixType::Index Index; const Index size = mat.rows(); eigen_assert(mat.cols() == size && w.size()==size); @@ -399,7 +394,7 @@ template<> struct ldlt_inplace template<> struct ldlt_inplace { template - static EIGEN_STRONG_INLINE bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, int* sign=0) + static EIGEN_STRONG_INLINE bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, SignMatrix& sign) { Transpose matt(mat); return ldlt_inplace::unblocked(matt, transpositions, temp, sign); @@ -417,16 +412,16 @@ template struct LDLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m; } - static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); } }; template struct LDLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m.adjoint(); } - static inline MatrixU getU(const MatrixType& m) { return m; } + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m.adjoint()); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m); } }; } // end namespace internal @@ -434,18 +429,22 @@ template struct LDLT_Traits /** Compute / recompute the LDLT decomposition A = L D L^* = U^* D U of \a matrix */ template -LDLT& LDLT::compute(const MatrixType& a) +template +LDLT& LDLT::compute(const EigenBase& a) { + check_template_parameters(); + eigen_assert(a.rows()==a.cols()); const Index size = a.rows(); - m_matrix = a; + m_matrix = a.derived(); m_transpositions.resize(size); m_isInitialized = false; m_temporary.resize(size); + m_sign = internal::ZeroSign; - internal::ldlt_inplace::unblocked(m_matrix, m_transpositions, m_temporary, &m_sign); + internal::ldlt_inplace::unblocked(m_matrix, m_transpositions, m_temporary, m_sign); m_isInitialized = true; return *this; @@ -458,8 +457,9 @@ LDLT& LDLT::compute(const MatrixType& a) */ template template -LDLT& LDLT::rankUpdate(const MatrixBase& w, const typename NumTraits::Real& sigma) +LDLT& LDLT::rankUpdate(const MatrixBase& w, const typename LDLT::RealScalar& sigma) { + typedef typename TranspositionType::StorageIndex IndexType; const Index size = w.rows(); if (m_isInitialized) { @@ -471,9 +471,9 @@ LDLT& LDLT::rankUpdate(const MatrixBase=0 ? 1 : -1; + m_sign = sigma>=0 ? internal::PositiveSemiDef : internal::NegativeSemiDef; m_isInitialized = true; } @@ -482,48 +482,45 @@ LDLT& LDLT::rankUpdate(const MatrixBase -struct solve_retval, Rhs> - : solve_retval_base, Rhs> +#ifndef EIGEN_PARSED_BY_DOXYGEN +template +template +void LDLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) const { - typedef LDLT<_MatrixType,_UpLo> LDLTType; - EIGEN_MAKE_SOLVE_HELPERS(LDLTType,Rhs) - - template void evalTo(Dest& dst) const + eigen_assert(rhs.rows() == rows()); + // dst = P b + dst = m_transpositions * rhs; + + // dst = L^-1 (P b) + matrixL().solveInPlace(dst); + + // dst = D^-1 (L^-1 P b) + // more precisely, use pseudo-inverse of D (see bug 241) + using std::abs; + const typename Diagonal::RealReturnType vecD(vectorD()); + // In some previous versions, tolerance was set to the max of 1/highest and the maximal diagonal entry * epsilon + // as motivated by LAPACK's xGELSS: + // RealScalar tolerance = numext::maxi(vecD.array().abs().maxCoeff() * NumTraits::epsilon(),RealScalar(1) / NumTraits::highest()); + // However, LDLT is not rank revealing, and so adjusting the tolerance wrt to the highest + // diagonal element is not well justified and leads to numerical issues in some cases. + // Moreover, Lapack's xSYTRS routines use 0 for the tolerance. + RealScalar tolerance = RealScalar(1) / NumTraits::highest(); + + for (Index i = 0; i < vecD.size(); ++i) { - eigen_assert(rhs().rows() == dec().matrixLDLT().rows()); - // dst = P b - dst = dec().transpositionsP() * rhs(); - - // dst = L^-1 (P b) - dec().matrixL().solveInPlace(dst); - - // dst = D^-1 (L^-1 P b) - // more precisely, use pseudo-inverse of D (see bug 241) - using std::abs; - using std::max; - typedef typename LDLTType::MatrixType MatrixType; - typedef typename LDLTType::Scalar Scalar; - typedef typename LDLTType::RealScalar RealScalar; - const Diagonal vectorD = dec().vectorD(); - RealScalar tolerance = (max)(vectorD.array().abs().maxCoeff() * NumTraits::epsilon(), - RealScalar(1) / NumTraits::highest()); // motivated by LAPACK's xGELSS - for (Index i = 0; i < vectorD.size(); ++i) { - if(abs(vectorD(i)) > tolerance) - dst.row(i) /= vectorD(i); - else - dst.row(i).setZero(); - } + if(abs(vecD(i)) > tolerance) + dst.row(i) /= vecD(i); + else + dst.row(i).setZero(); + } - // dst = L^-T (D^-1 L^-1 P b) - dec().matrixU().solveInPlace(dst); + // dst = L^-T (D^-1 L^-1 P b) + matrixU().solveInPlace(dst); - // dst = P^-1 (L^-T D^-1 L^-1 P b) = A^-1 b - dst = dec().transpositionsP().transpose() * dst; - } -}; + // dst = P^-1 (L^-T D^-1 L^-1 P b) = A^-1 b + dst = m_transpositions.transpose() * dst; } +#endif /** \internal use x = ldlt_object.solve(x); * @@ -566,7 +563,7 @@ MatrixType LDLT::reconstructedMatrix() const // L^* P res = matrixU() * res; // D(L^*P) - res = vectorD().asDiagonal() * res; + res = vectorD().real().asDiagonal() * res; // L(DL^*P) res = matrixL() * res; // P^T (LDL^*P) @@ -575,8 +572,10 @@ MatrixType LDLT::reconstructedMatrix() const return res; } +#ifndef __CUDACC__ /** \cholesky_module * \returns the Cholesky decomposition with full pivoting without square root of \c *this + * \sa MatrixBase::ldlt() */ template inline const LDLT::PlainObject, UpLo> @@ -587,6 +586,7 @@ SelfAdjointView::ldlt() const /** \cholesky_module * \returns the Cholesky decomposition with full pivoting without square root of \c *this + * \sa SelfAdjointView::ldlt() */ template inline const LDLT::PlainObject> @@ -594,6 +594,7 @@ MatrixBase::ldlt() const { return LDLT(derived()); } +#endif // __CUDACC__ } // end namespace Eigen diff --git a/nuparu/include/Eigen/src/Cholesky/LLT.h b/nuparu/include/Eigen/src/Cholesky/LLT.h index 2e6189f7..1f0091f3 100644 --- a/nuparu/include/Eigen/src/Cholesky/LLT.h +++ b/nuparu/include/Eigen/src/Cholesky/LLT.h @@ -41,7 +41,7 @@ template struct LLT_Traits; * Example: \include LLT_example.cpp * Output: \verbinclude LLT_example.out * - * \sa MatrixBase::llt(), class LDLT + * \sa MatrixBase::llt(), SelfAdjointView::llt(), class LDLT */ /* HEY THIS DOX IS DISABLED BECAUSE THERE's A BUG EITHER HERE OR IN LDLT ABOUT THAT (OR BOTH) * Note that during the decomposition, only the upper triangular part of A is considered. Therefore, @@ -59,7 +59,8 @@ template class LLT }; typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; - typedef typename MatrixType::Index Index; + typedef Eigen::Index Index; ///< \deprecated since Eigen 3.3 + typedef typename MatrixType::StorageIndex StorageIndex; enum { PacketSize = internal::packet_traits::size, @@ -83,14 +84,15 @@ template class LLT * according to the specified problem \a size. * \sa LLT() */ - LLT(Index size) : m_matrix(size, size), + explicit LLT(Index size) : m_matrix(size, size), m_isInitialized(false) {} - LLT(const MatrixType& matrix) + template + explicit LLT(const EigenBase& matrix) : m_matrix(matrix.rows(), matrix.cols()), m_isInitialized(false) { - compute(matrix); + compute(matrix.derived()); } /** \returns a view of the upper triangular matrix U */ @@ -115,33 +117,23 @@ template class LLT * Example: \include LLT_solve.cpp * Output: \verbinclude LLT_solve.out * - * \sa solveInPlace(), MatrixBase::llt() + * \sa solveInPlace(), MatrixBase::llt(), SelfAdjointView::llt() */ template - inline const internal::solve_retval + inline const Solve solve(const MatrixBase& b) const { eigen_assert(m_isInitialized && "LLT is not initialized."); eigen_assert(m_matrix.rows()==b.rows() && "LLT::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); + return Solve(*this, b.derived()); } - #ifdef EIGEN2_SUPPORT - template - bool solve(const MatrixBase& b, ResultType *result) const - { - *result = this->solve(b); - return true; - } - - bool isPositiveDefinite() const { return true; } - #endif - template void solveInPlace(MatrixBase &bAndX) const; - LLT& compute(const MatrixType& matrix); + template + LLT& compute(const EigenBase& matrix); /** \returns the LLT decomposition matrix * @@ -172,8 +164,20 @@ template class LLT template LLT rankUpdate(const VectorType& vec, const RealScalar& sigma = 1); + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_DEVICE_FUNC + void _solve_impl(const RhsType &rhs, DstType &dst) const; + #endif protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + /** \internal * Used to compute and store L * The strict upper part is not used and even not initialized. @@ -188,12 +192,11 @@ namespace internal { template struct llt_inplace; template -static typename MatrixType::Index llt_rank_update_lower(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) +static Index llt_rank_update_lower(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) { using std::sqrt; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; - typedef typename MatrixType::Index Index; typedef typename MatrixType::ColXpr ColXpr; typedef typename internal::remove_all::type ColXprCleaned; typedef typename ColXprCleaned::SegmentReturnType ColXprSegment; @@ -262,10 +265,9 @@ template struct llt_inplace { typedef typename NumTraits::Real RealScalar; template - static typename MatrixType::Index unblocked(MatrixType& mat) + static Index unblocked(MatrixType& mat) { using std::sqrt; - typedef typename MatrixType::Index Index; eigen_assert(mat.rows()==mat.cols()); const Index size = mat.rows(); @@ -283,15 +285,14 @@ template struct llt_inplace return k; mat.coeffRef(k,k) = x = sqrt(x); if (k>0 && rs>0) A21.noalias() -= A20 * A10.adjoint(); - if (rs>0) A21 *= RealScalar(1)/x; + if (rs>0) A21 /= x; } return -1; } template - static typename MatrixType::Index blocked(MatrixType& m) + static Index blocked(MatrixType& m) { - typedef typename MatrixType::Index Index; eigen_assert(m.rows()==m.cols()); Index size = m.rows(); if(size<32) @@ -322,7 +323,7 @@ template struct llt_inplace } template - static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma) + static Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma) { return Eigen::internal::llt_rank_update_lower(mat, vec, sigma); } @@ -333,19 +334,19 @@ template struct llt_inplace typedef typename NumTraits::Real RealScalar; template - static EIGEN_STRONG_INLINE typename MatrixType::Index unblocked(MatrixType& mat) + static EIGEN_STRONG_INLINE Index unblocked(MatrixType& mat) { Transpose matt(mat); return llt_inplace::unblocked(matt); } template - static EIGEN_STRONG_INLINE typename MatrixType::Index blocked(MatrixType& mat) + static EIGEN_STRONG_INLINE Index blocked(MatrixType& mat) { Transpose matt(mat); return llt_inplace::blocked(matt); } template - static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma) + static Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma) { Transpose matt(mat); return llt_inplace::rankUpdate(matt, vec.conjugate(), sigma); @@ -356,8 +357,8 @@ template struct LLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m; } - static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); } static bool inplace_decomposition(MatrixType& m) { return llt_inplace::blocked(m)==-1; } }; @@ -366,8 +367,8 @@ template struct LLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m.adjoint(); } - static inline MatrixU getU(const MatrixType& m) { return m; } + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m.adjoint()); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m); } static bool inplace_decomposition(MatrixType& m) { return llt_inplace::blocked(m)==-1; } }; @@ -382,12 +383,15 @@ template struct LLT_Traits * Output: \verbinclude TutorialLinAlgComputeTwice.out */ template -LLT& LLT::compute(const MatrixType& a) +template +LLT& LLT::compute(const EigenBase& a) { + check_template_parameters(); + eigen_assert(a.rows()==a.cols()); const Index size = a.rows(); m_matrix.resize(size, size); - m_matrix = a; + m_matrix = a.derived(); m_isInitialized = true; bool ok = Traits::inplace_decomposition(m_matrix); @@ -415,22 +419,16 @@ LLT<_MatrixType,_UpLo> LLT<_MatrixType,_UpLo>::rankUpdate(const VectorType& v, c return *this; } - -namespace internal { -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> + +#ifndef EIGEN_PARSED_BY_DOXYGEN +template +template +void LLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) const { - typedef LLT<_MatrixType,UpLo> LLTType; - EIGEN_MAKE_SOLVE_HELPERS(LLTType,Rhs) - - template void evalTo(Dest& dst) const - { - dst = rhs(); - dec().solveInPlace(dst); - } -}; + dst = rhs; + solveInPlace(dst); } +#endif /** \internal use x = llt_object.solve(x); * @@ -465,8 +463,10 @@ MatrixType LLT::reconstructedMatrix() const return matrixL() * matrixL().adjoint().toDenseMatrix(); } +#ifndef __CUDACC__ /** \cholesky_module * \returns the LLT decomposition of \c *this + * \sa SelfAdjointView::llt() */ template inline const LLT::PlainObject> @@ -477,6 +477,7 @@ MatrixBase::llt() const /** \cholesky_module * \returns the LLT decomposition of \c *this + * \sa SelfAdjointView::llt() */ template inline const LLT::PlainObject, UpLo> @@ -484,7 +485,8 @@ SelfAdjointView::llt() const { return LLT(m_matrix); } - +#endif // __CUDACC__ + } // end namespace Eigen #endif // EIGEN_LLT_H diff --git a/nuparu/include/Eigen/src/Cholesky/LLT_MKL.h b/nuparu/include/Eigen/src/Cholesky/LLT_MKL.h index 64daa445..0d42cb5b 100644 --- a/nuparu/include/Eigen/src/Cholesky/LLT_MKL.h +++ b/nuparu/include/Eigen/src/Cholesky/LLT_MKL.h @@ -46,7 +46,7 @@ template struct mkl_llt; template<> struct mkl_llt \ { \ template \ - static inline typename MatrixType::Index potrf(MatrixType& m, char uplo) \ + static inline Index potrf(MatrixType& m, char uplo) \ { \ lapack_int matrix_order; \ lapack_int size, lda, info, StorageOrder; \ @@ -60,30 +60,30 @@ template<> struct mkl_llt \ lda = m.outerStride(); \ \ info = LAPACKE_##MKLPREFIX##potrf( matrix_order, uplo, size, (MKLTYPE*)a, lda ); \ - info = (info==0) ? Success : NumericalIssue; \ + info = (info==0) ? -1 : info>0 ? info-1 : size; \ return info; \ } \ }; \ template<> struct llt_inplace \ { \ template \ - static typename MatrixType::Index blocked(MatrixType& m) \ + static Index blocked(MatrixType& m) \ { \ return mkl_llt::potrf(m, 'L'); \ } \ template \ - static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) \ + static Index rankUpdate(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) \ { return Eigen::internal::llt_rank_update_lower(mat, vec, sigma); } \ }; \ template<> struct llt_inplace \ { \ template \ - static typename MatrixType::Index blocked(MatrixType& m) \ + static Index blocked(MatrixType& m) \ { \ return mkl_llt::potrf(m, 'U'); \ } \ template \ - static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) \ + static Index rankUpdate(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) \ { \ Transpose matt(mat); \ return llt_inplace::rankUpdate(matt, vec.conjugate(), sigma); \ diff --git a/nuparu/include/Eigen/src/CholmodSupport/CholmodSupport.h b/nuparu/include/Eigen/src/CholmodSupport/CholmodSupport.h index 783324b0..06421d5e 100644 --- a/nuparu/include/Eigen/src/CholmodSupport/CholmodSupport.h +++ b/nuparu/include/Eigen/src/CholmodSupport/CholmodSupport.h @@ -48,8 +48,8 @@ void cholmod_configure_matrix(CholmodType& mat) /** Wraps the Eigen sparse matrix \a mat into a Cholmod sparse matrix object. * Note that the data are shared. */ -template -cholmod_sparse viewAsCholmod(SparseMatrix<_Scalar,_Options,_Index>& mat) +template +cholmod_sparse viewAsCholmod(SparseMatrix<_Scalar,_Options,_StorageIndex>& mat) { cholmod_sparse res; res.nzmax = mat.nonZeros(); @@ -58,10 +58,12 @@ cholmod_sparse viewAsCholmod(SparseMatrix<_Scalar,_Options,_Index>& mat) res.p = mat.outerIndexPtr(); res.i = mat.innerIndexPtr(); res.x = mat.valuePtr(); + res.z = 0; res.sorted = 1; if(mat.isCompressed()) { res.packed = 1; + res.nz = 0; } else { @@ -72,11 +74,11 @@ cholmod_sparse viewAsCholmod(SparseMatrix<_Scalar,_Options,_Index>& mat) res.dtype = 0; res.stype = -1; - if (internal::is_same<_Index,int>::value) + if (internal::is_same<_StorageIndex,int>::value) { res.itype = CHOLMOD_INT; } - else if (internal::is_same<_Index,UF_long>::value) + else if (internal::is_same<_StorageIndex,SuiteSparse_long>::value) { res.itype = CHOLMOD_LONG; } @@ -103,7 +105,7 @@ const cholmod_sparse viewAsCholmod(const SparseMatrix<_Scalar,_Options,_Index>& /** Returns a view of the Eigen sparse matrix \a mat as Cholmod sparse matrix. * The data are not copied but shared. */ template -cholmod_sparse viewAsCholmod(const SparseSelfAdjointView, UpLo>& mat) +cholmod_sparse viewAsCholmod(const SparseSelfAdjointView, UpLo>& mat) { cholmod_sparse res = viewAsCholmod(mat.matrix().const_cast_derived()); @@ -136,12 +138,12 @@ cholmod_dense viewAsCholmod(MatrixBase& mat) /** Returns a view of the Cholmod sparse matrix \a cm as an Eigen sparse matrix. * The data are not copied but shared. */ -template -MappedSparseMatrix viewAsEigen(cholmod_sparse& cm) +template +MappedSparseMatrix viewAsEigen(cholmod_sparse& cm) { - return MappedSparseMatrix - (cm.nrow, cm.ncol, static_cast(cm.p)[cm.ncol], - static_cast(cm.p), static_cast(cm.i),static_cast(cm.x) ); + return MappedSparseMatrix + (cm.nrow, cm.ncol, static_cast(cm.p)[cm.ncol], + static_cast(cm.p), static_cast(cm.i),static_cast(cm.x) ); } enum CholmodMode { @@ -155,26 +157,35 @@ enum CholmodMode { * \sa class CholmodSupernodalLLT, class CholmodSimplicialLDLT, class CholmodSimplicialLLT */ template -class CholmodBase : internal::noncopyable +class CholmodBase : public SparseSolverBase { + protected: + typedef SparseSolverBase Base; + using Base::derived; + using Base::m_isInitialized; public: typedef _MatrixType MatrixType; enum { UpLo = _UpLo }; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; typedef MatrixType CholMatrixType; - typedef typename MatrixType::Index Index; + typedef typename MatrixType::StorageIndex StorageIndex; + enum { + ColsAtCompileTime = MatrixType::ColsAtCompileTime, + MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime + }; public: CholmodBase() - : m_cholmodFactor(0), m_info(Success), m_isInitialized(false) + : m_cholmodFactor(0), m_info(Success) { + m_shiftOffset[0] = m_shiftOffset[1] = RealScalar(0.0); cholmod_start(&m_cholmod); } - CholmodBase(const MatrixType& matrix) - : m_cholmodFactor(0), m_info(Success), m_isInitialized(false) + explicit CholmodBase(const MatrixType& matrix) + : m_cholmodFactor(0), m_info(Success) { m_shiftOffset[0] = m_shiftOffset[1] = RealScalar(0.0); cholmod_start(&m_cholmod); @@ -188,11 +199,8 @@ class CholmodBase : internal::noncopyable cholmod_finish(&m_cholmod); } - inline Index cols() const { return m_cholmodFactor->n; } - inline Index rows() const { return m_cholmodFactor->n; } - - Derived& derived() { return *static_cast(this); } - const Derived& derived() const { return *static_cast(this); } + inline StorageIndex cols() const { return internal::convert_index(m_cholmodFactor->n); } + inline StorageIndex rows() const { return internal::convert_index(m_cholmodFactor->n); } /** \brief Reports whether previous computation was successful. * @@ -213,35 +221,7 @@ class CholmodBase : internal::noncopyable return derived(); } - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "LLT is not initialized."); - eigen_assert(rows()==b.rows() - && "CholmodDecomposition::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); - } - - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::sparse_solve_retval - solve(const SparseMatrixBase& b) const - { - eigen_assert(m_isInitialized && "LLT is not initialized."); - eigen_assert(rows()==b.rows() - && "CholmodDecomposition::solve(): invalid number of rows of the right hand side matrix b"); - return internal::sparse_solve_retval(*this, b.derived()); - } - - /** Performs a symbolic decomposition on the sparcity of \a matrix. + /** Performs a symbolic decomposition on the sparsity pattern of \a matrix. * * This function is particularly useful when solving for several problems having the same structure. * @@ -265,7 +245,7 @@ class CholmodBase : internal::noncopyable /** Performs a numeric decomposition of \a matrix * - * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed. + * The given matrix must have the same sparsity pattern as the matrix on which the symbolic decomposition has been performed. * * \sa analyzePattern() */ @@ -287,7 +267,7 @@ class CholmodBase : internal::noncopyable #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal */ template - void _solve(const MatrixBase &b, MatrixBase &dest) const + void _solve_impl(const MatrixBase &b, MatrixBase &dest) const { eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); const Index size = m_cholmodFactor->n; @@ -301,15 +281,16 @@ class CholmodBase : internal::noncopyable if(!x_cd) { this->m_info = NumericalIssue; + return; } - // TODO optimize this copy by swapping when possible (be carreful with alignment, etc.) + // TODO optimize this copy by swapping when possible (be careful with alignment, etc.) dest = Matrix::Map(reinterpret_cast(x_cd->x),b.rows(),b.cols()); cholmod_free_dense(&x_cd, &m_cholmod); } /** \internal */ template - void _solve(const SparseMatrix &b, SparseMatrix &dest) const + void _solve_impl(const SparseMatrix &b, SparseMatrix &dest) const { eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); const Index size = m_cholmodFactor->n; @@ -322,8 +303,9 @@ class CholmodBase : internal::noncopyable if(!x_cs) { this->m_info = NumericalIssue; + return; } - // TODO optimize this copy by swapping when possible (be carreful with alignment, etc.) + // TODO optimize this copy by swapping when possible (be careful with alignment, etc.) dest = viewAsEigen(*x_cs); cholmod_free_sparse(&x_cs, &m_cholmod); } @@ -354,7 +336,6 @@ class CholmodBase : internal::noncopyable cholmod_factor* m_cholmodFactor; RealScalar m_shiftOffset[2]; mutable ComputationInfo m_info; - bool m_isInitialized; int m_factorizationIsOk; int m_analysisIsOk; }; @@ -365,14 +346,16 @@ class CholmodBase : internal::noncopyable * * This class allows to solve for A.X = B sparse linear problems via a simplicial LL^T Cholesky factorization * using the Cholmod library. - * This simplicial variant is equivalent to Eigen's built-in SimplicialLLT class. Thefore, it has little practical interest. - * The sparse matrix A must be selfajoint and positive definite. The vectors or matrices + * This simplicial variant is equivalent to Eigen's built-in SimplicialLLT class. Therefore, it has little practical interest. + * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices * X and B can be either dense or sparse. * * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower * or Upper. Default is Lower. * + * \implsparsesolverconcept + * * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. * * \sa \ref TutorialSparseDirectSolvers, class CholmodSupernodalLLT, class SimplicialLLT @@ -392,7 +375,7 @@ class CholmodSimplicialLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimpl CholmodSimplicialLLT(const MatrixType& matrix) : Base() { init(); - compute(matrix); + this->compute(matrix); } ~CholmodSimplicialLLT() {} @@ -412,14 +395,16 @@ class CholmodSimplicialLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimpl * * This class allows to solve for A.X = B sparse linear problems via a simplicial LDL^T Cholesky factorization * using the Cholmod library. - * This simplicial variant is equivalent to Eigen's built-in SimplicialLDLT class. Thefore, it has little practical interest. - * The sparse matrix A must be selfajoint and positive definite. The vectors or matrices + * This simplicial variant is equivalent to Eigen's built-in SimplicialLDLT class. Therefore, it has little practical interest. + * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices * X and B can be either dense or sparse. * * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower * or Upper. Default is Lower. * + * \implsparsesolverconcept + * * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. * * \sa \ref TutorialSparseDirectSolvers, class CholmodSupernodalLLT, class SimplicialLDLT @@ -439,7 +424,7 @@ class CholmodSimplicialLDLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimp CholmodSimplicialLDLT(const MatrixType& matrix) : Base() { init(); - compute(matrix); + this->compute(matrix); } ~CholmodSimplicialLDLT() {} @@ -458,13 +443,15 @@ class CholmodSimplicialLDLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimp * This class allows to solve for A.X = B sparse linear problems via a supernodal LL^T Cholesky factorization * using the Cholmod library. * This supernodal variant performs best on dense enough problems, e.g., 3D FEM, or very high order 2D FEM. - * The sparse matrix A must be selfajoint and positive definite. The vectors or matrices + * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices * X and B can be either dense or sparse. * * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower * or Upper. Default is Lower. * + * \implsparsesolverconcept + * * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. * * \sa \ref TutorialSparseDirectSolvers @@ -484,7 +471,7 @@ class CholmodSupernodalLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSuper CholmodSupernodalLLT(const MatrixType& matrix) : Base() { init(); - compute(matrix); + this->compute(matrix); } ~CholmodSupernodalLLT() {} @@ -501,7 +488,7 @@ class CholmodSupernodalLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSuper * \brief A general Cholesky factorization and solver based on Cholmod * * This class allows to solve for A.X = B sparse linear problems via a LL^T or LDL^T Cholesky factorization - * using the Cholmod library. The sparse matrix A must be selfajoint and positive definite. The vectors or matrices + * using the Cholmod library. The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices * X and B can be either dense or sparse. * * This variant permits to change the underlying Cholesky method at runtime. @@ -512,6 +499,8 @@ class CholmodSupernodalLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSuper * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower * or Upper. Default is Lower. * + * \implsparsesolverconcept + * * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. * * \sa \ref TutorialSparseDirectSolvers @@ -531,7 +520,7 @@ class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecom CholmodDecomposition(const MatrixType& matrix) : Base() { init(); - compute(matrix); + this->compute(matrix); } ~CholmodDecomposition() {} @@ -569,36 +558,6 @@ class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecom } }; -namespace internal { - -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef CholmodBase<_MatrixType,_UpLo,Derived> Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve(rhs(),dst); - } -}; - -template -struct sparse_solve_retval, Rhs> - : sparse_solve_retval_base, Rhs> -{ - typedef CholmodBase<_MatrixType,_UpLo,Derived> Dec; - EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve(rhs(),dst); - } -}; - -} // end namespace internal - } // end namespace Eigen #endif // EIGEN_CHOLMODSUPPORT_H diff --git a/nuparu/include/Eigen/src/Core/Array.h b/nuparu/include/Eigen/src/Core/Array.h index 497efff6..e38eda72 100644 --- a/nuparu/include/Eigen/src/Core/Array.h +++ b/nuparu/include/Eigen/src/Core/Array.h @@ -24,6 +24,9 @@ namespace Eigen { * API for the %Matrix class provides easy access to linear-algebra * operations. * + * See documentation of class Matrix for detailed information on the template parameters + * storage layout. + * * This class can be extended with the help of the plugin mechanism described on the page * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_ARRAY_PLUGIN. * @@ -69,11 +72,27 @@ class Array * the usage of 'using'. This should be done only for operator=. */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array& operator=(const EigenBase &other) { return Base::operator=(other); } + /** Set all the entries to \a value. + * \sa DenseBase::setConstant(), DenseBase::fill() + */ + /* This overload is needed because the usage of + * using Base::operator=; + * fails on MSVC. Since the code below is working with GCC and MSVC, we skipped + * the usage of 'using'. This should be done only for operator=. + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Array& operator=(const Scalar &value) + { + Base::setConstant(value); + return *this; + } + /** Copies the value of the expression \a other into \c *this with automatic resizing. * * *this might be resized to match the dimensions of \a other. If *this was a null matrix (not already initialized), @@ -84,7 +103,8 @@ class Array * remain row-vectors and vectors remain vectors. */ template - EIGEN_STRONG_INLINE Array& operator=(const ArrayBase& other) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Array& operator=(const DenseBase& other) { return Base::_set(other); } @@ -92,11 +112,12 @@ class Array /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array& operator=(const Array& other) { return Base::_set(other); } - + /** Default constructor. * * For fixed-size matrices, does nothing. @@ -107,6 +128,7 @@ class Array * * \sa resize(Index,Index) */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array() : Base() { Base::_check_template_params(); @@ -116,6 +138,7 @@ class Array #ifndef EIGEN_PARSED_BY_DOXYGEN // FIXME is it still needed ?? /** \internal */ + EIGEN_DEVICE_FUNC Array(internal::constructor_without_unaligned_array_assert) : Base(internal::constructor_without_unaligned_array_assert()) { @@ -124,41 +147,64 @@ class Array } #endif - /** Constructs a vector or row-vector with given dimension. \only_for_vectors - * - * Note that this is only useful for dynamic-size vectors. For fixed-size vectors, - * it is redundant to pass the dimension here, so it makes more sense to use the default - * constructor Matrix() instead. - */ - EIGEN_STRONG_INLINE explicit Array(Index dim) - : Base(dim, RowsAtCompileTime == 1 ? 1 : dim, ColsAtCompileTime == 1 ? 1 : dim) +#ifdef EIGEN_HAVE_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + Array(Array&& other) + : Base(std::move(other)) { Base::_check_template_params(); - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Array) - eigen_assert(dim >= 0); - eigen_assert(SizeAtCompileTime == Dynamic || SizeAtCompileTime == dim); - EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + if (RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic) + Base::_set_noalias(other); } + EIGEN_DEVICE_FUNC + Array& operator=(Array&& other) + { + other.swap(*this); + return *this; + } +#endif #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE explicit Array(const T& x) + { + Base::_check_template_params(); + Base::template _init1(x); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const T0& val0, const T1& val1) { Base::_check_template_params(); this->template _init2(val0, val1); } #else - /** constructs an uninitialized matrix with \a rows rows and \a cols columns. + /** \brief Constructs a fixed-sized array initialized with coefficients starting at \a data */ + EIGEN_DEVICE_FUNC explicit Array(const Scalar *data); + /** Constructs a vector or row-vector with given dimension. \only_for_vectors * - * This is useful for dynamic-size matrices. For fixed-size matrices, + * Note that this is only useful for dynamic-size vectors. For fixed-size vectors, + * it is redundant to pass the dimension here, so it makes more sense to use the default + * constructor Array() instead. + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE explicit Array(Index dim); + /** constructs an initialized 1x1 Array with the given coefficient */ + Array(const Scalar& value); + /** constructs an uninitialized array with \a rows rows and \a cols columns. + * + * This is useful for dynamic-size arrays. For fixed-size arrays, * it is redundant to pass these parameters, so one should use the default constructor - * Matrix() instead. */ + * Array() instead. */ Array(Index rows, Index cols); /** constructs an initialized 2D vector with given coefficients */ Array(const Scalar& val0, const Scalar& val1); #endif /** constructs an initialized 3D vector with given coefficients */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const Scalar& val0, const Scalar& val1, const Scalar& val2) { Base::_check_template_params(); @@ -168,6 +214,7 @@ class Array m_storage.data()[2] = val2; } /** constructs an initialized 4D vector with given coefficients */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const Scalar& val0, const Scalar& val1, const Scalar& val2, const Scalar& val3) { Base::_check_template_params(); @@ -178,51 +225,21 @@ class Array m_storage.data()[3] = val3; } - explicit Array(const Scalar *data); - - /** Constructor copying the value of the expression \a other */ - template - EIGEN_STRONG_INLINE Array(const ArrayBase& other) - : Base(other.rows() * other.cols(), other.rows(), other.cols()) - { - Base::_check_template_params(); - Base::_set_noalias(other); - } /** Copy constructor */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const Array& other) - : Base(other.rows() * other.cols(), other.rows(), other.cols()) - { - Base::_check_template_params(); - Base::_set_noalias(other); - } - /** Copy constructor with in-place evaluation */ - template - EIGEN_STRONG_INLINE Array(const ReturnByValue& other) - { - Base::_check_template_params(); - Base::resize(other.rows(), other.cols()); - other.evalTo(*this); - } + : Base(other) + { } /** \sa MatrixBase::operator=(const EigenBase&) */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const EigenBase &other) - : Base(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols()) - { - Base::_check_template_params(); - Base::resize(other.rows(), other.cols()); - *this = other; - } - - /** Override MatrixBase::swap() since for dynamic-sized matrices of same type it is enough to swap the - * data pointers. - */ - template - void swap(ArrayBase const & other) - { this->_swap(other.derived()); } + : Base(other.derived()) + { } - inline Index innerStride() const { return 1; } - inline Index outerStride() const { return this->innerSize(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return 1; } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return this->innerSize(); } #ifdef EIGEN_ARRAY_PLUGIN #include EIGEN_ARRAY_PLUGIN diff --git a/nuparu/include/Eigen/src/Core/ArrayBase.h b/nuparu/include/Eigen/src/Core/ArrayBase.h index 38852600..b4c24a27 100644 --- a/nuparu/include/Eigen/src/Core/ArrayBase.h +++ b/nuparu/include/Eigen/src/Core/ArrayBase.h @@ -46,16 +46,14 @@ template class ArrayBase typedef ArrayBase Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl; - using internal::special_scalar_op_base::Scalar, - typename NumTraits::Scalar>::Real>::operator*; - typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; typedef DenseBase Base; + using Base::operator*; + using Base::operator/; using Base::RowsAtCompileTime; using Base::ColsAtCompileTime; using Base::SizeAtCompileTime; @@ -64,8 +62,7 @@ template class ArrayBase using Base::MaxSizeAtCompileTime; using Base::IsVectorAtCompileTime; using Base::Flags; - using Base::CoeffReadCost; - + using Base::derived; using Base::const_cast_derived; using Base::rows; @@ -85,22 +82,10 @@ template class ArrayBase #endif // not EIGEN_PARSED_BY_DOXYGEN #ifndef EIGEN_PARSED_BY_DOXYGEN - /** \internal the plain matrix type corresponding to this expression. Note that is not necessarily - * exactly the return type of eval(): in the case of plain matrices, the return type of eval() is a const - * reference to a matrix, not a matrix! It is however guaranteed that the return type of eval() is either - * PlainObject or const PlainObject&. - */ - typedef Array::Scalar, - internal::traits::RowsAtCompileTime, - internal::traits::ColsAtCompileTime, - AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), - internal::traits::MaxRowsAtCompileTime, - internal::traits::MaxColsAtCompileTime - > PlainObject; - + typedef typename Base::PlainObject PlainObject; /** \internal Represents a matrix with all coefficients equal to one another*/ - typedef CwiseNullaryOp,Derived> ConstantReturnType; + typedef CwiseNullaryOp,PlainObject> ConstantReturnType; #endif // not EIGEN_PARSED_BY_DOXYGEN #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::ArrayBase @@ -118,40 +103,57 @@ template class ArrayBase /** Special case of the template operator=, in order to prevent the compiler * from generating a default operator= (issue hit with g++ 4.1) */ + EIGEN_DEVICE_FUNC Derived& operator=(const ArrayBase& other) { - return internal::assign_selector::run(derived(), other.derived()); + internal::call_assignment(derived(), other.derived()); + return derived(); } - - Derived& operator+=(const Scalar& scalar) - { return *this = derived() + scalar; } - Derived& operator-=(const Scalar& scalar) - { return *this = derived() - scalar; } + + /** Set all the entries to \a value. + * \sa DenseBase::setConstant(), DenseBase::fill() */ + EIGEN_DEVICE_FUNC + Derived& operator=(const Scalar &value) + { Base::setConstant(value); return derived(); } + + EIGEN_DEVICE_FUNC + Derived& operator+=(const Scalar& scalar); + EIGEN_DEVICE_FUNC + Derived& operator-=(const Scalar& scalar); template + EIGEN_DEVICE_FUNC Derived& operator+=(const ArrayBase& other); template + EIGEN_DEVICE_FUNC Derived& operator-=(const ArrayBase& other); template + EIGEN_DEVICE_FUNC Derived& operator*=(const ArrayBase& other); template + EIGEN_DEVICE_FUNC Derived& operator/=(const ArrayBase& other); public: + EIGEN_DEVICE_FUNC ArrayBase& array() { return *this; } + EIGEN_DEVICE_FUNC const ArrayBase& array() const { return *this; } /** \returns an \link Eigen::MatrixBase Matrix \endlink expression of this array * \sa MatrixBase::array() */ - MatrixWrapper matrix() { return derived(); } - const MatrixWrapper matrix() const { return derived(); } + EIGEN_DEVICE_FUNC + MatrixWrapper matrix() { return MatrixWrapper(derived()); } + EIGEN_DEVICE_FUNC + const MatrixWrapper matrix() const { return MatrixWrapper(derived()); } // template // inline void evalTo(Dest& dst) const { dst = matrix(); } protected: + EIGEN_DEVICE_FUNC ArrayBase() : Base() {} private: @@ -176,8 +178,7 @@ template EIGEN_STRONG_INLINE Derived & ArrayBase::operator-=(const ArrayBase &other) { - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); + call_assignment(derived(), other.derived(), internal::sub_assign_op()); return derived(); } @@ -190,8 +191,7 @@ template EIGEN_STRONG_INLINE Derived & ArrayBase::operator+=(const ArrayBase& other) { - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); + call_assignment(derived(), other.derived(), internal::add_assign_op()); return derived(); } @@ -204,8 +204,7 @@ template EIGEN_STRONG_INLINE Derived & ArrayBase::operator*=(const ArrayBase& other) { - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); + call_assignment(derived(), other.derived(), internal::mul_assign_op()); return derived(); } @@ -218,8 +217,7 @@ template EIGEN_STRONG_INLINE Derived & ArrayBase::operator/=(const ArrayBase& other) { - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); + call_assignment(derived(), other.derived(), internal::div_assign_op()); return derived(); } diff --git a/nuparu/include/Eigen/src/Core/ArrayWrapper.h b/nuparu/include/Eigen/src/Core/ArrayWrapper.h index a791bc35..4e484f29 100644 --- a/nuparu/include/Eigen/src/Core/ArrayWrapper.h +++ b/nuparu/include/Eigen/src/Core/ArrayWrapper.h @@ -29,6 +29,11 @@ struct traits > : public traits::type > { typedef ArrayXpr XprKind; + // Let's remove NestByRefBit + enum { + Flags0 = traits::type >::Flags, + Flags = Flags0 & ~NestByRefBit + }; }; } @@ -39,6 +44,7 @@ class ArrayWrapper : public ArrayBase > typedef ArrayBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(ArrayWrapper) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(ArrayWrapper) + typedef typename internal::remove_all::type NestedExpression; typedef typename internal::conditional< internal::is_lvalue::value, @@ -46,43 +52,56 @@ class ArrayWrapper : public ArrayBase > const Scalar >::type ScalarWithConstIfNotLvalue; - typedef typename internal::nested::type NestedExpressionType; + typedef typename internal::ref_selector::type NestedExpressionType; - inline ArrayWrapper(ExpressionType& matrix) : m_expression(matrix) {} + EIGEN_DEVICE_FUNC + explicit EIGEN_STRONG_INLINE ArrayWrapper(ExpressionType& matrix) : m_expression(matrix) {} + EIGEN_DEVICE_FUNC inline Index rows() const { return m_expression.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_expression.cols(); } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_expression.outerStride(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_expression.innerStride(); } + EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue* data() { return m_expression.const_cast_derived().data(); } + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return m_expression.data(); } + EIGEN_DEVICE_FUNC inline CoeffReturnType coeff(Index rowId, Index colId) const { return m_expression.coeff(rowId, colId); } + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index rowId, Index colId) { return m_expression.const_cast_derived().coeffRef(rowId, colId); } + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index rowId, Index colId) const { return m_expression.const_cast_derived().coeffRef(rowId, colId); } + EIGEN_DEVICE_FUNC inline CoeffReturnType coeff(Index index) const { return m_expression.coeff(index); } + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index index) { return m_expression.const_cast_derived().coeffRef(index); } + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index index) const { return m_expression.const_cast_derived().coeffRef(index); @@ -113,9 +132,11 @@ class ArrayWrapper : public ArrayBase > } template + EIGEN_DEVICE_FUNC inline void evalTo(Dest& dst) const { dst = m_expression; } const typename internal::remove_all::type& + EIGEN_DEVICE_FUNC nestedExpression() const { return m_expression; @@ -123,10 +144,12 @@ class ArrayWrapper : public ArrayBase > /** Forwards the resizing request to the nested expression * \sa DenseBase::resize(Index) */ + EIGEN_DEVICE_FUNC void resize(Index newSize) { m_expression.const_cast_derived().resize(newSize); } /** Forwards the resizing request to the nested expression * \sa DenseBase::resize(Index,Index)*/ - void resize(Index nbRows, Index nbCols) { m_expression.const_cast_derived().resize(nbRows,nbCols); } + EIGEN_DEVICE_FUNC + void resize(Index rows, Index cols) { m_expression.const_cast_derived().resize(rows,cols); } protected: NestedExpressionType m_expression; @@ -149,6 +172,11 @@ struct traits > : public traits::type > { typedef MatrixXpr XprKind; + // Let's remove NestByRefBit + enum { + Flags0 = traits::type >::Flags, + Flags = Flags0 & ~NestByRefBit + }; }; } @@ -159,6 +187,7 @@ class MatrixWrapper : public MatrixBase > typedef MatrixBase > Base; EIGEN_DENSE_PUBLIC_INTERFACE(MatrixWrapper) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(MatrixWrapper) + typedef typename internal::remove_all::type NestedExpression; typedef typename internal::conditional< internal::is_lvalue::value, @@ -166,43 +195,56 @@ class MatrixWrapper : public MatrixBase > const Scalar >::type ScalarWithConstIfNotLvalue; - typedef typename internal::nested::type NestedExpressionType; + typedef typename internal::ref_selector::type NestedExpressionType; - inline MatrixWrapper(ExpressionType& a_matrix) : m_expression(a_matrix) {} + EIGEN_DEVICE_FUNC + explicit inline MatrixWrapper(ExpressionType& matrix) : m_expression(matrix) {} + EIGEN_DEVICE_FUNC inline Index rows() const { return m_expression.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_expression.cols(); } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_expression.outerStride(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_expression.innerStride(); } + EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue* data() { return m_expression.const_cast_derived().data(); } + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return m_expression.data(); } + EIGEN_DEVICE_FUNC inline CoeffReturnType coeff(Index rowId, Index colId) const { return m_expression.coeff(rowId, colId); } + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index rowId, Index colId) { return m_expression.const_cast_derived().coeffRef(rowId, colId); } + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index rowId, Index colId) const { return m_expression.derived().coeffRef(rowId, colId); } + EIGEN_DEVICE_FUNC inline CoeffReturnType coeff(Index index) const { return m_expression.coeff(index); } + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index index) { return m_expression.const_cast_derived().coeffRef(index); } + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index index) const { return m_expression.const_cast_derived().coeffRef(index); @@ -232,6 +274,7 @@ class MatrixWrapper : public MatrixBase > m_expression.const_cast_derived().template writePacket(index, val); } + EIGEN_DEVICE_FUNC const typename internal::remove_all::type& nestedExpression() const { @@ -240,10 +283,12 @@ class MatrixWrapper : public MatrixBase > /** Forwards the resizing request to the nested expression * \sa DenseBase::resize(Index) */ + EIGEN_DEVICE_FUNC void resize(Index newSize) { m_expression.const_cast_derived().resize(newSize); } /** Forwards the resizing request to the nested expression * \sa DenseBase::resize(Index,Index)*/ - void resize(Index nbRows, Index nbCols) { m_expression.const_cast_derived().resize(nbRows,nbCols); } + EIGEN_DEVICE_FUNC + void resize(Index rows, Index cols) { m_expression.const_cast_derived().resize(rows,cols); } protected: NestedExpressionType m_expression; diff --git a/nuparu/include/Eigen/src/Core/Assign.h b/nuparu/include/Eigen/src/Core/Assign.h index 1dccc2f4..53806ba3 100644 --- a/nuparu/include/Eigen/src/Core/Assign.h +++ b/nuparu/include/Eigen/src/Core/Assign.h @@ -14,471 +14,6 @@ namespace Eigen { -namespace internal { - -/*************************************************************************** -* Part 1 : the logic deciding a strategy for traversal and unrolling * -***************************************************************************/ - -template -struct assign_traits -{ -public: - enum { - DstIsAligned = Derived::Flags & AlignedBit, - DstHasDirectAccess = Derived::Flags & DirectAccessBit, - SrcIsAligned = OtherDerived::Flags & AlignedBit, - JointAlignment = bool(DstIsAligned) && bool(SrcIsAligned) ? Aligned : Unaligned - }; - -private: - enum { - InnerSize = int(Derived::IsVectorAtCompileTime) ? int(Derived::SizeAtCompileTime) - : int(Derived::Flags)&RowMajorBit ? int(Derived::ColsAtCompileTime) - : int(Derived::RowsAtCompileTime), - InnerMaxSize = int(Derived::IsVectorAtCompileTime) ? int(Derived::MaxSizeAtCompileTime) - : int(Derived::Flags)&RowMajorBit ? int(Derived::MaxColsAtCompileTime) - : int(Derived::MaxRowsAtCompileTime), - MaxSizeAtCompileTime = Derived::SizeAtCompileTime, - PacketSize = packet_traits::size - }; - - enum { - StorageOrdersAgree = (int(Derived::IsRowMajor) == int(OtherDerived::IsRowMajor)), - MightVectorize = StorageOrdersAgree - && (int(Derived::Flags) & int(OtherDerived::Flags) & ActualPacketAccessBit), - MayInnerVectorize = MightVectorize && int(InnerSize)!=Dynamic && int(InnerSize)%int(PacketSize)==0 - && int(DstIsAligned) && int(SrcIsAligned), - MayLinearize = StorageOrdersAgree && (int(Derived::Flags) & int(OtherDerived::Flags) & LinearAccessBit), - MayLinearVectorize = MightVectorize && MayLinearize && DstHasDirectAccess - && (DstIsAligned || MaxSizeAtCompileTime == Dynamic), - /* If the destination isn't aligned, we have to do runtime checks and we don't unroll, - so it's only good for large enough sizes. */ - MaySliceVectorize = MightVectorize && DstHasDirectAccess - && (int(InnerMaxSize)==Dynamic || int(InnerMaxSize)>=3*PacketSize) - /* slice vectorization can be slow, so we only want it if the slices are big, which is - indicated by InnerMaxSize rather than InnerSize, think of the case of a dynamic block - in a fixed-size matrix */ - }; - -public: - enum { - Traversal = int(MayInnerVectorize) ? int(InnerVectorizedTraversal) - : int(MayLinearVectorize) ? int(LinearVectorizedTraversal) - : int(MaySliceVectorize) ? int(SliceVectorizedTraversal) - : int(MayLinearize) ? int(LinearTraversal) - : int(DefaultTraversal), - Vectorized = int(Traversal) == InnerVectorizedTraversal - || int(Traversal) == LinearVectorizedTraversal - || int(Traversal) == SliceVectorizedTraversal - }; - -private: - enum { - UnrollingLimit = EIGEN_UNROLLING_LIMIT * (Vectorized ? int(PacketSize) : 1), - MayUnrollCompletely = int(Derived::SizeAtCompileTime) != Dynamic - && int(OtherDerived::CoeffReadCost) != Dynamic - && int(Derived::SizeAtCompileTime) * int(OtherDerived::CoeffReadCost) <= int(UnrollingLimit), - MayUnrollInner = int(InnerSize) != Dynamic - && int(OtherDerived::CoeffReadCost) != Dynamic - && int(InnerSize) * int(OtherDerived::CoeffReadCost) <= int(UnrollingLimit) - }; - -public: - enum { - Unrolling = (int(Traversal) == int(InnerVectorizedTraversal) || int(Traversal) == int(DefaultTraversal)) - ? ( - int(MayUnrollCompletely) ? int(CompleteUnrolling) - : int(MayUnrollInner) ? int(InnerUnrolling) - : int(NoUnrolling) - ) - : int(Traversal) == int(LinearVectorizedTraversal) - ? ( bool(MayUnrollCompletely) && bool(DstIsAligned) ? int(CompleteUnrolling) : int(NoUnrolling) ) - : int(Traversal) == int(LinearTraversal) - ? ( bool(MayUnrollCompletely) ? int(CompleteUnrolling) : int(NoUnrolling) ) - : int(NoUnrolling) - }; - -#ifdef EIGEN_DEBUG_ASSIGN - static void debug() - { - EIGEN_DEBUG_VAR(DstIsAligned) - EIGEN_DEBUG_VAR(SrcIsAligned) - EIGEN_DEBUG_VAR(JointAlignment) - EIGEN_DEBUG_VAR(InnerSize) - EIGEN_DEBUG_VAR(InnerMaxSize) - EIGEN_DEBUG_VAR(PacketSize) - EIGEN_DEBUG_VAR(StorageOrdersAgree) - EIGEN_DEBUG_VAR(MightVectorize) - EIGEN_DEBUG_VAR(MayLinearize) - EIGEN_DEBUG_VAR(MayInnerVectorize) - EIGEN_DEBUG_VAR(MayLinearVectorize) - EIGEN_DEBUG_VAR(MaySliceVectorize) - EIGEN_DEBUG_VAR(Traversal) - EIGEN_DEBUG_VAR(UnrollingLimit) - EIGEN_DEBUG_VAR(MayUnrollCompletely) - EIGEN_DEBUG_VAR(MayUnrollInner) - EIGEN_DEBUG_VAR(Unrolling) - } -#endif -}; - -/*************************************************************************** -* Part 2 : meta-unrollers -***************************************************************************/ - -/************************ -*** Default traversal *** -************************/ - -template -struct assign_DefaultTraversal_CompleteUnrolling -{ - enum { - outer = Index / Derived1::InnerSizeAtCompileTime, - inner = Index % Derived1::InnerSizeAtCompileTime - }; - - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - dst.copyCoeffByOuterInner(outer, inner, src); - assign_DefaultTraversal_CompleteUnrolling::run(dst, src); - } -}; - -template -struct assign_DefaultTraversal_CompleteUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {} -}; - -template -struct assign_DefaultTraversal_InnerUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src, typename Derived1::Index outer) - { - dst.copyCoeffByOuterInner(outer, Index, src); - assign_DefaultTraversal_InnerUnrolling::run(dst, src, outer); - } -}; - -template -struct assign_DefaultTraversal_InnerUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &, typename Derived1::Index) {} -}; - -/*********************** -*** Linear traversal *** -***********************/ - -template -struct assign_LinearTraversal_CompleteUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - dst.copyCoeff(Index, src); - assign_LinearTraversal_CompleteUnrolling::run(dst, src); - } -}; - -template -struct assign_LinearTraversal_CompleteUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {} -}; - -/************************** -*** Inner vectorization *** -**************************/ - -template -struct assign_innervec_CompleteUnrolling -{ - enum { - outer = Index / Derived1::InnerSizeAtCompileTime, - inner = Index % Derived1::InnerSizeAtCompileTime, - JointAlignment = assign_traits::JointAlignment - }; - - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - dst.template copyPacketByOuterInner(outer, inner, src); - assign_innervec_CompleteUnrolling::size, Stop>::run(dst, src); - } -}; - -template -struct assign_innervec_CompleteUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {} -}; - -template -struct assign_innervec_InnerUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src, typename Derived1::Index outer) - { - dst.template copyPacketByOuterInner(outer, Index, src); - assign_innervec_InnerUnrolling::size, Stop>::run(dst, src, outer); - } -}; - -template -struct assign_innervec_InnerUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &, typename Derived1::Index) {} -}; - -/*************************************************************************** -* Part 3 : implementation of all cases -***************************************************************************/ - -template::Traversal, - int Unrolling = assign_traits::Unrolling, - int Version = Specialized> -struct assign_impl; - -/************************ -*** Default traversal *** -************************/ - -template -struct assign_impl -{ - static inline void run(Derived1 &, const Derived2 &) { } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - const Index innerSize = dst.innerSize(); - const Index outerSize = dst.outerSize(); - for(Index outer = 0; outer < outerSize; ++outer) - for(Index inner = 0; inner < innerSize; ++inner) - dst.copyCoeffByOuterInner(outer, inner, src); - } -}; - -template -struct assign_impl -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - assign_DefaultTraversal_CompleteUnrolling - ::run(dst, src); - } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - const Index outerSize = dst.outerSize(); - for(Index outer = 0; outer < outerSize; ++outer) - assign_DefaultTraversal_InnerUnrolling - ::run(dst, src, outer); - } -}; - -/*********************** -*** Linear traversal *** -***********************/ - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - const Index size = dst.size(); - for(Index i = 0; i < size; ++i) - dst.copyCoeff(i, src); - } -}; - -template -struct assign_impl -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - assign_LinearTraversal_CompleteUnrolling - ::run(dst, src); - } -}; - -/************************** -*** Inner vectorization *** -**************************/ - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - const Index innerSize = dst.innerSize(); - const Index outerSize = dst.outerSize(); - const Index packetSize = packet_traits::size; - for(Index outer = 0; outer < outerSize; ++outer) - for(Index inner = 0; inner < innerSize; inner+=packetSize) - dst.template copyPacketByOuterInner(outer, inner, src); - } -}; - -template -struct assign_impl -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - assign_innervec_CompleteUnrolling - ::run(dst, src); - } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - const Index outerSize = dst.outerSize(); - for(Index outer = 0; outer < outerSize; ++outer) - assign_innervec_InnerUnrolling - ::run(dst, src, outer); - } -}; - -/*************************** -*** Linear vectorization *** -***************************/ - -template -struct unaligned_assign_impl -{ - template - static EIGEN_STRONG_INLINE void run(const Derived&, OtherDerived&, typename Derived::Index, typename Derived::Index) {} -}; - -template <> -struct unaligned_assign_impl -{ - // MSVC must not inline this functions. If it does, it fails to optimize the - // packet access path. -#ifdef _MSC_VER - template - static EIGEN_DONT_INLINE void run(const Derived& src, OtherDerived& dst, typename Derived::Index start, typename Derived::Index end) -#else - template - static EIGEN_STRONG_INLINE void run(const Derived& src, OtherDerived& dst, typename Derived::Index start, typename Derived::Index end) -#endif - { - for (typename Derived::Index index = start; index < end; ++index) - dst.copyCoeff(index, src); - } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - const Index size = dst.size(); - typedef packet_traits PacketTraits; - enum { - packetSize = PacketTraits::size, - dstAlignment = PacketTraits::AlignedOnScalar ? Aligned : int(assign_traits::DstIsAligned) , - srcAlignment = assign_traits::JointAlignment - }; - const Index alignedStart = assign_traits::DstIsAligned ? 0 - : internal::first_aligned(&dst.coeffRef(0), size); - const Index alignedEnd = alignedStart + ((size-alignedStart)/packetSize)*packetSize; - - unaligned_assign_impl::DstIsAligned!=0>::run(src,dst,0,alignedStart); - - for(Index index = alignedStart; index < alignedEnd; index += packetSize) - { - dst.template copyPacket(index, src); - } - - unaligned_assign_impl<>::run(src,dst,alignedEnd,size); - } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - enum { size = Derived1::SizeAtCompileTime, - packetSize = packet_traits::size, - alignedSize = (size/packetSize)*packetSize }; - - assign_innervec_CompleteUnrolling::run(dst, src); - assign_DefaultTraversal_CompleteUnrolling::run(dst, src); - } -}; - -/************************** -*** Slice vectorization *** -***************************/ - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - typedef packet_traits PacketTraits; - enum { - packetSize = PacketTraits::size, - alignable = PacketTraits::AlignedOnScalar, - dstAlignment = alignable ? Aligned : int(assign_traits::DstIsAligned) , - srcAlignment = assign_traits::JointAlignment - }; - const Index packetAlignedMask = packetSize - 1; - const Index innerSize = dst.innerSize(); - const Index outerSize = dst.outerSize(); - const Index alignedStep = alignable ? (packetSize - dst.outerStride() % packetSize) & packetAlignedMask : 0; - Index alignedStart = ((!alignable) || assign_traits::DstIsAligned) ? 0 - : internal::first_aligned(&dst.coeffRef(0,0), innerSize); - - for(Index outer = 0; outer < outerSize; ++outer) - { - const Index alignedEnd = alignedStart + ((innerSize-alignedStart) & ~packetAlignedMask); - // do the non-vectorizable part of the assignment - for(Index inner = 0; inner(outer, inner, src); - - // do the non-vectorizable part of the assignment - for(Index inner = alignedEnd; inner((alignedStart+alignedStep)%packetSize, innerSize); - } - } -}; - -} // end namespace internal - -/*************************************************************************** -* Part 4 : implementation of DenseBase methods -***************************************************************************/ - template template EIGEN_STRONG_INLINE Derived& DenseBase @@ -492,90 +27,62 @@ EIGEN_STRONG_INLINE Derived& DenseBase EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived) EIGEN_STATIC_ASSERT(SameType,YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) -#ifdef EIGEN_DEBUG_ASSIGN - internal::assign_traits::debug(); -#endif eigen_assert(rows() == other.rows() && cols() == other.cols()); - internal::assign_impl::Traversal) - : int(InvalidTraversal)>::run(derived(),other.derived()); -#ifndef EIGEN_NO_DEBUG - checkTransposeAliasing(other.derived()); -#endif + internal::call_assignment_no_alias(derived(),other.derived()); + return derived(); } -namespace internal { - -template::Flags) & EvalBeforeAssigningBit) != 0, - bool NeedToTranspose = ((int(Derived::RowsAtCompileTime) == 1 && int(OtherDerived::ColsAtCompileTime) == 1) - | // FIXME | instead of || to please GCC 4.4.0 stupid warning "suggest parentheses around &&". - // revert to || as soon as not needed anymore. - (int(Derived::ColsAtCompileTime) == 1 && int(OtherDerived::RowsAtCompileTime) == 1)) - && int(Derived::SizeAtCompileTime) != 1> -struct assign_selector; - -template -struct assign_selector { - static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.derived()); } - template - static EIGEN_STRONG_INLINE Derived& evalTo(ActualDerived& dst, const ActualOtherDerived& other) { other.evalTo(dst); return dst; } -}; -template -struct assign_selector { - static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.eval()); } -}; -template -struct assign_selector { - static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose()); } - template - static EIGEN_STRONG_INLINE Derived& evalTo(ActualDerived& dst, const ActualOtherDerived& other) { Transpose dstTrans(dst); other.evalTo(dstTrans); return dst; } -}; -template -struct assign_selector { - static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose().eval()); } -}; - -} // end namespace internal - template template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) { - return internal::assign_selector::run(derived(), other.derived()); + internal::call_assignment(derived(), other.derived()); + return derived(); } template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) { - return internal::assign_selector::run(derived(), other.derived()); + internal::call_assignment(derived(), other.derived()); + return derived(); } template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const MatrixBase& other) { - return internal::assign_selector::run(derived(), other.derived()); + internal::call_assignment(derived(), other.derived()); + return derived(); } template template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const DenseBase& other) { - return internal::assign_selector::run(derived(), other.derived()); + internal::call_assignment(derived(), other.derived()); + return derived(); } template template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const EigenBase& other) { - return internal::assign_selector::evalTo(derived(), other.derived()); + internal::call_assignment(derived(), other.derived()); + return derived(); } template template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const ReturnByValue& other) { - return internal::assign_selector::evalTo(derived(), other.derived()); + other.derived().evalTo(derived()); + return derived(); } } // end namespace Eigen diff --git a/nuparu/include/Eigen/src/Core/AssignEvaluator.h b/nuparu/include/Eigen/src/Core/AssignEvaluator.h new file mode 100755 index 00000000..9dfffbcc --- /dev/null +++ b/nuparu/include/Eigen/src/Core/AssignEvaluator.h @@ -0,0 +1,810 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2011 Benoit Jacob +// Copyright (C) 2011-2014 Gael Guennebaud +// Copyright (C) 2011-2012 Jitse Niesen +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_ASSIGN_EVALUATOR_H +#define EIGEN_ASSIGN_EVALUATOR_H + +namespace Eigen { + +// This implementation is based on Assign.h + +namespace internal { + +/*************************************************************************** +* Part 1 : the logic deciding a strategy for traversal and unrolling * +***************************************************************************/ + +// copy_using_evaluator_traits is based on assign_traits + +template +struct copy_using_evaluator_traits +{ + typedef typename DstEvaluator::XprType Dst; + typedef typename Dst::Scalar DstScalar; + // TODO distinguish between linear traversal and inner-traversals + typedef typename find_best_packet::type PacketType; + + enum { + DstFlags = DstEvaluator::Flags, + SrcFlags = SrcEvaluator::Flags, + RequiredAlignment = unpacket_traits::alignment + }; + +public: + enum { + DstAlignment = DstEvaluator::Alignment, + SrcAlignment = SrcEvaluator::Alignment, + DstHasDirectAccess = DstFlags & DirectAccessBit, + JointAlignment = EIGEN_PLAIN_ENUM_MIN(DstAlignment,SrcAlignment) + }; + +private: + enum { + InnerSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::SizeAtCompileTime) + : int(DstFlags)&RowMajorBit ? int(Dst::ColsAtCompileTime) + : int(Dst::RowsAtCompileTime), + InnerMaxSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::MaxSizeAtCompileTime) + : int(DstFlags)&RowMajorBit ? int(Dst::MaxColsAtCompileTime) + : int(Dst::MaxRowsAtCompileTime), + OuterStride = int(outer_stride_at_compile_time::ret), + MaxSizeAtCompileTime = Dst::SizeAtCompileTime, + PacketSize = unpacket_traits::size + }; + + enum { + DstIsRowMajor = DstFlags&RowMajorBit, + SrcIsRowMajor = SrcFlags&RowMajorBit, + StorageOrdersAgree = (int(DstIsRowMajor) == int(SrcIsRowMajor)), + MightVectorize = StorageOrdersAgree + && (int(DstFlags) & int(SrcFlags) & ActualPacketAccessBit) + && (functor_traits::PacketAccess), + MayInnerVectorize = MightVectorize + && int(InnerSize)!=Dynamic && int(InnerSize)%int(PacketSize)==0 + && int(OuterStride)!=Dynamic && int(OuterStride)%int(PacketSize)==0 + && int(JointAlignment)>=int(RequiredAlignment), + MayLinearize = StorageOrdersAgree && (int(DstFlags) & int(SrcFlags) & LinearAccessBit), + MayLinearVectorize = MightVectorize && MayLinearize && DstHasDirectAccess + && ((int(DstAlignment)>=int(RequiredAlignment)) || MaxSizeAtCompileTime == Dynamic), + /* If the destination isn't aligned, we have to do runtime checks and we don't unroll, + so it's only good for large enough sizes. */ + MaySliceVectorize = MightVectorize && DstHasDirectAccess + && (int(InnerMaxSize)==Dynamic || int(InnerMaxSize)>=3*PacketSize) + /* slice vectorization can be slow, so we only want it if the slices are big, which is + indicated by InnerMaxSize rather than InnerSize, think of the case of a dynamic block + in a fixed-size matrix */ + }; + +public: + enum { + Traversal = int(MayInnerVectorize) ? int(InnerVectorizedTraversal) + : int(MayLinearVectorize) ? int(LinearVectorizedTraversal) + : int(MaySliceVectorize) ? int(SliceVectorizedTraversal) + : int(MayLinearize) ? int(LinearTraversal) + : int(DefaultTraversal), + Vectorized = int(Traversal) == InnerVectorizedTraversal + || int(Traversal) == LinearVectorizedTraversal + || int(Traversal) == SliceVectorizedTraversal + }; + +private: + enum { + UnrollingLimit = EIGEN_UNROLLING_LIMIT * (Vectorized ? int(PacketSize) : 1), + MayUnrollCompletely = int(Dst::SizeAtCompileTime) != Dynamic + && int(Dst::SizeAtCompileTime) * int(SrcEvaluator::CoeffReadCost) <= int(UnrollingLimit), + MayUnrollInner = int(InnerSize) != Dynamic + && int(InnerSize) * int(SrcEvaluator::CoeffReadCost) <= int(UnrollingLimit) + }; + +public: + enum { + Unrolling = (int(Traversal) == int(InnerVectorizedTraversal) || int(Traversal) == int(DefaultTraversal)) + ? ( + int(MayUnrollCompletely) ? int(CompleteUnrolling) + : int(MayUnrollInner) ? int(InnerUnrolling) + : int(NoUnrolling) + ) + : int(Traversal) == int(LinearVectorizedTraversal) + ? ( bool(MayUnrollCompletely) && (int(DstAlignment)>=int(RequiredAlignment)) ? int(CompleteUnrolling) + : int(NoUnrolling) ) + : int(Traversal) == int(LinearTraversal) + ? ( bool(MayUnrollCompletely) ? int(CompleteUnrolling) + : int(NoUnrolling) ) + : int(NoUnrolling) + }; + +#ifdef EIGEN_DEBUG_ASSIGN + static void debug() + { + std::cerr << "DstXpr: " << typeid(typename DstEvaluator::XprType).name() << std::endl; + std::cerr << "SrcXpr: " << typeid(typename SrcEvaluator::XprType).name() << std::endl; + std::cerr.setf(std::ios::hex, std::ios::basefield); + std::cerr << "DstFlags" << " = " << DstFlags << " (" << demangle_flags(DstFlags) << " )" << std::endl; + std::cerr << "SrcFlags" << " = " << SrcFlags << " (" << demangle_flags(SrcFlags) << " )" << std::endl; + std::cerr.unsetf(std::ios::hex); + EIGEN_DEBUG_VAR(DstAlignment) + EIGEN_DEBUG_VAR(SrcAlignment) + EIGEN_DEBUG_VAR(RequiredAlignment) + EIGEN_DEBUG_VAR(JointAlignment) + EIGEN_DEBUG_VAR(InnerSize) + EIGEN_DEBUG_VAR(InnerMaxSize) + EIGEN_DEBUG_VAR(PacketSize) + EIGEN_DEBUG_VAR(StorageOrdersAgree) + EIGEN_DEBUG_VAR(MightVectorize) + EIGEN_DEBUG_VAR(MayLinearize) + EIGEN_DEBUG_VAR(MayInnerVectorize) + EIGEN_DEBUG_VAR(MayLinearVectorize) + EIGEN_DEBUG_VAR(MaySliceVectorize) + std::cerr << "Traversal" << " = " << Traversal << " (" << demangle_traversal(Traversal) << ")" << std::endl; + EIGEN_DEBUG_VAR(UnrollingLimit) + EIGEN_DEBUG_VAR(MayUnrollCompletely) + EIGEN_DEBUG_VAR(MayUnrollInner) + std::cerr << "Unrolling" << " = " << Unrolling << " (" << demangle_unrolling(Unrolling) << ")" << std::endl; + std::cerr << std::endl; + } +#endif +}; + +/*************************************************************************** +* Part 2 : meta-unrollers +***************************************************************************/ + +/************************ +*** Default traversal *** +************************/ + +template +struct copy_using_evaluator_DefaultTraversal_CompleteUnrolling +{ + // FIXME: this is not very clean, perhaps this information should be provided by the kernel? + typedef typename Kernel::DstEvaluatorType DstEvaluatorType; + typedef typename DstEvaluatorType::XprType DstXprType; + + enum { + outer = Index / DstXprType::InnerSizeAtCompileTime, + inner = Index % DstXprType::InnerSizeAtCompileTime + }; + + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + kernel.assignCoeffByOuterInner(outer, inner); + copy_using_evaluator_DefaultTraversal_CompleteUnrolling::run(kernel); + } +}; + +template +struct copy_using_evaluator_DefaultTraversal_CompleteUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&) { } +}; + +template +struct copy_using_evaluator_DefaultTraversal_InnerUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel, Index outer) + { + kernel.assignCoeffByOuterInner(outer, Index_); + copy_using_evaluator_DefaultTraversal_InnerUnrolling::run(kernel, outer); + } +}; + +template +struct copy_using_evaluator_DefaultTraversal_InnerUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&, Index) { } +}; + +/*********************** +*** Linear traversal *** +***********************/ + +template +struct copy_using_evaluator_LinearTraversal_CompleteUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel& kernel) + { + kernel.assignCoeff(Index); + copy_using_evaluator_LinearTraversal_CompleteUnrolling::run(kernel); + } +}; + +template +struct copy_using_evaluator_LinearTraversal_CompleteUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&) { } +}; + +/************************** +*** Inner vectorization *** +**************************/ + +template +struct copy_using_evaluator_innervec_CompleteUnrolling +{ + // FIXME: this is not very clean, perhaps this information should be provided by the kernel? + typedef typename Kernel::DstEvaluatorType DstEvaluatorType; + typedef typename DstEvaluatorType::XprType DstXprType; + typedef typename Kernel::PacketType PacketType; + + enum { + outer = Index / DstXprType::InnerSizeAtCompileTime, + inner = Index % DstXprType::InnerSizeAtCompileTime, + JointAlignment = Kernel::AssignmentTraits::JointAlignment + }; + + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + kernel.template assignPacketByOuterInner(outer, inner); + enum { NextIndex = Index + unpacket_traits::size }; + copy_using_evaluator_innervec_CompleteUnrolling::run(kernel); + } +}; + +template +struct copy_using_evaluator_innervec_CompleteUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&) { } +}; + +template +struct copy_using_evaluator_innervec_InnerUnrolling +{ + typedef typename Kernel::PacketType PacketType; + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel, Index outer) + { + kernel.template assignPacketByOuterInner(outer, Index_); + enum { NextIndex = Index_ + unpacket_traits::size }; + copy_using_evaluator_innervec_InnerUnrolling::run(kernel, outer); + } +}; + +template +struct copy_using_evaluator_innervec_InnerUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &, Index) { } +}; + +/*************************************************************************** +* Part 3 : implementation of all cases +***************************************************************************/ + +// dense_assignment_loop is based on assign_impl + +template +struct dense_assignment_loop; + +/************************ +*** Default traversal *** +************************/ + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static void EIGEN_STRONG_INLINE run(Kernel &kernel) + { + for(Index outer = 0; outer < kernel.outerSize(); ++outer) { + for(Index inner = 0; inner < kernel.innerSize(); ++inner) { + kernel.assignCoeffByOuterInner(outer, inner); + } + } + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + copy_using_evaluator_DefaultTraversal_CompleteUnrolling::run(kernel); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + + const Index outerSize = kernel.outerSize(); + for(Index outer = 0; outer < outerSize; ++outer) + copy_using_evaluator_DefaultTraversal_InnerUnrolling::run(kernel, outer); + } +}; + +/*************************** +*** Linear vectorization *** +***************************/ + + +// The goal of unaligned_dense_assignment_loop is simply to factorize the handling +// of the non vectorizable beginning and ending parts + +template +struct unaligned_dense_assignment_loop +{ + // if IsAligned = true, then do nothing + template + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&, Index, Index) {} +}; + +template <> +struct unaligned_dense_assignment_loop +{ + // MSVC must not inline this functions. If it does, it fails to optimize the + // packet access path. + // FIXME check which version exhibits this issue +#if EIGEN_COMP_MSVC + template + static EIGEN_DONT_INLINE void run(Kernel &kernel, + Index start, + Index end) +#else + template + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel, + Index start, + Index end) +#endif + { + for (Index index = start; index < end; ++index) + kernel.assignCoeff(index); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + const Index size = kernel.size(); + typedef typename Kernel::Scalar Scalar; + typedef typename Kernel::PacketType PacketType; + enum { + requestedAlignment = Kernel::AssignmentTraits::RequiredAlignment, + packetSize = unpacket_traits::size, + dstIsAligned = int(Kernel::AssignmentTraits::DstAlignment)>=int(requestedAlignment), + dstAlignment = packet_traits::AlignedOnScalar ? int(requestedAlignment) + : int(Kernel::AssignmentTraits::DstAlignment), + srcAlignment = Kernel::AssignmentTraits::JointAlignment + }; + const Index alignedStart = dstIsAligned ? 0 : internal::first_aligned(&kernel.dstEvaluator().coeffRef(0), size); + const Index alignedEnd = alignedStart + ((size-alignedStart)/packetSize)*packetSize; + + unaligned_dense_assignment_loop::run(kernel, 0, alignedStart); + + for(Index index = alignedStart; index < alignedEnd; index += packetSize) + kernel.template assignPacket(index); + + unaligned_dense_assignment_loop<>::run(kernel, alignedEnd, size); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + + enum { size = DstXprType::SizeAtCompileTime, + packetSize = packet_traits::size, + alignedSize = (size/packetSize)*packetSize }; + + copy_using_evaluator_innervec_CompleteUnrolling::run(kernel); + copy_using_evaluator_DefaultTraversal_CompleteUnrolling::run(kernel); + } +}; + +/************************** +*** Inner vectorization *** +**************************/ + +template +struct dense_assignment_loop +{ + typedef typename Kernel::PacketType PacketType; + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + const Index innerSize = kernel.innerSize(); + const Index outerSize = kernel.outerSize(); + const Index packetSize = unpacket_traits::size; + for(Index outer = 0; outer < outerSize; ++outer) + for(Index inner = 0; inner < innerSize; inner+=packetSize) + kernel.template assignPacketByOuterInner(outer, inner); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + copy_using_evaluator_innervec_CompleteUnrolling::run(kernel); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + const Index outerSize = kernel.outerSize(); + for(Index outer = 0; outer < outerSize; ++outer) + copy_using_evaluator_innervec_InnerUnrolling::run(kernel, outer); + } +}; + +/*********************** +*** Linear traversal *** +***********************/ + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + const Index size = kernel.size(); + for(Index i = 0; i < size; ++i) + kernel.assignCoeff(i); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + copy_using_evaluator_LinearTraversal_CompleteUnrolling::run(kernel); + } +}; + +/************************** +*** Slice vectorization *** +***************************/ + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static inline void run(Kernel &kernel) + { + typedef typename Kernel::Scalar Scalar; + typedef typename Kernel::PacketType PacketType; + enum { + packetSize = unpacket_traits::size, + requestedAlignment = int(Kernel::AssignmentTraits::RequiredAlignment), + alignable = packet_traits::AlignedOnScalar || int(Kernel::AssignmentTraits::DstAlignment)>=sizeof(Scalar), + dstIsAligned = int(Kernel::AssignmentTraits::DstAlignment)>=int(requestedAlignment), + dstAlignment = alignable ? int(requestedAlignment) + : int(Kernel::AssignmentTraits::DstAlignment) + }; + const Scalar *dst_ptr = &kernel.dstEvaluator().coeffRef(0,0); + if((!bool(dstIsAligned)) && (size_t(dst_ptr) % sizeof(Scalar))>0) + { + // the pointer is not aligend-on scalar, so alignment is not possible + return dense_assignment_loop::run(kernel); + } + const Index packetAlignedMask = packetSize - 1; + const Index innerSize = kernel.innerSize(); + const Index outerSize = kernel.outerSize(); + const Index alignedStep = alignable ? (packetSize - kernel.outerStride() % packetSize) & packetAlignedMask : 0; + Index alignedStart = ((!alignable) || bool(dstIsAligned)) ? 0 : internal::first_aligned(dst_ptr, innerSize); + + for(Index outer = 0; outer < outerSize; ++outer) + { + const Index alignedEnd = alignedStart + ((innerSize-alignedStart) & ~packetAlignedMask); + // do the non-vectorizable part of the assignment + for(Index inner = 0; inner(outer, inner); + + // do the non-vectorizable part of the assignment + for(Index inner = alignedEnd; inner((alignedStart+alignedStep)%packetSize, innerSize); + } + } +}; + +/*************************************************************************** +* Part 4 : Generic dense assignment kernel +***************************************************************************/ + +// This class generalize the assignment of a coefficient (or packet) from one dense evaluator +// to another dense writable evaluator. +// It is parametrized by the two evaluators, and the actual assignment functor. +// This abstraction level permits to keep the evaluation loops as simple and as generic as possible. +// One can customize the assignment using this generic dense_assignment_kernel with different +// functors, or by completely overloading it, by-passing a functor. +template +class generic_dense_assignment_kernel +{ +protected: + typedef typename DstEvaluatorTypeT::XprType DstXprType; + typedef typename SrcEvaluatorTypeT::XprType SrcXprType; +public: + + typedef DstEvaluatorTypeT DstEvaluatorType; + typedef SrcEvaluatorTypeT SrcEvaluatorType; + typedef typename DstEvaluatorType::Scalar Scalar; + typedef copy_using_evaluator_traits AssignmentTraits; + typedef typename AssignmentTraits::PacketType PacketType; + + + EIGEN_DEVICE_FUNC generic_dense_assignment_kernel(DstEvaluatorType &dst, const SrcEvaluatorType &src, const Functor &func, DstXprType& dstExpr) + : m_dst(dst), m_src(src), m_functor(func), m_dstExpr(dstExpr) + { + #ifdef EIGEN_DEBUG_ASSIGN + AssignmentTraits::debug(); + #endif + } + + EIGEN_DEVICE_FUNC Index size() const { return m_dstExpr.size(); } + EIGEN_DEVICE_FUNC Index innerSize() const { return m_dstExpr.innerSize(); } + EIGEN_DEVICE_FUNC Index outerSize() const { return m_dstExpr.outerSize(); } + EIGEN_DEVICE_FUNC Index rows() const { return m_dstExpr.rows(); } + EIGEN_DEVICE_FUNC Index cols() const { return m_dstExpr.cols(); } + EIGEN_DEVICE_FUNC Index outerStride() const { return m_dstExpr.outerStride(); } + + EIGEN_DEVICE_FUNC DstEvaluatorType& dstEvaluator() { return m_dst; } + EIGEN_DEVICE_FUNC const SrcEvaluatorType& srcEvaluator() const { return m_src; } + + /// Assign src(row,col) to dst(row,col) through the assignment functor. + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(Index row, Index col) + { + m_functor.assignCoeff(m_dst.coeffRef(row,col), m_src.coeff(row,col)); + } + + /// \sa assignCoeff(Index,Index) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(Index index) + { + m_functor.assignCoeff(m_dst.coeffRef(index), m_src.coeff(index)); + } + + /// \sa assignCoeff(Index,Index) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeffByOuterInner(Index outer, Index inner) + { + Index row = rowIndexByOuterInner(outer, inner); + Index col = colIndexByOuterInner(outer, inner); + assignCoeff(row, col); + } + + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignPacket(Index row, Index col) + { + m_functor.template assignPacket(&m_dst.coeffRef(row,col), m_src.template packet(row,col)); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignPacket(Index index) + { + m_functor.template assignPacket(&m_dst.coeffRef(index), m_src.template packet(index)); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignPacketByOuterInner(Index outer, Index inner) + { + Index row = rowIndexByOuterInner(outer, inner); + Index col = colIndexByOuterInner(outer, inner); + assignPacket(row, col); + } + + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Index rowIndexByOuterInner(Index outer, Index inner) + { + typedef typename DstEvaluatorType::ExpressionTraits Traits; + return int(Traits::RowsAtCompileTime) == 1 ? 0 + : int(Traits::ColsAtCompileTime) == 1 ? inner + : int(DstEvaluatorType::Flags)&RowMajorBit ? outer + : inner; + } + + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Index colIndexByOuterInner(Index outer, Index inner) + { + typedef typename DstEvaluatorType::ExpressionTraits Traits; + return int(Traits::ColsAtCompileTime) == 1 ? 0 + : int(Traits::RowsAtCompileTime) == 1 ? inner + : int(DstEvaluatorType::Flags)&RowMajorBit ? inner + : outer; + } + +protected: + DstEvaluatorType& m_dst; + const SrcEvaluatorType& m_src; + const Functor &m_functor; + // TODO find a way to avoid the needs of the original expression + DstXprType& m_dstExpr; +}; + +/*************************************************************************** +* Part 5 : Entry point for dense rectangular assignment +***************************************************************************/ + +template +EIGEN_DEVICE_FUNC void call_dense_assignment_loop(const DstXprType& dst, const SrcXprType& src, const Functor &func) +{ + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + + typedef evaluator DstEvaluatorType; + typedef evaluator SrcEvaluatorType; + + DstEvaluatorType dstEvaluator(dst); + SrcEvaluatorType srcEvaluator(src); + + typedef generic_dense_assignment_kernel Kernel; + Kernel kernel(dstEvaluator, srcEvaluator, func, dst.const_cast_derived()); + + dense_assignment_loop::run(kernel); +} + +template +EIGEN_DEVICE_FUNC void call_dense_assignment_loop(const DstXprType& dst, const SrcXprType& src) +{ + call_dense_assignment_loop(dst, src, internal::assign_op()); +} + +/*************************************************************************** +* Part 6 : Generic assignment +***************************************************************************/ + +// Based on the respective shapes of the destination and source, +// the class AssignmentKind determine the kind of assignment mechanism. +// AssignmentKind must define a Kind typedef. +template struct AssignmentKind; + +// Assignement kind defined in this file: +struct Dense2Dense {}; +struct EigenBase2EigenBase {}; + +template struct AssignmentKind { typedef EigenBase2EigenBase Kind; }; +template<> struct AssignmentKind { typedef Dense2Dense Kind; }; + +// This is the main assignment class +template< typename DstXprType, typename SrcXprType, typename Functor, + typename Kind = typename AssignmentKind< typename evaluator_traits::Shape , typename evaluator_traits::Shape >::Kind, + typename Scalar = typename DstXprType::Scalar> +struct Assignment; + + +// The only purpose of this call_assignment() function is to deal with noalias() / AssumeAliasing and automatic transposition. +// Indeed, I (Gael) think that this concept of AssumeAliasing was a mistake, and it makes thing quite complicated. +// So this intermediate function removes everything related to AssumeAliasing such that Assignment +// does not has to bother about these annoying details. + +template +EIGEN_DEVICE_FUNC void call_assignment(Dst& dst, const Src& src) +{ + call_assignment(dst, src, internal::assign_op()); +} +template +EIGEN_DEVICE_FUNC void call_assignment(const Dst& dst, const Src& src) +{ + call_assignment(dst, src, internal::assign_op()); +} + +// Deal with AssumeAliasing +template +EIGEN_DEVICE_FUNC void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if::AssumeAliasing==1, void*>::type = 0) +{ + typename plain_matrix_type::type tmp(src); + call_assignment_no_alias(dst, tmp, func); +} + +template +EIGEN_DEVICE_FUNC void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if::AssumeAliasing==0, void*>::type = 0) +{ + call_assignment_no_alias(dst, src, func); +} + +// by-pass AssumeAliasing +// When there is no aliasing, we require that 'dst' has been properly resized +template class StorageBase, typename Src, typename Func> +EIGEN_DEVICE_FUNC void call_assignment(NoAlias& dst, const Src& src, const Func& func) +{ + call_assignment_no_alias(dst.expression(), src, func); +} + + +template +EIGEN_DEVICE_FUNC void call_assignment_no_alias(Dst& dst, const Src& src, const Func& func) +{ + enum { + NeedToTranspose = ( (int(Dst::RowsAtCompileTime) == 1 && int(Src::ColsAtCompileTime) == 1) + || (int(Dst::ColsAtCompileTime) == 1 && int(Src::RowsAtCompileTime) == 1) + ) && int(Dst::SizeAtCompileTime) != 1 + }; + + Index dstRows = NeedToTranspose ? src.cols() : src.rows(); + Index dstCols = NeedToTranspose ? src.rows() : src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + + typedef typename internal::conditional, Dst>::type ActualDstTypeCleaned; + typedef typename internal::conditional, Dst&>::type ActualDstType; + ActualDstType actualDst(dst); + + // TODO check whether this is the right place to perform these checks: + EIGEN_STATIC_ASSERT_LVALUE(Dst) + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(ActualDstTypeCleaned,Src) + EIGEN_CHECK_BINARY_COMPATIBILIY(Func,typename ActualDstTypeCleaned::Scalar,typename Src::Scalar); + + Assignment::run(actualDst, src, func); +} +template +EIGEN_DEVICE_FUNC void call_assignment_no_alias(Dst& dst, const Src& src) +{ + call_assignment_no_alias(dst, src, internal::assign_op()); +} + +template +EIGEN_DEVICE_FUNC void call_assignment_no_alias_no_transpose(Dst& dst, const Src& src, const Func& func) +{ + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + + // TODO check whether this is the right place to perform these checks: + EIGEN_STATIC_ASSERT_LVALUE(Dst) + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Dst,Src) + + Assignment::run(dst, src, func); +} +template +EIGEN_DEVICE_FUNC void call_assignment_no_alias_no_transpose(Dst& dst, const Src& src) +{ + call_assignment_no_alias_no_transpose(dst, src, internal::assign_op()); +} + +// forward declaration +template void check_for_aliasing(const Dst &dst, const Src &src); + +// Generic Dense to Dense assignment +template< typename DstXprType, typename SrcXprType, typename Functor, typename Scalar> +struct Assignment +{ + EIGEN_DEVICE_FUNC static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) + { + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + +#ifndef EIGEN_NO_DEBUG + internal::check_for_aliasing(dst, src); +#endif + + call_dense_assignment_loop(dst, src, func); + } +}; + +// Generic assignment through evalTo. +// TODO: not sure we have to keep that one, but it helps porting current code to new evaluator mechanism. +template< typename DstXprType, typename SrcXprType, typename Functor, typename Scalar> +struct Assignment +{ + EIGEN_DEVICE_FUNC static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &/*func*/) + { + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + src.evalTo(dst); + } +}; + +} // namespace internal + +} // end namespace Eigen + +#endif // EIGEN_ASSIGN_EVALUATOR_H diff --git a/nuparu/include/Eigen/src/Core/Assign_MKL.h b/nuparu/include/Eigen/src/Core/Assign_MKL.h old mode 100644 new mode 100755 index 7772951b..897187a3 --- a/nuparu/include/Eigen/src/Core/Assign_MKL.h +++ b/nuparu/include/Eigen/src/Core/Assign_MKL.h @@ -1,6 +1,7 @@ /* Copyright (c) 2011, Intel Corporation. All rights reserved. - + Copyright (C) 2015 Gael Guennebaud + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -37,17 +38,13 @@ namespace Eigen { namespace internal { -template struct vml_call -{ enum { IsSupported = 0 }; }; - -template +template class vml_assign_traits { private: enum { DstHasDirectAccess = Dst::Flags & DirectAccessBit, SrcHasDirectAccess = Src::Flags & DirectAccessBit, - StorageOrdersAgree = (int(Dst::IsRowMajor) == int(Src::IsRowMajor)), InnerSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::SizeAtCompileTime) : int(Dst::Flags)&RowMajorBit ? int(Dst::ColsAtCompileTime) @@ -57,165 +54,118 @@ class vml_assign_traits : int(Dst::MaxRowsAtCompileTime), MaxSizeAtCompileTime = Dst::SizeAtCompileTime, - MightEnableVml = vml_call::IsSupported && StorageOrdersAgree && DstHasDirectAccess && SrcHasDirectAccess - && Src::InnerStrideAtCompileTime==1 && Dst::InnerStrideAtCompileTime==1, + MightEnableVml = StorageOrdersAgree && DstHasDirectAccess && SrcHasDirectAccess && Src::InnerStrideAtCompileTime==1 && Dst::InnerStrideAtCompileTime==1, MightLinearize = MightEnableVml && (int(Dst::Flags) & int(Src::Flags) & LinearAccessBit), VmlSize = MightLinearize ? MaxSizeAtCompileTime : InnerMaxSize, - LargeEnough = VmlSize==Dynamic || VmlSize>=EIGEN_MKL_VML_THRESHOLD, - MayEnableVml = MightEnableVml && LargeEnough, - MayLinearize = MayEnableVml && MightLinearize + LargeEnough = VmlSize==Dynamic || VmlSize>=EIGEN_MKL_VML_THRESHOLD }; public: enum { - Traversal = MayLinearize ? LinearVectorizedTraversal - : MayEnableVml ? InnerVectorizedTraversal - : DefaultTraversal + EnableVml = MightEnableVml && LargeEnough, + Traversal = MightLinearize ? LinearTraversal : DefaultTraversal }; }; -template::Traversal > -struct vml_assign_impl - : assign_impl,Traversal,Unrolling,BuiltIn> -{ -}; - -template -struct vml_assign_impl -{ - typedef typename Derived1::Scalar Scalar; - typedef typename Derived1::Index Index; - static inline void run(Derived1& dst, const CwiseUnaryOp& src) - { - // in case we want to (or have to) skip VML at runtime we can call: - // assign_impl,Traversal,Unrolling,BuiltIn>::run(dst,src); - const Index innerSize = dst.innerSize(); - const Index outerSize = dst.outerSize(); - for(Index outer = 0; outer < outerSize; ++outer) { - const Scalar *src_ptr = src.IsRowMajor ? &(src.nestedExpression().coeffRef(outer,0)) : - &(src.nestedExpression().coeffRef(0, outer)); - Scalar *dst_ptr = dst.IsRowMajor ? &(dst.coeffRef(outer,0)) : &(dst.coeffRef(0, outer)); - vml_call::run(src.functor(), innerSize, src_ptr, dst_ptr ); - } - } -}; - -template -struct vml_assign_impl -{ - static inline void run(Derived1& dst, const CwiseUnaryOp& src) - { - // in case we want to (or have to) skip VML at runtime we can call: - // assign_impl,Traversal,Unrolling,BuiltIn>::run(dst,src); - vml_call::run(src.functor(), dst.size(), src.nestedExpression().data(), dst.data() ); - } -}; - -// Macroses - -#define EIGEN_MKL_VML_SPECIALIZE_ASSIGN(TRAVERSAL,UNROLLING) \ - template \ - struct assign_impl, TRAVERSAL, UNROLLING, Specialized> { \ - static inline void run(Derived1 &dst, const Eigen::CwiseUnaryOp &src) { \ - vml_assign_impl::run(dst, src); \ - } \ - }; - -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(DefaultTraversal,NoUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(DefaultTraversal,CompleteUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(DefaultTraversal,InnerUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(LinearTraversal,NoUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(LinearTraversal,CompleteUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(InnerVectorizedTraversal,NoUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(InnerVectorizedTraversal,CompleteUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(InnerVectorizedTraversal,InnerUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(LinearVectorizedTraversal,CompleteUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(LinearVectorizedTraversal,NoUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(SliceVectorizedTraversal,NoUnrolling) - - +#define EIGEN_PP_EXPAND(ARG) ARG #if !defined (EIGEN_FAST_MATH) || (EIGEN_FAST_MATH != 1) -#define EIGEN_MKL_VML_MODE VML_HA +#define EIGEN_VMLMODE_EXPAND_LA , VML_HA #else -#define EIGEN_MKL_VML_MODE VML_LA +#define EIGEN_VMLMODE_EXPAND_LA , VML_LA #endif -#define EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE) \ - template<> struct vml_call< scalar_##EIGENOP##_op > { \ - enum { IsSupported = 1 }; \ - static inline void run( const scalar_##EIGENOP##_op& /*func*/, \ - int size, const EIGENTYPE* src, EIGENTYPE* dst) { \ - VMLOP(size, (const VMLTYPE*)src, (VMLTYPE*)dst); \ - } \ +#define EIGEN_VMLMODE_EXPAND__ + +#define EIGEN_VMLMODE_PREFIX_LA vm +#define EIGEN_VMLMODE_PREFIX__ v +#define EIGEN_VMLMODE_PREFIX(VMLMODE) EIGEN_CAT(EIGEN_VMLMODE_PREFIX_,VMLMODE) + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE, VMLMODE) \ + template< typename DstXprType, typename SrcXprNested> \ + struct Assignment, SrcXprNested>, assign_op, \ + Dense2Dense, typename enable_if::EnableVml,EIGENTYPE>::type> { \ + typedef CwiseUnaryOp, SrcXprNested> SrcXprType; \ + static void run(DstXprType &dst, const SrcXprType &src, const assign_op &/*func*/) { \ + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); \ + if(vml_assign_traits::Traversal==LinearTraversal) { \ + VMLOP(dst.size(), (const VMLTYPE*)src.nestedExpression().data(), \ + (VMLTYPE*)dst.data() EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_##VMLMODE) ); \ + } else { \ + const Index outerSize = dst.outerSize(); \ + for(Index outer = 0; outer < outerSize; ++outer) { \ + const EIGENTYPE *src_ptr = src.IsRowMajor ? &(src.nestedExpression().coeffRef(outer,0)) : \ + &(src.nestedExpression().coeffRef(0, outer)); \ + EIGENTYPE *dst_ptr = dst.IsRowMajor ? &(dst.coeffRef(outer,0)) : &(dst.coeffRef(0, outer)); \ + VMLOP( dst.innerSize(), (const VMLTYPE*)src_ptr, \ + (VMLTYPE*)dst_ptr EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_##VMLMODE)); \ + } \ + } \ + } \ + }; \ + + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE),s##VMLOP), float, float, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE),d##VMLOP), double, double, VMLMODE) + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_CPLX(EIGENOP, VMLOP, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE),c##VMLOP), scomplex, MKL_Complex8, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE),z##VMLOP), dcomplex, MKL_Complex16, VMLMODE) + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS(EIGENOP, VMLOP, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALLS_CPLX(EIGENOP, VMLOP, VMLMODE) + + +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(sin, Sin, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(asin, Asin, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(sinh, Sinh, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(cos, Cos, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(acos, Acos, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(cosh, Cosh, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(tan, Tan, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(atan, Atan, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(tanh, Tanh, LA) +// EIGEN_MKL_VML_DECLARE_UNARY_CALLS(abs, Abs, _) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(exp, Exp, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(log, Ln, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(log10, Log10, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(sqrt, Sqrt, _) + +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(square, Sqr, _) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_CPLX(arg, Arg, _) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(round, Round, _) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(floor, Floor, _) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(ceil, Ceil, _) + +#define EIGEN_MKL_VML_DECLARE_POW_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE, VMLMODE) \ + template< typename DstXprType, typename SrcXprNested> \ + struct Assignment, SrcXprNested>, assign_op, \ + Dense2Dense, typename enable_if::EnableVml,EIGENTYPE>::type> { \ + typedef CwiseUnaryOp, SrcXprNested> SrcXprType; \ + static void run(DstXprType &dst, const SrcXprType &src, const assign_op &/*func*/) { \ + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); \ + VMLTYPE exponent = reinterpret_cast(src.functor().m_exponent); \ + if(vml_assign_traits::Traversal==LinearTraversal) \ + { \ + VMLOP( dst.size(), (const VMLTYPE*)src.nestedExpression().data(), exponent, \ + (VMLTYPE*)dst.data() EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_##VMLMODE) ); \ + } else { \ + const Index outerSize = dst.outerSize(); \ + for(Index outer = 0; outer < outerSize; ++outer) { \ + const EIGENTYPE *src_ptr = src.IsRowMajor ? &(src.nestedExpression().coeffRef(outer,0)) : \ + &(src.nestedExpression().coeffRef(0, outer)); \ + EIGENTYPE *dst_ptr = dst.IsRowMajor ? &(dst.coeffRef(outer,0)) : &(dst.coeffRef(0, outer)); \ + VMLOP( dst.innerSize(), (const VMLTYPE*)src_ptr, exponent, \ + (VMLTYPE*)dst_ptr EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_##VMLMODE)); \ + } \ + } \ + } \ }; - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE) \ - template<> struct vml_call< scalar_##EIGENOP##_op > { \ - enum { IsSupported = 1 }; \ - static inline void run( const scalar_##EIGENOP##_op& /*func*/, \ - int size, const EIGENTYPE* src, EIGENTYPE* dst) { \ - MKL_INT64 vmlMode = EIGEN_MKL_VML_MODE; \ - VMLOP(size, (const VMLTYPE*)src, (VMLTYPE*)dst, vmlMode); \ - } \ - }; - -#define EIGEN_MKL_VML_DECLARE_POW_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE) \ - template<> struct vml_call< scalar_##EIGENOP##_op > { \ - enum { IsSupported = 1 }; \ - static inline void run( const scalar_##EIGENOP##_op& func, \ - int size, const EIGENTYPE* src, EIGENTYPE* dst) { \ - EIGENTYPE exponent = func.m_exponent; \ - MKL_INT64 vmlMode = EIGEN_MKL_VML_MODE; \ - VMLOP(&size, (const VMLTYPE*)src, (const VMLTYPE*)&exponent, \ - (VMLTYPE*)dst, &vmlMode); \ - } \ - }; - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vs##VMLOP, float, float) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vd##VMLOP, double, double) - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vc##VMLOP, scomplex, MKL_Complex8) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vz##VMLOP, dcomplex, MKL_Complex16) - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX(EIGENOP, VMLOP) - - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL_LA(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vms##VMLOP, float, float) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vmd##VMLOP, double, double) - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX_LA(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vmc##VMLOP, scomplex, MKL_Complex8) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vmz##VMLOP, dcomplex, MKL_Complex16) - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL_LA(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX_LA(EIGENOP, VMLOP) - - -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(sin, Sin) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(asin, Asin) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(cos, Cos) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(acos, Acos) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(tan, Tan) -//EIGEN_MKL_VML_DECLARE_UNARY_CALLS(abs, Abs) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(exp, Exp) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(log, Ln) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(sqrt, Sqrt) - -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(square, Sqr) - -// The vm*powx functions are not avaibale in the windows version of MKL. -#ifndef _WIN32 -EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmspowx_, float, float) -EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmdpowx_, double, double) -EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmcpowx_, scomplex, MKL_Complex8) -EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmzpowx_, dcomplex, MKL_Complex16) -#endif + +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmsPowx, float, float, LA) +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmdPowx, double, double, LA) +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmcPowx, scomplex, MKL_Complex8, LA) +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmzPowx, dcomplex, MKL_Complex16, LA) } // end namespace internal diff --git a/nuparu/include/Eigen/src/Core/BandMatrix.h b/nuparu/include/Eigen/src/Core/BandMatrix.h index ffd7fe8b..87c124fd 100644 --- a/nuparu/include/Eigen/src/Core/BandMatrix.h +++ b/nuparu/include/Eigen/src/Core/BandMatrix.h @@ -32,7 +32,7 @@ class BandMatrixBase : public EigenBase }; typedef typename internal::traits::Scalar Scalar; typedef Matrix DenseMatrixType; - typedef typename DenseMatrixType::Index Index; + typedef typename DenseMatrixType::StorageIndex StorageIndex; typedef typename internal::traits::CoefficientsType CoefficientsType; typedef EigenBase Base; @@ -179,7 +179,7 @@ struct traits > { typedef _Scalar Scalar; typedef Dense StorageKind; - typedef DenseIndex Index; + typedef Eigen::Index StorageIndex; enum { CoeffReadCost = NumTraits::ReadCost, RowsAtCompileTime = _Rows, @@ -201,10 +201,10 @@ class BandMatrix : public BandMatrixBase::Scalar Scalar; - typedef typename internal::traits::Index Index; + typedef typename internal::traits::StorageIndex StorageIndex; typedef typename internal::traits::CoefficientsType CoefficientsType; - inline BandMatrix(Index rows=Rows, Index cols=Cols, Index supers=Supers, Index subs=Subs) + explicit inline BandMatrix(Index rows=Rows, Index cols=Cols, Index supers=Supers, Index subs=Subs) : m_coeffs(1+supers+subs,cols), m_rows(rows), m_supers(supers), m_subs(subs) { @@ -241,7 +241,7 @@ struct traits::CoeffReadCost, RowsAtCompileTime = _Rows, @@ -264,9 +264,9 @@ class BandMatrixWrapper : public BandMatrixBase::Scalar Scalar; typedef typename internal::traits::CoefficientsType CoefficientsType; - typedef typename internal::traits::Index Index; + typedef typename internal::traits::StorageIndex StorageIndex; - inline BandMatrixWrapper(const CoefficientsType& coeffs, Index rows=_Rows, Index cols=_Cols, Index supers=_Supers, Index subs=_Subs) + explicit inline BandMatrixWrapper(const CoefficientsType& coeffs, Index rows=_Rows, Index cols=_Cols, Index supers=_Supers, Index subs=_Subs) : m_coeffs(coeffs), m_rows(rows), m_supers(supers), m_subs(subs) { @@ -312,9 +312,9 @@ template class TridiagonalMatrix : public BandMatrix { typedef BandMatrix Base; - typedef typename Base::Index Index; + typedef typename Base::StorageIndex StorageIndex; public: - TridiagonalMatrix(Index size = Size) : Base(size,size,Options&SelfAdjoint?0:1,1) {} + explicit TridiagonalMatrix(Index size = Size) : Base(size,size,Options&SelfAdjoint?0:1,1) {} inline typename Base::template DiagonalIntReturnType<1>::Type super() { return Base::template diagonal<1>(); } @@ -327,6 +327,25 @@ class TridiagonalMatrix : public BandMatrix +struct evaluator_traits > + : public evaluator_traits_base > +{ + typedef BandShape Shape; +}; + +template +struct evaluator_traits > + : public evaluator_traits_base > +{ + typedef BandShape Shape; +}; + +template<> struct AssignmentKind { typedef EigenBase2EigenBase Kind; }; + } // end namespace internal } // end namespace Eigen diff --git a/nuparu/include/Eigen/src/Core/Block.h b/nuparu/include/Eigen/src/Core/Block.h index 358b3188..3748e259 100644 --- a/nuparu/include/Eigen/src/Core/Block.h +++ b/nuparu/include/Eigen/src/Core/Block.h @@ -21,6 +21,9 @@ namespace Eigen { * \param XprType the type of the expression in which we are taking a block * \param BlockRows the number of rows of the block we are taking at compile time (optional) * \param BlockCols the number of columns of the block we are taking at compile time (optional) + * \param InnerPanel is true, if the block maps to a set of rows of a row major matrix or + * to set of columns of a column major matrix (optional). The parameter allows to determine + * at compile time whether aligned access is possible on the block expression. * * This class represents an expression of either a fixed-size or dynamic-size block. It is the return * type of DenseBase::block(Index,Index,Index,Index) and DenseBase::block(Index,Index) and @@ -52,7 +55,7 @@ struct traits > : traits::Scalar Scalar; typedef typename traits::StorageKind StorageKind; typedef typename traits::XprKind XprKind; - typedef typename nested::type XprTypeNested; + typedef typename ref_selector::type XprTypeNested; typedef typename remove_reference::type _XprTypeNested; enum{ MatrixRows = traits::RowsAtCompileTime, @@ -65,6 +68,7 @@ struct traits > : traits::MaxColsAtCompileTime), + XprTypeIsRowMajor = (int(traits::Flags)&RowMajorBit) != 0, IsRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 @@ -77,18 +81,16 @@ struct traits > : traits::ret) : int(inner_stride_at_compile_time::ret), - MaskPacketAccessBit = (InnerSize == Dynamic || (InnerSize % packet_traits::size) == 0) - && (InnerStrideAtCompileTime == 1) - ? PacketAccessBit : 0, - MaskAlignedBit = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % 16) == 0)) ? AlignedBit : 0, - FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1) ? LinearAccessBit : 0, + + // FIXME, this traits is rather specialized for dense object and it needs to be cleaned further FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0, - Flags0 = traits::Flags & ( (HereditaryBits & ~RowMajorBit) | - DirectAccessBit | - MaskPacketAccessBit | - MaskAlignedBit), - Flags = Flags0 | FlagsLinearAccessBit | FlagsLvalueBit | FlagsRowMajorBit + Flags = (traits::Flags & (DirectAccessBit | (InnerPanel?CompressedAccessBit:0))) | FlagsLvalueBit | FlagsRowMajorBit, + // FIXME DirectAccessBit should not be handled by expressions + // + // Alignment is needed by MapBase's assertions + // We can sefely set it to false here. Internal alignment errors will be detected by an eigen_internal_assert in the respective evaluator + Alignment = 0 }; }; @@ -108,9 +110,12 @@ template class typedef Impl Base; EIGEN_GENERIC_PUBLIC_INTERFACE(Block) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Block) + + typedef typename internal::remove_all::type NestedExpression; /** Column or Row constructor */ + EIGEN_DEVICE_FUNC inline Block(XprType& xpr, Index i) : Impl(xpr,i) { eigen_assert( (i>=0) && ( @@ -120,25 +125,27 @@ template class /** Fixed-size constructor */ - inline Block(XprType& xpr, Index a_startRow, Index a_startCol) - : Impl(xpr, a_startRow, a_startCol) + EIGEN_DEVICE_FUNC + inline Block(XprType& xpr, Index startRow, Index startCol) + : Impl(xpr, startRow, startCol) { EIGEN_STATIC_ASSERT(RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic,THIS_METHOD_IS_ONLY_FOR_FIXED_SIZE) - eigen_assert(a_startRow >= 0 && BlockRows >= 1 && a_startRow + BlockRows <= xpr.rows() - && a_startCol >= 0 && BlockCols >= 1 && a_startCol + BlockCols <= xpr.cols()); + eigen_assert(startRow >= 0 && BlockRows >= 1 && startRow + BlockRows <= xpr.rows() + && startCol >= 0 && BlockCols >= 1 && startCol + BlockCols <= xpr.cols()); } /** Dynamic-size constructor */ + EIGEN_DEVICE_FUNC inline Block(XprType& xpr, - Index a_startRow, Index a_startCol, + Index startRow, Index startCol, Index blockRows, Index blockCols) - : Impl(xpr, a_startRow, a_startCol, blockRows, blockCols) + : Impl(xpr, startRow, startCol, blockRows, blockCols) { eigen_assert((RowsAtCompileTime==Dynamic || RowsAtCompileTime==blockRows) && (ColsAtCompileTime==Dynamic || ColsAtCompileTime==blockCols)); - eigen_assert(a_startRow >= 0 && blockRows >= 0 && a_startRow <= xpr.rows() - blockRows - && a_startCol >= 0 && blockCols >= 0 && a_startCol <= xpr.cols() - blockCols); + eigen_assert(startRow >= 0 && blockRows >= 0 && startRow <= xpr.rows() - blockRows + && startCol >= 0 && blockCols >= 0 && startCol <= xpr.cols() - blockCols); } }; @@ -149,14 +156,15 @@ class BlockImpl : public internal::BlockImpl_dense { typedef internal::BlockImpl_dense Impl; - typedef typename XprType::Index Index; + typedef typename XprType::StorageIndex StorageIndex; public: typedef Impl Base; EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl) - inline BlockImpl(XprType& xpr, Index i) : Impl(xpr,i) {} - inline BlockImpl(XprType& xpr, Index a_startRow, Index a_startCol) : Impl(xpr, a_startRow, a_startCol) {} - inline BlockImpl(XprType& xpr, Index a_startRow, Index a_startCol, Index blockRows, Index blockCols) - : Impl(xpr, a_startRow, a_startCol, blockRows, blockCols) {} + EIGEN_DEVICE_FUNC inline BlockImpl(XprType& xpr, Index i) : Impl(xpr,i) {} + EIGEN_DEVICE_FUNC inline BlockImpl(XprType& xpr, Index startRow, Index startCol) : Impl(xpr, startRow, startCol) {} + EIGEN_DEVICE_FUNC + inline BlockImpl(XprType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols) + : Impl(xpr, startRow, startCol, blockRows, blockCols) {} }; namespace internal { @@ -172,10 +180,11 @@ template::type& nestedExpression() const + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& nestedExpression() const { return m_xpr; } - Index startRow() const + EIGEN_DEVICE_FUNC + StorageIndex startRow() const { return m_startRow.value(); } - Index startCol() const + EIGEN_DEVICE_FUNC + StorageIndex startCol() const { return m_startCol.value(); } @@ -302,10 +322,10 @@ template m_startRow; - const internal::variable_if_dynamic m_startCol; - const internal::variable_if_dynamic m_blockRows; - const internal::variable_if_dynamic m_blockCols; + const internal::variable_if_dynamic m_startRow; + const internal::variable_if_dynamic m_startCol; + const internal::variable_if_dynamic m_blockRows; + const internal::variable_if_dynamic m_blockCols; }; /** \internal Internal implementation of dense Blocks in the direct access case.*/ @@ -314,6 +334,9 @@ class BlockImpl_dense : public MapBase > { typedef Block BlockType; + enum { + XprTypeIsRowMajor = (int(traits::Flags)&RowMajorBit) != 0 + }; public: typedef MapBase Base; @@ -322,10 +345,10 @@ class BlockImpl_dense /** Column or Row constructor */ + EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index i) - : Base(internal::const_cast_ptr(&xpr.coeffRef( - (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0, - (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0)), + : Base(xpr.data() + i * ( ((BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) && (!XprTypeIsRowMajor)) + || ((BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) && ( XprTypeIsRowMajor)) ? xpr.innerStride() : xpr.outerStride()), BlockRows==1 ? 1 : xpr.rows(), BlockCols==1 ? 1 : xpr.cols()), m_xpr(xpr) @@ -335,29 +358,34 @@ class BlockImpl_dense /** Fixed-size constructor */ + EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index startRow, Index startCol) - : Base(internal::const_cast_ptr(&xpr.coeffRef(startRow,startCol))), m_xpr(xpr) + : Base(xpr.data()+xpr.innerStride()*(XprTypeIsRowMajor?startCol:startRow) + xpr.outerStride()*(XprTypeIsRowMajor?startRow:startCol)), + m_xpr(xpr) { init(); } /** Dynamic-size constructor */ + EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols) - : Base(internal::const_cast_ptr(&xpr.coeffRef(startRow,startCol)), blockRows, blockCols), + : Base(xpr.data()+xpr.innerStride()*(XprTypeIsRowMajor?startCol:startRow) + xpr.outerStride()*(XprTypeIsRowMajor?startRow:startCol), blockRows, blockCols), m_xpr(xpr) { init(); } - const typename internal::remove_all::type& nestedExpression() const + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& nestedExpression() const { return m_xpr; } /** \sa MapBase::innerStride() */ + EIGEN_DEVICE_FUNC inline Index innerStride() const { return internal::traits::HasSameStorageOrderAsXprType @@ -366,6 +394,7 @@ class BlockImpl_dense } /** \sa MapBase::outerStride() */ + EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_outerStride; @@ -379,6 +408,7 @@ class BlockImpl_dense #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal used by allowAligned() */ + EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, const Scalar* data, Index blockRows, Index blockCols) : Base(data, blockRows, blockCols), m_xpr(xpr) { @@ -387,6 +417,7 @@ class BlockImpl_dense #endif protected: + EIGEN_DEVICE_FUNC void init() { m_outerStride = internal::traits::HasSameStorageOrderAsXprType diff --git a/nuparu/include/Eigen/src/Core/BooleanRedux.h b/nuparu/include/Eigen/src/Core/BooleanRedux.h index 6e37e031..8409d874 100644 --- a/nuparu/include/Eigen/src/Core/BooleanRedux.h +++ b/nuparu/include/Eigen/src/Core/BooleanRedux.h @@ -17,9 +17,10 @@ namespace internal { template struct all_unroller { + typedef typename Derived::ExpressionTraits Traits; enum { - col = (UnrollCount-1) / Derived::RowsAtCompileTime, - row = (UnrollCount-1) % Derived::RowsAtCompileTime + col = (UnrollCount-1) / Traits::RowsAtCompileTime, + row = (UnrollCount-1) % Traits::RowsAtCompileTime }; static inline bool run(const Derived &mat) @@ -29,9 +30,9 @@ struct all_unroller }; template -struct all_unroller +struct all_unroller { - static inline bool run(const Derived &mat) { return mat.coeff(0, 0); } + static inline bool run(const Derived &/*mat*/) { return true; } }; template @@ -43,11 +44,12 @@ struct all_unroller template struct any_unroller { + typedef typename Derived::ExpressionTraits Traits; enum { - col = (UnrollCount-1) / Derived::RowsAtCompileTime, - row = (UnrollCount-1) % Derived::RowsAtCompileTime + col = (UnrollCount-1) / Traits::RowsAtCompileTime, + row = (UnrollCount-1) % Traits::RowsAtCompileTime }; - + static inline bool run(const Derived &mat) { return any_unroller::run(mat) || mat.coeff(row, col); @@ -55,9 +57,9 @@ struct any_unroller }; template -struct any_unroller +struct any_unroller { - static inline bool run(const Derived &mat) { return mat.coeff(0, 0); } + static inline bool run(const Derived & /*mat*/) { return false; } }; template @@ -78,19 +80,19 @@ struct any_unroller template inline bool DenseBase::all() const { + typedef internal::evaluator Evaluator; enum { unroll = SizeAtCompileTime != Dynamic - && CoeffReadCost != Dynamic - && NumTraits::AddCost != Dynamic - && SizeAtCompileTime * (CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT + && SizeAtCompileTime * (Evaluator::CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT }; + Evaluator evaluator(derived()); if(unroll) - return internal::all_unroller::run(derived()); + return internal::all_unroller::run(evaluator); else { for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < rows(); ++i) - if (!coeff(i, j)) return false; + if (!evaluator.coeff(i, j)) return false; return true; } } @@ -102,19 +104,19 @@ inline bool DenseBase::all() const template inline bool DenseBase::any() const { + typedef internal::evaluator Evaluator; enum { unroll = SizeAtCompileTime != Dynamic - && CoeffReadCost != Dynamic - && NumTraits::AddCost != Dynamic - && SizeAtCompileTime * (CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT + && SizeAtCompileTime * (Evaluator::CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT }; + Evaluator evaluator(derived()); if(unroll) - return internal::any_unroller::run(derived()); + return internal::any_unroller::run(evaluator); else { for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < rows(); ++i) - if (coeff(i, j)) return true; + if (evaluator.coeff(i, j)) return true; return false; } } @@ -124,7 +126,7 @@ inline bool DenseBase::any() const * \sa all(), any() */ template -inline typename DenseBase::Index DenseBase::count() const +inline Eigen::Index DenseBase::count() const { return derived().template cast().template cast().sum(); } @@ -136,7 +138,11 @@ inline typename DenseBase::Index DenseBase::count() const template inline bool DenseBase::hasNaN() const { +#if EIGEN_COMP_MSVC || (defined __FAST_MATH__) + return derived().array().isNaN().any(); +#else return !((derived().array()==derived().array()).all()); +#endif } /** \returns true if \c *this contains only finite numbers, i.e., no NaN and no +/-INF values. @@ -146,7 +152,11 @@ inline bool DenseBase::hasNaN() const template inline bool DenseBase::allFinite() const { +#if EIGEN_COMP_MSVC || (defined __FAST_MATH__) + return derived().array().isFinite().all(); +#else return !((derived()-derived()).hasNaN()); +#endif } } // end namespace Eigen diff --git a/nuparu/include/Eigen/src/Core/CMakeLists.txt b/nuparu/include/Eigen/src/Core/CMakeLists.txt index 2346fc2b..38c3afde 100644 --- a/nuparu/include/Eigen/src/Core/CMakeLists.txt +++ b/nuparu/include/Eigen/src/Core/CMakeLists.txt @@ -8,3 +8,4 @@ INSTALL(FILES ADD_SUBDIRECTORY(products) ADD_SUBDIRECTORY(util) ADD_SUBDIRECTORY(arch) +ADD_SUBDIRECTORY(functors) diff --git a/nuparu/include/Eigen/src/Core/CommaInitializer.h b/nuparu/include/Eigen/src/Core/CommaInitializer.h index a96867af..89bcd750 100644 --- a/nuparu/include/Eigen/src/Core/CommaInitializer.h +++ b/nuparu/include/Eigen/src/Core/CommaInitializer.h @@ -28,8 +28,8 @@ template struct CommaInitializer { typedef typename XprType::Scalar Scalar; - typedef typename XprType::Index Index; + EIGEN_DEVICE_FUNC inline CommaInitializer(XprType& xpr, const Scalar& s) : m_xpr(xpr), m_row(0), m_col(1), m_currentBlockRows(1) { @@ -37,13 +37,27 @@ struct CommaInitializer } template + EIGEN_DEVICE_FUNC inline CommaInitializer(XprType& xpr, const DenseBase& other) : m_xpr(xpr), m_row(0), m_col(other.cols()), m_currentBlockRows(other.rows()) { m_xpr.block(0, 0, other.rows(), other.cols()) = other; } + /* Copy/Move constructor which transfers ownership. This is crucial in + * absence of return value optimization to avoid assertions during destruction. */ + // FIXME in C++11 mode this could be replaced by a proper RValue constructor + EIGEN_DEVICE_FUNC + inline CommaInitializer(const CommaInitializer& o) + : m_xpr(o.m_xpr), m_row(o.m_row), m_col(o.m_col), m_currentBlockRows(o.m_currentBlockRows) { + // Mark original object as finished. In absence of R-value references we need to const_cast: + const_cast(o).m_row = m_xpr.rows(); + const_cast(o).m_col = m_xpr.cols(); + const_cast(o).m_currentBlockRows = 0; + } + /* inserts a scalar value in the target matrix */ + EIGEN_DEVICE_FUNC CommaInitializer& operator,(const Scalar& s) { if (m_col==m_xpr.cols()) @@ -63,6 +77,7 @@ struct CommaInitializer /* inserts a matrix expression in the target matrix */ template + EIGEN_DEVICE_FUNC CommaInitializer& operator,(const DenseBase& other) { if(other.cols()==0 || other.rows()==0) @@ -88,7 +103,11 @@ struct CommaInitializer return *this; } + EIGEN_DEVICE_FUNC inline ~CommaInitializer() +#if defined VERIFY_RAISES_ASSERT && (!defined EIGEN_NO_ASSERTION_CHECKING) && defined EIGEN_EXCEPTIONS + EIGEN_EXCEPTION_SPEC(Eigen::eigen_assert_exception) +#endif { eigen_assert((m_row+m_currentBlockRows) == m_xpr.rows() && m_col == m_xpr.cols() @@ -102,9 +121,10 @@ struct CommaInitializer * quaternion.fromRotationMatrix((Matrix3f() << axis0, axis1, axis2).finished()); * \endcode */ + EIGEN_DEVICE_FUNC inline XprType& finished() { return m_xpr; } - XprType& m_xpr; // target expression + XprType& m_xpr; // target expression Index m_row; // current row id Index m_col; // current col id Index m_currentBlockRows; // current block height diff --git a/nuparu/include/Eigen/src/Core/CoreEvaluators.h b/nuparu/include/Eigen/src/Core/CoreEvaluators.h new file mode 100644 index 00000000..f97dc33d --- /dev/null +++ b/nuparu/include/Eigen/src/Core/CoreEvaluators.h @@ -0,0 +1,1376 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2011 Benoit Jacob +// Copyright (C) 2011-2014 Gael Guennebaud +// Copyright (C) 2011-2012 Jitse Niesen +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +#ifndef EIGEN_COREEVALUATORS_H +#define EIGEN_COREEVALUATORS_H + +namespace Eigen { + +namespace internal { + +// This class returns the evaluator kind from the expression storage kind. +// Default assumes index based accessors +template +struct storage_kind_to_evaluator_kind { + typedef IndexBased Kind; +}; + +// This class returns the evaluator shape from the expression storage kind. +// It can be Dense, Sparse, Triangular, Diagonal, SelfAdjoint, Band, etc. +template struct storage_kind_to_shape; + +template<> struct storage_kind_to_shape { typedef DenseShape Shape; }; +template<> struct storage_kind_to_shape { typedef SolverShape Shape; }; +template<> struct storage_kind_to_shape { typedef PermutationShape Shape; }; +template<> struct storage_kind_to_shape { typedef TranspositionsShape Shape; }; + +// Evaluators have to be specialized with respect to various criteria such as: +// - storage/structure/shape +// - scalar type +// - etc. +// Therefore, we need specialization of evaluator providing additional template arguments for each kind of evaluators. +// We currently distinguish the following kind of evaluators: +// - unary_evaluator for expressions taking only one arguments (CwiseUnaryOp, CwiseUnaryView, Transpose, MatrixWrapper, ArrayWrapper, Reverse, Replicate) +// - binary_evaluator for expression taking two arguments (CwiseBinaryOp) +// - product_evaluator for linear algebra products (Product); special case of binary_evaluator because it requires additional tags for dispatching. +// - mapbase_evaluator for Map, Block, Ref +// - block_evaluator for Block (special dispatching to a mapbase_evaluator or unary_evaluator) + +template< typename T, + typename LhsKind = typename evaluator_traits::Kind, + typename RhsKind = typename evaluator_traits::Kind, + typename LhsScalar = typename traits::Scalar, + typename RhsScalar = typename traits::Scalar> struct binary_evaluator; + +template< typename T, + typename Kind = typename evaluator_traits::Kind, + typename Scalar = typename T::Scalar> struct unary_evaluator; + +// evaluator_traits contains traits for evaluator + +template +struct evaluator_traits_base +{ + // by default, get evaluator kind and shape from storage + typedef typename storage_kind_to_evaluator_kind::StorageKind>::Kind Kind; + typedef typename storage_kind_to_shape::StorageKind>::Shape Shape; + + // 1 if assignment A = B assumes aliasing when B is of type T and thus B needs to be evaluated into a + // temporary; 0 if not. + static const int AssumeAliasing = 0; +}; + +// Default evaluator traits +template +struct evaluator_traits : public evaluator_traits_base +{ +}; + + +// By default, we assume a unary expression: +template +struct evaluator : public unary_evaluator +{ + typedef unary_evaluator Base; + EIGEN_DEVICE_FUNC explicit evaluator(const T& xpr) : Base(xpr) {} +}; + + +// TODO: Think about const-correctness +template +struct evaluator + : evaluator +{ + EIGEN_DEVICE_FUNC + explicit evaluator(const T& xpr) : evaluator(xpr) {} +}; + +// ---------- base class for all evaluators ---------- + +template +struct evaluator_base : public noncopyable +{ + // TODO that's not very nice to have to propagate all these traits. They are currently only needed to handle outer,inner indices. + typedef traits ExpressionTraits; + + enum { + Alignment = 0 + }; +}; + +// -------------------- Matrix and Array -------------------- +// +// evaluator is a common base class for the +// Matrix and Array evaluators. +// Here we directly specialize evaluator. This is not really a unary expression, and it is, by definition, dense, +// so no need for more sophisticated dispatching. + +template +struct evaluator > + : evaluator_base +{ + typedef PlainObjectBase PlainObjectType; + typedef typename PlainObjectType::Scalar Scalar; + typedef typename PlainObjectType::CoeffReturnType CoeffReturnType; + + enum { + IsRowMajor = PlainObjectType::IsRowMajor, + IsVectorAtCompileTime = PlainObjectType::IsVectorAtCompileTime, + RowsAtCompileTime = PlainObjectType::RowsAtCompileTime, + ColsAtCompileTime = PlainObjectType::ColsAtCompileTime, + + CoeffReadCost = NumTraits::ReadCost, + Flags = traits::EvaluatorFlags, + Alignment = traits::Alignment + }; + + EIGEN_DEVICE_FUNC evaluator() + : m_data(0), + m_outerStride(IsVectorAtCompileTime ? 0 + : int(IsRowMajor) ? ColsAtCompileTime + : RowsAtCompileTime) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + EIGEN_DEVICE_FUNC explicit evaluator(const PlainObjectType& m) + : m_data(m.data()), m_outerStride(IsVectorAtCompileTime ? 0 : m.outerStride()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const + { + if (IsRowMajor) + return m_data[row * m_outerStride.value() + col]; + else + return m_data[row + col * m_outerStride.value()]; + } + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const + { + return m_data[index]; + } + + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index row, Index col) + { + if (IsRowMajor) + return const_cast(m_data)[row * m_outerStride.value() + col]; + else + return const_cast(m_data)[row + col * m_outerStride.value()]; + } + + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index index) + { + return const_cast(m_data)[index]; + } + + template + PacketType packet(Index row, Index col) const + { + if (IsRowMajor) + return ploadt(m_data + row * m_outerStride.value() + col); + else + return ploadt(m_data + row + col * m_outerStride.value()); + } + + template + PacketType packet(Index index) const + { + return ploadt(m_data + index); + } + + template + void writePacket(Index row, Index col, const PacketType& x) + { + if (IsRowMajor) + return pstoret + (const_cast(m_data) + row * m_outerStride.value() + col, x); + else + return pstoret + (const_cast(m_data) + row + col * m_outerStride.value(), x); + } + + template + void writePacket(Index index, const PacketType& x) + { + return pstoret(const_cast(m_data) + index, x); + } + +protected: + const Scalar *m_data; + + // We do not need to know the outer stride for vectors + variable_if_dynamic m_outerStride; +}; + +template +struct evaluator > + : evaluator > > +{ + typedef Matrix XprType; + + EIGEN_DEVICE_FUNC evaluator() {} + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& m) + : evaluator >(m) + { } +}; + +template +struct evaluator > + : evaluator > > +{ + typedef Array XprType; + + EIGEN_DEVICE_FUNC evaluator() {} + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& m) + : evaluator >(m) + { } +}; + +// -------------------- Transpose -------------------- + +template +struct unary_evaluator, IndexBased> + : evaluator_base > +{ + typedef Transpose XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + Flags = evaluator::Flags ^ RowMajorBit, + Alignment = evaluator::Alignment + }; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& t) : m_argImpl(t.nestedExpression()) {} + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const + { + return m_argImpl.coeff(col, row); + } + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const + { + return m_argImpl.coeff(index); + } + + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index row, Index col) + { + return m_argImpl.coeffRef(col, row); + } + + EIGEN_DEVICE_FUNC typename XprType::Scalar& coeffRef(Index index) + { + return m_argImpl.coeffRef(index); + } + + template + PacketType packet(Index row, Index col) const + { + return m_argImpl.template packet(col, row); + } + + template + PacketType packet(Index index) const + { + return m_argImpl.template packet(index); + } + + template + void writePacket(Index row, Index col, const PacketType& x) + { + m_argImpl.template writePacket(col, row, x); + } + + template + void writePacket(Index index, const PacketType& x) + { + m_argImpl.template writePacket(index, x); + } + +protected: + evaluator m_argImpl; +}; + +// -------------------- CwiseNullaryOp -------------------- +// Like Matrix and Array, this is not really a unary expression, so we directly specialize evaluator. +// Likewise, there is not need to more sophisticated dispatching here. + +template +struct evaluator > + : evaluator_base > +{ + typedef CwiseNullaryOp XprType; + typedef typename internal::remove_all::type PlainObjectTypeCleaned; + + enum { + CoeffReadCost = internal::functor_traits::Cost, + + Flags = (evaluator::Flags + & ( HereditaryBits + | (functor_has_linear_access::ret ? LinearAccessBit : 0) + | (functor_traits::PacketAccess ? PacketAccessBit : 0))) + | (functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit), + Alignment = AlignedMax + }; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& n) + : m_functor(n.functor()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const + { + return m_functor(row, col); + } + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const + { + return m_functor(index); + } + + template + PacketType packet(Index row, Index col) const + { + return m_functor.template packetOp(row, col); + } + + template + PacketType packet(Index index) const + { + return m_functor.template packetOp(index); + } + +protected: + const NullaryOp m_functor; +}; + +// -------------------- CwiseUnaryOp -------------------- + +template +struct unary_evaluator, IndexBased > + : evaluator_base > +{ + typedef CwiseUnaryOp XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost + functor_traits::Cost, + + Flags = evaluator::Flags + & (HereditaryBits | LinearAccessBit | (functor_traits::PacketAccess ? PacketAccessBit : 0)), + Alignment = evaluator::Alignment + }; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& op) + : m_functor(op.functor()), + m_argImpl(op.nestedExpression()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const + { + return m_functor(m_argImpl.coeff(row, col)); + } + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const + { + return m_functor(m_argImpl.coeff(index)); + } + + template + PacketType packet(Index row, Index col) const + { + return m_functor.packetOp(m_argImpl.template packet(row, col)); + } + + template + PacketType packet(Index index) const + { + return m_functor.packetOp(m_argImpl.template packet(index)); + } + +protected: + const UnaryOp m_functor; + evaluator m_argImpl; +}; + +// -------------------- CwiseBinaryOp -------------------- + +// this is a binary expression +template +struct evaluator > + : public binary_evaluator > +{ + typedef CwiseBinaryOp XprType; + typedef binary_evaluator > Base; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : Base(xpr) {} +}; + +template +struct binary_evaluator, IndexBased, IndexBased> + : evaluator_base > +{ + typedef CwiseBinaryOp XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::Cost, + + LhsFlags = evaluator::Flags, + RhsFlags = evaluator::Flags, + SameType = is_same::value, + StorageOrdersAgree = (int(LhsFlags)&RowMajorBit)==(int(RhsFlags)&RowMajorBit), + Flags0 = (int(LhsFlags) | int(RhsFlags)) & ( + HereditaryBits + | (int(LhsFlags) & int(RhsFlags) & + ( (StorageOrdersAgree ? LinearAccessBit : 0) + | (functor_traits::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0) + ) + ) + ), + Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit), + Alignment = EIGEN_PLAIN_ENUM_MIN(evaluator::Alignment,evaluator::Alignment) + }; + + EIGEN_DEVICE_FUNC explicit binary_evaluator(const XprType& xpr) + : m_functor(xpr.functor()), + m_lhsImpl(xpr.lhs()), + m_rhsImpl(xpr.rhs()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const + { + return m_functor(m_lhsImpl.coeff(row, col), m_rhsImpl.coeff(row, col)); + } + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const + { + return m_functor(m_lhsImpl.coeff(index), m_rhsImpl.coeff(index)); + } + + template + PacketType packet(Index row, Index col) const + { + return m_functor.packetOp(m_lhsImpl.template packet(row, col), + m_rhsImpl.template packet(row, col)); + } + + template + PacketType packet(Index index) const + { + return m_functor.packetOp(m_lhsImpl.template packet(index), + m_rhsImpl.template packet(index)); + } + +protected: + const BinaryOp m_functor; + evaluator m_lhsImpl; + evaluator m_rhsImpl; +}; + +// -------------------- CwiseUnaryView -------------------- + +template +struct unary_evaluator, IndexBased> + : evaluator_base > +{ + typedef CwiseUnaryView XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost + functor_traits::Cost, + + Flags = (evaluator::Flags & (HereditaryBits | LinearAccessBit | DirectAccessBit)), + + Alignment = 0 // FIXME it is not very clear why alignment is necessarily lost... + }; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& op) + : m_unaryOp(op.functor()), + m_argImpl(op.nestedExpression()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const + { + return m_unaryOp(m_argImpl.coeff(row, col)); + } + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const + { + return m_unaryOp(m_argImpl.coeff(index)); + } + + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index row, Index col) + { + return m_unaryOp(m_argImpl.coeffRef(row, col)); + } + + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index index) + { + return m_unaryOp(m_argImpl.coeffRef(index)); + } + +protected: + const UnaryOp m_unaryOp; + evaluator m_argImpl; +}; + +// -------------------- Map -------------------- + +// FIXME perhaps the PlainObjectType could be provided by Derived::PlainObject ? +// but that might complicate template specialization +template +struct mapbase_evaluator; + +template +struct mapbase_evaluator : evaluator_base +{ + typedef Derived XprType; + typedef typename XprType::PointerType PointerType; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + enum { + IsRowMajor = XprType::RowsAtCompileTime, + ColsAtCompileTime = XprType::ColsAtCompileTime, + CoeffReadCost = NumTraits::ReadCost + }; + + EIGEN_DEVICE_FUNC explicit mapbase_evaluator(const XprType& map) + : m_data(const_cast(map.data())), + m_xpr(map) + { + EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(evaluator::Flags&PacketAccessBit, internal::inner_stride_at_compile_time::ret==1), + PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const + { + return m_data[col * m_xpr.colStride() + row * m_xpr.rowStride()]; + } + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const + { + return m_data[index * m_xpr.innerStride()]; + } + + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index row, Index col) + { + return m_data[col * m_xpr.colStride() + row * m_xpr.rowStride()]; + } + + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index index) + { + return m_data[index * m_xpr.innerStride()]; + } + + template + PacketType packet(Index row, Index col) const + { + PointerType ptr = m_data + row * m_xpr.rowStride() + col * m_xpr.colStride(); + return internal::ploadt(ptr); + } + + template + PacketType packet(Index index) const + { + return internal::ploadt(m_data + index * m_xpr.innerStride()); + } + + template + void writePacket(Index row, Index col, const PacketType& x) + { + PointerType ptr = m_data + row * m_xpr.rowStride() + col * m_xpr.colStride(); + return internal::pstoret(ptr, x); + } + + template + void writePacket(Index index, const PacketType& x) + { + internal::pstoret(m_data + index * m_xpr.innerStride(), x); + } + +protected: + PointerType m_data; + const XprType& m_xpr; +}; + +template +struct evaluator > + : public mapbase_evaluator, PlainObjectType> +{ + typedef Map XprType; + typedef typename XprType::Scalar Scalar; + // TODO: should check for smaller packet types once we can handle multi-sized packet types + typedef typename packet_traits::type PacketScalar; + + enum { + InnerStrideAtCompileTime = StrideType::InnerStrideAtCompileTime == 0 + ? int(PlainObjectType::InnerStrideAtCompileTime) + : int(StrideType::InnerStrideAtCompileTime), + OuterStrideAtCompileTime = StrideType::OuterStrideAtCompileTime == 0 + ? int(PlainObjectType::OuterStrideAtCompileTime) + : int(StrideType::OuterStrideAtCompileTime), + HasNoInnerStride = InnerStrideAtCompileTime == 1, + HasNoOuterStride = StrideType::OuterStrideAtCompileTime == 0, + HasNoStride = HasNoInnerStride && HasNoOuterStride, + IsDynamicSize = PlainObjectType::SizeAtCompileTime==Dynamic, + + PacketAccessMask = bool(HasNoInnerStride) ? ~int(0) : ~int(PacketAccessBit), + LinearAccessMask = bool(HasNoStride) || bool(PlainObjectType::IsVectorAtCompileTime) ? ~int(0) : ~int(LinearAccessBit), + Flags = int( evaluator::Flags) & (LinearAccessMask&PacketAccessMask), + + Alignment = int(MapOptions)&int(AlignedMask) + }; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& map) + : mapbase_evaluator(map) + { } +}; + +// -------------------- Ref -------------------- + +template +struct evaluator > + : public mapbase_evaluator, PlainObjectType> +{ + typedef Ref XprType; + + enum { + Flags = evaluator >::Flags, + Alignment = evaluator >::Alignment + }; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& ref) + : mapbase_evaluator(ref) + { } +}; + +// -------------------- Block -------------------- + +template::ret> struct block_evaluator; + +template +struct evaluator > + : block_evaluator +{ + typedef Block XprType; + typedef typename XprType::Scalar Scalar; + // TODO: should check for smaller packet types once we can handle multi-sized packet types + typedef typename packet_traits::type PacketScalar; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + + RowsAtCompileTime = traits::RowsAtCompileTime, + ColsAtCompileTime = traits::ColsAtCompileTime, + MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = traits::MaxColsAtCompileTime, + + ArgTypeIsRowMajor = (int(evaluator::Flags)&RowMajorBit) != 0, + IsRowMajor = (MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1) ? 1 + : (MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1) ? 0 + : ArgTypeIsRowMajor, + HasSameStorageOrderAsArgType = (IsRowMajor == ArgTypeIsRowMajor), + InnerSize = IsRowMajor ? int(ColsAtCompileTime) : int(RowsAtCompileTime), + InnerStrideAtCompileTime = HasSameStorageOrderAsArgType + ? int(inner_stride_at_compile_time::ret) + : int(outer_stride_at_compile_time::ret), + OuterStrideAtCompileTime = HasSameStorageOrderAsArgType + ? int(outer_stride_at_compile_time::ret) + : int(inner_stride_at_compile_time::ret), + MaskPacketAccessBit = (InnerSize == Dynamic || (InnerSize % packet_traits::size) == 0) + && (InnerStrideAtCompileTime == 1) + ? PacketAccessBit : 0, + + FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1 || (InnerPanel && (evaluator::Flags&LinearAccessBit))) ? LinearAccessBit : 0, + FlagsRowMajorBit = XprType::Flags&RowMajorBit, + Flags0 = evaluator::Flags & ( (HereditaryBits & ~RowMajorBit) | + DirectAccessBit | + MaskPacketAccessBit), + Flags = Flags0 | FlagsLinearAccessBit | FlagsRowMajorBit, + + PacketAlignment = unpacket_traits::alignment, + Alignment0 = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % int(PacketAlignment)) == 0)) ? int(PacketAlignment) : 0, + Alignment = EIGEN_PLAIN_ENUM_MIN(evaluator::Alignment, Alignment0) + }; + typedef block_evaluator block_evaluator_type; + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& block) : block_evaluator_type(block) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } +}; + +// no direct-access => dispatch to a unary evaluator +template +struct block_evaluator + : unary_evaluator > +{ + typedef Block XprType; + + EIGEN_DEVICE_FUNC explicit block_evaluator(const XprType& block) + : unary_evaluator(block) + {} +}; + +template +struct unary_evaluator, IndexBased> + : evaluator_base > +{ + typedef Block XprType; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& block) + : m_argImpl(block.nestedExpression()), + m_startRow(block.startRow()), + m_startCol(block.startCol()) + { } + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + enum { + RowsAtCompileTime = XprType::RowsAtCompileTime + }; + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const + { + return m_argImpl.coeff(m_startRow.value() + row, m_startCol.value() + col); + } + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const + { + return coeff(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0); + } + + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index row, Index col) + { + return m_argImpl.coeffRef(m_startRow.value() + row, m_startCol.value() + col); + } + + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index index) + { + return coeffRef(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0); + } + + template + PacketType packet(Index row, Index col) const + { + return m_argImpl.template packet(m_startRow.value() + row, m_startCol.value() + col); + } + + template + PacketType packet(Index index) const + { + return packet(RowsAtCompileTime == 1 ? 0 : index, + RowsAtCompileTime == 1 ? index : 0); + } + + template + void writePacket(Index row, Index col, const PacketType& x) + { + return m_argImpl.template writePacket(m_startRow.value() + row, m_startCol.value() + col, x); + } + + template + void writePacket(Index index, const PacketType& x) + { + return writePacket(RowsAtCompileTime == 1 ? 0 : index, + RowsAtCompileTime == 1 ? index : 0, + x); + } + +protected: + evaluator m_argImpl; + const variable_if_dynamic m_startRow; + const variable_if_dynamic m_startCol; +}; + +// TODO: This evaluator does not actually use the child evaluator; +// all action is via the data() as returned by the Block expression. + +template +struct block_evaluator + : mapbase_evaluator, + typename Block::PlainObject> +{ + typedef Block XprType; + typedef typename XprType::Scalar Scalar; + + EIGEN_DEVICE_FUNC explicit block_evaluator(const XprType& block) + : mapbase_evaluator(block) + { + // TODO: for the 3.3 release, this should be turned to an internal assertion, but let's keep it as is for the beta lifetime + eigen_assert(((size_t(block.data()) % EIGEN_PLAIN_ENUM_MAX(1,evaluator::Alignment)) == 0) && "data is not aligned"); + } +}; + + +// -------------------- Select -------------------- +// NOTE shall we introduce a ternary_evaluator? + +// TODO enable vectorization for Select +template +struct evaluator > + : evaluator_base > +{ + typedef Select XprType; + enum { + CoeffReadCost = evaluator::CoeffReadCost + + EIGEN_PLAIN_ENUM_MAX(evaluator::CoeffReadCost, + evaluator::CoeffReadCost), + + Flags = (unsigned int)evaluator::Flags & evaluator::Flags & HereditaryBits, + + Alignment = EIGEN_PLAIN_ENUM_MIN(evaluator::Alignment, evaluator::Alignment) + }; + + inline EIGEN_DEVICE_FUNC explicit evaluator(const XprType& select) + : m_conditionImpl(select.conditionMatrix()), + m_thenImpl(select.thenMatrix()), + m_elseImpl(select.elseMatrix()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + inline EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const + { + if (m_conditionImpl.coeff(row, col)) + return m_thenImpl.coeff(row, col); + else + return m_elseImpl.coeff(row, col); + } + + inline EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const + { + if (m_conditionImpl.coeff(index)) + return m_thenImpl.coeff(index); + else + return m_elseImpl.coeff(index); + } + +protected: + evaluator m_conditionImpl; + evaluator m_thenImpl; + evaluator m_elseImpl; +}; + + +// -------------------- Replicate -------------------- + +template +struct unary_evaluator > + : evaluator_base > +{ + typedef Replicate XprType; + typedef typename XprType::CoeffReturnType CoeffReturnType; + enum { + Factor = (RowFactor==Dynamic || ColFactor==Dynamic) ? Dynamic : RowFactor*ColFactor + }; + typedef typename internal::nested_eval::type ArgTypeNested; + typedef typename internal::remove_all::type ArgTypeNestedCleaned; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + LinearAccessMask = XprType::IsVectorAtCompileTime ? LinearAccessBit : 0, + Flags = (evaluator::Flags & (HereditaryBits|LinearAccessMask) & ~RowMajorBit) | (traits::Flags & RowMajorBit), + + Alignment = evaluator::Alignment + }; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& replicate) + : m_arg(replicate.nestedExpression()), + m_argImpl(m_arg), + m_rows(replicate.nestedExpression().rows()), + m_cols(replicate.nestedExpression().cols()) + {} + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const + { + // try to avoid using modulo; this is a pure optimization strategy + const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 + : RowFactor==1 ? row + : row % m_rows.value(); + const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 + : ColFactor==1 ? col + : col % m_cols.value(); + + return m_argImpl.coeff(actual_row, actual_col); + } + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const + { + // try to avoid using modulo; this is a pure optimization strategy + const Index actual_index = internal::traits::RowsAtCompileTime==1 + ? (ColFactor==1 ? index : index%m_cols.value()) + : (RowFactor==1 ? index : index%m_rows.value()); + + return m_argImpl.coeff(actual_index); + } + + template + PacketType packet(Index row, Index col) const + { + const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 + : RowFactor==1 ? row + : row % m_rows.value(); + const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 + : ColFactor==1 ? col + : col % m_cols.value(); + + return m_argImpl.template packet(actual_row, actual_col); + } + + template + PacketType packet(Index index) const + { + const Index actual_index = internal::traits::RowsAtCompileTime==1 + ? (ColFactor==1 ? index : index%m_cols.value()) + : (RowFactor==1 ? index : index%m_rows.value()); + + return m_argImpl.template packet(actual_index); + } + +protected: + const ArgTypeNested m_arg; + evaluator m_argImpl; + const variable_if_dynamic m_rows; + const variable_if_dynamic m_cols; +}; + + +// -------------------- PartialReduxExpr -------------------- + +template< typename ArgType, typename MemberOp, int Direction> +struct evaluator > + : evaluator_base > +{ + typedef PartialReduxExpr XprType; + typedef typename internal::nested_eval::type ArgTypeNested; + typedef typename internal::remove_all::type ArgTypeNestedCleaned; + typedef typename ArgType::Scalar InputScalar; + typedef typename XprType::Scalar Scalar; + enum { + TraversalSize = Direction==int(Vertical) ? int(ArgType::RowsAtCompileTime) : int(ArgType::ColsAtCompileTime) + }; + typedef typename MemberOp::template Cost CostOpType; + enum { + CoeffReadCost = TraversalSize==Dynamic ? HugeCost + : TraversalSize * evaluator::CoeffReadCost + int(CostOpType::value), + + Flags = (traits::Flags&RowMajorBit) | (evaluator::Flags&(HereditaryBits&(~RowMajorBit))), + + Alignment = 0 // FIXME this will need to be improved once PartialReduxExpr is vectorized + }; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType xpr) + : m_arg(xpr.nestedExpression()), m_functor(xpr.functor()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(TraversalSize==Dynamic ? HugeCost : int(CostOpType::value)); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index i, Index j) const + { + if (Direction==Vertical) + return m_functor(m_arg.col(j)); + else + return m_functor(m_arg.row(i)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index index) const + { + if (Direction==Vertical) + return m_functor(m_arg.col(index)); + else + return m_functor(m_arg.row(index)); + } + +protected: + const ArgTypeNested m_arg; + const MemberOp m_functor; +}; + + +// -------------------- MatrixWrapper and ArrayWrapper -------------------- +// +// evaluator_wrapper_base is a common base class for the +// MatrixWrapper and ArrayWrapper evaluators. + +template +struct evaluator_wrapper_base + : evaluator_base +{ + typedef typename remove_all::type ArgType; + enum { + CoeffReadCost = evaluator::CoeffReadCost, + Flags = evaluator::Flags, + Alignment = evaluator::Alignment + }; + + EIGEN_DEVICE_FUNC explicit evaluator_wrapper_base(const ArgType& arg) : m_argImpl(arg) {} + + typedef typename ArgType::Scalar Scalar; + typedef typename ArgType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const + { + return m_argImpl.coeff(row, col); + } + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const + { + return m_argImpl.coeff(index); + } + + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index row, Index col) + { + return m_argImpl.coeffRef(row, col); + } + + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index index) + { + return m_argImpl.coeffRef(index); + } + + template + PacketType packet(Index row, Index col) const + { + return m_argImpl.template packet(row, col); + } + + template + PacketType packet(Index index) const + { + return m_argImpl.template packet(index); + } + + template + void writePacket(Index row, Index col, const PacketType& x) + { + m_argImpl.template writePacket(row, col, x); + } + + template + void writePacket(Index index, const PacketType& x) + { + m_argImpl.template writePacket(index, x); + } + +protected: + evaluator m_argImpl; +}; + +template +struct unary_evaluator > + : evaluator_wrapper_base > +{ + typedef MatrixWrapper XprType; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& wrapper) + : evaluator_wrapper_base >(wrapper.nestedExpression()) + { } +}; + +template +struct unary_evaluator > + : evaluator_wrapper_base > +{ + typedef ArrayWrapper XprType; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& wrapper) + : evaluator_wrapper_base >(wrapper.nestedExpression()) + { } +}; + + +// -------------------- Reverse -------------------- + +// defined in Reverse.h: +template struct reverse_packet_cond; + +template +struct unary_evaluator > + : evaluator_base > +{ + typedef Reverse XprType; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + enum { + IsRowMajor = XprType::IsRowMajor, + IsColMajor = !IsRowMajor, + ReverseRow = (Direction == Vertical) || (Direction == BothDirections), + ReverseCol = (Direction == Horizontal) || (Direction == BothDirections), + ReversePacket = (Direction == BothDirections) + || ((Direction == Vertical) && IsColMajor) + || ((Direction == Horizontal) && IsRowMajor), + + CoeffReadCost = evaluator::CoeffReadCost, + + // let's enable LinearAccess only with vectorization because of the product overhead + // FIXME enable DirectAccess with negative strides? + Flags0 = evaluator::Flags, + LinearAccess = ( (Direction==BothDirections) && (int(Flags0)&PacketAccessBit) ) + || ((ReverseRow && XprType::ColsAtCompileTime==1) || (ReverseCol && XprType::RowsAtCompileTime==1)) + ? LinearAccessBit : 0, + + Flags = int(Flags0) & (HereditaryBits | PacketAccessBit | LinearAccess), + + Alignment = 0 // FIXME in some rare cases, Alignment could be preserved, like a Vector4f. + }; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& reverse) + : m_argImpl(reverse.nestedExpression()), + m_rows(ReverseRow ? reverse.nestedExpression().rows() : 1), + m_cols(ReverseCol ? reverse.nestedExpression().cols() : 1) + { } + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const + { + return m_argImpl.coeff(ReverseRow ? m_rows.value() - row - 1 : row, + ReverseCol ? m_cols.value() - col - 1 : col); + } + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const + { + return m_argImpl.coeff(m_rows.value() * m_cols.value() - index - 1); + } + + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index row, Index col) + { + return m_argImpl.coeffRef(ReverseRow ? m_rows.value() - row - 1 : row, + ReverseCol ? m_cols.value() - col - 1 : col); + } + + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index index) + { + return m_argImpl.coeffRef(m_rows.value() * m_cols.value() - index - 1); + } + + template + PacketType packet(Index row, Index col) const + { + enum { + PacketSize = unpacket_traits::size, + OffsetRow = ReverseRow && IsColMajor ? PacketSize : 1, + OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1 + }; + typedef internal::reverse_packet_cond reverse_packet; + return reverse_packet::run(m_argImpl.template packet( + ReverseRow ? m_rows.value() - row - OffsetRow : row, + ReverseCol ? m_cols.value() - col - OffsetCol : col)); + } + + template + PacketType packet(Index index) const + { + enum { PacketSize = unpacket_traits::size }; + return preverse(m_argImpl.template packet(m_rows.value() * m_cols.value() - index - PacketSize)); + } + + template + void writePacket(Index row, Index col, const PacketType& x) + { + // FIXME we could factorize some code with packet(i,j) + enum { + PacketSize = unpacket_traits::size, + OffsetRow = ReverseRow && IsColMajor ? PacketSize : 1, + OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1 + }; + typedef internal::reverse_packet_cond reverse_packet; + m_argImpl.template writePacket( + ReverseRow ? m_rows.value() - row - OffsetRow : row, + ReverseCol ? m_cols.value() - col - OffsetCol : col, + reverse_packet::run(x)); + } + + template + void writePacket(Index index, const PacketType& x) + { + enum { PacketSize = unpacket_traits::size }; + m_argImpl.template writePacket + (m_rows.value() * m_cols.value() - index - PacketSize, preverse(x)); + } + +protected: + evaluator m_argImpl; + + // If we do not reverse rows, then we do not need to know the number of rows; same for columns + // Nonetheless, in this case it is important to set to 1 such that the coeff(index) method works fine for vectors. + const variable_if_dynamic m_rows; + const variable_if_dynamic m_cols; +}; + + +// -------------------- Diagonal -------------------- + +template +struct evaluator > + : evaluator_base > +{ + typedef Diagonal XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + + Flags = (unsigned int)evaluator::Flags & (HereditaryBits | LinearAccessBit | DirectAccessBit) & ~RowMajorBit, + + Alignment = 0 + }; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& diagonal) + : m_argImpl(diagonal.nestedExpression()), + m_index(diagonal.index()) + { } + + typedef typename XprType::Scalar Scalar; + // FIXME having to check whether ArgType is sparse here i not very nice. + typedef typename internal::conditional::value, + typename XprType::CoeffReturnType,Scalar>::type CoeffReturnType; + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index) const + { + return m_argImpl.coeff(row + rowOffset(), row + colOffset()); + } + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const + { + return m_argImpl.coeff(index + rowOffset(), index + colOffset()); + } + + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index row, Index) + { + return m_argImpl.coeffRef(row + rowOffset(), row + colOffset()); + } + + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index index) + { + return m_argImpl.coeffRef(index + rowOffset(), index + colOffset()); + } + +protected: + evaluator m_argImpl; + const internal::variable_if_dynamicindex m_index; + +private: + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rowOffset() const { return m_index.value() > 0 ? 0 : -m_index.value(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index colOffset() const { return m_index.value() > 0 ? m_index.value() : 0; } +}; + + +//---------------------------------------------------------------------- +// deprecated code +//---------------------------------------------------------------------- + +// -------------------- EvalToTemp -------------------- + +// expression class for evaluating nested expression to a temporary + +template class EvalToTemp; + +template +struct traits > + : public traits +{ }; + +template +class EvalToTemp + : public dense_xpr_base >::type +{ + public: + + typedef typename dense_xpr_base::type Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(EvalToTemp) + + explicit EvalToTemp(const ArgType& arg) + : m_arg(arg) + { } + + const ArgType& arg() const + { + return m_arg; + } + + Index rows() const + { + return m_arg.rows(); + } + + Index cols() const + { + return m_arg.cols(); + } + + private: + const ArgType& m_arg; +}; + +template +struct evaluator > + : public evaluator +{ + typedef EvalToTemp XprType; + typedef typename ArgType::PlainObject PlainObject; + typedef evaluator Base; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) + : m_result(xpr.arg()) + { + ::new (static_cast(this)) Base(m_result); + } + + // This constructor is used when nesting an EvalTo evaluator in another evaluator + EIGEN_DEVICE_FUNC evaluator(const ArgType& arg) + : m_result(arg) + { + ::new (static_cast(this)) Base(m_result); + } + +protected: + PlainObject m_result; +}; + +} // namespace internal + +} // end namespace Eigen + +#endif // EIGEN_COREEVALUATORS_H diff --git a/nuparu/include/Eigen/src/Core/CoreIterators.h b/nuparu/include/Eigen/src/Core/CoreIterators.h index 6da4683d..4eb42b93 100644 --- a/nuparu/include/Eigen/src/Core/CoreIterators.h +++ b/nuparu/include/Eigen/src/Core/CoreIterators.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -15,47 +15,113 @@ namespace Eigen { /* This file contains the respective InnerIterator definition of the expressions defined in Eigen/Core */ -/** \ingroup SparseCore_Module - * \class InnerIterator - * \brief An InnerIterator allows to loop over the element of a sparse (or dense) matrix or expression - * - * todo +namespace internal { + +template +class inner_iterator_selector; + +} + +/** \class InnerIterator + * \brief An InnerIterator allows to loop over the element of any matrix expression. + * + * \warning To be used with care because an evaluator is constructed every time an InnerIterator iterator is constructed. + * + * TODO: add a usage example */ +template +class InnerIterator +{ +protected: + typedef internal::inner_iterator_selector::Kind> IteratorType; + typedef internal::evaluator EvaluatorType; + typedef typename internal::traits::Scalar Scalar; +public: + /** Construct an iterator over the \a outerId -th row or column of \a xpr */ + InnerIterator(const XprType &xpr, const Index &outerId) + : m_eval(xpr), m_iter(m_eval, outerId, xpr.innerSize()) + {} + + /// \returns the value of the current coefficient. + EIGEN_STRONG_INLINE Scalar value() const { return m_iter.value(); } + /** Increment the iterator \c *this to the next non-zero coefficient. + * Explicit zeros are not skipped over. To skip explicit zeros, see class SparseView + */ + EIGEN_STRONG_INLINE InnerIterator& operator++() { m_iter.operator++(); return *this; } + /// \returns the column or row index of the current coefficient. + EIGEN_STRONG_INLINE Index index() const { return m_iter.index(); } + /// \returns the row index of the current coefficient. + EIGEN_STRONG_INLINE Index row() const { return m_iter.row(); } + /// \returns the column index of the current coefficient. + EIGEN_STRONG_INLINE Index col() const { return m_iter.col(); } + /// \returns \c true if the iterator \c *this still references a valid coefficient. + EIGEN_STRONG_INLINE operator bool() const { return m_iter; } + +protected: + EvaluatorType m_eval; + IteratorType m_iter; +private: + // If you get here, then you're not using the right InnerIterator type, e.g.: + // SparseMatrix A; + // SparseMatrix::InnerIterator it(A,0); + template InnerIterator(const EigenBase&,Index outer); +}; + +namespace internal { -// generic version for dense matrix and expressions -template class DenseBase::InnerIterator +// Generic inner iterator implementation for dense objects +template +class inner_iterator_selector { - protected: - typedef typename Derived::Scalar Scalar; - typedef typename Derived::Index Index; - - enum { IsRowMajor = (Derived::Flags&RowMajorBit)==RowMajorBit }; - public: - EIGEN_STRONG_INLINE InnerIterator(const Derived& expr, Index outer) - : m_expression(expr), m_inner(0), m_outer(outer), m_end(expr.innerSize()) - {} - - EIGEN_STRONG_INLINE Scalar value() const - { - return (IsRowMajor) ? m_expression.coeff(m_outer, m_inner) - : m_expression.coeff(m_inner, m_outer); - } - - EIGEN_STRONG_INLINE InnerIterator& operator++() { m_inner++; return *this; } - - EIGEN_STRONG_INLINE Index index() const { return m_inner; } - inline Index row() const { return IsRowMajor ? m_outer : index(); } - inline Index col() const { return IsRowMajor ? index() : m_outer; } - - EIGEN_STRONG_INLINE operator bool() const { return m_inner < m_end && m_inner>=0; } - - protected: - const Derived& m_expression; - Index m_inner; - const Index m_outer; - const Index m_end; +protected: + typedef evaluator EvaluatorType; + typedef typename traits::Scalar Scalar; + enum { IsRowMajor = (XprType::Flags&RowMajorBit)==RowMajorBit }; + +public: + EIGEN_STRONG_INLINE inner_iterator_selector(const EvaluatorType &eval, const Index &outerId, const Index &innerSize) + : m_eval(eval), m_inner(0), m_outer(outerId), m_end(innerSize) + {} + + EIGEN_STRONG_INLINE Scalar value() const + { + return (IsRowMajor) ? m_eval.coeff(m_outer, m_inner) + : m_eval.coeff(m_inner, m_outer); + } + + EIGEN_STRONG_INLINE inner_iterator_selector& operator++() { m_inner++; return *this; } + + EIGEN_STRONG_INLINE Index index() const { return m_inner; } + inline Index row() const { return IsRowMajor ? m_outer : index(); } + inline Index col() const { return IsRowMajor ? index() : m_outer; } + + EIGEN_STRONG_INLINE operator bool() const { return m_inner < m_end && m_inner>=0; } + +protected: + const EvaluatorType& m_eval; + Index m_inner; + const Index m_outer; + const Index m_end; }; +// For iterator-based evaluator, inner-iterator is already implemented as +// evaluator<>::InnerIterator +template +class inner_iterator_selector + : public evaluator::InnerIterator +{ +protected: + typedef typename evaluator::InnerIterator Base; + typedef evaluator EvaluatorType; + +public: + EIGEN_STRONG_INLINE inner_iterator_selector(const EvaluatorType &eval, const Index &outerId, const Index &/*innerSize*/) + : Base(eval, outerId) + {} +}; + +} // end namespace internal + } // end namespace Eigen #endif // EIGEN_COREITERATORS_H diff --git a/nuparu/include/Eigen/src/Core/CwiseBinaryOp.h b/nuparu/include/Eigen/src/Core/CwiseBinaryOp.h index 586f77aa..e42c3031 100644 --- a/nuparu/include/Eigen/src/Core/CwiseBinaryOp.h +++ b/nuparu/include/Eigen/src/Core/CwiseBinaryOp.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla @@ -56,72 +56,51 @@ struct traits > typename Rhs::Scalar ) >::type Scalar; - typedef typename promote_storage_type::StorageKind, - typename traits::StorageKind>::ret StorageKind; - typedef typename promote_index_type::Index, - typename traits::Index>::type Index; + typedef typename cwise_promote_storage_type::StorageKind, + typename traits::StorageKind, + BinaryOp>::ret StorageKind; + typedef typename promote_index_type::StorageIndex, + typename traits::StorageIndex>::type StorageIndex; typedef typename Lhs::Nested LhsNested; typedef typename Rhs::Nested RhsNested; typedef typename remove_reference::type _LhsNested; typedef typename remove_reference::type _RhsNested; enum { - LhsCoeffReadCost = _LhsNested::CoeffReadCost, - RhsCoeffReadCost = _RhsNested::CoeffReadCost, - LhsFlags = _LhsNested::Flags, - RhsFlags = _RhsNested::Flags, - SameType = is_same::value, - StorageOrdersAgree = (int(Lhs::Flags)&RowMajorBit)==(int(Rhs::Flags)&RowMajorBit), - Flags0 = (int(LhsFlags) | int(RhsFlags)) & ( - HereditaryBits - | (int(LhsFlags) & int(RhsFlags) & - ( AlignedBit - | (StorageOrdersAgree ? LinearAccessBit : 0) - | (functor_traits::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0) - ) - ) - ), - Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit), - CoeffReadCost = LhsCoeffReadCost + RhsCoeffReadCost + functor_traits::Cost + Flags = _LhsNested::Flags & RowMajorBit }; }; } // end namespace internal -// we require Lhs and Rhs to have the same scalar type. Currently there is no example of a binary functor -// that would take two operands of different types. If there were such an example, then this check should be -// moved to the BinaryOp functors, on a per-case basis. This would however require a change in the BinaryOp functors, as -// currently they take only one typename Scalar template parameter. -// It is tempting to always allow mixing different types but remember that this is often impossible in the vectorized paths. -// So allowing mixing different types gives very unexpected errors when enabling vectorization, when the user tries to -// add together a float matrix and a double matrix. -#define EIGEN_CHECK_BINARY_COMPATIBILIY(BINOP,LHS,RHS) \ - EIGEN_STATIC_ASSERT((internal::functor_is_product_like::ret \ - ? int(internal::scalar_product_traits::Defined) \ - : int(internal::is_same::value)), \ - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - template class CwiseBinaryOpImpl; -template -class CwiseBinaryOp : internal::no_assignment_operator, +template +class CwiseBinaryOp : public CwiseBinaryOpImpl< - BinaryOp, Lhs, Rhs, - typename internal::promote_storage_type::StorageKind, - typename internal::traits::StorageKind>::ret> + BinaryOp, LhsType, RhsType, + typename internal::cwise_promote_storage_type::StorageKind, + typename internal::traits::StorageKind, + BinaryOp>::ret>, + internal::no_assignment_operator { public: + + typedef typename internal::remove_all::type Lhs; + typedef typename internal::remove_all::type Rhs; typedef typename CwiseBinaryOpImpl< - BinaryOp, Lhs, Rhs, - typename internal::promote_storage_type::StorageKind, - typename internal::traits::StorageKind>::ret>::Base Base; + BinaryOp, LhsType, RhsType, + typename internal::cwise_promote_storage_type::StorageKind, + typename internal::traits::StorageKind, + BinaryOp>::ret>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseBinaryOp) - typedef typename internal::nested::type LhsNested; - typedef typename internal::nested::type RhsNested; + typedef typename internal::ref_selector::type LhsNested; + typedef typename internal::ref_selector::type RhsNested; typedef typename internal::remove_reference::type _LhsNested; typedef typename internal::remove_reference::type _RhsNested; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CwiseBinaryOp(const Lhs& aLhs, const Rhs& aRhs, const BinaryOp& func = BinaryOp()) : m_lhs(aLhs), m_rhs(aRhs), m_functor(func) { @@ -131,6 +110,7 @@ class CwiseBinaryOp : internal::no_assignment_operator, eigen_assert(aLhs.rows() == aRhs.rows() && aLhs.cols() == aRhs.cols()); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { // return the fixed size type if available to enable compile time optimizations if (internal::traits::type>::RowsAtCompileTime==Dynamic) @@ -138,6 +118,7 @@ class CwiseBinaryOp : internal::no_assignment_operator, else return m_lhs.rows(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { // return the fixed size type if available to enable compile time optimizations if (internal::traits::type>::ColsAtCompileTime==Dynamic) @@ -147,10 +128,13 @@ class CwiseBinaryOp : internal::no_assignment_operator, } /** \returns the left hand side nested expression */ + EIGEN_DEVICE_FUNC const _LhsNested& lhs() const { return m_lhs; } /** \returns the right hand side nested expression */ + EIGEN_DEVICE_FUNC const _RhsNested& rhs() const { return m_rhs; } /** \returns the functor representing the binary operation */ + EIGEN_DEVICE_FUNC const BinaryOp& functor() const { return m_functor; } protected: @@ -159,41 +143,13 @@ class CwiseBinaryOp : internal::no_assignment_operator, const BinaryOp m_functor; }; -template -class CwiseBinaryOpImpl - : public internal::dense_xpr_base >::type +// Generic API dispatcher +template +class CwiseBinaryOpImpl + : public internal::generic_xpr_base >::type { - typedef CwiseBinaryOp Derived; - public: - - typedef typename internal::dense_xpr_base >::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE( Derived ) - - EIGEN_STRONG_INLINE const Scalar coeff(Index rowId, Index colId) const - { - return derived().functor()(derived().lhs().coeff(rowId, colId), - derived().rhs().coeff(rowId, colId)); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const - { - return derived().functor().packetOp(derived().lhs().template packet(rowId, colId), - derived().rhs().template packet(rowId, colId)); - } - - EIGEN_STRONG_INLINE const Scalar coeff(Index index) const - { - return derived().functor()(derived().lhs().coeff(index), - derived().rhs().coeff(index)); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index index) const - { - return derived().functor().packetOp(derived().lhs().template packet(index), - derived().rhs().template packet(index)); - } +public: + typedef typename internal::generic_xpr_base >::type Base; }; /** replaces \c *this by \c *this - \a other. @@ -205,8 +161,7 @@ template EIGEN_STRONG_INLINE Derived & MatrixBase::operator-=(const MatrixBase &other) { - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); + call_assignment(derived(), other.derived(), internal::sub_assign_op()); return derived(); } @@ -219,11 +174,11 @@ template EIGEN_STRONG_INLINE Derived & MatrixBase::operator+=(const MatrixBase& other) { - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); + call_assignment(derived(), other.derived(), internal::add_assign_op()); return derived(); } } // end namespace Eigen #endif // EIGEN_CWISE_BINARY_OP_H + diff --git a/nuparu/include/Eigen/src/Core/CwiseNullaryOp.h b/nuparu/include/Eigen/src/Core/CwiseNullaryOp.h index a93bab2d..2bc6933d 100644 --- a/nuparu/include/Eigen/src/Core/CwiseNullaryOp.h +++ b/nuparu/include/Eigen/src/Core/CwiseNullaryOp.h @@ -35,37 +35,35 @@ template struct traits > : traits { enum { - Flags = (traits::Flags - & ( HereditaryBits - | (functor_has_linear_access::ret ? LinearAccessBit : 0) - | (functor_traits::PacketAccess ? PacketAccessBit : 0))) - | (functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit), - CoeffReadCost = functor_traits::Cost + Flags = traits::Flags & RowMajorBit }; }; } template -class CwiseNullaryOp : internal::no_assignment_operator, - public internal::dense_xpr_base< CwiseNullaryOp >::type +class CwiseNullaryOp : public internal::dense_xpr_base< CwiseNullaryOp >::type, internal::no_assignment_operator { public: typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(CwiseNullaryOp) - CwiseNullaryOp(Index nbRows, Index nbCols, const NullaryOp& func = NullaryOp()) - : m_rows(nbRows), m_cols(nbCols), m_functor(func) + EIGEN_DEVICE_FUNC + CwiseNullaryOp(Index rows, Index cols, const NullaryOp& func = NullaryOp()) + : m_rows(rows), m_cols(cols), m_functor(func) { - eigen_assert(nbRows >= 0 - && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == nbRows) - && nbCols >= 0 - && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == nbCols)); + eigen_assert(rows >= 0 + && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == rows) + && cols >= 0 + && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols)); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { return m_rows.value(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { return m_cols.value(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index rowId, Index colId) const { return m_functor(rowId, colId); @@ -77,6 +75,7 @@ class CwiseNullaryOp : internal::no_assignment_operator, return m_functor.packetOp(rowId, colId); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index index) const { return m_functor(index); @@ -89,6 +88,7 @@ class CwiseNullaryOp : internal::no_assignment_operator, } /** \returns the functor representing the nullary operation */ + EIGEN_DEVICE_FUNC const NullaryOp& functor() const { return m_functor; } protected: @@ -113,10 +113,10 @@ class CwiseNullaryOp : internal::no_assignment_operator, */ template template -EIGEN_STRONG_INLINE const CwiseNullaryOp +EIGEN_STRONG_INLINE const CwiseNullaryOp::PlainObject> DenseBase::NullaryExpr(Index rows, Index cols, const CustomNullaryOp& func) { - return CwiseNullaryOp(rows, cols, func); + return CwiseNullaryOp(rows, cols, func); } /** \returns an expression of a matrix defined by a custom functor \a func @@ -132,16 +132,19 @@ DenseBase::NullaryExpr(Index rows, Index cols, const CustomNullaryOp& f * * The template parameter \a CustomNullaryOp is the type of the functor. * + * Here is an example with C++11 random generators: \include random_cpp11.cpp + * Output: \verbinclude random_cpp11.out + * * \sa class CwiseNullaryOp */ template template -EIGEN_STRONG_INLINE const CwiseNullaryOp +EIGEN_STRONG_INLINE const CwiseNullaryOp::PlainObject> DenseBase::NullaryExpr(Index size, const CustomNullaryOp& func) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - if(RowsAtCompileTime == 1) return CwiseNullaryOp(1, size, func); - else return CwiseNullaryOp(size, 1, func); + if(RowsAtCompileTime == 1) return CwiseNullaryOp(1, size, func); + else return CwiseNullaryOp(size, 1, func); } /** \returns an expression of a matrix defined by a custom functor \a func @@ -155,19 +158,19 @@ DenseBase::NullaryExpr(Index size, const CustomNullaryOp& func) */ template template -EIGEN_STRONG_INLINE const CwiseNullaryOp +EIGEN_STRONG_INLINE const CwiseNullaryOp::PlainObject> DenseBase::NullaryExpr(const CustomNullaryOp& func) { - return CwiseNullaryOp(RowsAtCompileTime, ColsAtCompileTime, func); + return CwiseNullaryOp(RowsAtCompileTime, ColsAtCompileTime, func); } /** \returns an expression of a constant matrix of value \a value * - * The parameters \a nbRows and \a nbCols are the number of rows and of columns of + * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this DenseBase type. * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, - * it is redundant to pass \a nbRows and \a nbCols as arguments, so Zero() should be used + * it is redundant to pass \a rows and \a cols as arguments, so Zero() should be used * instead. * * The template parameter \a CustomNullaryOp is the type of the functor. @@ -176,9 +179,9 @@ DenseBase::NullaryExpr(const CustomNullaryOp& func) */ template EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType -DenseBase::Constant(Index nbRows, Index nbCols, const Scalar& value) +DenseBase::Constant(Index rows, Index cols, const Scalar& value) { - return DenseBase::NullaryExpr(nbRows, nbCols, internal::scalar_constant_op(value)); + return DenseBase::NullaryExpr(rows, cols, internal::scalar_constant_op(value)); } /** \returns an expression of a constant matrix of value \a value @@ -242,7 +245,7 @@ EIGEN_STRONG_INLINE const typename DenseBase::SequentialLinSpacedReturn DenseBase::LinSpaced(Sequential_t, Index size, const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); + return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); } /** @@ -255,7 +258,7 @@ DenseBase::LinSpaced(Sequential_t, const Scalar& low, const Scalar& hig { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) - return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); + return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); } /** @@ -276,7 +279,7 @@ EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedRetu DenseBase::LinSpaced(Index size, const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); + return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); } /** @@ -289,7 +292,7 @@ DenseBase::LinSpaced(const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) - return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); + return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); } /** \returns true if all coefficients in this matrix are approximately equal to \a val, to within precision \a prec */ @@ -297,9 +300,10 @@ template bool DenseBase::isApproxToConstant (const Scalar& val, const RealScalar& prec) const { + typename internal::nested_eval::type self(derived()); for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < rows(); ++i) - if(!internal::isApprox(this->coeff(i, j), val, prec)) + if(!internal::isApprox(self.coeff(i, j), val, prec)) return false; return true; } @@ -353,8 +357,8 @@ PlainObjectBase::setConstant(Index size, const Scalar& val) /** Resizes to the given size, and sets all coefficients in this expression to the given \a value. * - * \param nbRows the new number of rows - * \param nbCols the new number of columns + * \param rows the new number of rows + * \param cols the new number of columns * \param val the value to which all coefficients are set * * Example: \include Matrix_setConstant_int_int.cpp @@ -364,9 +368,9 @@ PlainObjectBase::setConstant(Index size, const Scalar& val) */ template EIGEN_STRONG_INLINE Derived& -PlainObjectBase::setConstant(Index nbRows, Index nbCols, const Scalar& val) +PlainObjectBase::setConstant(Index rows, Index cols, const Scalar& val) { - resize(nbRows, nbCols); + resize(rows, cols); return setConstant(val); } @@ -387,7 +391,7 @@ template EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(Index newSize, const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return derived() = Derived::NullaryExpr(newSize, internal::linspaced_op(low,high,newSize)); + return derived() = Derived::NullaryExpr(newSize, internal::linspaced_op(low,high,newSize)); } /** @@ -425,9 +429,9 @@ EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(const Scalar& low, */ template EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType -DenseBase::Zero(Index nbRows, Index nbCols) +DenseBase::Zero(Index rows, Index cols) { - return Constant(nbRows, nbCols, Scalar(0)); + return Constant(rows, cols, Scalar(0)); } /** \returns an expression of a zero vector. @@ -481,9 +485,10 @@ DenseBase::Zero() template bool DenseBase::isZero(const RealScalar& prec) const { + typename internal::nested_eval::type self(derived()); for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < rows(); ++i) - if(!internal::isMuchSmallerThan(this->coeff(i, j), static_cast(1), prec)) + if(!internal::isMuchSmallerThan(self.coeff(i, j), static_cast(1), prec)) return false; return true; } @@ -520,8 +525,8 @@ PlainObjectBase::setZero(Index newSize) /** Resizes to the given size, and sets all coefficients in this expression to zero. * - * \param nbRows the new number of rows - * \param nbCols the new number of columns + * \param rows the new number of rows + * \param cols the new number of columns * * Example: \include Matrix_setZero_int_int.cpp * Output: \verbinclude Matrix_setZero_int_int.out @@ -530,9 +535,9 @@ PlainObjectBase::setZero(Index newSize) */ template EIGEN_STRONG_INLINE Derived& -PlainObjectBase::setZero(Index nbRows, Index nbCols) +PlainObjectBase::setZero(Index rows, Index cols) { - resize(nbRows, nbCols); + resize(rows, cols); return setConstant(Scalar(0)); } @@ -540,7 +545,7 @@ PlainObjectBase::setZero(Index nbRows, Index nbCols) /** \returns an expression of a matrix where all coefficients equal one. * - * The parameters \a nbRows and \a nbCols are the number of rows and of columns of + * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this MatrixBase type. * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, @@ -554,9 +559,9 @@ PlainObjectBase::setZero(Index nbRows, Index nbCols) */ template EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType -DenseBase::Ones(Index nbRows, Index nbCols) +DenseBase::Ones(Index rows, Index cols) { - return Constant(nbRows, nbCols, Scalar(1)); + return Constant(rows, cols, Scalar(1)); } /** \returns an expression of a vector where all coefficients equal one. @@ -646,8 +651,8 @@ PlainObjectBase::setOnes(Index newSize) /** Resizes to the given size, and sets all coefficients in this expression to one. * - * \param nbRows the new number of rows - * \param nbCols the new number of columns + * \param rows the new number of rows + * \param cols the new number of columns * * Example: \include Matrix_setOnes_int_int.cpp * Output: \verbinclude Matrix_setOnes_int_int.out @@ -656,9 +661,9 @@ PlainObjectBase::setOnes(Index newSize) */ template EIGEN_STRONG_INLINE Derived& -PlainObjectBase::setOnes(Index nbRows, Index nbCols) +PlainObjectBase::setOnes(Index rows, Index cols) { - resize(nbRows, nbCols); + resize(rows, cols); return setConstant(Scalar(1)); } @@ -666,7 +671,7 @@ PlainObjectBase::setOnes(Index nbRows, Index nbCols) /** \returns an expression of the identity matrix (not necessarily square). * - * The parameters \a nbRows and \a nbCols are the number of rows and of columns of + * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this MatrixBase type. * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, @@ -680,9 +685,9 @@ PlainObjectBase::setOnes(Index nbRows, Index nbCols) */ template EIGEN_STRONG_INLINE const typename MatrixBase::IdentityReturnType -MatrixBase::Identity(Index nbRows, Index nbCols) +MatrixBase::Identity(Index rows, Index cols) { - return DenseBase::NullaryExpr(nbRows, nbCols, internal::scalar_identity_op()); + return DenseBase::NullaryExpr(rows, cols, internal::scalar_identity_op()); } /** \returns an expression of the identity matrix (not necessarily square). @@ -716,18 +721,19 @@ template bool MatrixBase::isIdentity (const RealScalar& prec) const { + typename internal::nested_eval::type self(derived()); for(Index j = 0; j < cols(); ++j) { for(Index i = 0; i < rows(); ++i) { if(i == j) { - if(!internal::isApprox(this->coeff(i, j), static_cast(1), prec)) + if(!internal::isApprox(self.coeff(i, j), static_cast(1), prec)) return false; } else { - if(!internal::isMuchSmallerThan(this->coeff(i, j), static_cast(1), prec)) + if(!internal::isMuchSmallerThan(self.coeff(i, j), static_cast(1), prec)) return false; } } @@ -740,6 +746,7 @@ namespace internal { template=16)> struct setIdentity_impl { + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Derived& run(Derived& m) { return m = Derived::Identity(m.rows(), m.cols()); @@ -749,7 +756,7 @@ struct setIdentity_impl template struct setIdentity_impl { - typedef typename Derived::Index Index; + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Derived& run(Derived& m) { m.setZero(); @@ -776,8 +783,8 @@ EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity() /** \brief Resizes to the given size, and writes the identity expression (not necessarily square) into *this. * - * \param nbRows the new number of rows - * \param nbCols the new number of columns + * \param rows the new number of rows + * \param cols the new number of columns * * Example: \include Matrix_setIdentity_int_int.cpp * Output: \verbinclude Matrix_setIdentity_int_int.out @@ -785,9 +792,9 @@ EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity() * \sa MatrixBase::setIdentity(), class CwiseNullaryOp, MatrixBase::Identity() */ template -EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity(Index nbRows, Index nbCols) +EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity(Index rows, Index cols) { - derived().resize(nbRows, nbCols); + derived().resize(rows, cols); return setIdentity(); } diff --git a/nuparu/include/Eigen/src/Core/CwiseUnaryOp.h b/nuparu/include/Eigen/src/Core/CwiseUnaryOp.h index f2de749f..da1d1992 100644 --- a/nuparu/include/Eigen/src/Core/CwiseUnaryOp.h +++ b/nuparu/include/Eigen/src/Core/CwiseUnaryOp.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla @@ -44,10 +44,7 @@ struct traits > typedef typename XprType::Nested XprTypeNested; typedef typename remove_reference::type _XprTypeNested; enum { - Flags = _XprTypeNested::Flags & ( - HereditaryBits | LinearAccessBit | AlignedBit - | (functor_traits::PacketAccess ? PacketAccessBit : 0)), - CoeffReadCost = _XprTypeNested::CoeffReadCost + functor_traits::Cost + Flags = _XprTypeNested::Flags & RowMajorBit }; }; } @@ -56,28 +53,34 @@ template class CwiseUnaryOpImpl; template -class CwiseUnaryOp : internal::no_assignment_operator, - public CwiseUnaryOpImpl::StorageKind> +class CwiseUnaryOp : public CwiseUnaryOpImpl::StorageKind>, internal::no_assignment_operator { public: typedef typename CwiseUnaryOpImpl::StorageKind>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryOp) + typedef typename internal::remove_all::type NestedExpression; - inline CwiseUnaryOp(const XprType& xpr, const UnaryOp& func = UnaryOp()) + EIGEN_DEVICE_FUNC + explicit inline CwiseUnaryOp(const XprType& xpr, const UnaryOp& func = UnaryOp()) : m_xpr(xpr), m_functor(func) {} + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { return m_xpr.rows(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { return m_xpr.cols(); } /** \returns the functor representing the unary operation */ + EIGEN_DEVICE_FUNC const UnaryOp& functor() const { return m_functor; } /** \returns the nested expression */ + EIGEN_DEVICE_FUNC const typename internal::remove_all::type& nestedExpression() const { return m_xpr; } /** \returns the nested expression */ + EIGEN_DEVICE_FUNC typename internal::remove_all::type& nestedExpression() { return m_xpr.const_cast_derived(); } @@ -86,39 +89,13 @@ class CwiseUnaryOp : internal::no_assignment_operator, const UnaryOp m_functor; }; -// This is the generic implementation for dense storage. -// It can be used for any expression types implementing the dense concept. -template -class CwiseUnaryOpImpl - : public internal::dense_xpr_base >::type +// Generic API dispatcher +template +class CwiseUnaryOpImpl + : public internal::generic_xpr_base >::type { - public: - - typedef CwiseUnaryOp Derived; - typedef typename internal::dense_xpr_base >::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE(Derived) - - EIGEN_STRONG_INLINE const Scalar coeff(Index rowId, Index colId) const - { - return derived().functor()(derived().nestedExpression().coeff(rowId, colId)); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const - { - return derived().functor().packetOp(derived().nestedExpression().template packet(rowId, colId)); - } - - EIGEN_STRONG_INLINE const Scalar coeff(Index index) const - { - return derived().functor()(derived().nestedExpression().coeff(index)); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index index) const - { - return derived().functor().packetOp(derived().nestedExpression().template packet(index)); - } +public: + typedef typename internal::generic_xpr_base >::type Base; }; } // end namespace Eigen diff --git a/nuparu/include/Eigen/src/Core/CwiseUnaryView.h b/nuparu/include/Eigen/src/Core/CwiseUnaryView.h index b2638d32..72244751 100644 --- a/nuparu/include/Eigen/src/Core/CwiseUnaryView.h +++ b/nuparu/include/Eigen/src/Core/CwiseUnaryView.h @@ -37,8 +37,8 @@ struct traits > typedef typename MatrixType::Nested MatrixTypeNested; typedef typename remove_all::type _MatrixTypeNested; enum { - Flags = (traits<_MatrixTypeNested>::Flags & (HereditaryBits | LvalueBit | LinearAccessBit | DirectAccessBit)), - CoeffReadCost = traits<_MatrixTypeNested>::CoeffReadCost + functor_traits::Cost, + FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, + Flags = traits<_MatrixTypeNested>::Flags & (RowMajorBit | FlagsLvalueBit | DirectAccessBit), // FIXME DirectAccessBit should not be handled by expressions MatrixTypeInnerStride = inner_stride_at_compile_time::ret, // need to cast the sizeof's from size_t to int explicitly, otherwise: // "error: no integral type can represent all of the enumerator values @@ -62,8 +62,9 @@ class CwiseUnaryView : public CwiseUnaryViewImpl::StorageKind>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryView) + typedef typename internal::remove_all::type NestedExpression; - inline CwiseUnaryView(const MatrixType& mat, const ViewOp& func = ViewOp()) + explicit inline CwiseUnaryView(MatrixType& mat, const ViewOp& func = ViewOp()) : m_matrix(mat), m_functor(func) {} EIGEN_INHERIT_ASSIGNMENT_OPERATORS(CwiseUnaryView) @@ -83,11 +84,19 @@ class CwiseUnaryView : public CwiseUnaryViewImpl::type m_matrix; + typename internal::ref_selector::type m_matrix; ViewOp m_functor; }; +// Generic API dispatcher +template +class CwiseUnaryViewImpl + : public internal::generic_xpr_base >::type +{ +public: + typedef typename internal::generic_xpr_base >::type Base; +}; + template class CwiseUnaryViewImpl : public internal::dense_xpr_base< CwiseUnaryView >::type @@ -100,38 +109,18 @@ class CwiseUnaryViewImpl EIGEN_DENSE_PUBLIC_INTERFACE(Derived) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(CwiseUnaryViewImpl) - inline Scalar* data() { return &coeffRef(0); } - inline const Scalar* data() const { return &coeff(0); } + EIGEN_DEVICE_FUNC inline Scalar* data() { return &(this->coeffRef(0)); } + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return &(this->coeff(0)); } - inline Index innerStride() const + EIGEN_DEVICE_FUNC inline Index innerStride() const { return derived().nestedExpression().innerStride() * sizeof(typename internal::traits::Scalar) / sizeof(Scalar); } - inline Index outerStride() const + EIGEN_DEVICE_FUNC inline Index outerStride() const { return derived().nestedExpression().outerStride() * sizeof(typename internal::traits::Scalar) / sizeof(Scalar); } - - EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const - { - return derived().functor()(derived().nestedExpression().coeff(row, col)); - } - - EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const - { - return derived().functor()(derived().nestedExpression().coeff(index)); - } - - EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) - { - return derived().functor()(const_cast_derived().nestedExpression().coeffRef(row, col)); - } - - EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) - { - return derived().functor()(const_cast_derived().nestedExpression().coeffRef(index)); - } }; } // end namespace Eigen diff --git a/nuparu/include/Eigen/src/Core/DenseBase.h b/nuparu/include/Eigen/src/Core/DenseBase.h index c5800f6c..e181dafa 100644 --- a/nuparu/include/Eigen/src/Core/DenseBase.h +++ b/nuparu/include/Eigen/src/Core/DenseBase.h @@ -40,31 +40,43 @@ static inline void check_DenseIndex_is_signed() { */ template class DenseBase #ifndef EIGEN_PARSED_BY_DOXYGEN - : public internal::special_scalar_op_base::Scalar, - typename NumTraits::Scalar>::Real> + : public internal::special_scalar_op_base::Scalar, + typename NumTraits::Scalar>::Real, + DenseCoeffsBase > #else : public DenseCoeffsBase #endif // not EIGEN_PARSED_BY_DOXYGEN { public: - using internal::special_scalar_op_base::Scalar, - typename NumTraits::Scalar>::Real>::operator*; - class InnerIterator; + /** Inner iterator type to iterate over the coefficients of a row or column. + * \sa class InnerIterator + */ + typedef Eigen::InnerIterator InnerIterator; typedef typename internal::traits::StorageKind StorageKind; - /** \brief The type of indices - * \details To change this, \c \#define the preprocessor symbol \c EIGEN_DEFAULT_DENSE_INDEX_TYPE. - * \sa \ref TopicPreprocessorDirectives. - */ - typedef typename internal::traits::Index Index; + /** + * \brief The type used to store indices + * \details This typedef is relevant for types that store multiple indices such as + * PermutationMatrix or Transpositions, otherwise it defaults to Eigen::Index + * \sa \ref TopicPreprocessorDirectives, Eigen::Index, SparseMatrixBase. + */ + typedef typename internal::traits::StorageIndex StorageIndex; + /** The numeric type of the expression' coefficients, e.g. float, double, int or std::complex, etc. */ typedef typename internal::traits::Scalar Scalar; - typedef typename internal::packet_traits::type PacketScalar; + + /** The numeric type of the expression' coefficients, e.g. float, double, int or std::complex, etc. + * + * It is an alias for the Scalar type */ + typedef Scalar value_type; + typedef typename NumTraits::Real RealScalar; + typedef internal::special_scalar_op_base > Base; - typedef DenseCoeffsBase Base; + using Base::operator*; + using Base::operator/; using Base::derived; using Base::const_cast_derived; using Base::rows; @@ -74,16 +86,6 @@ template class DenseBase using Base::colIndexByOuterInner; using Base::coeff; using Base::coeffByOuterInner; - using Base::packet; - using Base::packetByOuterInner; - using Base::writePacket; - using Base::writePacketByOuterInner; - using Base::coeffRef; - using Base::coeffRefByOuterInner; - using Base::copyCoeff; - using Base::copyCoeffByOuterInner; - using Base::copyPacket; - using Base::copyPacketByOuterInner; using Base::operator(); using Base::operator[]; using Base::x; @@ -169,30 +171,54 @@ template class DenseBase InnerSizeAtCompileTime = int(IsVectorAtCompileTime) ? int(SizeAtCompileTime) : int(IsRowMajor) ? int(ColsAtCompileTime) : int(RowsAtCompileTime), - CoeffReadCost = internal::traits::CoeffReadCost, - /**< This is a rough measure of how expensive it is to read one coefficient from - * this expression. - */ - InnerStrideAtCompileTime = internal::inner_stride_at_compile_time::ret, OuterStrideAtCompileTime = internal::outer_stride_at_compile_time::ret }; + + typedef typename internal::find_best_packet::type PacketScalar; - enum { ThisConstantIsPrivateInPlainObjectBase }; + enum { IsPlainObjectBase = 0 }; + + /** The plain matrix type corresponding to this expression. + * \sa PlainObject */ + typedef Matrix::Scalar, + internal::traits::RowsAtCompileTime, + internal::traits::ColsAtCompileTime, + AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), + internal::traits::MaxRowsAtCompileTime, + internal::traits::MaxColsAtCompileTime + > PlainMatrix; + + /** The plain array type corresponding to this expression. + * \sa PlainObject */ + typedef Array::Scalar, + internal::traits::RowsAtCompileTime, + internal::traits::ColsAtCompileTime, + AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), + internal::traits::MaxRowsAtCompileTime, + internal::traits::MaxColsAtCompileTime + > PlainArray; + + /** \brief The plain matrix or array type corresponding to this expression. + * + * This is not necessarily exactly the return type of eval(). In the case of plain matrices, + * the return type of eval() is a const reference to a matrix, not a matrix! It is however guaranteed + * that the return type of eval() is either PlainObject or const PlainObject&. + */ + typedef typename internal::conditional::XprKind,MatrixXpr >::value, + PlainMatrix, PlainArray>::type PlainObject; /** \returns the number of nonzero coefficients which is in practice the number * of stored coefficients. */ + EIGEN_DEVICE_FUNC inline Index nonZeros() const { return size(); } - /** \returns true if either the number of rows or the number of columns is equal to 1. - * In other words, this function returns - * \code rows()==1 || cols()==1 \endcode - * \sa rows(), cols(), IsVectorAtCompileTime. */ /** \returns the outer size. * * \note For a vector, this returns just 1. For a matrix (non-vector), this is the major dimension * with respect to the \ref TopicStorageOrders "storage order", i.e., the number of columns for a * column-major matrix, and the number of rows for a row-major matrix. */ + EIGEN_DEVICE_FUNC Index outerSize() const { return IsVectorAtCompileTime ? 1 @@ -204,6 +230,7 @@ template class DenseBase * \note For a vector, this is just the size. For a matrix (non-vector), this is the minor dimension * with respect to the \ref TopicStorageOrders "storage order", i.e., the number of rows for a * column-major matrix, and the number of columns for a row-major matrix. */ + EIGEN_DEVICE_FUNC Index innerSize() const { return IsVectorAtCompileTime ? this->size() @@ -214,6 +241,7 @@ template class DenseBase * Matrix::resize() and Array::resize(). The present method only asserts that the new size equals the old size, and does * nothing else. */ + EIGEN_DEVICE_FUNC void resize(Index newSize) { EIGEN_ONLY_USED_FOR_DEBUG(newSize); @@ -224,22 +252,22 @@ template class DenseBase * Matrix::resize() and Array::resize(). The present method only asserts that the new size equals the old size, and does * nothing else. */ - void resize(Index nbRows, Index nbCols) + EIGEN_DEVICE_FUNC + void resize(Index rows, Index cols) { - EIGEN_ONLY_USED_FOR_DEBUG(nbRows); - EIGEN_ONLY_USED_FOR_DEBUG(nbCols); - eigen_assert(nbRows == this->rows() && nbCols == this->cols() + EIGEN_ONLY_USED_FOR_DEBUG(rows); + EIGEN_ONLY_USED_FOR_DEBUG(cols); + eigen_assert(rows == this->rows() && cols == this->cols() && "DenseBase::resize() does not actually allow to resize."); } #ifndef EIGEN_PARSED_BY_DOXYGEN - /** \internal Represents a matrix with all coefficients equal to one another*/ - typedef CwiseNullaryOp,Derived> ConstantReturnType; + typedef CwiseNullaryOp,PlainObject> ConstantReturnType; /** \internal Represents a vector with linearly spaced coefficients that allows sequential access only. */ - typedef CwiseNullaryOp,Derived> SequentialLinSpacedReturnType; + typedef CwiseNullaryOp,PlainObject> SequentialLinSpacedReturnType; /** \internal Represents a vector with linearly spaced coefficients that allows random access. */ - typedef CwiseNullaryOp,Derived> RandomAccessLinSpacedReturnType; + typedef CwiseNullaryOp,PlainObject> RandomAccessLinSpacedReturnType; /** \internal the return type of MatrixBase::eigenvalues() */ typedef Matrix::Scalar>::Real, internal::traits::ColsAtCompileTime, 1> EigenvaluesReturnType; @@ -247,110 +275,122 @@ template class DenseBase /** Copies \a other into *this. \returns a reference to *this. */ template + EIGEN_DEVICE_FUNC Derived& operator=(const DenseBase& other); /** Special case of the template operator=, in order to prevent the compiler * from generating a default operator= (issue hit with g++ 4.1) */ + EIGEN_DEVICE_FUNC Derived& operator=(const DenseBase& other); template + EIGEN_DEVICE_FUNC Derived& operator=(const EigenBase &other); template + EIGEN_DEVICE_FUNC Derived& operator+=(const EigenBase &other); template + EIGEN_DEVICE_FUNC Derived& operator-=(const EigenBase &other); template + EIGEN_DEVICE_FUNC Derived& operator=(const ReturnByValue& func); -#ifndef EIGEN_PARSED_BY_DOXYGEN - /** Copies \a other into *this without evaluating other. \returns a reference to *this. */ + /** \ínternal + * Copies \a other into *this without evaluating other. \returns a reference to *this. + * \deprecated */ template + EIGEN_DEVICE_FUNC Derived& lazyAssign(const DenseBase& other); -#endif // not EIGEN_PARSED_BY_DOXYGEN + EIGEN_DEVICE_FUNC CommaInitializer operator<< (const Scalar& s); + /** \deprecated it now returns \c *this */ template - const Flagged flagged() const; + EIGEN_DEPRECATED + const Derived& flagged() const + { return derived(); } template + EIGEN_DEVICE_FUNC CommaInitializer operator<< (const DenseBase& other); - Eigen::Transpose transpose(); - typedef typename internal::add_const >::type ConstTransposeReturnType; + typedef Transpose TransposeReturnType; + EIGEN_DEVICE_FUNC + TransposeReturnType transpose(); + typedef typename internal::add_const >::type ConstTransposeReturnType; + EIGEN_DEVICE_FUNC ConstTransposeReturnType transpose() const; + EIGEN_DEVICE_FUNC void transposeInPlace(); -#ifndef EIGEN_NO_DEBUG - protected: - template - void checkTransposeAliasing(const OtherDerived& other) const; - public: -#endif - - static const ConstantReturnType + EIGEN_DEVICE_FUNC static const ConstantReturnType Constant(Index rows, Index cols, const Scalar& value); - static const ConstantReturnType + EIGEN_DEVICE_FUNC static const ConstantReturnType Constant(Index size, const Scalar& value); - static const ConstantReturnType + EIGEN_DEVICE_FUNC static const ConstantReturnType Constant(const Scalar& value); - static const SequentialLinSpacedReturnType + EIGEN_DEVICE_FUNC static const SequentialLinSpacedReturnType LinSpaced(Sequential_t, Index size, const Scalar& low, const Scalar& high); - static const RandomAccessLinSpacedReturnType + EIGEN_DEVICE_FUNC static const RandomAccessLinSpacedReturnType LinSpaced(Index size, const Scalar& low, const Scalar& high); - static const SequentialLinSpacedReturnType + EIGEN_DEVICE_FUNC static const SequentialLinSpacedReturnType LinSpaced(Sequential_t, const Scalar& low, const Scalar& high); - static const RandomAccessLinSpacedReturnType + EIGEN_DEVICE_FUNC static const RandomAccessLinSpacedReturnType LinSpaced(const Scalar& low, const Scalar& high); - template - static const CwiseNullaryOp + template EIGEN_DEVICE_FUNC + static const CwiseNullaryOp NullaryExpr(Index rows, Index cols, const CustomNullaryOp& func); - template - static const CwiseNullaryOp + template EIGEN_DEVICE_FUNC + static const CwiseNullaryOp NullaryExpr(Index size, const CustomNullaryOp& func); - template - static const CwiseNullaryOp + template EIGEN_DEVICE_FUNC + static const CwiseNullaryOp NullaryExpr(const CustomNullaryOp& func); - static const ConstantReturnType Zero(Index rows, Index cols); - static const ConstantReturnType Zero(Index size); - static const ConstantReturnType Zero(); - static const ConstantReturnType Ones(Index rows, Index cols); - static const ConstantReturnType Ones(Index size); - static const ConstantReturnType Ones(); - - void fill(const Scalar& value); - Derived& setConstant(const Scalar& value); - Derived& setLinSpaced(Index size, const Scalar& low, const Scalar& high); - Derived& setLinSpaced(const Scalar& low, const Scalar& high); - Derived& setZero(); - Derived& setOnes(); - Derived& setRandom(); - - template + EIGEN_DEVICE_FUNC static const ConstantReturnType Zero(Index rows, Index cols); + EIGEN_DEVICE_FUNC static const ConstantReturnType Zero(Index size); + EIGEN_DEVICE_FUNC static const ConstantReturnType Zero(); + EIGEN_DEVICE_FUNC static const ConstantReturnType Ones(Index rows, Index cols); + EIGEN_DEVICE_FUNC static const ConstantReturnType Ones(Index size); + EIGEN_DEVICE_FUNC static const ConstantReturnType Ones(); + + EIGEN_DEVICE_FUNC void fill(const Scalar& value); + EIGEN_DEVICE_FUNC Derived& setConstant(const Scalar& value); + EIGEN_DEVICE_FUNC Derived& setLinSpaced(Index size, const Scalar& low, const Scalar& high); + EIGEN_DEVICE_FUNC Derived& setLinSpaced(const Scalar& low, const Scalar& high); + EIGEN_DEVICE_FUNC Derived& setZero(); + EIGEN_DEVICE_FUNC Derived& setOnes(); + EIGEN_DEVICE_FUNC Derived& setRandom(); + + template EIGEN_DEVICE_FUNC bool isApprox(const DenseBase& other, const RealScalar& prec = NumTraits::dummy_precision()) const; + EIGEN_DEVICE_FUNC bool isMuchSmallerThan(const RealScalar& other, const RealScalar& prec = NumTraits::dummy_precision()) const; - template + template EIGEN_DEVICE_FUNC bool isMuchSmallerThan(const DenseBase& other, const RealScalar& prec = NumTraits::dummy_precision()) const; - bool isApproxToConstant(const Scalar& value, const RealScalar& prec = NumTraits::dummy_precision()) const; - bool isConstant(const Scalar& value, const RealScalar& prec = NumTraits::dummy_precision()) const; - bool isZero(const RealScalar& prec = NumTraits::dummy_precision()) const; - bool isOnes(const RealScalar& prec = NumTraits::dummy_precision()) const; + EIGEN_DEVICE_FUNC bool isApproxToConstant(const Scalar& value, const RealScalar& prec = NumTraits::dummy_precision()) const; + EIGEN_DEVICE_FUNC bool isConstant(const Scalar& value, const RealScalar& prec = NumTraits::dummy_precision()) const; + EIGEN_DEVICE_FUNC bool isZero(const RealScalar& prec = NumTraits::dummy_precision()) const; + EIGEN_DEVICE_FUNC bool isOnes(const RealScalar& prec = NumTraits::dummy_precision()) const; inline bool hasNaN() const; inline bool allFinite() const; + EIGEN_DEVICE_FUNC inline Derived& operator*=(const Scalar& other); + EIGEN_DEVICE_FUNC inline Derived& operator/=(const Scalar& other); typedef typename internal::add_const_on_value_type::type>::type EvalReturnType; @@ -358,7 +398,10 @@ template class DenseBase * * Notice that in the case of a plain matrix or vector (not an expression) this function just returns * a const reference, in order to avoid a useless copy. + * + * \warning Be carefull with eval() and the auto C++ keyword, as detailed in this \link TopicPitfalls_auto_keyword page \endlink. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EvalReturnType eval() const { // Even though MSVC does not honor strong inlining when the return type @@ -366,61 +409,68 @@ template class DenseBase // size types on MSVC. return typename internal::eval::type(derived()); } - + /** swaps *this with the expression \a other. * */ template - void swap(const DenseBase& other, - int = OtherDerived::ThisConstantIsPrivateInPlainObjectBase) + EIGEN_DEVICE_FUNC + void swap(const DenseBase& other) { - SwapWrapper(derived()).lazyAssign(other.derived()); + EIGEN_STATIC_ASSERT(!OtherDerived::IsPlainObjectBase,THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); + eigen_assert(rows()==other.rows() && cols()==other.cols()); + call_assignment(derived(), other.const_cast_derived(), internal::swap_assign_op()); } /** swaps *this with the matrix or array \a other. * */ template + EIGEN_DEVICE_FUNC void swap(PlainObjectBase& other) { - SwapWrapper(derived()).lazyAssign(other.derived()); + eigen_assert(rows()==other.rows() && cols()==other.cols()); + call_assignment(derived(), other.derived(), internal::swap_assign_op()); } + EIGEN_DEVICE_FUNC inline const NestByValue nestByValue() const; + EIGEN_DEVICE_FUNC inline const ForceAlignedAccess forceAlignedAccess() const; + EIGEN_DEVICE_FUNC inline ForceAlignedAccess forceAlignedAccess(); + template EIGEN_DEVICE_FUNC + inline const typename internal::conditional,Derived&>::type forceAlignedAccessIf() const; + template EIGEN_DEVICE_FUNC + inline typename internal::conditional,Derived&>::type forceAlignedAccessIf(); - inline const NestByValue nestByValue() const; - inline const ForceAlignedAccess forceAlignedAccess() const; - inline ForceAlignedAccess forceAlignedAccess(); - template inline const typename internal::conditional,Derived&>::type forceAlignedAccessIf() const; - template inline typename internal::conditional,Derived&>::type forceAlignedAccessIf(); + EIGEN_DEVICE_FUNC Scalar sum() const; + EIGEN_DEVICE_FUNC Scalar mean() const; + EIGEN_DEVICE_FUNC Scalar trace() const; - Scalar sum() const; - Scalar mean() const; - Scalar trace() const; + EIGEN_DEVICE_FUNC Scalar prod() const; - Scalar prod() const; + EIGEN_DEVICE_FUNC typename internal::traits::Scalar minCoeff() const; + EIGEN_DEVICE_FUNC typename internal::traits::Scalar maxCoeff() const; - typename internal::traits::Scalar minCoeff() const; - typename internal::traits::Scalar maxCoeff() const; - - template + template EIGEN_DEVICE_FUNC typename internal::traits::Scalar minCoeff(IndexType* row, IndexType* col) const; - template + template EIGEN_DEVICE_FUNC typename internal::traits::Scalar maxCoeff(IndexType* row, IndexType* col) const; - template + template EIGEN_DEVICE_FUNC typename internal::traits::Scalar minCoeff(IndexType* index) const; - template + template EIGEN_DEVICE_FUNC typename internal::traits::Scalar maxCoeff(IndexType* index) const; template - typename internal::result_of::Scalar)>::type - redux(const BinaryOp& func) const; + EIGEN_DEVICE_FUNC + Scalar redux(const BinaryOp& func) const; template + EIGEN_DEVICE_FUNC void visit(Visitor& func) const; inline const WithFormat format(const IOFormat& fmt) const; /** \returns the unique coefficient of a 1x1 expression */ + EIGEN_DEVICE_FUNC CoeffReturnType value() const { EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) @@ -428,8 +478,8 @@ template class DenseBase return derived().coeff(0,0); } - bool all(void) const; - bool any(void) const; + bool all() const; + bool any() const; Index count() const; typedef VectorwiseOp RowwiseReturnType; @@ -437,14 +487,35 @@ template class DenseBase typedef VectorwiseOp ColwiseReturnType; typedef const VectorwiseOp ConstColwiseReturnType; - ConstRowwiseReturnType rowwise() const; - RowwiseReturnType rowwise(); - ConstColwiseReturnType colwise() const; - ColwiseReturnType colwise(); + /** \returns a VectorwiseOp wrapper of *this providing additional partial reduction operations + * + * Example: \include MatrixBase_rowwise.cpp + * Output: \verbinclude MatrixBase_rowwise.out + * + * \sa colwise(), class VectorwiseOp, \ref TutorialReductionsVisitorsBroadcasting + */ + //Code moved here due to a CUDA compiler bug + EIGEN_DEVICE_FUNC inline ConstRowwiseReturnType rowwise() const { + return ConstRowwiseReturnType(derived()); + } + EIGEN_DEVICE_FUNC RowwiseReturnType rowwise(); + + /** \returns a VectorwiseOp wrapper of *this providing additional partial reduction operations + * + * Example: \include MatrixBase_colwise.cpp + * Output: \verbinclude MatrixBase_colwise.out + * + * \sa rowwise(), class VectorwiseOp, \ref TutorialReductionsVisitorsBroadcasting + */ + EIGEN_DEVICE_FUNC inline ConstColwiseReturnType colwise() const { + return ConstColwiseReturnType(derived()); + } + EIGEN_DEVICE_FUNC ColwiseReturnType colwise(); - static const CwiseNullaryOp,Derived> Random(Index rows, Index cols); - static const CwiseNullaryOp,Derived> Random(Index size); - static const CwiseNullaryOp,Derived> Random(); + typedef CwiseNullaryOp,PlainObject> RandomReturnType; + static const RandomReturnType Random(Index rows, Index cols); + static const RandomReturnType Random(Index size); + static const RandomReturnType Random(); template const Select @@ -462,14 +533,33 @@ template class DenseBase template RealScalar lpNorm() const; template + EIGEN_DEVICE_FUNC const Replicate replicate() const; - const Replicate replicate(Index rowFacor,Index colFactor) const; + /** + * \return an expression of the replication of \c *this + * + * Example: \include MatrixBase_replicate_int_int.cpp + * Output: \verbinclude MatrixBase_replicate_int_int.out + * + * \sa VectorwiseOp::replicate(), DenseBase::replicate(), class Replicate + */ + //Code moved here due to a CUDA compiler bug + EIGEN_DEVICE_FUNC + const Replicate replicate(Index rowFactor, Index colFactor) const + { + return Replicate(derived(), rowFactor, colFactor); + } typedef Reverse ReverseReturnType; typedef const Reverse ConstReverseReturnType; - ReverseReturnType reverse(); - ConstReverseReturnType reverse() const; - void reverseInPlace(); + EIGEN_DEVICE_FUNC ReverseReturnType reverse(); + /** This is the const version of reverse(). */ + //Code moved here due to a CUDA compiler bug + EIGEN_DEVICE_FUNC ConstReverseReturnType reverse() const + { + return ConstReverseReturnType(derived()); + } + EIGEN_DEVICE_FUNC void reverseInPlace(); #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::DenseBase # include "../plugins/BlockMethods.h" @@ -478,27 +568,18 @@ template class DenseBase # endif #undef EIGEN_CURRENT_STORAGE_BASE_CLASS -#ifdef EIGEN2_SUPPORT - - Block corner(CornerType type, Index cRows, Index cCols); - const Block corner(CornerType type, Index cRows, Index cCols) const; - template - Block corner(CornerType type); - template - const Block corner(CornerType type) const; - -#endif // EIGEN2_SUPPORT - // disable the use of evalTo for dense objects with a nice compilation error - template inline void evalTo(Dest& ) const + template + EIGEN_DEVICE_FUNC + inline void evalTo(Dest& ) const { EIGEN_STATIC_ASSERT((internal::is_same::value),THE_EVAL_EVALTO_FUNCTION_SHOULD_NEVER_BE_CALLED_FOR_DENSE_OBJECTS); } protected: /** Default constructor. Do nothing. */ - DenseBase() + EIGEN_DEVICE_FUNC DenseBase() { /* Just checks for self-consistency of the flags. * Only do it when debugging Eigen, as this borders on paranoiac and could slow compilation down @@ -511,9 +592,9 @@ template class DenseBase } private: - explicit DenseBase(int); - DenseBase(int,int); - template explicit DenseBase(const DenseBase&); + EIGEN_DEVICE_FUNC explicit DenseBase(int); + EIGEN_DEVICE_FUNC DenseBase(int,int); + template EIGEN_DEVICE_FUNC explicit DenseBase(const DenseBase&); }; } // end namespace Eigen diff --git a/nuparu/include/Eigen/src/Core/DenseCoeffsBase.h b/nuparu/include/Eigen/src/Core/DenseCoeffsBase.h index 3c890f21..820a90e6 100644 --- a/nuparu/include/Eigen/src/Core/DenseCoeffsBase.h +++ b/nuparu/include/Eigen/src/Core/DenseCoeffsBase.h @@ -35,7 +35,6 @@ class DenseCoeffsBase : public EigenBase { public: typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; @@ -61,6 +60,7 @@ class DenseCoeffsBase : public EigenBase using Base::size; using Base::derived; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rowIndexByOuterInner(Index outer, Index inner) const { return int(Derived::RowsAtCompileTime) == 1 ? 0 @@ -69,6 +69,7 @@ class DenseCoeffsBase : public EigenBase : inner; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index colIndexByOuterInner(Index outer, Index inner) const { return int(Derived::ColsAtCompileTime) == 1 ? 0 @@ -91,13 +92,15 @@ class DenseCoeffsBase : public EigenBase * * \sa operator()(Index,Index) const, coeffRef(Index,Index), coeff(Index) const */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const { eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - return derived().coeff(row, col); + && col >= 0 && col < cols()); + return internal::evaluator(derived()).coeff(row,col); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeffByOuterInner(Index outer, Index inner) const { return coeff(rowIndexByOuterInner(outer, inner), @@ -108,11 +111,12 @@ class DenseCoeffsBase : public EigenBase * * \sa operator()(Index,Index), operator[](Index) */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType operator()(Index row, Index col) const { eigen_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); - return derived().coeff(row, col); + return coeff(row, col); } /** Short version: don't use this function, use @@ -130,11 +134,14 @@ class DenseCoeffsBase : public EigenBase * \sa operator[](Index) const, coeffRef(Index), coeff(Index,Index) const */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { + EIGEN_STATIC_ASSERT(internal::evaluator::Flags & LinearAccessBit, + THIS_COEFFICIENT_ACCESSOR_TAKING_ONE_ACCESS_IS_ONLY_FOR_EXPRESSIONS_ALLOWING_LINEAR_ACCESS) eigen_internal_assert(index >= 0 && index < size()); - return derived().coeff(index); + return internal::evaluator(derived()).coeff(index); } @@ -146,15 +153,14 @@ class DenseCoeffsBase : public EigenBase * z() const, w() const */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType operator[](Index index) const { - #ifndef EIGEN2_SUPPORT EIGEN_STATIC_ASSERT(Derived::IsVectorAtCompileTime, THE_BRACKET_OPERATOR_IS_ONLY_FOR_VECTORS__USE_THE_PARENTHESIS_OPERATOR_INSTEAD) - #endif eigen_assert(index >= 0 && index < size()); - return derived().coeff(index); + return coeff(index); } /** \returns the coefficient at given index. @@ -167,30 +173,35 @@ class DenseCoeffsBase : public EigenBase * z() const, w() const */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType operator()(Index index) const { eigen_assert(index >= 0 && index < size()); - return derived().coeff(index); + return coeff(index); } /** equivalent to operator[](0). */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType x() const { return (*this)[0]; } /** equivalent to operator[](1). */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType y() const { return (*this)[1]; } /** equivalent to operator[](2). */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType z() const { return (*this)[2]; } /** equivalent to operator[](3). */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType w() const { return (*this)[3]; } @@ -207,9 +218,9 @@ class DenseCoeffsBase : public EigenBase template EIGEN_STRONG_INLINE PacketReturnType packet(Index row, Index col) const { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - return derived().template packet(row,col); + typedef typename internal::packet_traits::type DefaultPacketType; + eigen_internal_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); + return internal::evaluator(derived()).template packet(row,col); } @@ -234,8 +245,11 @@ class DenseCoeffsBase : public EigenBase template EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const { + EIGEN_STATIC_ASSERT(internal::evaluator::Flags & LinearAccessBit, + THIS_COEFFICIENT_ACCESSOR_TAKING_ONE_ACCESS_IS_ONLY_FOR_EXPRESSIONS_ALLOWING_LINEAR_ACCESS) + typedef typename internal::packet_traits::type DefaultPacketType; eigen_internal_assert(index >= 0 && index < size()); - return derived().template packet(index); + return internal::evaluator(derived()).template packet(index); } protected: @@ -278,7 +292,6 @@ class DenseCoeffsBase : public DenseCoeffsBase Base; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; @@ -311,13 +324,15 @@ class DenseCoeffsBase : public DenseCoeffsBase= 0 && row < rows() - && col >= 0 && col < cols()); - return derived().coeffRef(row, col); + && col >= 0 && col < cols()); + return internal::evaluator(derived()).coeffRef(row,col); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRefByOuterInner(Index outer, Index inner) { @@ -330,12 +345,13 @@ class DenseCoeffsBase : public DenseCoeffsBase= 0 && row < rows() && col >= 0 && col < cols()); - return derived().coeffRef(row, col); + return coeffRef(row, col); } @@ -354,11 +370,14 @@ class DenseCoeffsBase : public DenseCoeffsBase::Flags & LinearAccessBit, + THIS_COEFFICIENT_ACCESSOR_TAKING_ONE_ACCESS_IS_ONLY_FOR_EXPRESSIONS_ALLOWING_LINEAR_ACCESS) eigen_internal_assert(index >= 0 && index < size()); - return derived().coeffRef(index); + return internal::evaluator(derived()).coeffRef(index); } /** \returns a reference to the coefficient at given index. @@ -368,15 +387,14 @@ class DenseCoeffsBase : public DenseCoeffsBase= 0 && index < size()); - return derived().coeffRef(index); + return coeffRef(index); } /** \returns a reference to the coefficient at given index. @@ -388,167 +406,37 @@ class DenseCoeffsBase : public DenseCoeffsBase= 0 && index < size()); - return derived().coeffRef(index); + return coeffRef(index); } /** equivalent to operator[](0). */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& x() { return (*this)[0]; } /** equivalent to operator[](1). */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& y() { return (*this)[1]; } /** equivalent to operator[](2). */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& z() { return (*this)[2]; } /** equivalent to operator[](3). */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& w() { return (*this)[3]; } - - /** \internal - * Stores the given packet of coefficients, at the given row and column of this expression. It is your responsibility - * to ensure that a packet really starts there. This method is only available on expressions having the - * PacketAccessBit. - * - * The \a LoadMode parameter may have the value \a #Aligned or \a #Unaligned. Its effect is to select - * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets - * starting at an address which is a multiple of the packet size. - */ - - template - EIGEN_STRONG_INLINE void writePacket - (Index row, Index col, const typename internal::packet_traits::type& val) - { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - derived().template writePacket(row,col,val); - } - - - /** \internal */ - template - EIGEN_STRONG_INLINE void writePacketByOuterInner - (Index outer, Index inner, const typename internal::packet_traits::type& val) - { - writePacket(rowIndexByOuterInner(outer, inner), - colIndexByOuterInner(outer, inner), - val); - } - - /** \internal - * Stores the given packet of coefficients, at the given index in this expression. It is your responsibility - * to ensure that a packet really starts there. This method is only available on expressions having the - * PacketAccessBit and the LinearAccessBit. - * - * The \a LoadMode parameter may have the value \a Aligned or \a Unaligned. Its effect is to select - * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets - * starting at an address which is a multiple of the packet size. - */ - template - EIGEN_STRONG_INLINE void writePacket - (Index index, const typename internal::packet_traits::type& val) - { - eigen_internal_assert(index >= 0 && index < size()); - derived().template writePacket(index,val); - } - -#ifndef EIGEN_PARSED_BY_DOXYGEN - - /** \internal Copies the coefficient at position (row,col) of other into *this. - * - * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code - * with usual assignments. - * - * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. - */ - - template - EIGEN_STRONG_INLINE void copyCoeff(Index row, Index col, const DenseBase& other) - { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - derived().coeffRef(row, col) = other.derived().coeff(row, col); - } - - /** \internal Copies the coefficient at the given index of other into *this. - * - * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code - * with usual assignments. - * - * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. - */ - - template - EIGEN_STRONG_INLINE void copyCoeff(Index index, const DenseBase& other) - { - eigen_internal_assert(index >= 0 && index < size()); - derived().coeffRef(index) = other.derived().coeff(index); - } - - - template - EIGEN_STRONG_INLINE void copyCoeffByOuterInner(Index outer, Index inner, const DenseBase& other) - { - const Index row = rowIndexByOuterInner(outer,inner); - const Index col = colIndexByOuterInner(outer,inner); - // derived() is important here: copyCoeff() may be reimplemented in Derived! - derived().copyCoeff(row, col, other); - } - - /** \internal Copies the packet at position (row,col) of other into *this. - * - * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code - * with usual assignments. - * - * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. - */ - - template - EIGEN_STRONG_INLINE void copyPacket(Index row, Index col, const DenseBase& other) - { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - derived().template writePacket(row, col, - other.derived().template packet(row, col)); - } - - /** \internal Copies the packet at the given index of other into *this. - * - * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code - * with usual assignments. - * - * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. - */ - - template - EIGEN_STRONG_INLINE void copyPacket(Index index, const DenseBase& other) - { - eigen_internal_assert(index >= 0 && index < size()); - derived().template writePacket(index, - other.derived().template packet(index)); - } - - /** \internal */ - template - EIGEN_STRONG_INLINE void copyPacketByOuterInner(Index outer, Index inner, const DenseBase& other) - { - const Index row = rowIndexByOuterInner(outer,inner); - const Index col = colIndexByOuterInner(outer,inner); - // derived() is important here: copyCoeff() may be reimplemented in Derived! - derived().template copyPacket< OtherDerived, StoreMode, LoadMode>(row, col, other); - } -#endif - }; /** \brief Base class providing direct read-only coefficient access to matrices and arrays. @@ -568,7 +456,6 @@ class DenseCoeffsBase : public DenseCoeffsBase Base; - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename NumTraits::Real RealScalar; @@ -581,6 +468,7 @@ class DenseCoeffsBase : public DenseCoeffsBase : public DenseCoeffsBase : public DenseCoeffsBase : public DenseCoeffsBase public: typedef DenseCoeffsBase Base; - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename NumTraits::Real RealScalar; @@ -652,6 +542,7 @@ class DenseCoeffsBase * * \sa outerStride(), rowStride(), colStride() */ + EIGEN_DEVICE_FUNC inline Index innerStride() const { return derived().innerStride(); @@ -662,6 +553,7 @@ class DenseCoeffsBase * * \sa innerStride(), rowStride(), colStride() */ + EIGEN_DEVICE_FUNC inline Index outerStride() const { return derived().outerStride(); @@ -677,6 +569,7 @@ class DenseCoeffsBase * * \sa innerStride(), outerStride(), colStride() */ + EIGEN_DEVICE_FUNC inline Index rowStride() const { return Derived::IsRowMajor ? outerStride() : innerStride(); @@ -686,6 +579,7 @@ class DenseCoeffsBase * * \sa innerStride(), outerStride(), rowStride() */ + EIGEN_DEVICE_FUNC inline Index colStride() const { return Derived::IsRowMajor ? innerStride() : outerStride(); @@ -694,33 +588,42 @@ class DenseCoeffsBase namespace internal { -template +template struct first_aligned_impl { - static inline typename Derived::Index run(const Derived&) + static inline Index run(const Derived&) { return 0; } }; -template -struct first_aligned_impl +template +struct first_aligned_impl { - static inline typename Derived::Index run(const Derived& m) + static inline Index run(const Derived& m) { - return internal::first_aligned(&m.const_cast_derived().coeffRef(0,0), m.size()); + return internal::first_aligned(&m.const_cast_derived().coeffRef(0,0), m.size()); } }; -/** \internal \returns the index of the first element of the array that is well aligned for vectorization. +/** \internal \returns the index of the first element of the array stored by \a m that is properly aligned with respect to \a Alignment for vectorization. + * + * \tparam Alignment requested alignment in Bytes. * * There is also the variant first_aligned(const Scalar*, Integer) defined in Memory.h. See it for more * documentation. */ +template +static inline Index first_aligned(const DenseBase& m) +{ + enum { ReturnZero = (int(evaluator::Alignment) >= Alignment) || !(Derived::Flags & DirectAccessBit) }; + return first_aligned_impl::run(m.derived()); +} + template -static inline typename Derived::Index first_aligned(const Derived& m) +static inline Index first_default_aligned(const DenseBase& m) { - return first_aligned_impl - - ::run(m); + typedef typename Derived::Scalar Scalar; + typedef typename packet_traits::type DefaultPacketType; + return internal::first_aligned::alignment),Derived>(m); } template::ret> diff --git a/nuparu/include/Eigen/src/Core/DenseStorage.h b/nuparu/include/Eigen/src/Core/DenseStorage.h index 3e7f9c1b..34048461 100644 --- a/nuparu/include/Eigen/src/Core/DenseStorage.h +++ b/nuparu/include/Eigen/src/Core/DenseStorage.h @@ -3,7 +3,7 @@ // // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2006-2009 Benoit Jacob -// Copyright (C) 2010 Hauke Heibel +// Copyright (C) 2010-2013 Hauke Heibel // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -24,26 +24,37 @@ namespace internal { struct constructor_without_unaligned_array_assert {}; +template +EIGEN_DEVICE_FUNC +void check_static_allocation_size() +{ + // if EIGEN_STACK_ALLOCATION_LIMIT is defined to 0, then no limit + #if EIGEN_STACK_ALLOCATION_LIMIT + EIGEN_STATIC_ASSERT(Size * sizeof(T) <= EIGEN_STACK_ALLOCATION_LIMIT, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG); + #endif +} + /** \internal * Static array. If the MatrixOrArrayOptions require auto-alignment, the array will be automatically aligned: * to 16 bytes boundary if the total size is a multiple of 16 bytes. */ template + : compute_default_alignment::value > struct plain_array { T array[Size]; - plain_array() + EIGEN_DEVICE_FUNC + plain_array() { - EIGEN_STATIC_ASSERT(Size * sizeof(T) <= 128 * 128 * 8, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG); + check_static_allocation_size(); } - plain_array(constructor_without_unaligned_array_assert) + EIGEN_DEVICE_FUNC + plain_array(constructor_without_unaligned_array_assert) { - EIGEN_STATIC_ASSERT(Size * sizeof(T) <= 128 * 128 * 8, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG); + check_static_allocation_size(); } }; @@ -56,41 +67,100 @@ struct plain_array template EIGEN_ALWAYS_INLINE PtrType eigen_unaligned_array_assert_workaround_gcc47(PtrType array) { return array; } #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ - eigen_assert((reinterpret_cast(eigen_unaligned_array_assert_workaround_gcc47(array)) & sizemask) == 0 \ + eigen_assert((reinterpret_cast(eigen_unaligned_array_assert_workaround_gcc47(array)) & (sizemask)) == 0 \ && "this assertion is explained here: " \ "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" \ " **** READ THIS WEB PAGE !!! ****"); #else #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ - eigen_assert((reinterpret_cast(array) & sizemask) == 0 \ + eigen_assert((reinterpret_cast(array) & (sizemask)) == 0 \ && "this assertion is explained here: " \ "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" \ " **** READ THIS WEB PAGE !!! ****"); #endif +template +struct plain_array +{ + EIGEN_ALIGN_TO_BOUNDARY(8) T array[Size]; + + EIGEN_DEVICE_FUNC + plain_array() + { + EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(7); + check_static_allocation_size(); + } + + EIGEN_DEVICE_FUNC + plain_array(constructor_without_unaligned_array_assert) + { + check_static_allocation_size(); + } +}; + template struct plain_array { - EIGEN_USER_ALIGN16 T array[Size]; + EIGEN_ALIGN_TO_BOUNDARY(16) T array[Size]; + + EIGEN_DEVICE_FUNC + plain_array() + { + EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(15); + check_static_allocation_size(); + } + + EIGEN_DEVICE_FUNC + plain_array(constructor_without_unaligned_array_assert) + { + check_static_allocation_size(); + } +}; + +template +struct plain_array +{ + EIGEN_ALIGN_TO_BOUNDARY(32) T array[Size]; + + EIGEN_DEVICE_FUNC + plain_array() + { + EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(31); + check_static_allocation_size(); + } + + EIGEN_DEVICE_FUNC + plain_array(constructor_without_unaligned_array_assert) + { + check_static_allocation_size(); + } +}; + +template +struct plain_array +{ + EIGEN_ALIGN_TO_BOUNDARY(64) T array[Size]; + EIGEN_DEVICE_FUNC plain_array() { - EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(0xf); - EIGEN_STATIC_ASSERT(Size * sizeof(T) <= 128 * 128 * 8, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG); + EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(63); + check_static_allocation_size(); } + EIGEN_DEVICE_FUNC plain_array(constructor_without_unaligned_array_assert) { - EIGEN_STATIC_ASSERT(Size * sizeof(T) <= 128 * 128 * 8, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG); + check_static_allocation_size(); } }; template struct plain_array { - EIGEN_USER_ALIGN16 T array[1]; - plain_array() {} - plain_array(constructor_without_unaligned_array_assert) {} + T array[1]; + EIGEN_DEVICE_FUNC plain_array() {} + EIGEN_DEVICE_FUNC plain_array(constructor_without_unaligned_array_assert) {} }; } // end namespace internal @@ -114,33 +184,50 @@ template class DenseSt { internal::plain_array m_data; public: - inline DenseStorage() {} - inline DenseStorage(internal::constructor_without_unaligned_array_assert) + EIGEN_DEVICE_FUNC DenseStorage() {} + EIGEN_DEVICE_FUNC + explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(internal::constructor_without_unaligned_array_assert()) {} - inline DenseStorage(DenseIndex,DenseIndex,DenseIndex) {} - inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); } - static inline DenseIndex rows(void) {return _Rows;} - static inline DenseIndex cols(void) {return _Cols;} - inline void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {} - inline void resize(DenseIndex,DenseIndex,DenseIndex) {} - inline const T *data() const { return m_data.array; } - inline T *data() { return m_data.array; } + EIGEN_DEVICE_FUNC + DenseStorage(const DenseStorage& other) : m_data(other.m_data) {} + EIGEN_DEVICE_FUNC + DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) m_data = other.m_data; + return *this; + } + EIGEN_DEVICE_FUNC DenseStorage(Index size, Index rows, Index cols) { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN + eigen_internal_assert(size==rows*cols && rows==_Rows && cols==_Cols); + EIGEN_UNUSED_VARIABLE(size); + EIGEN_UNUSED_VARIABLE(rows); + EIGEN_UNUSED_VARIABLE(cols); + } + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); } + EIGEN_DEVICE_FUNC static Index rows(void) {return _Rows;} + EIGEN_DEVICE_FUNC static Index cols(void) {return _Cols;} + EIGEN_DEVICE_FUNC void conservativeResize(Index,Index,Index) {} + EIGEN_DEVICE_FUNC void resize(Index,Index,Index) {} + EIGEN_DEVICE_FUNC const T *data() const { return m_data.array; } + EIGEN_DEVICE_FUNC T *data() { return m_data.array; } }; // null matrix template class DenseStorage { public: - inline DenseStorage() {} - inline DenseStorage(internal::constructor_without_unaligned_array_assert) {} - inline DenseStorage(DenseIndex,DenseIndex,DenseIndex) {} - inline void swap(DenseStorage& ) {} - static inline DenseIndex rows(void) {return _Rows;} - static inline DenseIndex cols(void) {return _Cols;} - inline void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {} - inline void resize(DenseIndex,DenseIndex,DenseIndex) {} - inline const T *data() const { return 0; } - inline T *data() { return 0; } + EIGEN_DEVICE_FUNC DenseStorage() {} + EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) {} + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage&) {} + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage&) { return *this; } + EIGEN_DEVICE_FUNC DenseStorage(Index,Index,Index) {} + EIGEN_DEVICE_FUNC void swap(DenseStorage& ) {} + EIGEN_DEVICE_FUNC static Index rows(void) {return _Rows;} + EIGEN_DEVICE_FUNC static Index cols(void) {return _Cols;} + EIGEN_DEVICE_FUNC void conservativeResize(Index,Index,Index) {} + EIGEN_DEVICE_FUNC void resize(Index,Index,Index) {} + EIGEN_DEVICE_FUNC const T *data() const { return 0; } + EIGEN_DEVICE_FUNC T *data() { return 0; } }; // more specializations for null matrices; these are necessary to resolve ambiguities @@ -157,86 +244,157 @@ template class DenseStorage class DenseStorage { internal::plain_array m_data; - DenseIndex m_rows; - DenseIndex m_cols; + Index m_rows; + Index m_cols; public: - inline DenseStorage() : m_rows(0), m_cols(0) {} - inline DenseStorage(internal::constructor_without_unaligned_array_assert) + EIGEN_DEVICE_FUNC DenseStorage() : m_rows(0), m_cols(0) {} + EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0), m_cols(0) {} - inline DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) : m_rows(nbRows), m_cols(nbCols) {} - inline void swap(DenseStorage& other) + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_rows(other.m_rows), m_cols(other.m_cols) {} + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + m_data = other.m_data; + m_rows = other.m_rows; + m_cols = other.m_cols; + } + return *this; + } + EIGEN_DEVICE_FUNC DenseStorage(Index, Index rows, Index cols) : m_rows(rows), m_cols(cols) {} + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); } - inline DenseIndex rows() const {return m_rows;} - inline DenseIndex cols() const {return m_cols;} - inline void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; } - inline void resize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; } - inline const T *data() const { return m_data.array; } - inline T *data() { return m_data.array; } + EIGEN_DEVICE_FUNC Index rows() const {return m_rows;} + EIGEN_DEVICE_FUNC Index cols() const {return m_cols;} + EIGEN_DEVICE_FUNC void conservativeResize(Index, Index rows, Index cols) { m_rows = rows; m_cols = cols; } + EIGEN_DEVICE_FUNC void resize(Index, Index rows, Index cols) { m_rows = rows; m_cols = cols; } + EIGEN_DEVICE_FUNC const T *data() const { return m_data.array; } + EIGEN_DEVICE_FUNC T *data() { return m_data.array; } }; // dynamic-size matrix with fixed-size storage and fixed width template class DenseStorage { internal::plain_array m_data; - DenseIndex m_rows; + Index m_rows; public: - inline DenseStorage() : m_rows(0) {} - inline DenseStorage(internal::constructor_without_unaligned_array_assert) + EIGEN_DEVICE_FUNC DenseStorage() : m_rows(0) {} + EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0) {} - inline DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex) : m_rows(nbRows) {} - inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } - inline DenseIndex rows(void) const {return m_rows;} - inline DenseIndex cols(void) const {return _Cols;} - inline void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; } - inline void resize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; } - inline const T *data() const { return m_data.array; } - inline T *data() { return m_data.array; } + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_rows(other.m_rows) {} + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + m_data = other.m_data; + m_rows = other.m_rows; + } + return *this; + } + EIGEN_DEVICE_FUNC DenseStorage(Index, Index rows, Index) : m_rows(rows) {} + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } + EIGEN_DEVICE_FUNC Index rows(void) const {return m_rows;} + EIGEN_DEVICE_FUNC Index cols(void) const {return _Cols;} + EIGEN_DEVICE_FUNC void conservativeResize(Index, Index rows, Index) { m_rows = rows; } + EIGEN_DEVICE_FUNC void resize(Index, Index rows, Index) { m_rows = rows; } + EIGEN_DEVICE_FUNC const T *data() const { return m_data.array; } + EIGEN_DEVICE_FUNC T *data() { return m_data.array; } }; // dynamic-size matrix with fixed-size storage and fixed height template class DenseStorage { internal::plain_array m_data; - DenseIndex m_cols; + Index m_cols; public: - inline DenseStorage() : m_cols(0) {} - inline DenseStorage(internal::constructor_without_unaligned_array_assert) + EIGEN_DEVICE_FUNC DenseStorage() : m_cols(0) {} + EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(internal::constructor_without_unaligned_array_assert()), m_cols(0) {} - inline DenseStorage(DenseIndex, DenseIndex, DenseIndex nbCols) : m_cols(nbCols) {} - inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } - inline DenseIndex rows(void) const {return _Rows;} - inline DenseIndex cols(void) const {return m_cols;} - inline void conservativeResize(DenseIndex, DenseIndex, DenseIndex nbCols) { m_cols = nbCols; } - inline void resize(DenseIndex, DenseIndex, DenseIndex nbCols) { m_cols = nbCols; } - inline const T *data() const { return m_data.array; } - inline T *data() { return m_data.array; } + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_cols(other.m_cols) {} + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + m_data = other.m_data; + m_cols = other.m_cols; + } + return *this; + } + EIGEN_DEVICE_FUNC DenseStorage(Index, Index, Index cols) : m_cols(cols) {} + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } + EIGEN_DEVICE_FUNC Index rows(void) const {return _Rows;} + EIGEN_DEVICE_FUNC Index cols(void) const {return m_cols;} + void conservativeResize(Index, Index, Index cols) { m_cols = cols; } + void resize(Index, Index, Index cols) { m_cols = cols; } + EIGEN_DEVICE_FUNC const T *data() const { return m_data.array; } + EIGEN_DEVICE_FUNC T *data() { return m_data.array; } }; // purely dynamic matrix. template class DenseStorage { T *m_data; - DenseIndex m_rows; - DenseIndex m_cols; + Index m_rows; + Index m_cols; public: - inline DenseStorage() : m_data(0), m_rows(0), m_cols(0) {} - inline DenseStorage(internal::constructor_without_unaligned_array_assert) + EIGEN_DEVICE_FUNC DenseStorage() : m_data(0), m_rows(0), m_cols(0) {} + EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0), m_cols(0) {} - inline DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) - : m_data(internal::conditional_aligned_new_auto(size)), m_rows(nbRows), m_cols(nbCols) - { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } - inline ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, m_rows*m_cols); } - inline void swap(DenseStorage& other) + EIGEN_DEVICE_FUNC DenseStorage(Index size, Index rows, Index cols) + : m_data(internal::conditional_aligned_new_auto(size)), m_rows(rows), m_cols(cols) + { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN + eigen_internal_assert(size==rows*cols && rows>=0 && cols >=0); + } + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) + : m_data(internal::conditional_aligned_new_auto(other.m_rows*other.m_cols)) + , m_rows(other.m_rows) + , m_cols(other.m_cols) + { + internal::smart_copy(other.m_data, other.m_data+other.m_rows*other.m_cols, m_data); + } + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + DenseStorage tmp(other); + this->swap(tmp); + } + return *this; + } +#ifdef EIGEN_HAVE_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + DenseStorage(DenseStorage&& other) + : m_data(std::move(other.m_data)) + , m_rows(std::move(other.m_rows)) + , m_cols(std::move(other.m_cols)) + { + other.m_data = nullptr; + other.m_rows = 0; + other.m_cols = 0; + } + EIGEN_DEVICE_FUNC + DenseStorage& operator=(DenseStorage&& other) + { + using std::swap; + swap(m_data, other.m_data); + swap(m_rows, other.m_rows); + swap(m_cols, other.m_cols); + return *this; + } +#endif + EIGEN_DEVICE_FUNC ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, m_rows*m_cols); } + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); } - inline DenseIndex rows(void) const {return m_rows;} - inline DenseIndex cols(void) const {return m_cols;} - inline void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) + EIGEN_DEVICE_FUNC Index rows(void) const {return m_rows;} + EIGEN_DEVICE_FUNC Index cols(void) const {return m_cols;} + void conservativeResize(Index size, Index rows, Index cols) { m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, m_rows*m_cols); - m_rows = nbRows; - m_cols = nbCols; + m_rows = rows; + m_cols = cols; } - void resize(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) + EIGEN_DEVICE_FUNC void resize(Index size, Index rows, Index cols) { if(size != m_rows*m_cols) { @@ -247,33 +405,70 @@ template class DenseStorage class DenseStorage { T *m_data; - DenseIndex m_cols; + Index m_cols; public: - inline DenseStorage() : m_data(0), m_cols(0) {} - inline DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_cols(0) {} - inline DenseStorage(DenseIndex size, DenseIndex, DenseIndex nbCols) : m_data(internal::conditional_aligned_new_auto(size)), m_cols(nbCols) - { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } - inline ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, _Rows*m_cols); } - inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } - static inline DenseIndex rows(void) {return _Rows;} - inline DenseIndex cols(void) const {return m_cols;} - inline void conservativeResize(DenseIndex size, DenseIndex, DenseIndex nbCols) + EIGEN_DEVICE_FUNC DenseStorage() : m_data(0), m_cols(0) {} + explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_cols(0) {} + EIGEN_DEVICE_FUNC DenseStorage(Index size, Index rows, Index cols) : m_data(internal::conditional_aligned_new_auto(size)), m_cols(cols) + { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN + eigen_internal_assert(size==rows*cols && rows==_Rows && cols >=0); + EIGEN_UNUSED_VARIABLE(rows); + } + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) + : m_data(internal::conditional_aligned_new_auto(_Rows*other.m_cols)) + , m_cols(other.m_cols) + { + internal::smart_copy(other.m_data, other.m_data+_Rows*m_cols, m_data); + } + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + DenseStorage tmp(other); + this->swap(tmp); + } + return *this; + } +#ifdef EIGEN_HAVE_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + DenseStorage(DenseStorage&& other) + : m_data(std::move(other.m_data)) + , m_cols(std::move(other.m_cols)) + { + other.m_data = nullptr; + other.m_cols = 0; + } + EIGEN_DEVICE_FUNC + DenseStorage& operator=(DenseStorage&& other) + { + using std::swap; + swap(m_data, other.m_data); + swap(m_cols, other.m_cols); + return *this; + } +#endif + EIGEN_DEVICE_FUNC ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, _Rows*m_cols); } + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } + EIGEN_DEVICE_FUNC static Index rows(void) {return _Rows;} + EIGEN_DEVICE_FUNC Index cols(void) const {return m_cols;} + EIGEN_DEVICE_FUNC void conservativeResize(Index size, Index, Index cols) { m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, _Rows*m_cols); - m_cols = nbCols; + m_cols = cols; } - EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex, DenseIndex nbCols) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resize(Index size, Index, Index cols) { if(size != _Rows*m_cols) { @@ -284,32 +479,69 @@ template class DenseStorage class DenseStorage { T *m_data; - DenseIndex m_rows; + Index m_rows; public: - inline DenseStorage() : m_data(0), m_rows(0) {} - inline DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0) {} - inline DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex) : m_data(internal::conditional_aligned_new_auto(size)), m_rows(nbRows) - { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } - inline ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, _Cols*m_rows); } - inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } - inline DenseIndex rows(void) const {return m_rows;} - static inline DenseIndex cols(void) {return _Cols;} - inline void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex) + EIGEN_DEVICE_FUNC DenseStorage() : m_data(0), m_rows(0) {} + explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0) {} + EIGEN_DEVICE_FUNC DenseStorage(Index size, Index rows, Index cols) : m_data(internal::conditional_aligned_new_auto(size)), m_rows(rows) + { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN + eigen_internal_assert(size==rows*cols && rows>=0 && cols == _Cols); + EIGEN_UNUSED_VARIABLE(cols); + } + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) + : m_data(internal::conditional_aligned_new_auto(other.m_rows*_Cols)) + , m_rows(other.m_rows) + { + internal::smart_copy(other.m_data, other.m_data+other.m_rows*_Cols, m_data); + } + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + DenseStorage tmp(other); + this->swap(tmp); + } + return *this; + } +#ifdef EIGEN_HAVE_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + DenseStorage(DenseStorage&& other) + : m_data(std::move(other.m_data)) + , m_rows(std::move(other.m_rows)) + { + other.m_data = nullptr; + other.m_rows = 0; + } + EIGEN_DEVICE_FUNC + DenseStorage& operator=(DenseStorage&& other) + { + using std::swap; + swap(m_data, other.m_data); + swap(m_rows, other.m_rows); + return *this; + } +#endif + EIGEN_DEVICE_FUNC ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, _Cols*m_rows); } + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } + EIGEN_DEVICE_FUNC Index rows(void) const {return m_rows;} + EIGEN_DEVICE_FUNC static Index cols(void) {return _Cols;} + void conservativeResize(Index size, Index rows, Index) { m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, m_rows*_Cols); - m_rows = nbRows; + m_rows = rows; } - EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex nbRows, DenseIndex) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resize(Index size, Index rows, Index) { if(size != m_rows*_Cols) { @@ -320,10 +552,10 @@ template class DenseStorage struct traits > : traits { - typedef typename nested::type MatrixTypeNested; + typedef typename ref_selector::type MatrixTypeNested; typedef typename remove_reference::type _MatrixTypeNested; typedef typename MatrixType::StorageKind StorageKind; enum { @@ -52,8 +52,7 @@ struct traits > MatrixType::MaxColsAtCompileTime - EIGEN_PLAIN_ENUM_MAX( DiagIndex, 0))), MaxColsAtCompileTime = 1, MaskLvalueBit = is_lvalue::value ? LvalueBit : 0, - Flags = (unsigned int)_MatrixTypeNested::Flags & (HereditaryBits | LinearAccessBit | MaskLvalueBit | DirectAccessBit) & ~RowMajorBit, - CoeffReadCost = _MatrixTypeNested::CoeffReadCost, + Flags = (unsigned int)_MatrixTypeNested::Flags & (RowMajorBit | MaskLvalueBit | DirectAccessBit) & ~RowMajorBit, // FIXME DirectAccessBit should not be handled by expressions MatrixTypeOuterStride = outer_stride_at_compile_time::ret, InnerStrideAtCompileTime = MatrixTypeOuterStride == Dynamic ? Dynamic : MatrixTypeOuterStride+1, OuterStrideAtCompileTime = 0 @@ -70,20 +69,28 @@ template class Diagonal typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Diagonal) - inline Diagonal(MatrixType& matrix, Index a_index = DiagIndex) : m_matrix(matrix), m_index(a_index) {} + EIGEN_DEVICE_FUNC + explicit inline Diagonal(MatrixType& matrix, Index a_index = DiagIndex) : m_matrix(matrix), m_index(a_index) {} EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Diagonal) + EIGEN_DEVICE_FUNC inline Index rows() const - { return m_index.value()<0 ? (std::min)(m_matrix.cols(),m_matrix.rows()+m_index.value()) : (std::min)(m_matrix.rows(),m_matrix.cols()-m_index.value()); } + { + return m_index.value()<0 ? numext::mini(m_matrix.cols(),m_matrix.rows()+m_index.value()) + : numext::mini(m_matrix.rows(),m_matrix.cols()-m_index.value()); + } + EIGEN_DEVICE_FUNC inline Index cols() const { return 1; } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_matrix.outerStride() + 1; } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return 0; @@ -95,48 +102,58 @@ template class Diagonal const Scalar >::type ScalarWithConstIfNotLvalue; + EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue* data() { return &(m_matrix.const_cast_derived().coeffRef(rowOffset(), colOffset())); } + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return &(m_matrix.const_cast_derived().coeffRef(rowOffset(), colOffset())); } + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index) { EIGEN_STATIC_ASSERT_LVALUE(MatrixType) return m_matrix.const_cast_derived().coeffRef(row+rowOffset(), row+colOffset()); } + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index row, Index) const { return m_matrix.const_cast_derived().coeffRef(row+rowOffset(), row+colOffset()); } + EIGEN_DEVICE_FUNC inline CoeffReturnType coeff(Index row, Index) const { return m_matrix.coeff(row+rowOffset(), row+colOffset()); } + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index idx) { EIGEN_STATIC_ASSERT_LVALUE(MatrixType) return m_matrix.const_cast_derived().coeffRef(idx+rowOffset(), idx+colOffset()); } + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index idx) const { return m_matrix.const_cast_derived().coeffRef(idx+rowOffset(), idx+colOffset()); } + EIGEN_DEVICE_FUNC inline CoeffReturnType coeff(Index idx) const { return m_matrix.coeff(idx+rowOffset(), idx+colOffset()); } - const typename internal::remove_all::type& + EIGEN_DEVICE_FUNC + inline const typename internal::remove_all::type& nestedExpression() const { return m_matrix; } - int index() const + EIGEN_DEVICE_FUNC + inline Index index() const { return m_index.value(); } @@ -147,10 +164,13 @@ template class Diagonal private: // some compilers may fail to optimize std::max etc in case of compile-time constants... + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index absDiagIndex() const { return m_index.value()>0 ? m_index.value() : -m_index.value(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rowOffset() const { return m_index.value()>0 ? 0 : -m_index.value(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index colOffset() const { return m_index.value()>0 ? m_index.value() : 0; } - // triger a compile time error is someone try to call packet + // trigger a compile-time error if someone try to call packet template typename MatrixType::PacketReturnType packet(Index) const; template typename MatrixType::PacketReturnType packet(Index,Index) const; }; @@ -167,7 +187,7 @@ template inline typename MatrixBase::DiagonalReturnType MatrixBase::diagonal() { - return derived(); + return DiagonalReturnType(derived()); } /** This is the const version of diagonal(). */ @@ -190,18 +210,18 @@ MatrixBase::diagonal() const * * \sa MatrixBase::diagonal(), class Diagonal */ template -inline typename MatrixBase::template DiagonalIndexReturnType::Type +inline typename MatrixBase::DiagonalDynamicIndexReturnType MatrixBase::diagonal(Index index) { - return typename DiagonalIndexReturnType::Type(derived(), index); + return DiagonalDynamicIndexReturnType(derived(), index); } /** This is the const version of diagonal(Index). */ template -inline typename MatrixBase::template ConstDiagonalIndexReturnType::Type +inline typename MatrixBase::ConstDiagonalDynamicIndexReturnType MatrixBase::diagonal(Index index) const { - return typename ConstDiagonalIndexReturnType::Type(derived(), index); + return ConstDiagonalDynamicIndexReturnType(derived(), index); } /** \returns an expression of the \a DiagIndex-th sub or super diagonal of the matrix \c *this @@ -216,20 +236,20 @@ MatrixBase::diagonal(Index index) const * * \sa MatrixBase::diagonal(), class Diagonal */ template -template -inline typename MatrixBase::template DiagonalIndexReturnType::Type +template +inline typename MatrixBase::template DiagonalIndexReturnType::Type MatrixBase::diagonal() { - return derived(); + return typename DiagonalIndexReturnType::Type(derived()); } /** This is the const version of diagonal(). */ template -template -inline typename MatrixBase::template ConstDiagonalIndexReturnType::Type +template +inline typename MatrixBase::template ConstDiagonalIndexReturnType::Type MatrixBase::diagonal() const { - return derived(); + return typename ConstDiagonalIndexReturnType::Type(derived()); } } // end namespace Eigen diff --git a/nuparu/include/Eigen/src/Core/DiagonalMatrix.h b/nuparu/include/Eigen/src/Core/DiagonalMatrix.h index e6c220f4..5a9e3abd 100644 --- a/nuparu/include/Eigen/src/Core/DiagonalMatrix.h +++ b/nuparu/include/Eigen/src/Core/DiagonalMatrix.h @@ -22,7 +22,7 @@ class DiagonalBase : public EigenBase typedef typename DiagonalVectorType::Scalar Scalar; typedef typename DiagonalVectorType::RealScalar RealScalar; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; + typedef typename internal::traits::StorageIndex StorageIndex; enum { RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, @@ -30,79 +30,62 @@ class DiagonalBase : public EigenBase MaxRowsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, MaxColsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, IsVectorAtCompileTime = 0, - Flags = 0 + Flags = NoPreferredStorageOrderBit }; typedef Matrix DenseMatrixType; typedef DenseMatrixType DenseType; typedef DiagonalMatrix PlainObject; + EIGEN_DEVICE_FUNC inline const Derived& derived() const { return *static_cast(this); } + EIGEN_DEVICE_FUNC inline Derived& derived() { return *static_cast(this); } + EIGEN_DEVICE_FUNC DenseMatrixType toDenseMatrix() const { return derived(); } - template - void evalTo(MatrixBase &other) const; - template - void addTo(MatrixBase &other) const - { other.diagonal() += diagonal(); } - template - void subTo(MatrixBase &other) const - { other.diagonal() -= diagonal(); } - + + EIGEN_DEVICE_FUNC inline const DiagonalVectorType& diagonal() const { return derived().diagonal(); } + EIGEN_DEVICE_FUNC inline DiagonalVectorType& diagonal() { return derived().diagonal(); } + EIGEN_DEVICE_FUNC inline Index rows() const { return diagonal().size(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return diagonal().size(); } - /** \returns the diagonal matrix product of \c *this by the matrix \a matrix. - */ template - const DiagonalProduct + EIGEN_DEVICE_FUNC + const Product operator*(const MatrixBase &matrix) const { - return DiagonalProduct(matrix.derived(), derived()); + return Product(derived(),matrix.derived()); } - inline const DiagonalWrapper, const DiagonalVectorType> > + typedef DiagonalWrapper, const DiagonalVectorType> > InverseReturnType; + EIGEN_DEVICE_FUNC + inline const InverseReturnType inverse() const { - return diagonal().cwiseInverse(); + return InverseReturnType(diagonal().cwiseInverse()); } - inline const DiagonalWrapper, const DiagonalVectorType> > + typedef DiagonalWrapper, const DiagonalVectorType> > ScalarMultipleReturnType; + EIGEN_DEVICE_FUNC + inline const ScalarMultipleReturnType operator*(const Scalar& scalar) const { - return diagonal() * scalar; + return ScalarMultipleReturnType(diagonal() * scalar); } - friend inline const DiagonalWrapper, const DiagonalVectorType> > + EIGEN_DEVICE_FUNC + friend inline const ScalarMultipleReturnType operator*(const Scalar& scalar, const DiagonalBase& other) { - return other.diagonal() * scalar; - } - - #ifdef EIGEN2_SUPPORT - template - bool isApprox(const DiagonalBase& other, typename NumTraits::Real precision = NumTraits::dummy_precision()) const - { - return diagonal().isApprox(other.diagonal(), precision); + return ScalarMultipleReturnType(other.diagonal() * scalar); } - template - bool isApprox(const MatrixBase& other, typename NumTraits::Real precision = NumTraits::dummy_precision()) const - { - return toDenseMatrix().isApprox(other, precision); - } - #endif }; -template -template -void DiagonalBase::evalTo(MatrixBase &other) const -{ - other.setZero(); - other.diagonal() = diagonal(); -} #endif /** \class DiagonalMatrix @@ -124,10 +107,9 @@ struct traits > : traits > { typedef Matrix<_Scalar,SizeAtCompileTime,1,0,MaxSizeAtCompileTime,1> DiagonalVectorType; - typedef Dense StorageKind; - typedef DenseIndex Index; + typedef DiagonalShape StorageKind; enum { - Flags = LvalueBit + Flags = LvalueBit | NoPreferredStorageOrderBit }; }; } @@ -141,7 +123,7 @@ class DiagonalMatrix typedef const DiagonalMatrix& Nested; typedef _Scalar Scalar; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; + typedef typename internal::traits::StorageIndex StorageIndex; #endif protected: @@ -151,24 +133,31 @@ class DiagonalMatrix public: /** const version of diagonal(). */ + EIGEN_DEVICE_FUNC inline const DiagonalVectorType& diagonal() const { return m_diagonal; } /** \returns a reference to the stored vector of diagonal coefficients. */ + EIGEN_DEVICE_FUNC inline DiagonalVectorType& diagonal() { return m_diagonal; } /** Default constructor without initialization */ + EIGEN_DEVICE_FUNC inline DiagonalMatrix() {} /** Constructs a diagonal matrix with given dimension */ - inline DiagonalMatrix(Index dim) : m_diagonal(dim) {} + EIGEN_DEVICE_FUNC + explicit inline DiagonalMatrix(Index dim) : m_diagonal(dim) {} /** 2D constructor. */ + EIGEN_DEVICE_FUNC inline DiagonalMatrix(const Scalar& x, const Scalar& y) : m_diagonal(x,y) {} /** 3D constructor. */ + EIGEN_DEVICE_FUNC inline DiagonalMatrix(const Scalar& x, const Scalar& y, const Scalar& z) : m_diagonal(x,y,z) {} /** Copy constructor. */ template + EIGEN_DEVICE_FUNC inline DiagonalMatrix(const DiagonalBase& other) : m_diagonal(other.diagonal()) {} #ifndef EIGEN_PARSED_BY_DOXYGEN @@ -178,11 +167,13 @@ class DiagonalMatrix /** generic constructor from expression of the diagonal coefficients */ template + EIGEN_DEVICE_FUNC explicit inline DiagonalMatrix(const MatrixBase& other) : m_diagonal(other) {} /** Copy operator. */ template + EIGEN_DEVICE_FUNC DiagonalMatrix& operator=(const DiagonalBase& other) { m_diagonal = other.diagonal(); @@ -193,6 +184,7 @@ class DiagonalMatrix /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. */ + EIGEN_DEVICE_FUNC DiagonalMatrix& operator=(const DiagonalMatrix& other) { m_diagonal = other.diagonal(); @@ -201,14 +193,19 @@ class DiagonalMatrix #endif /** Resizes to given size. */ + EIGEN_DEVICE_FUNC inline void resize(Index size) { m_diagonal.resize(size); } /** Sets all coefficients to zero. */ + EIGEN_DEVICE_FUNC inline void setZero() { m_diagonal.setZero(); } /** Resizes and sets all coefficients to zero. */ + EIGEN_DEVICE_FUNC inline void setZero(Index size) { m_diagonal.setZero(size); } /** Sets this matrix to be the identity matrix of the current size. */ + EIGEN_DEVICE_FUNC inline void setIdentity() { m_diagonal.setOnes(); } /** Sets this matrix to be the identity matrix of the given size. */ + EIGEN_DEVICE_FUNC inline void setIdentity(Index size) { m_diagonal.setOnes(size); } }; @@ -232,14 +229,15 @@ struct traits > { typedef _DiagonalVectorType DiagonalVectorType; typedef typename DiagonalVectorType::Scalar Scalar; - typedef typename DiagonalVectorType::Index Index; - typedef typename DiagonalVectorType::StorageKind StorageKind; + typedef typename DiagonalVectorType::StorageIndex StorageIndex; + typedef DiagonalShape StorageKind; + typedef typename traits::XprKind XprKind; enum { RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, ColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, - MaxRowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, - MaxColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, - Flags = traits::Flags & LvalueBit + MaxRowsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, + MaxColsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, + Flags = (traits::Flags & LvalueBit) | NoPreferredStorageOrderBit }; }; } @@ -255,9 +253,11 @@ class DiagonalWrapper #endif /** Constructor from expression of diagonal coefficients to wrap. */ - inline DiagonalWrapper(DiagonalVectorType& a_diagonal) : m_diagonal(a_diagonal) {} + EIGEN_DEVICE_FUNC + explicit inline DiagonalWrapper(DiagonalVectorType& a_diagonal) : m_diagonal(a_diagonal) {} /** \returns a const reference to the wrapped expression of diagonal coefficients. */ + EIGEN_DEVICE_FUNC const DiagonalVectorType& diagonal() const { return m_diagonal; } protected: @@ -277,7 +277,7 @@ template inline const DiagonalWrapper MatrixBase::asDiagonal() const { - return derived(); + return DiagonalWrapper(derived()); } /** \returns true if *this is approximately equal to a diagonal matrix, @@ -308,6 +308,33 @@ bool MatrixBase::isDiagonal(const RealScalar& prec) const return true; } +namespace internal { + +template<> struct storage_kind_to_shape { typedef DiagonalShape Shape; }; + +struct Diagonal2Dense {}; + +template<> struct AssignmentKind { typedef Diagonal2Dense Kind; }; + +// Diagonal matrix to Dense assignment +template< typename DstXprType, typename SrcXprType, typename Functor, typename Scalar> +struct Assignment +{ + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &/*func*/) + { + dst.setZero(); + dst.diagonal() = src.diagonal(); + } + + static void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &/*func*/) + { dst.diagonal() += src.diagonal(); } + + static void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &/*func*/) + { dst.diagonal() -= src.diagonal(); } +}; + +} // namespace internal + } // end namespace Eigen #endif // EIGEN_DIAGONALMATRIX_H diff --git a/nuparu/include/Eigen/src/Core/DiagonalProduct.h b/nuparu/include/Eigen/src/Core/DiagonalProduct.h index c03a0c2e..d372b938 100644 --- a/nuparu/include/Eigen/src/Core/DiagonalProduct.h +++ b/nuparu/include/Eigen/src/Core/DiagonalProduct.h @@ -13,116 +13,14 @@ namespace Eigen { -namespace internal { -template -struct traits > - : traits -{ - typedef typename scalar_product_traits::ReturnType Scalar; - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime, - MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, - MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, - - _StorageOrder = MatrixType::Flags & RowMajorBit ? RowMajor : ColMajor, - _ScalarAccessOnDiag = !((int(_StorageOrder) == ColMajor && int(ProductOrder) == OnTheLeft) - ||(int(_StorageOrder) == RowMajor && int(ProductOrder) == OnTheRight)), - _SameTypes = is_same::value, - // FIXME currently we need same types, but in the future the next rule should be the one - //_Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && ((!_PacketOnDiag) || (_SameTypes && bool(int(DiagonalType::DiagonalVectorType::Flags)&PacketAccessBit))), - _Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && _SameTypes && (_ScalarAccessOnDiag || (bool(int(DiagonalType::DiagonalVectorType::Flags)&PacketAccessBit))), - _LinearAccessMask = (RowsAtCompileTime==1 || ColsAtCompileTime==1) ? LinearAccessBit : 0, - - Flags = ((HereditaryBits|_LinearAccessMask) & (unsigned int)(MatrixType::Flags)) | (_Vectorizable ? PacketAccessBit : 0) | AlignedBit,//(int(MatrixType::Flags)&int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit), - CoeffReadCost = NumTraits::MulCost + MatrixType::CoeffReadCost + DiagonalType::DiagonalVectorType::CoeffReadCost - }; -}; -} - -template -class DiagonalProduct : internal::no_assignment_operator, - public MatrixBase > -{ - public: - - typedef MatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(DiagonalProduct) - - inline DiagonalProduct(const MatrixType& matrix, const DiagonalType& diagonal) - : m_matrix(matrix), m_diagonal(diagonal) - { - eigen_assert(diagonal.diagonal().size() == (ProductOrder == OnTheLeft ? matrix.rows() : matrix.cols())); - } - - EIGEN_STRONG_INLINE Index rows() const { return m_matrix.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return m_matrix.cols(); } - - EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const - { - return m_diagonal.diagonal().coeff(ProductOrder == OnTheLeft ? row : col) * m_matrix.coeff(row, col); - } - - EIGEN_STRONG_INLINE const Scalar coeff(Index idx) const - { - enum { - StorageOrder = int(MatrixType::Flags) & RowMajorBit ? RowMajor : ColMajor - }; - return coeff(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const - { - enum { - StorageOrder = Flags & RowMajorBit ? RowMajor : ColMajor - }; - const Index indexInDiagonalVector = ProductOrder == OnTheLeft ? row : col; - return packet_impl(row,col,indexInDiagonalVector,typename internal::conditional< - ((int(StorageOrder) == RowMajor && int(ProductOrder) == OnTheLeft) - ||(int(StorageOrder) == ColMajor && int(ProductOrder) == OnTheRight)), internal::true_type, internal::false_type>::type()); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index idx) const - { - enum { - StorageOrder = int(MatrixType::Flags) & RowMajorBit ? RowMajor : ColMajor - }; - return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); - } - - protected: - template - EIGEN_STRONG_INLINE PacketScalar packet_impl(Index row, Index col, Index id, internal::true_type) const - { - return internal::pmul(m_matrix.template packet(row, col), - internal::pset1(m_diagonal.diagonal().coeff(id))); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet_impl(Index row, Index col, Index id, internal::false_type) const - { - enum { - InnerSize = (MatrixType::Flags & RowMajorBit) ? MatrixType::ColsAtCompileTime : MatrixType::RowsAtCompileTime, - DiagonalVectorPacketLoadMode = (LoadMode == Aligned && (((InnerSize%16) == 0) || (int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit)==AlignedBit) ? Aligned : Unaligned) - }; - return internal::pmul(m_matrix.template packet(row, col), - m_diagonal.diagonal().template packet(id)); - } - - typename MatrixType::Nested m_matrix; - typename DiagonalType::Nested m_diagonal; -}; - /** \returns the diagonal matrix product of \c *this by the diagonal matrix \a diagonal. */ template template -inline const DiagonalProduct +inline const Product MatrixBase::operator*(const DiagonalBase &a_diagonal) const { - return DiagonalProduct(derived(), a_diagonal.derived()); + return Product(derived(),a_diagonal.derived()); } } // end namespace Eigen diff --git a/nuparu/include/Eigen/src/Core/Dot.h b/nuparu/include/Eigen/src/Core/Dot.h index 9d7651f1..003450f1 100644 --- a/nuparu/include/Eigen/src/Core/Dot.h +++ b/nuparu/include/Eigen/src/Core/Dot.h @@ -29,6 +29,7 @@ template::Scalar,typename traits::Scalar>::ReturnType ResScalar; + EIGEN_DEVICE_FUNC static inline ResScalar run(const MatrixBase& a, const MatrixBase& b) { return a.template binaryExpr::Scalar,typename traits::Scalar> >(b).sum(); @@ -39,6 +40,7 @@ template struct dot_nocheck { typedef typename scalar_product_traits::Scalar,typename traits::Scalar>::ReturnType ResScalar; + EIGEN_DEVICE_FUNC static inline ResScalar run(const MatrixBase& a, const MatrixBase& b) { return a.transpose().template binaryExpr::Scalar,typename traits::Scalar> >(b).sum(); @@ -59,6 +61,7 @@ struct dot_nocheck */ template template +EIGEN_DEVICE_FUNC typename internal::scalar_product_traits::Scalar,typename internal::traits::Scalar>::ReturnType MatrixBase::dot(const MatrixBase& other) const { @@ -73,34 +76,6 @@ MatrixBase::dot(const MatrixBase& other) const return internal::dot_nocheck::run(*this, other); } -#ifdef EIGEN2_SUPPORT -/** \returns the dot product of *this with other, with the Eigen2 convention that the dot product is linear in the first variable - * (conjugating the second variable). Of course this only makes a difference in the complex case. - * - * This method is only available in EIGEN2_SUPPORT mode. - * - * \only_for_vectors - * - * \sa dot() - */ -template -template -typename internal::traits::Scalar -MatrixBase::eigen2_dot(const MatrixBase& other) const -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) - EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived) - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - - eigen_assert(size() == other.size()); - - return internal::dot_nocheck::run(other,*this); -} -#endif - - //---------- implementation of L2 norm and related functions ---------- /** \returns, for vectors, the squared \em l2 norm of \c *this, and for matrices the Frobenius norm. @@ -124,7 +99,7 @@ EIGEN_STRONG_INLINE typename NumTraits::Scala template inline typename NumTraits::Scalar>::Real MatrixBase::norm() const { - using std::sqrt; + EIGEN_USING_STD_MATH(sqrt) return sqrt(squaredNorm()); } @@ -138,8 +113,7 @@ template inline const typename MatrixBase::PlainObject MatrixBase::normalized() const { - typedef typename internal::nested::type Nested; - typedef typename internal::remove_reference::type _Nested; + typedef typename internal::nested_eval::type _Nested; _Nested n(derived()); return n / n.norm(); } @@ -164,9 +138,10 @@ template struct lpNorm_selector { typedef typename NumTraits::Scalar>::Real RealScalar; + EIGEN_DEVICE_FUNC static inline RealScalar run(const MatrixBase& m) { - using std::pow; + EIGEN_USING_STD_MATH(pow) return pow(m.cwiseAbs().array().pow(p).sum(), RealScalar(1)/p); } }; @@ -174,6 +149,7 @@ struct lpNorm_selector template struct lpNorm_selector { + EIGEN_DEVICE_FUNC static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) { return m.cwiseAbs().sum(); @@ -183,6 +159,7 @@ struct lpNorm_selector template struct lpNorm_selector { + EIGEN_DEVICE_FUNC static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) { return m.norm(); @@ -192,6 +169,7 @@ struct lpNorm_selector template struct lpNorm_selector { + EIGEN_DEVICE_FUNC static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) { return m.cwiseAbs().maxCoeff(); @@ -200,9 +178,11 @@ struct lpNorm_selector } // end namespace internal -/** \returns the \f$ \ell^p \f$ norm of *this, that is, returns the p-th root of the sum of the p-th powers of the absolute values - * of the coefficients of *this. If \a p is the special value \a Eigen::Infinity, this function returns the \f$ \ell^\infty \f$ - * norm, that is the maximum of the absolute values of the coefficients of *this. +/** \returns the \b coefficient-wise \f$ \ell^p \f$ norm of \c *this, that is, returns the p-th root of the sum of the p-th powers of the absolute values + * of the coefficients of \c *this. If \a p is the special value \a Eigen::Infinity, this function returns the \f$ \ell^\infty \f$ + * norm, that is the maximum of the absolute values of the coefficients of \c *this. + * + * \note For matrices, this function does not compute the operator-norm. That is, if \c *this is a matrix, then its coefficients are interpreted as a 1D vector. Nonetheless, you can easily compute the 1-norm and \f$\infty\f$-norm matrix operator norms using \link TutorialReductionsVisitorsBroadcastingReductionsNorm partial reductions \endlink. * * \sa norm() */ @@ -227,8 +207,8 @@ template bool MatrixBase::isOrthogonal (const MatrixBase& other, const RealScalar& prec) const { - typename internal::nested::type nested(derived()); - typename internal::nested::type otherNested(other.derived()); + typename internal::nested_eval::type nested(derived()); + typename internal::nested_eval::type otherNested(other.derived()); return numext::abs2(nested.dot(otherNested)) <= prec * prec * nested.squaredNorm() * otherNested.squaredNorm(); } @@ -246,13 +226,13 @@ bool MatrixBase::isOrthogonal template bool MatrixBase::isUnitary(const RealScalar& prec) const { - typename Derived::Nested nested(derived()); + typename internal::nested_eval::type self(derived()); for(Index i = 0; i < cols(); ++i) { - if(!internal::isApprox(nested.col(i).squaredNorm(), static_cast(1), prec)) + if(!internal::isApprox(self.col(i).squaredNorm(), static_cast(1), prec)) return false; for(Index j = 0; j < i; ++j) - if(!internal::isMuchSmallerThan(nested.col(i).dot(nested.col(j)), static_cast(1), prec)) + if(!internal::isMuchSmallerThan(self.col(i).dot(self.col(j)), static_cast(1), prec)) return false; } return true; diff --git a/nuparu/include/Eigen/src/Core/EigenBase.h b/nuparu/include/Eigen/src/Core/EigenBase.h index 2b8dd1b7..79dabda3 100644 --- a/nuparu/include/Eigen/src/Core/EigenBase.h +++ b/nuparu/include/Eigen/src/Core/EigenBase.h @@ -13,7 +13,9 @@ namespace Eigen { -/** Common base class for all classes T such that MatrixBase has an operator=(T) and a constructor MatrixBase(T). +/** \class EigenBase + * + * Common base class for all classes T such that MatrixBase has an operator=(T) and a constructor MatrixBase(T). * * In other words, an EigenBase object is an object that can be copied into a MatrixBase. * @@ -26,34 +28,52 @@ namespace Eigen { template struct EigenBase { // typedef typename internal::plain_matrix_type::type PlainObject; - + + /** \brief The interface type of indices + * \details To change this, \c \#define the preprocessor symbol \c EIGEN_DEFAULT_DENSE_INDEX_TYPE. + * \deprecated Since Eigen 3.3, its usage is deprecated. Use Eigen::Index instead. + * \sa StorageIndex, \ref TopicPreprocessorDirectives. + */ + typedef Eigen::Index Index; + + // FIXME is it needed? typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; /** \returns a reference to the derived object */ + EIGEN_DEVICE_FUNC Derived& derived() { return *static_cast(this); } /** \returns a const reference to the derived object */ + EIGEN_DEVICE_FUNC const Derived& derived() const { return *static_cast(this); } + EIGEN_DEVICE_FUNC inline Derived& const_cast_derived() const { return *static_cast(const_cast(this)); } + EIGEN_DEVICE_FUNC inline const Derived& const_derived() const { return *static_cast(this); } /** \returns the number of rows. \sa cols(), RowsAtCompileTime */ + EIGEN_DEVICE_FUNC inline Index rows() const { return derived().rows(); } /** \returns the number of columns. \sa rows(), ColsAtCompileTime*/ + EIGEN_DEVICE_FUNC inline Index cols() const { return derived().cols(); } /** \returns the number of coefficients, which is rows()*cols(). * \sa rows(), cols(), SizeAtCompileTime. */ + EIGEN_DEVICE_FUNC inline Index size() const { return rows() * cols(); } /** \internal Don't use it, but do the equivalent: \code dst = *this; \endcode */ - template inline void evalTo(Dest& dst) const + template + EIGEN_DEVICE_FUNC + inline void evalTo(Dest& dst) const { derived().evalTo(dst); } /** \internal Don't use it, but do the equivalent: \code dst += *this; \endcode */ - template inline void addTo(Dest& dst) const + template + EIGEN_DEVICE_FUNC + inline void addTo(Dest& dst) const { // This is the default implementation, // derived class can reimplement it in a more optimized way. @@ -63,7 +83,9 @@ template struct EigenBase } /** \internal Don't use it, but do the equivalent: \code dst -= *this; \endcode */ - template inline void subTo(Dest& dst) const + template + EIGEN_DEVICE_FUNC + inline void subTo(Dest& dst) const { // This is the default implementation, // derived class can reimplement it in a more optimized way. @@ -73,7 +95,8 @@ template struct EigenBase } /** \internal Don't use it, but do the equivalent: \code dst.applyOnTheRight(*this); \endcode */ - template inline void applyThisOnTheRight(Dest& dst) const + template + EIGEN_DEVICE_FUNC inline void applyThisOnTheRight(Dest& dst) const { // This is the default implementation, // derived class can reimplement it in a more optimized way. @@ -81,7 +104,8 @@ template struct EigenBase } /** \internal Don't use it, but do the equivalent: \code dst.applyOnTheLeft(*this); \endcode */ - template inline void applyThisOnTheLeft(Dest& dst) const + template + EIGEN_DEVICE_FUNC inline void applyThisOnTheLeft(Dest& dst) const { // This is the default implementation, // derived class can reimplement it in a more optimized way. @@ -106,7 +130,7 @@ template template Derived& DenseBase::operator=(const EigenBase &other) { - other.derived().evalTo(derived()); + call_assignment(derived(), other.derived()); return derived(); } @@ -114,7 +138,7 @@ template template Derived& DenseBase::operator+=(const EigenBase &other) { - other.derived().addTo(derived()); + call_assignment(derived(), other.derived(), internal::add_assign_op()); return derived(); } @@ -122,40 +146,10 @@ template template Derived& DenseBase::operator-=(const EigenBase &other) { - other.derived().subTo(derived()); - return derived(); -} - -/** replaces \c *this by \c *this * \a other. - * - * \returns a reference to \c *this - */ -template -template -inline Derived& -MatrixBase::operator*=(const EigenBase &other) -{ - other.derived().applyThisOnTheRight(derived()); + call_assignment(derived(), other.derived(), internal::sub_assign_op()); return derived(); } -/** replaces \c *this by \c *this * \a other. It is equivalent to MatrixBase::operator*=(). - */ -template -template -inline void MatrixBase::applyOnTheRight(const EigenBase &other) -{ - other.derived().applyThisOnTheRight(derived()); -} - -/** replaces \c *this by \c *this * \a other. */ -template -template -inline void MatrixBase::applyOnTheLeft(const EigenBase &other) -{ - other.derived().applyThisOnTheLeft(derived()); -} - } // end namespace Eigen #endif // EIGEN_EIGENBASE_H diff --git a/nuparu/include/Eigen/src/Core/Flagged.h b/nuparu/include/Eigen/src/Core/Flagged.h deleted file mode 100644 index 1f2955fc..00000000 --- a/nuparu/include/Eigen/src/Core/Flagged.h +++ /dev/null @@ -1,140 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_FLAGGED_H -#define EIGEN_FLAGGED_H - -namespace Eigen { - -/** \class Flagged - * \ingroup Core_Module - * - * \brief Expression with modified flags - * - * \param ExpressionType the type of the object of which we are modifying the flags - * \param Added the flags added to the expression - * \param Removed the flags removed from the expression (has priority over Added). - * - * This class represents an expression whose flags have been modified. - * It is the return type of MatrixBase::flagged() - * and most of the time this is the only way it is used. - * - * \sa MatrixBase::flagged() - */ - -namespace internal { -template -struct traits > : traits -{ - enum { Flags = (ExpressionType::Flags | Added) & ~Removed }; -}; -} - -template class Flagged - : public MatrixBase > -{ - public: - - typedef MatrixBase Base; - - EIGEN_DENSE_PUBLIC_INTERFACE(Flagged) - typedef typename internal::conditional::ret, - ExpressionType, const ExpressionType&>::type ExpressionTypeNested; - typedef typename ExpressionType::InnerIterator InnerIterator; - - inline Flagged(const ExpressionType& matrix) : m_matrix(matrix) {} - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - inline Index outerStride() const { return m_matrix.outerStride(); } - inline Index innerStride() const { return m_matrix.innerStride(); } - - inline CoeffReturnType coeff(Index row, Index col) const - { - return m_matrix.coeff(row, col); - } - - inline CoeffReturnType coeff(Index index) const - { - return m_matrix.coeff(index); - } - - inline const Scalar& coeffRef(Index row, Index col) const - { - return m_matrix.const_cast_derived().coeffRef(row, col); - } - - inline const Scalar& coeffRef(Index index) const - { - return m_matrix.const_cast_derived().coeffRef(index); - } - - inline Scalar& coeffRef(Index row, Index col) - { - return m_matrix.const_cast_derived().coeffRef(row, col); - } - - inline Scalar& coeffRef(Index index) - { - return m_matrix.const_cast_derived().coeffRef(index); - } - - template - inline const PacketScalar packet(Index row, Index col) const - { - return m_matrix.template packet(row, col); - } - - template - inline void writePacket(Index row, Index col, const PacketScalar& x) - { - m_matrix.const_cast_derived().template writePacket(row, col, x); - } - - template - inline const PacketScalar packet(Index index) const - { - return m_matrix.template packet(index); - } - - template - inline void writePacket(Index index, const PacketScalar& x) - { - m_matrix.const_cast_derived().template writePacket(index, x); - } - - const ExpressionType& _expression() const { return m_matrix; } - - template - typename ExpressionType::PlainObject solveTriangular(const MatrixBase& other) const; - - template - void solveTriangularInPlace(const MatrixBase& other) const; - - protected: - ExpressionTypeNested m_matrix; -}; - -/** \returns an expression of *this with added and removed flags - * - * This is mostly for internal use. - * - * \sa class Flagged - */ -template -template -inline const Flagged -DenseBase::flagged() const -{ - return derived(); -} - -} // end namespace Eigen - -#endif // EIGEN_FLAGGED_H diff --git a/nuparu/include/Eigen/src/Core/ForceAlignedAccess.h b/nuparu/include/Eigen/src/Core/ForceAlignedAccess.h index 807c7a29..7b08b45e 100644 --- a/nuparu/include/Eigen/src/Core/ForceAlignedAccess.h +++ b/nuparu/include/Eigen/src/Core/ForceAlignedAccess.h @@ -39,29 +39,29 @@ template class ForceAlignedAccess typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(ForceAlignedAccess) - inline ForceAlignedAccess(const ExpressionType& matrix) : m_expression(matrix) {} + EIGEN_DEVICE_FUNC explicit inline ForceAlignedAccess(const ExpressionType& matrix) : m_expression(matrix) {} - inline Index rows() const { return m_expression.rows(); } - inline Index cols() const { return m_expression.cols(); } - inline Index outerStride() const { return m_expression.outerStride(); } - inline Index innerStride() const { return m_expression.innerStride(); } + EIGEN_DEVICE_FUNC inline Index rows() const { return m_expression.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_expression.cols(); } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_expression.outerStride(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_expression.innerStride(); } - inline const CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index row, Index col) const { return m_expression.coeff(row, col); } - inline Scalar& coeffRef(Index row, Index col) + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index col) { return m_expression.const_cast_derived().coeffRef(row, col); } - inline const CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index index) const { return m_expression.coeff(index); } - inline Scalar& coeffRef(Index index) + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index index) { return m_expression.const_cast_derived().coeffRef(index); } @@ -90,7 +90,7 @@ template class ForceAlignedAccess m_expression.const_cast_derived().template writePacket(index, x); } - operator const ExpressionType&() const { return m_expression; } + EIGEN_DEVICE_FUNC operator const ExpressionType&() const { return m_expression; } protected: const ExpressionType& m_expression; @@ -127,7 +127,7 @@ template inline typename internal::add_const_on_value_type,Derived&>::type>::type MatrixBase::forceAlignedAccessIf() const { - return derived(); + return derived(); // FIXME This should not work but apparently is never used } /** \returns an expression of *this with forced aligned access if \a Enable is true. @@ -138,7 +138,7 @@ template inline typename internal::conditional,Derived&>::type MatrixBase::forceAlignedAccessIf() { - return derived(); + return derived(); // FIXME This should not work but apparently is never used } } // end namespace Eigen diff --git a/nuparu/include/Eigen/src/Core/Functors.h b/nuparu/include/Eigen/src/Core/Functors.h deleted file mode 100644 index 04fb2173..00000000 --- a/nuparu/include/Eigen/src/Core/Functors.h +++ /dev/null @@ -1,985 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_FUNCTORS_H -#define EIGEN_FUNCTORS_H - -namespace Eigen { - -namespace internal { - -// associative functors: - -/** \internal - * \brief Template functor to compute the sum of two scalars - * - * \sa class CwiseBinaryOp, MatrixBase::operator+, class VectorwiseOp, MatrixBase::sum() - */ -template struct scalar_sum_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_sum_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { return a + b; } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::padd(a,b); } - template - EIGEN_STRONG_INLINE const Scalar predux(const Packet& a) const - { return internal::predux(a); } -}; -template -struct functor_traits > { - enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasAdd - }; -}; - -/** \internal - * \brief Template functor to compute the product of two scalars - * - * \sa class CwiseBinaryOp, Cwise::operator*(), class VectorwiseOp, MatrixBase::redux() - */ -template struct scalar_product_op { - enum { - // TODO vectorize mixed product - Vectorizable = is_same::value && packet_traits::HasMul && packet_traits::HasMul - }; - typedef typename scalar_product_traits::ReturnType result_type; - EIGEN_EMPTY_STRUCT_CTOR(scalar_product_op) - EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a * b; } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pmul(a,b); } - template - EIGEN_STRONG_INLINE const result_type predux(const Packet& a) const - { return internal::predux_mul(a); } -}; -template -struct functor_traits > { - enum { - Cost = (NumTraits::MulCost + NumTraits::MulCost)/2, // rough estimate! - PacketAccess = scalar_product_op::Vectorizable - }; -}; - -/** \internal - * \brief Template functor to compute the conjugate product of two scalars - * - * This is a short cut for conj(x) * y which is needed for optimization purpose; in Eigen2 support mode, this becomes x * conj(y) - */ -template struct scalar_conj_product_op { - - enum { - Conj = NumTraits::IsComplex - }; - - typedef typename scalar_product_traits::ReturnType result_type; - - EIGEN_EMPTY_STRUCT_CTOR(scalar_conj_product_op) - EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const - { return conj_helper().pmul(a,b); } - - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return conj_helper().pmul(a,b); } -}; -template -struct functor_traits > { - enum { - Cost = NumTraits::MulCost, - PacketAccess = internal::is_same::value && packet_traits::HasMul - }; -}; - -/** \internal - * \brief Template functor to compute the min of two scalars - * - * \sa class CwiseBinaryOp, MatrixBase::cwiseMin, class VectorwiseOp, MatrixBase::minCoeff() - */ -template struct scalar_min_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_min_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { using std::min; return (min)(a, b); } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pmin(a,b); } - template - EIGEN_STRONG_INLINE const Scalar predux(const Packet& a) const - { return internal::predux_min(a); } -}; -template -struct functor_traits > { - enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasMin - }; -}; - -/** \internal - * \brief Template functor to compute the max of two scalars - * - * \sa class CwiseBinaryOp, MatrixBase::cwiseMax, class VectorwiseOp, MatrixBase::maxCoeff() - */ -template struct scalar_max_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_max_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { using std::max; return (max)(a, b); } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pmax(a,b); } - template - EIGEN_STRONG_INLINE const Scalar predux(const Packet& a) const - { return internal::predux_max(a); } -}; -template -struct functor_traits > { - enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasMax - }; -}; - -/** \internal - * \brief Template functor to compute the hypot of two scalars - * - * \sa MatrixBase::stableNorm(), class Redux - */ -template struct scalar_hypot_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_hypot_op) -// typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& _x, const Scalar& _y) const - { - using std::max; - using std::min; - using std::sqrt; - Scalar p = (max)(_x, _y); - Scalar q = (min)(_x, _y); - Scalar qp = q/p; - return p * sqrt(Scalar(1) + qp*qp); - } -}; -template -struct functor_traits > { - enum { Cost = 5 * NumTraits::MulCost, PacketAccess=0 }; -}; - -/** \internal - * \brief Template functor to compute the pow of two scalars - */ -template struct scalar_binary_pow_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_binary_pow_op) - inline Scalar operator() (const Scalar& a, const OtherScalar& b) const { return numext::pow(a, b); } -}; -template -struct functor_traits > { - enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false }; -}; - -// other binary functors: - -/** \internal - * \brief Template functor to compute the difference of two scalars - * - * \sa class CwiseBinaryOp, MatrixBase::operator- - */ -template struct scalar_difference_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_difference_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { return a - b; } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::psub(a,b); } -}; -template -struct functor_traits > { - enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasSub - }; -}; - -/** \internal - * \brief Template functor to compute the quotient of two scalars - * - * \sa class CwiseBinaryOp, Cwise::operator/() - */ -template struct scalar_quotient_op { - enum { - // TODO vectorize mixed product - Vectorizable = is_same::value && packet_traits::HasDiv && packet_traits::HasDiv - }; - typedef typename scalar_product_traits::ReturnType result_type; - EIGEN_EMPTY_STRUCT_CTOR(scalar_quotient_op) - EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a / b; } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pdiv(a,b); } -}; -template -struct functor_traits > { - enum { - Cost = (NumTraits::MulCost + NumTraits::MulCost), // rough estimate! - PacketAccess = scalar_quotient_op::Vectorizable - }; -}; - - - -/** \internal - * \brief Template functor to compute the and of two booleans - * - * \sa class CwiseBinaryOp, ArrayBase::operator&& - */ -struct scalar_boolean_and_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_boolean_and_op) - EIGEN_STRONG_INLINE bool operator() (const bool& a, const bool& b) const { return a && b; } -}; -template<> struct functor_traits { - enum { - Cost = NumTraits::AddCost, - PacketAccess = false - }; -}; - -/** \internal - * \brief Template functor to compute the or of two booleans - * - * \sa class CwiseBinaryOp, ArrayBase::operator|| - */ -struct scalar_boolean_or_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_boolean_or_op) - EIGEN_STRONG_INLINE bool operator() (const bool& a, const bool& b) const { return a || b; } -}; -template<> struct functor_traits { - enum { - Cost = NumTraits::AddCost, - PacketAccess = false - }; -}; - -// unary functors: - -/** \internal - * \brief Template functor to compute the opposite of a scalar - * - * \sa class CwiseUnaryOp, MatrixBase::operator- - */ -template struct scalar_opposite_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_opposite_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { return -a; } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const - { return internal::pnegate(a); } -}; -template -struct functor_traits > -{ enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasNegate }; -}; - -/** \internal - * \brief Template functor to compute the absolute value of a scalar - * - * \sa class CwiseUnaryOp, Cwise::abs - */ -template struct scalar_abs_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_abs_op) - typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a) const { using std::abs; return abs(a); } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const - { return internal::pabs(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasAbs - }; -}; - -/** \internal - * \brief Template functor to compute the squared absolute value of a scalar - * - * \sa class CwiseUnaryOp, Cwise::abs2 - */ -template struct scalar_abs2_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_abs2_op) - typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a) const { return numext::abs2(a); } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const - { return internal::pmul(a,a); } -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasAbs2 }; }; - -/** \internal - * \brief Template functor to compute the conjugate of a complex value - * - * \sa class CwiseUnaryOp, MatrixBase::conjugate() - */ -template struct scalar_conjugate_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_conjugate_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { using numext::conj; return conj(a); } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const { return internal::pconj(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = NumTraits::IsComplex ? NumTraits::AddCost : 0, - PacketAccess = packet_traits::HasConj - }; -}; - -/** \internal - * \brief Template functor to cast a scalar to another type - * - * \sa class CwiseUnaryOp, MatrixBase::cast() - */ -template -struct scalar_cast_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cast_op) - typedef NewType result_type; - EIGEN_STRONG_INLINE const NewType operator() (const Scalar& a) const { return cast(a); } -}; -template -struct functor_traits > -{ enum { Cost = is_same::value ? 0 : NumTraits::AddCost, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to extract the real part of a complex - * - * \sa class CwiseUnaryOp, MatrixBase::real() - */ -template -struct scalar_real_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_real_op) - typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return numext::real(a); } -}; -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to extract the imaginary part of a complex - * - * \sa class CwiseUnaryOp, MatrixBase::imag() - */ -template -struct scalar_imag_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_imag_op) - typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return numext::imag(a); } -}; -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to extract the real part of a complex as a reference - * - * \sa class CwiseUnaryOp, MatrixBase::real() - */ -template -struct scalar_real_ref_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_real_ref_op) - typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE result_type& operator() (const Scalar& a) const { return numext::real_ref(*const_cast(&a)); } -}; -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to extract the imaginary part of a complex as a reference - * - * \sa class CwiseUnaryOp, MatrixBase::imag() - */ -template -struct scalar_imag_ref_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_imag_ref_op) - typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE result_type& operator() (const Scalar& a) const { return numext::imag_ref(*const_cast(&a)); } -}; -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -/** \internal - * - * \brief Template functor to compute the exponential of a scalar - * - * \sa class CwiseUnaryOp, Cwise::exp() - */ -template struct scalar_exp_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_exp_op) - inline const Scalar operator() (const Scalar& a) const { using std::exp; return exp(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::pexp(a); } -}; -template -struct functor_traits > -{ enum { Cost = 5 * NumTraits::MulCost, PacketAccess = packet_traits::HasExp }; }; - -/** \internal - * - * \brief Template functor to compute the logarithm of a scalar - * - * \sa class CwiseUnaryOp, Cwise::log() - */ -template struct scalar_log_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_log_op) - inline const Scalar operator() (const Scalar& a) const { using std::log; return log(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::plog(a); } -}; -template -struct functor_traits > -{ enum { Cost = 5 * NumTraits::MulCost, PacketAccess = packet_traits::HasLog }; }; - -/** \internal - * \brief Template functor to multiply a scalar by a fixed other one - * - * \sa class CwiseUnaryOp, MatrixBase::operator*, MatrixBase::operator/ - */ -/* NOTE why doing the pset1() in packetOp *is* an optimization ? - * indeed it seems better to declare m_other as a Packet and do the pset1() once - * in the constructor. However, in practice: - * - GCC does not like m_other as a Packet and generate a load every time it needs it - * - on the other hand GCC is able to moves the pset1() outside the loop :) - * - simpler code ;) - * (ICC and gcc 4.4 seems to perform well in both cases, the issue is visible with y = a*x + b*y) - */ -template -struct scalar_multiple_op { - typedef typename packet_traits::type Packet; - // FIXME default copy constructors seems bugged with std::complex<> - EIGEN_STRONG_INLINE scalar_multiple_op(const scalar_multiple_op& other) : m_other(other.m_other) { } - EIGEN_STRONG_INLINE scalar_multiple_op(const Scalar& other) : m_other(other) { } - EIGEN_STRONG_INLINE Scalar operator() (const Scalar& a) const { return a * m_other; } - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const - { return internal::pmul(a, pset1(m_other)); } - typename add_const_on_value_type::Nested>::type m_other; -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasMul }; }; - -template -struct scalar_multiple2_op { - typedef typename scalar_product_traits::ReturnType result_type; - EIGEN_STRONG_INLINE scalar_multiple2_op(const scalar_multiple2_op& other) : m_other(other.m_other) { } - EIGEN_STRONG_INLINE scalar_multiple2_op(const Scalar2& other) : m_other(other) { } - EIGEN_STRONG_INLINE result_type operator() (const Scalar1& a) const { return a * m_other; } - typename add_const_on_value_type::Nested>::type m_other; -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to divide a scalar by a fixed other one - * - * This functor is used to implement the quotient of a matrix by - * a scalar where the scalar type is not necessarily a floating point type. - * - * \sa class CwiseUnaryOp, MatrixBase::operator/ - */ -template -struct scalar_quotient1_op { - typedef typename packet_traits::type Packet; - // FIXME default copy constructors seems bugged with std::complex<> - EIGEN_STRONG_INLINE scalar_quotient1_op(const scalar_quotient1_op& other) : m_other(other.m_other) { } - EIGEN_STRONG_INLINE scalar_quotient1_op(const Scalar& other) : m_other(other) {} - EIGEN_STRONG_INLINE Scalar operator() (const Scalar& a) const { return a / m_other; } - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const - { return internal::pdiv(a, pset1(m_other)); } - typename add_const_on_value_type::Nested>::type m_other; -}; -template -struct functor_traits > -{ enum { Cost = 2 * NumTraits::MulCost, PacketAccess = packet_traits::HasDiv }; }; - -// nullary functors - -template -struct scalar_constant_op { - typedef typename packet_traits::type Packet; - EIGEN_STRONG_INLINE scalar_constant_op(const scalar_constant_op& other) : m_other(other.m_other) { } - EIGEN_STRONG_INLINE scalar_constant_op(const Scalar& other) : m_other(other) { } - template - EIGEN_STRONG_INLINE const Scalar operator() (Index, Index = 0) const { return m_other; } - template - EIGEN_STRONG_INLINE const Packet packetOp(Index, Index = 0) const { return internal::pset1(m_other); } - const Scalar m_other; -}; -template -struct functor_traits > -// FIXME replace this packet test by a safe one -{ enum { Cost = 1, PacketAccess = packet_traits::Vectorizable, IsRepeatable = true }; }; - -template struct scalar_identity_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_identity_op) - template - EIGEN_STRONG_INLINE const Scalar operator() (Index row, Index col) const { return row==col ? Scalar(1) : Scalar(0); } -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::AddCost, PacketAccess = false, IsRepeatable = true }; }; - -template struct linspaced_op_impl; - -// linear access for packet ops: -// 1) initialization -// base = [low, ..., low] + ([step, ..., step] * [-size, ..., 0]) -// 2) each step (where size is 1 for coeff access or PacketSize for packet access) -// base += [size*step, ..., size*step] -// -// TODO: Perhaps it's better to initialize lazily (so not in the constructor but in packetOp) -// in order to avoid the padd() in operator() ? -template -struct linspaced_op_impl -{ - typedef typename packet_traits::type Packet; - - linspaced_op_impl(const Scalar& low, const Scalar& step) : - m_low(low), m_step(step), - m_packetStep(pset1(packet_traits::size*step)), - m_base(padd(pset1(low), pmul(pset1(step),plset(-packet_traits::size)))) {} - - template - EIGEN_STRONG_INLINE const Scalar operator() (Index i) const - { - m_base = padd(m_base, pset1(m_step)); - return m_low+Scalar(i)*m_step; - } - - template - EIGEN_STRONG_INLINE const Packet packetOp(Index) const { return m_base = padd(m_base,m_packetStep); } - - const Scalar m_low; - const Scalar m_step; - const Packet m_packetStep; - mutable Packet m_base; -}; - -// random access for packet ops: -// 1) each step -// [low, ..., low] + ( [step, ..., step] * ( [i, ..., i] + [0, ..., size] ) ) -template -struct linspaced_op_impl -{ - typedef typename packet_traits::type Packet; - - linspaced_op_impl(const Scalar& low, const Scalar& step) : - m_low(low), m_step(step), - m_lowPacket(pset1(m_low)), m_stepPacket(pset1(m_step)), m_interPacket(plset(0)) {} - - template - EIGEN_STRONG_INLINE const Scalar operator() (Index i) const { return m_low+i*m_step; } - - template - EIGEN_STRONG_INLINE const Packet packetOp(Index i) const - { return internal::padd(m_lowPacket, pmul(m_stepPacket, padd(pset1(i),m_interPacket))); } - - const Scalar m_low; - const Scalar m_step; - const Packet m_lowPacket; - const Packet m_stepPacket; - const Packet m_interPacket; -}; - -// ----- Linspace functor ---------------------------------------------------------------- - -// Forward declaration (we default to random access which does not really give -// us a speed gain when using packet access but it allows to use the functor in -// nested expressions). -template struct linspaced_op; -template struct functor_traits< linspaced_op > -{ enum { Cost = 1, PacketAccess = packet_traits::HasSetLinear, IsRepeatable = true }; }; -template struct linspaced_op -{ - typedef typename packet_traits::type Packet; - linspaced_op(const Scalar& low, const Scalar& high, DenseIndex num_steps) : impl((num_steps==1 ? high : low), (num_steps==1 ? Scalar() : (high-low)/(num_steps-1))) {} - - template - EIGEN_STRONG_INLINE const Scalar operator() (Index i) const { return impl(i); } - - // We need this function when assigning e.g. a RowVectorXd to a MatrixXd since - // there row==0 and col is used for the actual iteration. - template - EIGEN_STRONG_INLINE const Scalar operator() (Index row, Index col) const - { - eigen_assert(col==0 || row==0); - return impl(col + row); - } - - template - EIGEN_STRONG_INLINE const Packet packetOp(Index i) const { return impl.packetOp(i); } - - // We need this function when assigning e.g. a RowVectorXd to a MatrixXd since - // there row==0 and col is used for the actual iteration. - template - EIGEN_STRONG_INLINE const Packet packetOp(Index row, Index col) const - { - eigen_assert(col==0 || row==0); - return impl.packetOp(col + row); - } - - // This proxy object handles the actual required temporaries, the different - // implementations (random vs. sequential access) as well as the - // correct piping to size 2/4 packet operations. - const linspaced_op_impl impl; -}; - -// all functors allow linear access, except scalar_identity_op. So we fix here a quick meta -// to indicate whether a functor allows linear access, just always answering 'yes' except for -// scalar_identity_op. -// FIXME move this to functor_traits adding a functor_default -template struct functor_has_linear_access { enum { ret = 1 }; }; -template struct functor_has_linear_access > { enum { ret = 0 }; }; - -// In Eigen, any binary op (Product, CwiseBinaryOp) require the Lhs and Rhs to have the same scalar type, except for multiplication -// where the mixing of different types is handled by scalar_product_traits -// In particular, real * complex is allowed. -// FIXME move this to functor_traits adding a functor_default -template struct functor_is_product_like { enum { ret = 0 }; }; -template struct functor_is_product_like > { enum { ret = 1 }; }; -template struct functor_is_product_like > { enum { ret = 1 }; }; -template struct functor_is_product_like > { enum { ret = 1 }; }; - - -/** \internal - * \brief Template functor to add a scalar to a fixed other one - * \sa class CwiseUnaryOp, Array::operator+ - */ -/* If you wonder why doing the pset1() in packetOp() is an optimization check scalar_multiple_op */ -template -struct scalar_add_op { - typedef typename packet_traits::type Packet; - // FIXME default copy constructors seems bugged with std::complex<> - inline scalar_add_op(const scalar_add_op& other) : m_other(other.m_other) { } - inline scalar_add_op(const Scalar& other) : m_other(other) { } - inline Scalar operator() (const Scalar& a) const { return a + m_other; } - inline const Packet packetOp(const Packet& a) const - { return internal::padd(a, pset1(m_other)); } - const Scalar m_other; -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasAdd }; }; - -/** \internal - * \brief Template functor to compute the square root of a scalar - * \sa class CwiseUnaryOp, Cwise::sqrt() - */ -template struct scalar_sqrt_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_sqrt_op) - inline const Scalar operator() (const Scalar& a) const { using std::sqrt; return sqrt(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::psqrt(a); } -}; -template -struct functor_traits > -{ enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasSqrt - }; -}; - -/** \internal - * \brief Template functor to compute the cosine of a scalar - * \sa class CwiseUnaryOp, ArrayBase::cos() - */ -template struct scalar_cos_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cos_op) - inline Scalar operator() (const Scalar& a) const { using std::cos; return cos(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::pcos(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasCos - }; -}; - -/** \internal - * \brief Template functor to compute the sine of a scalar - * \sa class CwiseUnaryOp, ArrayBase::sin() - */ -template struct scalar_sin_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_sin_op) - inline const Scalar operator() (const Scalar& a) const { using std::sin; return sin(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::psin(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasSin - }; -}; - - -/** \internal - * \brief Template functor to compute the tan of a scalar - * \sa class CwiseUnaryOp, ArrayBase::tan() - */ -template struct scalar_tan_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_tan_op) - inline const Scalar operator() (const Scalar& a) const { using std::tan; return tan(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::ptan(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasTan - }; -}; - -/** \internal - * \brief Template functor to compute the arc cosine of a scalar - * \sa class CwiseUnaryOp, ArrayBase::acos() - */ -template struct scalar_acos_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_acos_op) - inline const Scalar operator() (const Scalar& a) const { using std::acos; return acos(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::pacos(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasACos - }; -}; - -/** \internal - * \brief Template functor to compute the arc sine of a scalar - * \sa class CwiseUnaryOp, ArrayBase::asin() - */ -template struct scalar_asin_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_asin_op) - inline const Scalar operator() (const Scalar& a) const { using std::asin; return asin(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::pasin(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasASin - }; -}; - -/** \internal - * \brief Template functor to raise a scalar to a power - * \sa class CwiseUnaryOp, Cwise::pow - */ -template -struct scalar_pow_op { - // FIXME default copy constructors seems bugged with std::complex<> - inline scalar_pow_op(const scalar_pow_op& other) : m_exponent(other.m_exponent) { } - inline scalar_pow_op(const Scalar& exponent) : m_exponent(exponent) {} - inline Scalar operator() (const Scalar& a) const { return numext::pow(a, m_exponent); } - const Scalar m_exponent; -}; -template -struct functor_traits > -{ enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to compute the quotient between a scalar and array entries. - * \sa class CwiseUnaryOp, Cwise::inverse() - */ -template -struct scalar_inverse_mult_op { - scalar_inverse_mult_op(const Scalar& other) : m_other(other) {} - inline Scalar operator() (const Scalar& a) const { return m_other / a; } - template - inline const Packet packetOp(const Packet& a) const - { return internal::pdiv(pset1(m_other),a); } - Scalar m_other; -}; - -/** \internal - * \brief Template functor to compute the inverse of a scalar - * \sa class CwiseUnaryOp, Cwise::inverse() - */ -template -struct scalar_inverse_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_inverse_op) - inline Scalar operator() (const Scalar& a) const { return Scalar(1)/a; } - template - inline const Packet packetOp(const Packet& a) const - { return internal::pdiv(pset1(Scalar(1)),a); } -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasDiv }; }; - -/** \internal - * \brief Template functor to compute the square of a scalar - * \sa class CwiseUnaryOp, Cwise::square() - */ -template -struct scalar_square_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_square_op) - inline Scalar operator() (const Scalar& a) const { return a*a; } - template - inline const Packet packetOp(const Packet& a) const - { return internal::pmul(a,a); } -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasMul }; }; - -/** \internal - * \brief Template functor to compute the cube of a scalar - * \sa class CwiseUnaryOp, Cwise::cube() - */ -template -struct scalar_cube_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cube_op) - inline Scalar operator() (const Scalar& a) const { return a*a*a; } - template - inline const Packet packetOp(const Packet& a) const - { return internal::pmul(a,pmul(a,a)); } -}; -template -struct functor_traits > -{ enum { Cost = 2*NumTraits::MulCost, PacketAccess = packet_traits::HasMul }; }; - -// default functor traits for STL functors: - -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = functor_traits::Cost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = functor_traits::Cost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1 + functor_traits::Cost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1 + functor_traits::Cost, PacketAccess = false }; }; - -#ifdef EIGEN_STDEXT_SUPPORT - -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -template -struct functor_traits > > -{ enum { Cost = 0, PacketAccess = false }; }; - -template -struct functor_traits > > -{ enum { Cost = 0, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = functor_traits::Cost + functor_traits::Cost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = functor_traits::Cost + functor_traits::Cost + functor_traits::Cost, PacketAccess = false }; }; - -#endif // EIGEN_STDEXT_SUPPORT - -// allow to add new functors and specializations of functor_traits from outside Eigen. -// this macro is really needed because functor_traits must be specialized after it is declared but before it is used... -#ifdef EIGEN_FUNCTORS_PLUGIN -#include EIGEN_FUNCTORS_PLUGIN -#endif - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_FUNCTORS_H diff --git a/nuparu/include/Eigen/src/Core/Fuzzy.h b/nuparu/include/Eigen/src/Core/Fuzzy.h index fe63bd29..3e403a09 100644 --- a/nuparu/include/Eigen/src/Core/Fuzzy.h +++ b/nuparu/include/Eigen/src/Core/Fuzzy.h @@ -19,18 +19,19 @@ namespace internal template::IsInteger> struct isApprox_selector { + EIGEN_DEVICE_FUNC static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar& prec) { - using std::min; - typename internal::nested::type nested(x); - typename internal::nested::type otherNested(y); - return (nested - otherNested).cwiseAbs2().sum() <= prec * prec * (min)(nested.cwiseAbs2().sum(), otherNested.cwiseAbs2().sum()); + typename internal::nested_eval::type nested(x); + typename internal::nested_eval::type otherNested(y); + return (nested - otherNested).cwiseAbs2().sum() <= prec * prec * numext::mini(nested.cwiseAbs2().sum(), otherNested.cwiseAbs2().sum()); } }; template struct isApprox_selector { + EIGEN_DEVICE_FUNC static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar&) { return x.matrix() == y.matrix(); @@ -40,6 +41,7 @@ struct isApprox_selector template::IsInteger> struct isMuchSmallerThan_object_selector { + EIGEN_DEVICE_FUNC static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar& prec) { return x.cwiseAbs2().sum() <= numext::abs2(prec) * y.cwiseAbs2().sum(); @@ -49,6 +51,7 @@ struct isMuchSmallerThan_object_selector template struct isMuchSmallerThan_object_selector { + EIGEN_DEVICE_FUNC static bool run(const Derived& x, const OtherDerived&, const typename Derived::RealScalar&) { return x.matrix() == Derived::Zero(x.rows(), x.cols()).matrix(); @@ -58,6 +61,7 @@ struct isMuchSmallerThan_object_selector template::IsInteger> struct isMuchSmallerThan_scalar_selector { + EIGEN_DEVICE_FUNC static bool run(const Derived& x, const typename Derived::RealScalar& y, const typename Derived::RealScalar& prec) { return x.cwiseAbs2().sum() <= numext::abs2(prec * y); @@ -67,6 +71,7 @@ struct isMuchSmallerThan_scalar_selector template struct isMuchSmallerThan_scalar_selector { + EIGEN_DEVICE_FUNC static bool run(const Derived& x, const typename Derived::RealScalar&, const typename Derived::RealScalar&) { return x.matrix() == Derived::Zero(x.rows(), x.cols()).matrix(); diff --git a/nuparu/include/Eigen/src/Core/GeneralProduct.h b/nuparu/include/Eigen/src/Core/GeneralProduct.h index 2a59d946..fe8204ac 100644 --- a/nuparu/include/Eigen/src/Core/GeneralProduct.h +++ b/nuparu/include/Eigen/src/Core/GeneralProduct.h @@ -11,29 +11,7 @@ #ifndef EIGEN_GENERAL_PRODUCT_H #define EIGEN_GENERAL_PRODUCT_H -namespace Eigen { - -/** \class GeneralProduct - * \ingroup Core_Module - * - * \brief Expression of the product of two general matrices or vectors - * - * \param LhsNested the type used to store the left-hand side - * \param RhsNested the type used to store the right-hand side - * \param ProductMode the type of the product - * - * This class represents an expression of the product of two general matrices. - * We call a general matrix, a dense matrix with full storage. For instance, - * This excludes triangular, selfadjoint, and sparse matrices. - * It is the return type of the operator* between general matrices. Its template - * arguments are determined automatically by ProductReturnType. Therefore, - * GeneralProduct should never be used direclty. To determine the result type of a - * function which involves a matrix product, use ProductReturnType::Type. - * - * \sa ProductReturnType, MatrixBase::operator*(const MatrixBase&) - */ -template::value> -class GeneralProduct; +namespace Eigen { enum { Large = 2, @@ -59,15 +37,14 @@ template struct product_type typedef typename remove_all::type _Lhs; typedef typename remove_all::type _Rhs; enum { - MaxRows = _Lhs::MaxRowsAtCompileTime, - Rows = _Lhs::RowsAtCompileTime, - MaxCols = _Rhs::MaxColsAtCompileTime, - Cols = _Rhs::ColsAtCompileTime, - MaxDepth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::MaxColsAtCompileTime, - _Rhs::MaxRowsAtCompileTime), - Depth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::ColsAtCompileTime, - _Rhs::RowsAtCompileTime), - LargeThreshold = EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD + MaxRows = traits<_Lhs>::MaxRowsAtCompileTime, + Rows = traits<_Lhs>::RowsAtCompileTime, + MaxCols = traits<_Rhs>::MaxColsAtCompileTime, + Cols = traits<_Rhs>::ColsAtCompileTime, + MaxDepth = EIGEN_SIZE_MIN_PREFER_FIXED(traits<_Lhs>::MaxColsAtCompileTime, + traits<_Rhs>::MaxRowsAtCompileTime), + Depth = EIGEN_SIZE_MIN_PREFER_FIXED(traits<_Lhs>::ColsAtCompileTime, + traits<_Rhs>::RowsAtCompileTime) }; // the splitting into different lines of code here, introducing the _select enums and the typedef below, @@ -82,7 +59,8 @@ template struct product_type public: enum { - value = selector::ret + value = selector::ret, + ret = selector::ret }; #ifdef EIGEN_DEBUG_PRODUCT static void debug() @@ -98,6 +76,31 @@ template struct product_type #endif }; +// template struct product_tag +// { +// private: +// +// typedef typename remove_all::type _Lhs; +// typedef typename remove_all::type _Rhs; +// enum { +// Rows = _Lhs::RowsAtCompileTime, +// Cols = _Rhs::ColsAtCompileTime, +// Depth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::ColsAtCompileTime, _Rhs::RowsAtCompileTime) +// }; +// +// enum { +// rows_select = Rows==1 ? int(Rows) : int(Large), +// cols_select = Cols==1 ? int(Cols) : int(Large), +// depth_select = Depth==1 ? int(Depth) : int(Large) +// }; +// typedef product_type_selector selector; +// +// public: +// enum { +// ret = selector::ret +// }; +// +// }; /* The following allows to select the kind of product at compile time * based on the three dimensions of the product. @@ -128,54 +131,6 @@ template<> struct product_type_selector { enum } // end namespace internal -/** \class ProductReturnType - * \ingroup Core_Module - * - * \brief Helper class to get the correct and optimized returned type of operator* - * - * \param Lhs the type of the left-hand side - * \param Rhs the type of the right-hand side - * \param ProductMode the type of the product (determined automatically by internal::product_mode) - * - * This class defines the typename Type representing the optimized product expression - * between two matrix expressions. In practice, using ProductReturnType::Type - * is the recommended way to define the result type of a function returning an expression - * which involve a matrix product. The class Product should never be - * used directly. - * - * \sa class Product, MatrixBase::operator*(const MatrixBase&) - */ -template -struct ProductReturnType -{ - // TODO use the nested type to reduce instanciations ???? -// typedef typename internal::nested::type LhsNested; -// typedef typename internal::nested::type RhsNested; - - typedef GeneralProduct Type; -}; - -template -struct ProductReturnType -{ - typedef typename internal::nested::type >::type LhsNested; - typedef typename internal::nested::type >::type RhsNested; - typedef CoeffBasedProduct Type; -}; - -template -struct ProductReturnType -{ - typedef typename internal::nested::type >::type LhsNested; - typedef typename internal::nested::type >::type RhsNested; - typedef CoeffBasedProduct Type; -}; - -// this is a workaround for sun CC -template -struct LazyProductReturnType : public ProductReturnType -{}; - /*********************************************************************** * Implementation of Inner Vector Vector Product ***********************************************************************/ @@ -187,119 +142,10 @@ struct LazyProductReturnType : public ProductReturnType with: operator=(Scalar x); -namespace internal { - -template -struct traits > - : traits::ReturnType,1,1> > -{}; - -} - -template -class GeneralProduct - : internal::no_assignment_operator, - public Matrix::ReturnType,1,1> -{ - typedef Matrix::ReturnType,1,1> Base; - public: - GeneralProduct(const Lhs& lhs, const Rhs& rhs) - { - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - - Base::coeffRef(0,0) = (lhs.transpose().cwiseProduct(rhs)).sum(); - } - - /** Convertion to scalar */ - operator const typename Base::Scalar() const { - return Base::coeff(0,0); - } -}; - /*********************************************************************** * Implementation of Outer Vector Vector Product ***********************************************************************/ -namespace internal { - -// Column major -template -EIGEN_DONT_INLINE void outer_product_selector_run(const ProductType& prod, Dest& dest, const Func& func, const false_type&) -{ - typedef typename Dest::Index Index; - // FIXME make sure lhs is sequentially stored - // FIXME not very good if rhs is real and lhs complex while alpha is real too - const Index cols = dest.cols(); - for (Index j=0; j -EIGEN_DONT_INLINE void outer_product_selector_run(const ProductType& prod, Dest& dest, const Func& func, const true_type&) { - typedef typename Dest::Index Index; - // FIXME make sure rhs is sequentially stored - // FIXME not very good if lhs is real and rhs complex while alpha is real too - const Index rows = dest.rows(); - for (Index i=0; i -struct traits > - : traits, Lhs, Rhs> > -{}; - -} - -template -class GeneralProduct - : public ProductBase, Lhs, Rhs> -{ - template struct IsRowMajor : internal::conditional<(int(T::Flags)&RowMajorBit), internal::true_type, internal::false_type>::type {}; - - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) - - GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - { - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - } - - struct set { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() = src; } }; - struct add { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() += src; } }; - struct sub { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() -= src; } }; - struct adds { - Scalar m_scale; - adds(const Scalar& s) : m_scale(s) {} - template void operator()(const Dst& dst, const Src& src) const { - dst.const_cast_derived() += m_scale * src; - } - }; - - template - inline void evalTo(Dest& dest) const { - internal::outer_product_selector_run(*this, dest, set(), IsRowMajor()); - } - - template - inline void addTo(Dest& dest) const { - internal::outer_product_selector_run(*this, dest, add(), IsRowMajor()); - } - - template - inline void subTo(Dest& dest) const { - internal::outer_product_selector_run(*this, dest, sub(), IsRowMajor()); - } - - template void scaleAndAddTo(Dest& dest, const Scalar& alpha) const - { - internal::outer_product_selector_run(*this, dest, adds(alpha), IsRowMajor()); - } -}; - /*********************************************************************** * Implementation of General Matrix Vector Product ***********************************************************************/ @@ -313,60 +159,13 @@ class GeneralProduct */ namespace internal { -template -struct traits > - : traits, Lhs, Rhs> > -{}; - template -struct gemv_selector; +struct gemv_dense_selector; } // end namespace internal -template -class GeneralProduct - : public ProductBase, Lhs, Rhs> -{ - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) - - typedef typename Lhs::Scalar LhsScalar; - typedef typename Rhs::Scalar RhsScalar; - - GeneralProduct(const Lhs& a_lhs, const Rhs& a_rhs) : Base(a_lhs,a_rhs) - { -// EIGEN_STATIC_ASSERT((internal::is_same::value), -// YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - } - - enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight }; - typedef typename internal::conditional::type MatrixType; - - template void scaleAndAddTo(Dest& dst, const Scalar& alpha) const - { - eigen_assert(m_lhs.rows() == dst.rows() && m_rhs.cols() == dst.cols()); - internal::gemv_selector::HasUsableDirectAccess)>::run(*this, dst, alpha); - } -}; - namespace internal { -// The vector is on the left => transposition -template -struct gemv_selector -{ - template - static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) - { - Transpose destT(dest); - enum { OtherStorageOrder = StorageOrder == RowMajor ? ColMajor : RowMajor }; - gemv_selector - ::run(GeneralProduct,Transpose, GemvProduct> - (prod.rhs().transpose(), prod.lhs().transpose()), destT, alpha); - } -}; - template struct gemv_static_vector_if; template @@ -384,7 +183,7 @@ struct gemv_static_vector_if template struct gemv_static_vector_if { - #if EIGEN_ALIGN_STATICALLY + #if EIGEN_MAX_STATIC_ALIGN_BYTES!=0 internal::plain_array m_data; EIGEN_STRONG_INLINE Scalar* data() { return m_data.array; } #else @@ -397,33 +196,48 @@ struct gemv_static_vector_if internal::plain_array m_data; EIGEN_STRONG_INLINE Scalar* data() { return ForceAlignment - ? reinterpret_cast((reinterpret_cast(m_data.array) & ~(size_t(15))) + 16) + ? reinterpret_cast((reinterpret_cast(m_data.array) & ~(size_t(EIGEN_MAX_ALIGN_BYTES-1))) + EIGEN_MAX_ALIGN_BYTES) : m_data.array; } #endif }; -template<> struct gemv_selector +// The vector is on the left => transposition +template +struct gemv_dense_selector +{ + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) + { + Transpose destT(dest); + enum { OtherStorageOrder = StorageOrder == RowMajor ? ColMajor : RowMajor }; + gemv_dense_selector + ::run(rhs.transpose(), lhs.transpose(), destT, alpha); + } +}; + +template<> struct gemv_dense_selector { - template - static inline void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) + template + static inline void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) { - typedef typename ProductType::Index Index; - typedef typename ProductType::LhsScalar LhsScalar; - typedef typename ProductType::RhsScalar RhsScalar; - typedef typename ProductType::Scalar ResScalar; - typedef typename ProductType::RealScalar RealScalar; - typedef typename ProductType::ActualLhsType ActualLhsType; - typedef typename ProductType::ActualRhsType ActualRhsType; - typedef typename ProductType::LhsBlasTraits LhsBlasTraits; - typedef typename ProductType::RhsBlasTraits RhsBlasTraits; + typedef typename Lhs::Scalar LhsScalar; + typedef typename Rhs::Scalar RhsScalar; + typedef typename Dest::Scalar ResScalar; + typedef typename Dest::RealScalar RealScalar; + + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + typedef Map, Aligned> MappedDest; - ActualLhsType actualLhs = LhsBlasTraits::extract(prod.lhs()); - ActualRhsType actualRhs = RhsBlasTraits::extract(prod.rhs()); + ActualLhsType actualLhs = LhsBlasTraits::extract(lhs); + ActualRhsType actualRhs = RhsBlasTraits::extract(rhs); - ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) - * RhsBlasTraits::extractScalarFactor(prod.rhs()); + ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(lhs) + * RhsBlasTraits::extractScalarFactor(rhs); enum { // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 @@ -435,18 +249,18 @@ template<> struct gemv_selector gemv_static_vector_if static_dest; - bool alphaIsCompatible = (!ComplexByReal) || (numext::imag(actualAlpha)==RealScalar(0)); - bool evalToDest = EvalToDestAtCompileTime && alphaIsCompatible; - + const bool alphaIsCompatible = (!ComplexByReal) || (numext::imag(actualAlpha)==RealScalar(0)); + const bool evalToDest = EvalToDestAtCompileTime && alphaIsCompatible; + RhsScalar compatibleAlpha = get_factor::run(actualAlpha); ei_declare_aligned_stack_constructed_variable(ResScalar,actualDestPtr,dest.size(), evalToDest ? dest.data() : static_dest.data()); - + if(!evalToDest) { #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - int size = dest.size(); + Index size = dest.size(); EIGEN_DENSE_STORAGE_CTOR_PLUGIN #endif if(!alphaIsCompatible) @@ -458,11 +272,13 @@ template<> struct gemv_selector MappedDest(actualDestPtr, dest.size()) = dest; } + typedef const_blas_data_mapper LhsMapper; + typedef const_blas_data_mapper RhsMapper; general_matrix_vector_product - ::run( + ::run( actualLhs.rows(), actualLhs.cols(), - actualLhs.data(), actualLhs.outerStride(), - actualRhs.data(), actualRhs.innerStride(), + LhsMapper(actualLhs.data(), actualLhs.outerStride()), + RhsMapper(actualRhs.data(), actualRhs.innerStride()), actualDestPtr, 1, compatibleAlpha); @@ -476,34 +292,34 @@ template<> struct gemv_selector } }; -template<> struct gemv_selector +template<> struct gemv_dense_selector { - template - static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) { - typedef typename ProductType::LhsScalar LhsScalar; - typedef typename ProductType::RhsScalar RhsScalar; - typedef typename ProductType::Scalar ResScalar; - typedef typename ProductType::Index Index; - typedef typename ProductType::ActualLhsType ActualLhsType; - typedef typename ProductType::ActualRhsType ActualRhsType; - typedef typename ProductType::_ActualRhsType _ActualRhsType; - typedef typename ProductType::LhsBlasTraits LhsBlasTraits; - typedef typename ProductType::RhsBlasTraits RhsBlasTraits; - - typename add_const::type actualLhs = LhsBlasTraits::extract(prod.lhs()); - typename add_const::type actualRhs = RhsBlasTraits::extract(prod.rhs()); - - ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) - * RhsBlasTraits::extractScalarFactor(prod.rhs()); + typedef typename Lhs::Scalar LhsScalar; + typedef typename Rhs::Scalar RhsScalar; + typedef typename Dest::Scalar ResScalar; + + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + typedef typename internal::remove_all::type ActualRhsTypeCleaned; + + typename add_const::type actualLhs = LhsBlasTraits::extract(lhs); + typename add_const::type actualRhs = RhsBlasTraits::extract(rhs); + + ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(lhs) + * RhsBlasTraits::extractScalarFactor(rhs); enum { // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 // on, the other hand it is good for the cache to pack the vector anyways... - DirectlyUseRhs = _ActualRhsType::InnerStrideAtCompileTime==1 + DirectlyUseRhs = ActualRhsTypeCleaned::InnerStrideAtCompileTime==1 }; - gemv_static_vector_if static_rhs; + gemv_static_vector_if static_rhs; ei_declare_aligned_stack_constructed_variable(RhsScalar,actualRhsPtr,actualRhs.size(), DirectlyUseRhs ? const_cast(actualRhs.data()) : static_rhs.data()); @@ -511,45 +327,46 @@ template<> struct gemv_selector if(!DirectlyUseRhs) { #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - int size = actualRhs.size(); + Index size = actualRhs.size(); EIGEN_DENSE_STORAGE_CTOR_PLUGIN #endif - Map(actualRhsPtr, actualRhs.size()) = actualRhs; + Map(actualRhsPtr, actualRhs.size()) = actualRhs; } + typedef const_blas_data_mapper LhsMapper; + typedef const_blas_data_mapper RhsMapper; general_matrix_vector_product - ::run( + ::run( actualLhs.rows(), actualLhs.cols(), - actualLhs.data(), actualLhs.outerStride(), - actualRhsPtr, 1, + LhsMapper(actualLhs.data(), actualLhs.outerStride()), + RhsMapper(actualRhsPtr, 1), dest.data(), dest.innerStride(), actualAlpha); } }; -template<> struct gemv_selector +template<> struct gemv_dense_selector { - template - static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) { - typedef typename Dest::Index Index; - // TODO makes sure dest is sequentially stored in memory, otherwise use a temp - const Index size = prod.rhs().rows(); + // TODO if rhs is large enough it might be beneficial to make sure that dest is sequentially stored in memory, otherwise use a temp + typename nested_eval::type actual_rhs(rhs); + const Index size = rhs.rows(); for(Index k=0; k struct gemv_selector +template<> struct gemv_dense_selector { - template - static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) { - typedef typename Dest::Index Index; - // TODO makes sure rhs is sequentially stored in memory, otherwise use a temp - const Index rows = prod.rows(); + typename nested_eval::type actual_rhs(rhs); + const Index rows = dest.rows(); for(Index i=0; i struct gemv_selector * * \sa lazyProduct(), operator*=(const MatrixBase&), Cwise::operator*() */ +#ifndef __CUDACC__ + template template -inline const typename ProductReturnType::Type +inline const Product MatrixBase::operator*(const MatrixBase &other) const { // A note regarding the function declaration: In MSVC, this function will sometimes @@ -592,9 +411,12 @@ MatrixBase::operator*(const MatrixBase &other) const #ifdef EIGEN_DEBUG_PRODUCT internal::product_type::debug(); #endif - return typename ProductReturnType::Type(derived(), other.derived()); + + return Product(derived(), other.derived()); } +#endif // __CUDACC__ + /** \returns an expression of the matrix product of \c *this and \a other without implicit evaluation. * * The returned product will behave like any other expressions: the coefficients of the product will be @@ -608,7 +430,7 @@ MatrixBase::operator*(const MatrixBase &other) const */ template template -const typename LazyProductReturnType::Type +const Product MatrixBase::lazyProduct(const MatrixBase &other) const { enum { @@ -627,7 +449,7 @@ MatrixBase::lazyProduct(const MatrixBase &other) const INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION) EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT) - return typename LazyProductReturnType::Type(derived(), other.derived()); + return Product(derived(), other.derived()); } } // end namespace Eigen diff --git a/nuparu/include/Eigen/src/Core/GenericPacketMath.h b/nuparu/include/Eigen/src/Core/GenericPacketMath.h index 5f783ebe..8ad51bad 100644 --- a/nuparu/include/Eigen/src/Core/GenericPacketMath.h +++ b/nuparu/include/Eigen/src/Core/GenericPacketMath.h @@ -42,21 +42,27 @@ namespace internal { struct default_packet_traits { enum { + HasHalfPacket = 0, + HasAdd = 1, HasSub = 1, HasMul = 1, HasNegate = 1, HasAbs = 1, + HasArg = 0, HasAbs2 = 1, HasMin = 1, HasMax = 1, HasConj = 1, HasSetLinear = 1, + HasBlend = 0, HasDiv = 0, HasSqrt = 0, + HasRsqrt = 0, HasExp = 0, HasLog = 0, + HasLog10 = 0, HasPow = 0, HasSin = 0, @@ -64,17 +70,31 @@ struct default_packet_traits HasTan = 0, HasASin = 0, HasACos = 0, - HasATan = 0 + HasATan = 0, + HasSinh = 0, + HasCosh = 0, + HasTanh = 0, + HasLGamma = 0, + HasErf = 0, + HasErfc = 0, + + HasRound = 0, + HasFloor = 0, + HasCeil = 0, + + HasSign = 0 }; }; template struct packet_traits : default_packet_traits { typedef T type; + typedef T half; enum { Vectorizable = 0, size = 1, - AlignedOnScalar = 0 + AlignedOnScalar = 0, + HasHalfPacket = 0 }; enum { HasAdd = 0, @@ -90,135 +110,250 @@ template struct packet_traits : default_packet_traits }; }; +template struct packet_traits : packet_traits { }; + +template struct type_casting_traits { + enum { + VectorizedCast = 0, + SrcCoeffRatio = 1, + TgtCoeffRatio = 1 + }; +}; + + +/** \internal \returns static_cast(a) (coeff-wise) */ +template +EIGEN_DEVICE_FUNC inline TgtPacket +pcast(const SrcPacket& a) { + return static_cast(a); +} +template +EIGEN_DEVICE_FUNC inline TgtPacket +pcast(const SrcPacket& a, const SrcPacket& /*b*/) { + return static_cast(a); +} + + /** \internal \returns a + b (coeff-wise) */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet padd(const Packet& a, const Packet& b) { return a+b; } /** \internal \returns a - b (coeff-wise) */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet psub(const Packet& a, const Packet& b) { return a-b; } /** \internal \returns -a (coeff-wise) */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pnegate(const Packet& a) { return -a; } /** \internal \returns conj(a) (coeff-wise) */ -template inline Packet + +template EIGEN_DEVICE_FUNC inline Packet pconj(const Packet& a) { return numext::conj(a); } /** \internal \returns a * b (coeff-wise) */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pmul(const Packet& a, const Packet& b) { return a*b; } /** \internal \returns a / b (coeff-wise) */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pdiv(const Packet& a, const Packet& b) { return a/b; } /** \internal \returns the min of \a a and \a b (coeff-wise) */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pmin(const Packet& a, - const Packet& b) { using std::min; return (min)(a, b); } + const Packet& b) { return numext::mini(a, b); } /** \internal \returns the max of \a a and \a b (coeff-wise) */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pmax(const Packet& a, - const Packet& b) { using std::max; return (max)(a, b); } + const Packet& b) { return numext::maxi(a, b); } /** \internal \returns the absolute value of \a a */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pabs(const Packet& a) { using std::abs; return abs(a); } +/** \internal \returns the phase angle of \a a */ +template EIGEN_DEVICE_FUNC inline Packet +parg(const Packet& a) { using numext::arg; return arg(a); } + /** \internal \returns the bitwise and of \a a and \a b */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pand(const Packet& a, const Packet& b) { return a & b; } /** \internal \returns the bitwise or of \a a and \a b */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet por(const Packet& a, const Packet& b) { return a | b; } /** \internal \returns the bitwise xor of \a a and \a b */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pxor(const Packet& a, const Packet& b) { return a ^ b; } /** \internal \returns the bitwise andnot of \a a and \a b */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pandnot(const Packet& a, const Packet& b) { return a & (!b); } /** \internal \returns a packet version of \a *from, from must be 16 bytes aligned */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pload(const typename unpacket_traits::type* from) { return *from; } /** \internal \returns a packet version of \a *from, (un-aligned load) */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet ploadu(const typename unpacket_traits::type* from) { return *from; } +/** \internal \returns a packet with constant coefficients \a a, e.g.: (a,a,a,a) */ +template EIGEN_DEVICE_FUNC inline Packet +pset1(const typename unpacket_traits::type& a) { return a; } + +/** \internal \returns a packet with constant coefficients \a a[0], e.g.: (a[0],a[0],a[0],a[0]) */ +template EIGEN_DEVICE_FUNC inline Packet +pload1(const typename unpacket_traits::type *a) { return pset1(*a); } + /** \internal \returns a packet with elements of \a *from duplicated. - * For instance, for a packet of 8 elements, 4 scalar will be read from \a *from and - * duplicated to form: {from[0],from[0],from[1],from[1],,from[2],from[2],,from[3],from[3]} + * For instance, for a packet of 8 elements, 4 scalars will be read from \a *from and + * duplicated to form: {from[0],from[0],from[1],from[1],from[2],from[2],from[3],from[3]} * Currently, this function is only used for scalar * complex products. - */ -template inline Packet + */ +template EIGEN_DEVICE_FUNC inline Packet ploaddup(const typename unpacket_traits::type* from) { return *from; } -/** \internal \returns a packet with constant coefficients \a a, e.g.: (a,a,a,a) */ -template inline Packet -pset1(const typename unpacket_traits::type& a) { return a; } +/** \internal \returns a packet with elements of \a *from quadrupled. + * For instance, for a packet of 8 elements, 2 scalars will be read from \a *from and + * replicated to form: {from[0],from[0],from[0],from[0],from[1],from[1],from[1],from[1]} + * Currently, this function is only used in matrix products. + * For packet-size smaller or equal to 4, this function is equivalent to pload1 + */ +template EIGEN_DEVICE_FUNC inline Packet +ploadquad(const typename unpacket_traits::type* from) +{ return pload1(from); } + +/** \internal equivalent to + * \code + * a0 = pload1(a+0); + * a1 = pload1(a+1); + * a2 = pload1(a+2); + * a3 = pload1(a+3); + * \endcode + * \sa pset1, pload1, ploaddup, pbroadcast2 + */ +template EIGEN_DEVICE_FUNC +inline void pbroadcast4(const typename unpacket_traits::type *a, + Packet& a0, Packet& a1, Packet& a2, Packet& a3) +{ + a0 = pload1(a+0); + a1 = pload1(a+1); + a2 = pload1(a+2); + a3 = pload1(a+3); +} + +/** \internal equivalent to + * \code + * a0 = pload1(a+0); + * a1 = pload1(a+1); + * \endcode + * \sa pset1, pload1, ploaddup, pbroadcast4 + */ +template EIGEN_DEVICE_FUNC +inline void pbroadcast2(const typename unpacket_traits::type *a, + Packet& a0, Packet& a1) +{ + a0 = pload1(a+0); + a1 = pload1(a+1); +} /** \internal \brief Returns a packet with coefficients (a,a+1,...,a+packet_size-1). */ -template inline typename packet_traits::type -plset(const Scalar& a) { return a; } +template inline Packet +plset(const typename unpacket_traits::type& a) { return a; } /** \internal copy the packet \a from to \a *to, \a to must be 16 bytes aligned */ -template inline void pstore(Scalar* to, const Packet& from) +template EIGEN_DEVICE_FUNC inline void pstore(Scalar* to, const Packet& from) { (*to) = from; } /** \internal copy the packet \a from to \a *to, (un-aligned store) */ -template inline void pstoreu(Scalar* to, const Packet& from) -{ (*to) = from; } +template EIGEN_DEVICE_FUNC inline void pstoreu(Scalar* to, const Packet& from) +{ (*to) = from; } + + template EIGEN_DEVICE_FUNC inline Packet pgather(const Scalar* from, Index /*stride*/) + { return ploadu(from); } + + template EIGEN_DEVICE_FUNC inline void pscatter(Scalar* to, const Packet& from, Index /*stride*/) + { pstore(to, from); } /** \internal tries to do cache prefetching of \a addr */ template inline void prefetch(const Scalar* addr) { -#if !defined(_MSC_VER) -__builtin_prefetch(addr); +#ifdef __CUDA_ARCH__ +#if defined(__LP64__) + // 64-bit pointer operand constraint for inlined asm + asm(" prefetch.L1 [ %1 ];" : "=l"(addr) : "l"(addr)); +#else + // 32-bit pointer operand constraint for inlined asm + asm(" prefetch.L1 [ %1 ];" : "=r"(addr) : "r"(addr)); +#endif +#elif !EIGEN_COMP_MSVC + __builtin_prefetch(addr); #endif } /** \internal \returns the first element of a packet */ -template inline typename unpacket_traits::type pfirst(const Packet& a) +template EIGEN_DEVICE_FUNC inline typename unpacket_traits::type pfirst(const Packet& a) { return a; } /** \internal \returns a packet where the element i contains the sum of the packet of \a vec[i] */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet preduxp(const Packet* vecs) { return vecs[0]; } /** \internal \returns the sum of the elements of \a a*/ -template inline typename unpacket_traits::type predux(const Packet& a) +template EIGEN_DEVICE_FUNC inline typename unpacket_traits::type predux(const Packet& a) +{ return a; } + +/** \internal \returns the sum of the elements of \a a by block of 4 elements. + * For a packet {a0, a1, a2, a3, a4, a5, a6, a7}, it returns a half packet {a0+a4, a1+a5, a2+a6, a3+a7} + * For packet-size smaller or equal to 4, this boils down to a noop. + */ +template EIGEN_DEVICE_FUNC inline +typename conditional<(unpacket_traits::size%8)==0,typename unpacket_traits::half,Packet>::type +predux4(const Packet& a) { return a; } /** \internal \returns the product of the elements of \a a*/ -template inline typename unpacket_traits::type predux_mul(const Packet& a) +template EIGEN_DEVICE_FUNC inline typename unpacket_traits::type predux_mul(const Packet& a) { return a; } /** \internal \returns the min of the elements of \a a*/ -template inline typename unpacket_traits::type predux_min(const Packet& a) +template EIGEN_DEVICE_FUNC inline typename unpacket_traits::type predux_min(const Packet& a) { return a; } /** \internal \returns the max of the elements of \a a*/ -template inline typename unpacket_traits::type predux_max(const Packet& a) +template EIGEN_DEVICE_FUNC inline typename unpacket_traits::type predux_max(const Packet& a) { return a; } /** \internal \returns the reversed elements of \a a*/ -template inline Packet preverse(const Packet& a) +template EIGEN_DEVICE_FUNC inline Packet preverse(const Packet& a) { return a; } +template +struct protate_impl +{ + // Empty so attempts to use this unimplemented path will fail to compile. + // Only specializations of this template should be used. +}; + +/** \internal \returns a packet with the coefficients rotated to the right in little-endian convention, + * by the given offset, e.g. for offset == 1: + * (packet[3], packet[2], packet[1], packet[0]) becomes (packet[0], packet[3], packet[2], packet[1]) + */ +template EIGEN_DEVICE_FUNC inline Packet protate(const Packet& a) +{ + return offset ? protate_impl::run(a) : a; +} /** \internal \returns \a a with real and imaginary part flipped (for complex type only) */ -template inline Packet pcplxflip(const Packet& a) +template EIGEN_DEVICE_FUNC inline Packet pcplxflip(const Packet& a) { // FIXME: uncomment the following in case we drop the internal imag and real functions. // using std::imag; @@ -250,6 +385,22 @@ Packet pasin(const Packet& a) { using std::asin; return asin(a); } template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pacos(const Packet& a) { using std::acos; return acos(a); } +/** \internal \returns the arc tangent of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet patan(const Packet& a) { using std::atan; return atan(a); } + +/** \internal \returns the hyperbolic sine of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet psinh(const Packet& a) { using std::sinh; return sinh(a); } + +/** \internal \returns the hyperbolic cosine of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pcosh(const Packet& a) { using std::cosh; return cosh(a); } + +/** \internal \returns the hyperbolic tan of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet ptanh(const Packet& a) { using std::tanh; return tanh(a); } + /** \internal \returns the exp of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pexp(const Packet& a) { using std::exp; return exp(a); } @@ -258,10 +409,44 @@ Packet pexp(const Packet& a) { using std::exp; return exp(a); } template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog(const Packet& a) { using std::log; return log(a); } +/** \internal \returns the log10 of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet plog10(const Packet& a) { using std::log10; return log10(a); } + /** \internal \returns the square-root of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet psqrt(const Packet& a) { using std::sqrt; return sqrt(a); } +/** \internal \returns the reciprocal square-root of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet prsqrt(const Packet& a) { + return pdiv(pset1(1), psqrt(a)); +} + +/** \internal \returns the rounded value of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pround(const Packet& a) { using numext::round; return round(a); } + +/** \internal \returns the floor of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pfloor(const Packet& a) { using numext::floor; return floor(a); } + +/** \internal \returns the ceil of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pceil(const Packet& a) { using numext::ceil; return ceil(a); } + +/** \internal \returns the ln(|gamma(\a a)|) (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet plgamma(const Packet& a) { using numext::lgamma; return lgamma(a); } + +/** \internal \returns the erf(\a a) (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet perf(const Packet& a) { using numext::erf; return erf(a); } + +/** \internal \returns the erfc(\a a) (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet perfc(const Packet& a) { using numext::erfc; return erfc(a); } + /*************************************************************************** * The following functions might not have to be overwritten for vectorized types ***************************************************************************/ @@ -275,34 +460,45 @@ inline void pstore1(typename unpacket_traits::type* to, const typename u } /** \internal \returns a * b + c (coeff-wise) */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pmadd(const Packet& a, const Packet& b, const Packet& c) { return padd(pmul(a, b),c); } /** \internal \returns a packet version of \a *from. - * If LoadMode equals #Aligned, \a from must be 16 bytes aligned */ -template -inline Packet ploadt(const typename unpacket_traits::type* from) + * The pointer \a from must be aligned on a \a Alignment bytes boundary. */ +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Packet ploadt(const typename unpacket_traits::type* from) { - if(LoadMode == Aligned) + if(Alignment >= unpacket_traits::alignment) return pload(from); else return ploadu(from); } /** \internal copy the packet \a from to \a *to. - * If StoreMode equals #Aligned, \a to must be 16 bytes aligned */ -template -inline void pstoret(Scalar* to, const Packet& from) + * The pointer \a from must be aligned on a \a Alignment bytes boundary. */ +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE void pstoret(Scalar* to, const Packet& from) { - if(LoadMode == Aligned) + if(Alignment >= unpacket_traits::alignment) pstore(to, from); else pstoreu(to, from); } +/** \internal \returns a packet version of \a *from. + * Unlike ploadt, ploadt_ro takes advantage of the read-only memory path on the + * hardware if available to speedup the loading of data that won't be modified + * by the current computation. + */ +template +inline Packet ploadt_ro(const typename unpacket_traits::type* from) +{ + return ploadt(from); +} + /** \internal default implementation of palign() allowing partial specialization */ template struct palign_impl @@ -336,15 +532,46 @@ inline void palign(PacketType& first, const PacketType& second) * Fast complex products (GCC generates a function call which is very slow) ***************************************************************************/ +// Eigen+CUDA does not support complexes. +#ifndef __CUDACC__ + template<> inline std::complex pmul(const std::complex& a, const std::complex& b) { return std::complex(real(a)*real(b) - imag(a)*imag(b), imag(a)*real(b) + real(a)*imag(b)); } template<> inline std::complex pmul(const std::complex& a, const std::complex& b) { return std::complex(real(a)*real(b) - imag(a)*imag(b), imag(a)*real(b) + real(a)*imag(b)); } +#endif + + +/*************************************************************************** + * PacketBlock, that is a collection of N packets where the number of words + * in the packet is a multiple of N. +***************************************************************************/ +template ::size> struct PacketBlock { + Packet packet[N]; +}; + +template EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& /*kernel*/) { + // Nothing to do in the scalar case, i.e. a 1x1 matrix. +} + +/*************************************************************************** + * Selector, i.e. vector of N boolean values used to select (i.e. blend) + * words from 2 packets. +***************************************************************************/ +template struct Selector { + bool select[N]; +}; + +template EIGEN_DEVICE_FUNC inline Packet +pblend(const Selector::size>& ifPacket, const Packet& thenPacket, const Packet& elsePacket) { + return ifPacket.select[0] ? thenPacket : elsePacket; +} + } // end namespace internal } // end namespace Eigen #endif // EIGEN_GENERIC_PACKET_MATH_H - diff --git a/nuparu/include/Eigen/src/Core/GlobalFunctions.h b/nuparu/include/Eigen/src/Core/GlobalFunctions.h index 2acf9772..62fec700 100644 --- a/nuparu/include/Eigen/src/Core/GlobalFunctions.h +++ b/nuparu/include/Eigen/src/Core/GlobalFunctions.h @@ -14,8 +14,8 @@ #define EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(NAME,FUNCTOR) \ template \ inline const Eigen::CwiseUnaryOp, const Derived> \ - NAME(const Eigen::ArrayBase& x) { \ - return x.derived(); \ + (NAME)(const Eigen::ArrayBase& x) { \ + return Eigen::CwiseUnaryOp, const Derived>(x.derived()); \ } #define EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(NAME,FUNCTOR) \ @@ -30,25 +30,44 @@ { \ static inline typename NAME##_retval >::type run(const Eigen::ArrayBase& x) \ { \ - return x.derived(); \ + return typename NAME##_retval >::type(x.derived()); \ } \ }; - namespace Eigen { EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(real,scalar_real_op) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(imag,scalar_imag_op) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(conj,scalar_conjugate_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(inverse,scalar_inverse_op) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sin,scalar_sin_op) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cos,scalar_cos_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(tan,scalar_tan_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(atan,scalar_atan_op) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(asin,scalar_asin_op) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(acos,scalar_acos_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(tan,scalar_tan_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sinh,scalar_sinh_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cosh,scalar_cosh_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(tanh,scalar_tanh_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(lgamma,scalar_lgamma_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(erf,scalar_erf_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(erfc,scalar_erfc_op) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(exp,scalar_exp_op) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log,scalar_log_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log10,scalar_log10_op) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(abs,scalar_abs_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(abs2,scalar_abs2_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(arg,scalar_arg_op) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sqrt,scalar_sqrt_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(square,scalar_square_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cube,scalar_cube_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(round,scalar_round_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(floor,scalar_floor_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(ceil,scalar_ceil_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(isnan,scalar_isnan_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(isinf,scalar_isinf_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(isfinite,scalar_isfinite_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sign,scalar_sign_op) template inline const Eigen::CwiseUnaryOp, const Derived> @@ -56,16 +75,46 @@ namespace Eigen return x.derived().pow(exponent); } - template - inline const Eigen::CwiseBinaryOp, const Derived, const Derived> - pow(const Eigen::ArrayBase& x, const Eigen::ArrayBase& exponents) + /** \returns an expression of the coefficient-wise power of \a x to the given array of \a exponents. + * + * This function computes the coefficient-wise power. + * + * Example: \include Cwise_array_power_array.cpp + * Output: \verbinclude Cwise_array_power_array.out + * + * \sa ArrayBase::pow() + */ + template + inline const Eigen::CwiseBinaryOp, const Derived, const ExponentDerived> + pow(const Eigen::ArrayBase& x, const Eigen::ArrayBase& exponents) { - return Eigen::CwiseBinaryOp, const Derived, const Derived>( + return Eigen::CwiseBinaryOp, const Derived, const ExponentDerived>( x.derived(), exponents.derived() ); } + /** \returns an expression of the coefficient-wise power of the scalar \a x to the given array of \a exponents. + * + * This function computes the coefficient-wise power between a scalar and an array of exponents. + * Beaware that the scalar type of the input scalar \a x and the exponents \a exponents must be the same. + * + * Example: \include Cwise_scalar_power_array.cpp + * Output: \verbinclude Cwise_scalar_power_array.out + * + * \sa ArrayBase::pow() + */ + template + inline const Eigen::CwiseBinaryOp, const typename Derived::ConstantReturnType, const Derived> + pow(const typename Derived::Scalar& x, const Eigen::ArrayBase& exponents) + { + typename Derived::ConstantReturnType constant_x(exponents.rows(), exponents.cols(), x); + return Eigen::CwiseBinaryOp, const typename Derived::ConstantReturnType, const Derived>( + constant_x, + exponents.derived() + ); + } + /** * \brief Component-wise division of a scalar by array elements. **/ diff --git a/nuparu/include/Eigen/src/Core/IO.h b/nuparu/include/Eigen/src/Core/IO.h index c8d5f637..9ae37bb5 100644 --- a/nuparu/include/Eigen/src/Core/IO.h +++ b/nuparu/include/Eigen/src/Core/IO.h @@ -49,7 +49,7 @@ std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& */ struct IOFormat { - /** Default contructor, see class IOFormat for the meaning of the parameters */ + /** Default constructor, see class IOFormat for the meaning of the parameters */ IOFormat(int _precision = StreamPrecision, int _flags = 0, const std::string& _coeffSeparator = " ", const std::string& _rowSeparator = "\n", const std::string& _rowPrefix="", const std::string& _rowSuffix="", @@ -57,6 +57,10 @@ struct IOFormat : matPrefix(_matPrefix), matSuffix(_matSuffix), rowPrefix(_rowPrefix), rowSuffix(_rowSuffix), rowSeparator(_rowSeparator), rowSpacer(""), coeffSeparator(_coeffSeparator), precision(_precision), flags(_flags) { + // TODO check if rowPrefix, rowSuffix or rowSeparator contains a newline + // don't add rowSpacer if columns are not to be aligned + if((flags & DontAlignCols)) + return; int i = int(matSuffix.length())-1; while (i>=0 && matSuffix[i]!='\n') { @@ -160,7 +164,6 @@ std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& typename Derived::Nested m = _m; typedef typename Derived::Scalar Scalar; - typedef typename Derived::Index Index; Index width = 0; @@ -185,21 +188,22 @@ std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& explicit_precision = fmt.precision; } + std::streamsize old_precision = 0; + if(explicit_precision) old_precision = s.precision(explicit_precision); + bool align_cols = !(fmt.flags & DontAlignCols); if(align_cols) { // compute the largest width - for(Index j = 1; j < m.cols(); ++j) + for(Index j = 0; j < m.cols(); ++j) for(Index i = 0; i < m.rows(); ++i) { std::stringstream sstr; - if(explicit_precision) sstr.precision(explicit_precision); + sstr.copyfmt(s); sstr << m.coeff(i,j); width = std::max(width, Index(sstr.str().length())); } } - std::streamsize old_precision = 0; - if(explicit_precision) old_precision = s.precision(explicit_precision); s << fmt.matPrefix; for(Index i = 0; i < m.rows(); ++i) { diff --git a/nuparu/include/Eigen/src/Core/Inverse.h b/nuparu/include/Eigen/src/Core/Inverse.h new file mode 100644 index 00000000..f3ec8499 --- /dev/null +++ b/nuparu/include/Eigen/src/Core/Inverse.h @@ -0,0 +1,117 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_INVERSE_H +#define EIGEN_INVERSE_H + +namespace Eigen { + +template class InverseImpl; + +namespace internal { + +template +struct traits > + : traits +{ + typedef typename XprType::PlainObject PlainObject; + typedef traits BaseTraits; + enum { + Flags = BaseTraits::Flags & RowMajorBit + }; +}; + +} // end namespace internal + +/** \class Inverse + * + * \brief Expression of the inverse of another expression + * + * \tparam XprType the type of the expression we are taking the inverse + * + * This class represents an abstract expression of A.inverse() + * and most of the time this is the only way it is used. + * + */ +template +class Inverse : public InverseImpl::StorageKind> +{ +public: + typedef typename XprType::StorageIndex StorageIndex; + typedef typename XprType::PlainObject PlainObject; + typedef typename internal::ref_selector::type XprTypeNested; + typedef typename internal::remove_all::type XprTypeNestedCleaned; + typedef typename internal::ref_selector::type Nested; + typedef typename internal::remove_all::type NestedExpression; + + explicit Inverse(const XprType &xpr) + : m_xpr(xpr) + {} + + EIGEN_DEVICE_FUNC Index rows() const { return m_xpr.rows(); } + EIGEN_DEVICE_FUNC Index cols() const { return m_xpr.cols(); } + + EIGEN_DEVICE_FUNC const XprTypeNestedCleaned& nestedExpression() const { return m_xpr; } + +protected: + XprTypeNested m_xpr; +}; + +// Generic API dispatcher +template +class InverseImpl + : public internal::generic_xpr_base >::type +{ +public: + typedef typename internal::generic_xpr_base >::type Base; + typedef typename XprType::Scalar Scalar; +private: + + Scalar coeff(Index row, Index col) const; + Scalar coeff(Index i) const; +}; + +namespace internal { + +/** \internal + * \brief Default evaluator for Inverse expression. + * + * This default evaluator for Inverse expression simply evaluate the inverse into a temporary + * by a call to internal::call_assignment_no_alias. + * Therefore, inverse implementers only have to specialize Assignment, ...> for + * there own nested expression. + * + * \sa class Inverse + */ +template +struct unary_evaluator > + : public evaluator::PlainObject> +{ + typedef Inverse InverseType; + typedef typename InverseType::PlainObject PlainObject; + typedef evaluator Base; + + enum { Flags = Base::Flags | EvalBeforeNestingBit }; + + unary_evaluator(const InverseType& inv_xpr) + : m_result(inv_xpr.rows(), inv_xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + internal::call_assignment_no_alias(m_result, inv_xpr); + } + +protected: + PlainObject m_result; +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_INVERSE_H diff --git a/nuparu/include/Eigen/src/Core/Map.h b/nuparu/include/Eigen/src/Core/Map.h index f804c89d..3a8375da 100644 --- a/nuparu/include/Eigen/src/Core/Map.h +++ b/nuparu/include/Eigen/src/Core/Map.h @@ -19,7 +19,7 @@ namespace Eigen { * \brief A matrix or vector expression mapping an existing array of data. * * \tparam PlainObjectType the equivalent matrix type of the mapped data - * \tparam MapOptions specifies whether the pointer is \c #Aligned, or \c #Unaligned. + * \tparam MapOptions specifies the pointer alignment in bytes. It can be: \c #Aligned128, , \c #Aligned64, \c #Aligned32, \c #Aligned16, \c #Aligned8 or \c #Unaligned. * The default is \c #Unaligned. * \tparam StrideType optionally specifies strides. By default, Map assumes the memory layout * of an ordinary, contiguous array. This can be overridden by specifying strides. @@ -70,8 +70,6 @@ struct traits > : public traits { typedef traits TraitsBase; - typedef typename PlainObjectType::Index Index; - typedef typename PlainObjectType::Scalar Scalar; enum { InnerStrideAtCompileTime = StrideType::InnerStrideAtCompileTime == 0 ? int(PlainObjectType::InnerStrideAtCompileTime) @@ -79,22 +77,9 @@ struct traits > OuterStrideAtCompileTime = StrideType::OuterStrideAtCompileTime == 0 ? int(PlainObjectType::OuterStrideAtCompileTime) : int(StrideType::OuterStrideAtCompileTime), - HasNoInnerStride = InnerStrideAtCompileTime == 1, - HasNoOuterStride = StrideType::OuterStrideAtCompileTime == 0, - HasNoStride = HasNoInnerStride && HasNoOuterStride, - IsAligned = bool(EIGEN_ALIGN) && ((int(MapOptions)&Aligned)==Aligned), - IsDynamicSize = PlainObjectType::SizeAtCompileTime==Dynamic, - KeepsPacketAccess = bool(HasNoInnerStride) - && ( bool(IsDynamicSize) - || HasNoOuterStride - || ( OuterStrideAtCompileTime!=Dynamic - && ((static_cast(sizeof(Scalar))*OuterStrideAtCompileTime)%16)==0 ) ), + Alignment = int(MapOptions)&int(AlignedMask), Flags0 = TraitsBase::Flags & (~NestByRefBit), - Flags1 = IsAligned ? (int(Flags0) | AlignedBit) : (int(Flags0) & ~AlignedBit), - Flags2 = (bool(HasNoStride) || bool(PlainObjectType::IsVectorAtCompileTime)) - ? int(Flags1) : int(Flags1 & ~LinearAccessBit), - Flags3 = is_lvalue::value ? int(Flags2) : (int(Flags2) & ~LvalueBit), - Flags = KeepsPacketAccess ? int(Flags3) : (int(Flags3) & ~PacketAccessBit) + Flags = is_lvalue::value ? int(Flags0) : (int(Flags0) & ~LvalueBit) }; private: enum { Options }; // Expressions don't have Options @@ -110,19 +95,17 @@ template class Ma EIGEN_DENSE_PUBLIC_INTERFACE(Map) typedef typename Base::PointerType PointerType; -#if EIGEN2_SUPPORT_STAGE <= STAGE30_FULL_EIGEN3_API - typedef const Scalar* PointerArgType; - inline PointerType cast_to_pointer_type(PointerArgType ptr) { return const_cast(ptr); } -#else typedef PointerType PointerArgType; + EIGEN_DEVICE_FUNC inline PointerType cast_to_pointer_type(PointerArgType ptr) { return ptr; } -#endif + EIGEN_DEVICE_FUNC inline Index innerStride() const { return StrideType::InnerStrideAtCompileTime != 0 ? m_stride.inner() : 1; } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return StrideType::OuterStrideAtCompileTime != 0 ? m_stride.outer() @@ -134,10 +117,11 @@ template class Ma /** Constructor in the fixed-size case. * * \param dataPtr pointer to the array to map - * \param a_stride optional Stride object, passing the strides. + * \param stride optional Stride object, passing the strides. */ - inline Map(PointerArgType dataPtr, const StrideType& a_stride = StrideType()) - : Base(cast_to_pointer_type(dataPtr)), m_stride(a_stride) + EIGEN_DEVICE_FUNC + explicit inline Map(PointerArgType dataPtr, const StrideType& stride = StrideType()) + : Base(cast_to_pointer_type(dataPtr)), m_stride(stride) { PlainObjectType::Base::_check_template_params(); } @@ -145,11 +129,12 @@ template class Ma /** Constructor in the dynamic-size vector case. * * \param dataPtr pointer to the array to map - * \param a_size the size of the vector expression - * \param a_stride optional Stride object, passing the strides. + * \param size the size of the vector expression + * \param stride optional Stride object, passing the strides. */ - inline Map(PointerArgType dataPtr, Index a_size, const StrideType& a_stride = StrideType()) - : Base(cast_to_pointer_type(dataPtr), a_size), m_stride(a_stride) + EIGEN_DEVICE_FUNC + inline Map(PointerArgType dataPtr, Index size, const StrideType& stride = StrideType()) + : Base(cast_to_pointer_type(dataPtr), size), m_stride(stride) { PlainObjectType::Base::_check_template_params(); } @@ -157,12 +142,13 @@ template class Ma /** Constructor in the dynamic-size matrix case. * * \param dataPtr pointer to the array to map - * \param nbRows the number of rows of the matrix expression - * \param nbCols the number of columns of the matrix expression - * \param a_stride optional Stride object, passing the strides. + * \param rows the number of rows of the matrix expression + * \param cols the number of columns of the matrix expression + * \param stride optional Stride object, passing the strides. */ - inline Map(PointerArgType dataPtr, Index nbRows, Index nbCols, const StrideType& a_stride = StrideType()) - : Base(cast_to_pointer_type(dataPtr), nbRows, nbCols), m_stride(a_stride) + EIGEN_DEVICE_FUNC + inline Map(PointerArgType dataPtr, Index rows, Index cols, const StrideType& stride = StrideType()) + : Base(cast_to_pointer_type(dataPtr), rows, cols), m_stride(stride) { PlainObjectType::Base::_check_template_params(); } @@ -173,19 +159,6 @@ template class Ma StrideType m_stride; }; -template -inline Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> - ::Array(const Scalar *data) -{ - this->_set_noalias(Eigen::Map(data)); -} - -template -inline Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> - ::Matrix(const Scalar *data) -{ - this->_set_noalias(Eigen::Map(data)); -} } // end namespace Eigen diff --git a/nuparu/include/Eigen/src/Core/MapBase.h b/nuparu/include/Eigen/src/Core/MapBase.h index 6876de58..75a80daa 100644 --- a/nuparu/include/Eigen/src/Core/MapBase.h +++ b/nuparu/include/Eigen/src/Core/MapBase.h @@ -12,7 +12,7 @@ #define EIGEN_MAPBASE_H #define EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) \ - EIGEN_STATIC_ASSERT((int(internal::traits::Flags) & LinearAccessBit) || Derived::IsVectorAtCompileTime, \ + EIGEN_STATIC_ASSERT((int(internal::evaluator::Flags) & LinearAccessBit) || Derived::IsVectorAtCompileTime, \ YOU_ARE_TRYING_TO_USE_AN_INDEX_BASED_ACCESSOR_ON_AN_EXPRESSION_THAT_DOES_NOT_SUPPORT_THAT) namespace Eigen { @@ -37,7 +37,6 @@ template class MapBase }; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; @@ -76,8 +75,8 @@ template class MapBase typedef typename Base::CoeffReturnType CoeffReturnType; - inline Index rows() const { return m_rows.value(); } - inline Index cols() const { return m_cols.value(); } + EIGEN_DEVICE_FUNC inline Index rows() const { return m_rows.value(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_cols.value(); } /** Returns a pointer to the first coefficient of the matrix or vector. * @@ -85,24 +84,28 @@ template class MapBase * * \sa innerStride(), outerStride() */ - inline const Scalar* data() const { return m_data; } + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return m_data; } + EIGEN_DEVICE_FUNC inline const Scalar& coeff(Index rowId, Index colId) const { return m_data[colId * colStride() + rowId * rowStride()]; } + EIGEN_DEVICE_FUNC inline const Scalar& coeff(Index index) const { EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) return m_data[index * innerStride()]; } + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index rowId, Index colId) const { return this->m_data[colId * colStride() + rowId * rowStride()]; } + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index index) const { EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) @@ -123,12 +126,14 @@ template class MapBase return internal::ploadt(m_data + index * innerStride()); } - inline MapBase(PointerType dataPtr) : m_data(dataPtr), m_rows(RowsAtCompileTime), m_cols(ColsAtCompileTime) + EIGEN_DEVICE_FUNC + explicit inline MapBase(PointerType dataPtr) : m_data(dataPtr), m_rows(RowsAtCompileTime), m_cols(ColsAtCompileTime) { EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) checkSanity(); } + EIGEN_DEVICE_FUNC inline MapBase(PointerType dataPtr, Index vecSize) : m_data(dataPtr), m_rows(RowsAtCompileTime == Dynamic ? vecSize : Index(RowsAtCompileTime)), @@ -140,24 +145,28 @@ template class MapBase checkSanity(); } - inline MapBase(PointerType dataPtr, Index nbRows, Index nbCols) - : m_data(dataPtr), m_rows(nbRows), m_cols(nbCols) + EIGEN_DEVICE_FUNC + inline MapBase(PointerType dataPtr, Index rows, Index cols) + : m_data(dataPtr), m_rows(rows), m_cols(cols) { eigen_assert( (dataPtr == 0) - || ( nbRows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == nbRows) - && nbCols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == nbCols))); + || ( rows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == rows) + && cols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols))); checkSanity(); } + #ifdef EIGEN_MAPBASE_PLUGIN + #include EIGEN_MAPBASE_PLUGIN + #endif + protected: + EIGEN_DEVICE_FUNC void checkSanity() const { - EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(internal::traits::Flags&PacketAccessBit, - internal::inner_stride_at_compile_time::ret==1), - PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1); - eigen_assert(EIGEN_IMPLIES(internal::traits::Flags&AlignedBit, (size_t(m_data) % 16) == 0) - && "data is not aligned"); +#if EIGEN_MAX_ALIGN_BYTES>0 + eigen_assert(((size_t(m_data) % EIGEN_PLAIN_ENUM_MAX(1,internal::traits::Alignment)) == 0) && "data is not aligned"); +#endif } PointerType m_data; @@ -168,13 +177,14 @@ template class MapBase template class MapBase : public MapBase { + typedef MapBase ReadOnlyMapBase; public: typedef MapBase Base; typedef typename Base::Scalar Scalar; typedef typename Base::PacketScalar PacketScalar; - typedef typename Base::Index Index; + typedef typename Base::StorageIndex StorageIndex; typedef typename Base::PointerType PointerType; using Base::derived; @@ -195,14 +205,18 @@ template class MapBase const Scalar >::type ScalarWithConstIfNotLvalue; + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return this->m_data; } + EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue* data() { return this->m_data; } // no const-cast here so non-const-correct code will give a compile error + EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue& coeffRef(Index row, Index col) { return this->m_data[col * colStride() + row * rowStride()]; } + EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue& coeffRef(Index index) { EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) @@ -224,19 +238,24 @@ template class MapBase (this->m_data + index * innerStride(), val); } - explicit inline MapBase(PointerType dataPtr) : Base(dataPtr) {} - inline MapBase(PointerType dataPtr, Index vecSize) : Base(dataPtr, vecSize) {} - inline MapBase(PointerType dataPtr, Index nbRows, Index nbCols) : Base(dataPtr, nbRows, nbCols) {} + EIGEN_DEVICE_FUNC explicit inline MapBase(PointerType dataPtr) : Base(dataPtr) {} + EIGEN_DEVICE_FUNC inline MapBase(PointerType dataPtr, Index vecSize) : Base(dataPtr, vecSize) {} + EIGEN_DEVICE_FUNC inline MapBase(PointerType dataPtr, Index rows, Index cols) : Base(dataPtr, rows, cols) {} + EIGEN_DEVICE_FUNC Derived& operator=(const MapBase& other) { - Base::Base::operator=(other); + ReadOnlyMapBase::Base::operator=(other); return derived(); } - using Base::Base::operator=; + // In theory we could simply refer to Base:Base::operator=, but MSVC does not like Base::Base, + // see bugs 821 and 920. + using ReadOnlyMapBase::Base::operator=; }; +#undef EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS + } // end namespace Eigen #endif // EIGEN_MAPBASE_H diff --git a/nuparu/include/Eigen/src/Core/MathFunctions.h b/nuparu/include/Eigen/src/Core/MathFunctions.h index 2bfc5ebd..48cf565f 100644 --- a/nuparu/include/Eigen/src/Core/MathFunctions.h +++ b/nuparu/include/Eigen/src/Core/MathFunctions.h @@ -10,8 +10,20 @@ #ifndef EIGEN_MATHFUNCTIONS_H #define EIGEN_MATHFUNCTIONS_H +// source: http://www.geom.uiuc.edu/~huberty/math5337/groupe/digits.html +#define EIGEN_PI 3.141592653589793238462643383279502884197169399375105820974944592307816406 + namespace Eigen { +// On WINCE, std::abs is defined for int only, so let's defined our own overloads: +// This issue has been confirmed with MSVC 2008 only, but the issue might exist for more recent versions too. +#if EIGEN_OS_WINCE && EIGEN_COMP_MSVC && EIGEN_COMP_MSVC<=1500 +long abs(long x) { return (labs(x)); } +double abs(double x) { return (fabs(x)); } +float abs(float x) { return (fabsf(x)); } +long double abs(long double x) { return (fabsl(x)); } +#endif + namespace internal { /** \internal \struct global_math_functions_filtering_base @@ -62,6 +74,7 @@ template::IsComplex> struct real_default_impl { typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar& x) { return x; @@ -72,6 +85,7 @@ template struct real_default_impl { typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar& x) { using std::real; @@ -87,7 +101,6 @@ struct real_retval typedef typename NumTraits::Real type; }; - /**************************************************************************** * Implementation of imag * ****************************************************************************/ @@ -96,6 +109,7 @@ template::IsComplex> struct imag_default_impl { typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar&) { return RealScalar(0); @@ -106,6 +120,7 @@ template struct imag_default_impl { typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar& x) { using std::imag; @@ -129,10 +144,12 @@ template struct real_ref_impl { typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC static inline RealScalar& run(Scalar& x) { return reinterpret_cast(&x)[0]; } + EIGEN_DEVICE_FUNC static inline const RealScalar& run(const Scalar& x) { return reinterpret_cast(&x)[0]; @@ -153,10 +170,12 @@ template struct imag_ref_default_impl { typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC static inline RealScalar& run(Scalar& x) { return reinterpret_cast(&x)[1]; } + EIGEN_DEVICE_FUNC static inline const RealScalar& run(const Scalar& x) { return reinterpret_cast(&x)[1]; @@ -166,10 +185,12 @@ struct imag_ref_default_impl template struct imag_ref_default_impl { + EIGEN_DEVICE_FUNC static inline Scalar run(Scalar&) { return Scalar(0); } + EIGEN_DEVICE_FUNC static inline const Scalar run(const Scalar&) { return Scalar(0); @@ -192,6 +213,7 @@ struct imag_ref_retval template::IsComplex> struct conj_impl { + EIGEN_DEVICE_FUNC static inline Scalar run(const Scalar& x) { return x; @@ -201,6 +223,7 @@ struct conj_impl template struct conj_impl { + EIGEN_DEVICE_FUNC static inline Scalar run(const Scalar& x) { using std::conj; @@ -218,25 +241,39 @@ struct conj_retval * Implementation of abs2 * ****************************************************************************/ -template -struct abs2_impl +template +struct abs2_impl_default { typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar& x) { return x*x; } }; -template -struct abs2_impl > +template +struct abs2_impl_default // IsComplex { - static inline RealScalar run(const std::complex& x) + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) { return real(x)*real(x) + imag(x)*imag(x); } }; +template +struct abs2_impl +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + return abs2_impl_default::IsComplex>::run(x); + } +}; + template struct abs2_retval { @@ -251,9 +288,10 @@ template struct norm1_default_impl { typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar& x) { - using std::abs; + EIGEN_USING_STD_MATH(abs); return abs(real(x)) + abs(imag(x)); } }; @@ -261,9 +299,10 @@ struct norm1_default_impl template struct norm1_default_impl { + EIGEN_DEVICE_FUNC static inline Scalar run(const Scalar& x) { - using std::abs; + EIGEN_USING_STD_MATH(abs); return abs(x); } }; @@ -287,16 +326,22 @@ struct hypot_impl typedef typename NumTraits::Real RealScalar; static inline RealScalar run(const Scalar& x, const Scalar& y) { - using std::max; - using std::min; - using std::abs; - using std::sqrt; + EIGEN_USING_STD_MATH(abs); + EIGEN_USING_STD_MATH(sqrt); RealScalar _x = abs(x); RealScalar _y = abs(y); - RealScalar p = (max)(_x, _y); - if(p==RealScalar(0)) return 0; - RealScalar q = (min)(_x, _y); - RealScalar qp = q/p; + Scalar p, qp; + if(_x>_y) + { + p = _x; + qp = _y / p; + } + else + { + p = _y; + qp = _x / p; + } + if(p==RealScalar(0)) return RealScalar(0); return p * sqrt(RealScalar(1) + qp*qp); } }; @@ -314,6 +359,7 @@ struct hypot_retval template struct cast_impl { + EIGEN_DEVICE_FUNC static inline NewType run(const OldType& x) { return static_cast(x); @@ -323,48 +369,121 @@ struct cast_impl // here, for once, we're plainly returning NewType: we don't want cast to do weird things. template +EIGEN_DEVICE_FUNC inline NewType cast(const OldType& x) { return cast_impl::run(x); } /**************************************************************************** -* Implementation of atanh2 * +* Implementation of round * ****************************************************************************/ -template -struct atanh2_default_impl -{ - typedef Scalar retval; - typedef typename NumTraits::Real RealScalar; - static inline Scalar run(const Scalar& x, const Scalar& y) +#if EIGEN_HAS_CXX11_MATH + template + struct round_impl { + static inline Scalar run(const Scalar& x) + { + EIGEN_STATIC_ASSERT((!NumTraits::IsComplex), NUMERIC_TYPE_MUST_BE_REAL) + using std::round; + return round(x); + } + }; +#else + template + struct round_impl { - using std::abs; - using std::log; - using std::sqrt; - Scalar z = x / y; - if (y == Scalar(0) || abs(z) > sqrt(NumTraits::epsilon())) - return RealScalar(0.5) * log((y + x) / (y - x)); - else - return z + z*z*z / RealScalar(3); - } + static inline Scalar run(const Scalar& x) + { + EIGEN_STATIC_ASSERT((!NumTraits::IsComplex), NUMERIC_TYPE_MUST_BE_REAL) + EIGEN_USING_STD_MATH(floor); + EIGEN_USING_STD_MATH(ceil); + return (x > Scalar(0)) ? floor(x + Scalar(0.5)) : ceil(x - Scalar(0.5)); + } + }; +#endif + +template +struct round_retval +{ + typedef Scalar type; }; +/**************************************************************************** +* Implementation of arg * +****************************************************************************/ + +#if EIGEN_HAS_CXX11_MATH + template + struct arg_impl { + static inline Scalar run(const Scalar& x) + { + EIGEN_USING_STD_MATH(arg); + return arg(x); + } + }; +#else + template::IsComplex> + struct arg_default_impl + { + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + return (x < Scalar(0)) ? Scalar(EIGEN_PI) : Scalar(0); } + }; + + template + struct arg_default_impl + { + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + EIGEN_USING_STD_MATH(arg); + return arg(x); + } + }; + + template struct arg_impl : arg_default_impl {}; +#endif + template -struct atanh2_default_impl +struct arg_retval +{ + typedef typename NumTraits::Real type; +}; + +/**************************************************************************** +* Implementation of log1p * +****************************************************************************/ +template::IsComplex > +struct log1p_impl { - static inline Scalar run(const Scalar&, const Scalar&) + static inline Scalar run(const Scalar& x) { EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) - return Scalar(0); + typedef typename NumTraits::Real RealScalar; + EIGEN_USING_STD_MATH(log); + Scalar x1p = RealScalar(1) + x; + return ( x1p == Scalar(1) ) ? x : x * ( log(x1p) / (x1p - RealScalar(1)) ); } }; +#if EIGEN_HAS_CXX11_MATH template -struct atanh2_impl : atanh2_default_impl::IsInteger> {}; +struct log1p_impl { + static inline Scalar run(const Scalar& x) + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) + using std::log1p; + return log1p(x); + } +}; +#endif template -struct atanh2_retval +struct log1p_retval { typedef Scalar type; }; @@ -379,7 +498,7 @@ struct pow_default_impl typedef Scalar retval; static inline Scalar run(const Scalar& x, const Scalar& y) { - using std::pow; + EIGEN_USING_STD_MATH(pow); return pow(x, y); } }; @@ -447,48 +566,48 @@ struct random_default_impl }; enum { - floor_log2_terminate, - floor_log2_move_up, - floor_log2_move_down, - floor_log2_bogus + meta_floor_log2_terminate, + meta_floor_log2_move_up, + meta_floor_log2_move_down, + meta_floor_log2_bogus }; -template struct floor_log2_selector +template struct meta_floor_log2_selector { enum { middle = (lower + upper) / 2, - value = (upper <= lower + 1) ? int(floor_log2_terminate) - : (n < (1 << middle)) ? int(floor_log2_move_down) - : (n==0) ? int(floor_log2_bogus) - : int(floor_log2_move_up) + value = (upper <= lower + 1) ? int(meta_floor_log2_terminate) + : (n < (1 << middle)) ? int(meta_floor_log2_move_down) + : (n==0) ? int(meta_floor_log2_bogus) + : int(meta_floor_log2_move_up) }; }; template::value> -struct floor_log2 {}; + int selector = meta_floor_log2_selector::value> +struct meta_floor_log2 {}; template -struct floor_log2 +struct meta_floor_log2 { - enum { value = floor_log2::middle>::value }; + enum { value = meta_floor_log2::middle>::value }; }; template -struct floor_log2 +struct meta_floor_log2 { - enum { value = floor_log2::middle, upper>::value }; + enum { value = meta_floor_log2::middle, upper>::value }; }; template -struct floor_log2 +struct meta_floor_log2 { enum { value = (n >= ((unsigned int)(1) << (lower+1))) ? lower+1 : lower }; }; template -struct floor_log2 +struct meta_floor_log2 { // no value, error at compile time }; @@ -496,11 +615,22 @@ struct floor_log2 template struct random_default_impl { - typedef typename NumTraits::NonInteger NonInteger; - static inline Scalar run(const Scalar& x, const Scalar& y) - { - return x + Scalar((NonInteger(y)-x+1) * std::rand() / (RAND_MAX + NonInteger(1))); + { + typedef typename conditional::IsSigned,std::ptrdiff_t,std::size_t>::type ScalarX; + if(y range); + + return Scalar(ScalarX(x) + offset); } static inline Scalar run() @@ -508,7 +638,7 @@ struct random_default_impl #ifdef EIGEN_MAKING_DOCS return run(Scalar(NumTraits::IsSigned ? -10 : 0), Scalar(10)); #else - enum { rand_bits = floor_log2<(unsigned int)(RAND_MAX)+1>::value, + enum { rand_bits = meta_floor_log2<(unsigned int)(RAND_MAX)+1>::value, scalar_bits = sizeof(Scalar) * CHAR_BIT, shift = EIGEN_PLAIN_ENUM_MAX(0, int(rand_bits) - int(scalar_bits)), offset = NumTraits::IsSigned ? (1 << (EIGEN_PLAIN_ENUM_MIN(rand_bits,scalar_bits)-1)) : 0 @@ -545,97 +675,322 @@ inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random() return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(); } +// Implementatin of is* functions + +// std::is* do not work with fast-math and gcc, std::is* are available on MSVC 2013 and newer, as well as in clang. +#if (EIGEN_HAS_CXX11_MATH && !(EIGEN_COMP_GNUC_STRICT && __FINITE_MATH_ONLY__)) || (EIGEN_COMP_MSVC>=1800) || (EIGEN_COMP_CLANG) +#define EIGEN_USE_STD_FPCLASSIFY 1 +#else +#define EIGEN_USE_STD_FPCLASSIFY 0 +#endif + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if::value,bool>::type +isnan_impl(const T&) { return false; } + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if::value,bool>::type +isinf_impl(const T&) { return false; } + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if::value,bool>::type +isfinite_impl(const T&) { return true; } + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if<(!internal::is_integral::value)&&(!NumTraits::IsComplex),bool>::type +isfinite_impl(const T& x) +{ + #if EIGEN_USE_STD_FPCLASSIFY + using std::isfinite; + return isfinite EIGEN_NOT_A_MACRO (x); + #else + return x::highest() && x>NumTraits::lowest(); + #endif +} + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if<(!internal::is_integral::value)&&(!NumTraits::IsComplex),bool>::type +isinf_impl(const T& x) +{ + #if EIGEN_USE_STD_FPCLASSIFY + using std::isinf; + return isinf EIGEN_NOT_A_MACRO (x); + #else + return x>NumTraits::highest() || x::lowest(); + #endif +} + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if<(!internal::is_integral::value)&&(!NumTraits::IsComplex),bool>::type +isnan_impl(const T& x) +{ + #if EIGEN_USE_STD_FPCLASSIFY + using std::isnan; + return isnan EIGEN_NOT_A_MACRO (x); + #else + return x != x; + #endif +} + +#if (!EIGEN_USE_STD_FPCLASSIFY) + +#if EIGEN_COMP_MSVC + +template EIGEN_DEVICE_FUNC bool isinf_msvc_helper(T x) +{ + return _fpclass(x)==_FPCLASS_NINF || _fpclass(x)==_FPCLASS_PINF; +} + +//MSVC defines a _isnan builtin function, but for double only +EIGEN_DEVICE_FUNC inline bool isnan_impl(const long double& x) { return _isnan(x); } +EIGEN_DEVICE_FUNC inline bool isnan_impl(const double& x) { return _isnan(x); } +EIGEN_DEVICE_FUNC inline bool isnan_impl(const float& x) { return _isnan(x); } + +EIGEN_DEVICE_FUNC inline bool isinf_impl(const long double& x) { return isinf_msvc_helper(x); } +EIGEN_DEVICE_FUNC inline bool isinf_impl(const double& x) { return isinf_msvc_helper(x); } +EIGEN_DEVICE_FUNC inline bool isinf_impl(const float& x) { return isinf_msvc_helper(x); } + +#elif (defined __FINITE_MATH_ONLY__ && __FINITE_MATH_ONLY__ && EIGEN_COMP_GNUC) + +#if EIGEN_GNUC_AT_LEAST(5,0) + #define EIGEN_TMP_NOOPT_ATTRIB EIGEN_DEVICE_FUNC inline __attribute__((optimize("no-finite-math-only"))) +#else + // NOTE the inline qualifier and noinline attribute are both needed: the former is to avoid linking issue (duplicate symbol), + // while the second prevent too aggressive optimizations in fast-math mode: + #define EIGEN_TMP_NOOPT_ATTRIB EIGEN_DEVICE_FUNC inline __attribute__((noinline,optimize("no-finite-math-only"))) +#endif + +template<> EIGEN_TMP_NOOPT_ATTRIB bool isnan_impl(const long double& x) { return __builtin_isnan(x); } +template<> EIGEN_TMP_NOOPT_ATTRIB bool isnan_impl(const double& x) { return __builtin_isnan(x); } +template<> EIGEN_TMP_NOOPT_ATTRIB bool isnan_impl(const float& x) { return __builtin_isnan(x); } +template<> EIGEN_TMP_NOOPT_ATTRIB bool isinf_impl(const double& x) { return __builtin_isinf(x); } +template<> EIGEN_TMP_NOOPT_ATTRIB bool isinf_impl(const float& x) { return __builtin_isinf(x); } +template<> EIGEN_TMP_NOOPT_ATTRIB bool isinf_impl(const long double& x) { return __builtin_isinf(x); } + +#undef EIGEN_TMP_NOOPT_ATTRIB + +#endif + +#endif + +// The following overload are defined at the end of this file +template bool isfinite_impl(const std::complex& x); +template bool isnan_impl(const std::complex& x); +template bool isinf_impl(const std::complex& x); + } // end namespace internal /**************************************************************************** -* Generic math function * +* Generic math functions * ****************************************************************************/ namespace numext { +#ifndef __CUDA_ARCH__ +template +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE T mini(const T& x, const T& y) +{ + EIGEN_USING_STD_MATH(min); + return min EIGEN_NOT_A_MACRO (x,y); +} + +template +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE T maxi(const T& x, const T& y) +{ + EIGEN_USING_STD_MATH(max); + return max EIGEN_NOT_A_MACRO (x,y); +} +#else +template +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE T mini(const T& x, const T& y) +{ + return y < x ? y : x; +} +template<> +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE float mini(const float& x, const float& y) +{ + return fmin(x, y); +} +template +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE T maxi(const T& x, const T& y) +{ + return x < y ? y : x; +} +template<> +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE float maxi(const float& x, const float& y) +{ + return fmax(x, y); +} +#endif + + template +EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(real, Scalar) real(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(real, Scalar)::run(x); } template +EIGEN_DEVICE_FUNC inline typename internal::add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) >::type real_ref(const Scalar& x) { return internal::real_ref_impl::run(x); } template +EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) real_ref(Scalar& x) { return EIGEN_MATHFUNC_IMPL(real_ref, Scalar)::run(x); } template +EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(imag, Scalar) imag(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(imag, Scalar)::run(x); } template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(arg, Scalar) arg(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(arg, Scalar)::run(x); +} + +template +EIGEN_DEVICE_FUNC inline typename internal::add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) >::type imag_ref(const Scalar& x) { return internal::imag_ref_impl::run(x); } template +EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) imag_ref(Scalar& x) { return EIGEN_MATHFUNC_IMPL(imag_ref, Scalar)::run(x); } template +EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(conj, Scalar) conj(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(conj, Scalar)::run(x); } template +EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(abs2, Scalar) abs2(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(abs2, Scalar)::run(x); } template +EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(norm1, Scalar) norm1(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(norm1, Scalar)::run(x); } template +EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(hypot, Scalar) hypot(const Scalar& x, const Scalar& y) { return EIGEN_MATHFUNC_IMPL(hypot, Scalar)::run(x, y); } template -inline EIGEN_MATHFUNC_RETVAL(atanh2, Scalar) atanh2(const Scalar& x, const Scalar& y) +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(log1p, Scalar) log1p(const Scalar& x) { - return EIGEN_MATHFUNC_IMPL(atanh2, Scalar)::run(x, y); + return EIGEN_MATHFUNC_IMPL(log1p, Scalar)::run(x); } template +EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(pow, Scalar) pow(const Scalar& x, const Scalar& y) { return EIGEN_MATHFUNC_IMPL(pow, Scalar)::run(x, y); } -// std::isfinite is non standard, so let's define our own version, -// even though it is not very efficient. -template bool (isfinite)(const T& x) +template EIGEN_DEVICE_FUNC bool (isnan) (const T &x) { return internal::isnan_impl(x); } +template EIGEN_DEVICE_FUNC bool (isinf) (const T &x) { return internal::isinf_impl(x); } +template EIGEN_DEVICE_FUNC bool (isfinite)(const T &x) { return internal::isfinite_impl(x); } + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(round, Scalar) round(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(round, Scalar)::run(x); +} + +template +EIGEN_DEVICE_FUNC +T (floor)(const T& x) +{ + EIGEN_USING_STD_MATH(floor); + return floor(x); +} + +template +EIGEN_DEVICE_FUNC +T (ceil)(const T& x) { - return x::highest() && x>NumTraits::lowest(); + EIGEN_USING_STD_MATH(ceil); + return ceil(x); +} + +// Log base 2 for 32 bits positive integers. +// Conveniently returns 0 for x==0. +inline int log2(int x) +{ + eigen_assert(x>=0); + unsigned int v(x); + static const int table[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 }; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + return table[(v * 0x07C4ACDDU) >> 27]; } } // end namespace numext namespace internal { +template +bool isfinite_impl(const std::complex& x) +{ + return (numext::isfinite)(numext::real(x)) && (numext::isfinite)(numext::imag(x)); +} + +template +bool isnan_impl(const std::complex& x) +{ + return (numext::isnan)(numext::real(x)) || (numext::isnan)(numext::imag(x)); +} + +template +bool isinf_impl(const std::complex& x) +{ + return ((numext::isinf)(numext::real(x)) || (numext::isinf)(numext::imag(x))) && (!(numext::isnan)(x)); +} + /**************************************************************************** * Implementation of fuzzy comparisons * ****************************************************************************/ @@ -649,18 +1004,19 @@ template struct scalar_fuzzy_default_impl { typedef typename NumTraits::Real RealScalar; - template + template EIGEN_DEVICE_FUNC static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec) { - using std::abs; + EIGEN_USING_STD_MATH(abs); return abs(x) <= abs(y) * prec; } + EIGEN_DEVICE_FUNC static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) { - using std::min; - using std::abs; - return abs(x - y) <= (min)(abs(x), abs(y)) * prec; + EIGEN_USING_STD_MATH(abs); + return abs(x - y) <= numext::mini(abs(x), abs(y)) * prec; } + EIGEN_DEVICE_FUNC static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar& prec) { return x <= y || isApprox(x, y, prec); @@ -671,15 +1027,17 @@ template struct scalar_fuzzy_default_impl { typedef typename NumTraits::Real RealScalar; - template + template EIGEN_DEVICE_FUNC static inline bool isMuchSmallerThan(const Scalar& x, const Scalar&, const RealScalar&) { return x == Scalar(0); } + EIGEN_DEVICE_FUNC static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar&) { return x == y; } + EIGEN_DEVICE_FUNC static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar&) { return x <= y; @@ -697,29 +1055,28 @@ struct scalar_fuzzy_default_impl } static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) { - using std::min; - return numext::abs2(x - y) <= (min)(numext::abs2(x), numext::abs2(y)) * prec * prec; + return numext::abs2(x - y) <= numext::mini(numext::abs2(x), numext::abs2(y)) * prec * prec; } }; template struct scalar_fuzzy_impl : scalar_fuzzy_default_impl::IsComplex, NumTraits::IsInteger> {}; -template +template EIGEN_DEVICE_FUNC inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, typename NumTraits::Real precision = NumTraits::dummy_precision()) { return scalar_fuzzy_impl::template isMuchSmallerThan(x, y, precision); } -template +template EIGEN_DEVICE_FUNC inline bool isApprox(const Scalar& x, const Scalar& y, typename NumTraits::Real precision = NumTraits::dummy_precision()) { return scalar_fuzzy_impl::isApprox(x, y, precision); } -template +template EIGEN_DEVICE_FUNC inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, typename NumTraits::Real precision = NumTraits::dummy_precision()) { @@ -742,17 +1099,19 @@ template<> struct scalar_fuzzy_impl { typedef bool RealScalar; - template + template EIGEN_DEVICE_FUNC static inline bool isMuchSmallerThan(const bool& x, const bool&, const bool&) { return !x; } + EIGEN_DEVICE_FUNC static inline bool isApprox(bool x, bool y, bool) { return x == y; } + EIGEN_DEVICE_FUNC static inline bool isApproxOrLessThan(const bool& x, const bool& y, const bool&) { return (!x) || y; diff --git a/nuparu/include/Eigen/src/Core/Matrix.h b/nuparu/include/Eigen/src/Core/Matrix.h index 0ba5d90c..ce1b70d2 100644 --- a/nuparu/include/Eigen/src/Core/Matrix.h +++ b/nuparu/include/Eigen/src/Core/Matrix.h @@ -24,13 +24,13 @@ namespace Eigen { * The %Matrix class encompasses \em both fixed-size and dynamic-size objects (\ref fixedsize "note"). * * The first three template parameters are required: - * \tparam _Scalar \anchor matrix_tparam_scalar Numeric type, e.g. float, double, int or std::complex. - * User defined sclar types are supported as well (see \ref user_defined_scalars "here"). + * \tparam _Scalar Numeric type, e.g. float, double, int or std::complex. + * User defined scalar types are supported as well (see \ref user_defined_scalars "here"). * \tparam _Rows Number of rows, or \b Dynamic * \tparam _Cols Number of columns, or \b Dynamic * * The remaining template parameters are optional -- in most cases you don't have to worry about them. - * \tparam _Options \anchor matrix_tparam_options A combination of either \b #RowMajor or \b #ColMajor, and of either + * \tparam _Options A combination of either \b #RowMajor or \b #ColMajor, and of either * \b #AutoAlign or \b #DontAlign. * The former controls \ref TopicStorageOrders "storage order", and defaults to column-major. The latter controls alignment, which is required * for vectorization. It defaults to aligning matrices except for fixed sizes that aren't a multiple of the packet size. @@ -97,6 +97,40 @@ namespace Eigen { * are the dimensions of the original matrix, while _Rows and _Cols are Dynamic. * * + * ABI and storage layout + * + * The table below summarizes the ABI of some possible Matrix instances which is fixed thorough the lifetime of Eigen 3. + * + * + * + * + * + * + *
Matrix typeEquivalent C structure
\code Matrix \endcode\code + * struct { + * T *data; // with (size_t(data)%EIGEN_MAX_ALIGN_BYTES)==0 + * Eigen::Index rows, cols; + * }; + * \endcode
\code + * Matrix + * Matrix \endcode\code + * struct { + * T *data; // with (size_t(data)%EIGEN_MAX_ALIGN_BYTES)==0 + * Eigen::Index size; + * }; + * \endcode
\code Matrix \endcode\code + * struct { + * T data[Rows*Cols]; // with (size_t(data)%A(Rows*Cols*sizeof(T)))==0 + * }; + * \endcode
\code Matrix \endcode\code + * struct { + * T data[MaxRows*MaxCols]; // with (size_t(data)%A(MaxRows*MaxCols*sizeof(T)))==0 + * Eigen::Index rows, cols; + * }; + * \endcode
+ * Note that in this table Rows, Cols, MaxRows and MaxCols are all positive integers. A(S) is defined to the largest possible power-of-two + * smaller to EIGEN_MAX_STATIC_ALIGN_BYTES. + * * \see MatrixBase for the majority of the API methods for matrices, \ref TopicClassHierarchy, * \ref TopicStorageOrders */ @@ -105,9 +139,23 @@ namespace internal { template struct traits > { +private: + enum { size = internal::size_at_compile_time<_Rows,_Cols>::ret }; + typedef typename find_best_packet<_Scalar,size>::type PacketScalar; + enum { + row_major_bit = _Options&RowMajor ? RowMajorBit : 0, + is_dynamic_size_storage = _MaxRows==Dynamic || _MaxCols==Dynamic, + max_size = is_dynamic_size_storage ? Dynamic : _MaxRows*_MaxCols, + default_alignment = compute_default_alignment<_Scalar,max_size>::value, + actual_alignment = ((_Options&DontAlign)==0) ? default_alignment : 0, + required_alignment = unpacket_traits::alignment, + packet_access_bit = packet_traits<_Scalar>::Vectorizable && (actual_alignment>=required_alignment) ? PacketAccessBit : 0 + }; + +public: typedef _Scalar Scalar; typedef Dense StorageKind; - typedef DenseIndex Index; + typedef Eigen::Index StorageIndex; typedef MatrixXpr XprKind; enum { RowsAtCompileTime = _Rows, @@ -115,10 +163,13 @@ struct traits > MaxRowsAtCompileTime = _MaxRows, MaxColsAtCompileTime = _MaxCols, Flags = compute_matrix_flags<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::ret, - CoeffReadCost = NumTraits::ReadCost, Options = _Options, InnerStrideAtCompileTime = 1, - OuterStrideAtCompileTime = (Options&RowMajor) ? ColsAtCompileTime : RowsAtCompileTime + OuterStrideAtCompileTime = (Options&RowMajor) ? ColsAtCompileTime : RowsAtCompileTime, + + // FIXME, the following flag in only used to define NeedsToAlign in PlainObjectBase + EvaluatorFlags = LinearAccessBit | DirectAccessBit | packet_access_bit | row_major_bit, + Alignment = actual_alignment }; }; } @@ -151,6 +202,7 @@ class Matrix * * \callgraph */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix& operator=(const Matrix& other) { return Base::_set(other); @@ -167,7 +219,8 @@ class Matrix * remain row-vectors and vectors remain vectors. */ template - EIGEN_STRONG_INLINE Matrix& operator=(const MatrixBase& other) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Matrix& operator=(const DenseBase& other) { return Base::_set(other); } @@ -179,12 +232,14 @@ class Matrix * \copydetails DenseBase::operator=(const EigenBase &other) */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix& operator=(const EigenBase &other) { return Base::operator=(other); } template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix& operator=(const ReturnByValue& func) { return Base::operator=(func); @@ -200,6 +255,7 @@ class Matrix * * \sa resize(Index,Index) */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix() : Base() { Base::_check_template_params(); @@ -207,45 +263,87 @@ class Matrix } // FIXME is it still needed - Matrix(internal::constructor_without_unaligned_array_assert) + EIGEN_DEVICE_FUNC + explicit Matrix(internal::constructor_without_unaligned_array_assert) : Base(internal::constructor_without_unaligned_array_assert()) { Base::_check_template_params(); EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED } - /** \brief Constructs a vector or row-vector with given dimension. \only_for_vectors - * - * Note that this is only useful for dynamic-size vectors. For fixed-size vectors, - * it is redundant to pass the dimension here, so it makes more sense to use the default - * constructor Matrix() instead. - */ - EIGEN_STRONG_INLINE explicit Matrix(Index dim) - : Base(dim, RowsAtCompileTime == 1 ? 1 : dim, ColsAtCompileTime == 1 ? 1 : dim) +#ifdef EIGEN_HAVE_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + Matrix(Matrix&& other) + : Base(std::move(other)) { Base::_check_template_params(); - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Matrix) - eigen_assert(dim >= 0); - eigen_assert(SizeAtCompileTime == Dynamic || SizeAtCompileTime == dim); - EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + if (RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic) + Base::_set_noalias(other); } + EIGEN_DEVICE_FUNC + Matrix& operator=(Matrix&& other) + { + other.swap(*this); + return *this; + } +#endif #ifndef EIGEN_PARSED_BY_DOXYGEN + + // This constructor is for both 1x1 matrices and dynamic vectors + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE explicit Matrix(const T& x) + { + Base::_check_template_params(); + Base::template _init1(x); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix(const T0& x, const T1& y) { Base::_check_template_params(); Base::template _init2(x, y); } #else + /** \brief Constructs a fixed-sized matrix initialized with coefficients starting at \a data */ + EIGEN_DEVICE_FUNC + explicit Matrix(const Scalar *data); + + /** \brief Constructs a vector or row-vector with given dimension. \only_for_vectors + * + * This is useful for dynamic-size vectors. For fixed-size vectors, + * it is redundant to pass these parameters, so one should use the default constructor + * Matrix() instead. + * + * \warning This constructor is disabled for fixed-size \c 1x1 matrices. For instance, + * calling Matrix(1) will call the initialization constructor: Matrix(const Scalar&). + * For fixed-size \c 1x1 matrices it is therefore recommended to use the default + * constructor Matrix() instead, especially when using one of the non standard + * \c EIGEN_INITIALIZE_MATRICES_BY_{ZERO,\c NAN} macros (see \ref TopicPreprocessorDirectives). + */ + EIGEN_STRONG_INLINE explicit Matrix(Index dim); + /** \brief Constructs an initialized 1x1 matrix with the given coefficient */ + Matrix(const Scalar& x); /** \brief Constructs an uninitialized matrix with \a rows rows and \a cols columns. * * This is useful for dynamic-size matrices. For fixed-size matrices, * it is redundant to pass these parameters, so one should use the default constructor - * Matrix() instead. */ + * Matrix() instead. + * + * \warning This constructor is disabled for fixed-size \c 1x2 and \c 2x1 vectors. For instance, + * calling Matrix2f(2,1) will call the initialization constructor: Matrix(const Scalar& x, const Scalar& y). + * For fixed-size \c 1x2 or \c 2x1 vectors it is therefore recommended to use the default + * constructor Matrix() instead, especially when using one of the non standard + * \c EIGEN_INITIALIZE_MATRICES_BY_{ZERO,\c NAN} macros (see \ref TopicPreprocessorDirectives). + */ + EIGEN_DEVICE_FUNC Matrix(Index rows, Index cols); + /** \brief Constructs an initialized 2D vector with given coefficients */ Matrix(const Scalar& x, const Scalar& y); #endif /** \brief Constructs an initialized 3D vector with given coefficients */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z) { Base::_check_template_params(); @@ -255,6 +353,7 @@ class Matrix m_storage.data()[2] = z; } /** \brief Constructs an initialized 4D vector with given coefficients */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z, const Scalar& w) { Base::_check_template_params(); @@ -265,76 +364,33 @@ class Matrix m_storage.data()[3] = w; } - explicit Matrix(const Scalar *data); - /** \brief Constructor copying the value of the expression \a other */ - template - EIGEN_STRONG_INLINE Matrix(const MatrixBase& other) - : Base(other.rows() * other.cols(), other.rows(), other.cols()) - { - // This test resides here, to bring the error messages closer to the user. Normally, these checks - // are performed deeply within the library, thus causing long and scary error traces. - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - - Base::_check_template_params(); - Base::_set_noalias(other); - } /** \brief Copy constructor */ - EIGEN_STRONG_INLINE Matrix(const Matrix& other) - : Base(other.rows() * other.cols(), other.rows(), other.cols()) - { - Base::_check_template_params(); - Base::_set_noalias(other); - } - /** \brief Copy constructor with in-place evaluation */ - template - EIGEN_STRONG_INLINE Matrix(const ReturnByValue& other) - { - Base::_check_template_params(); - Base::resize(other.rows(), other.cols()); - other.evalTo(*this); - } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Matrix(const Matrix& other) : Base(other) + { } /** \brief Copy constructor for generic expressions. * \sa MatrixBase::operator=(const EigenBase&) */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix(const EigenBase &other) - : Base(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols()) - { - Base::_check_template_params(); - Base::resize(other.rows(), other.cols()); - // FIXME/CHECK: isn't *this = other.derived() more efficient. it allows to - // go for pure _set() implementations, right? - *this = other; - } - - /** \internal - * \brief Override MatrixBase::swap() since for dynamic-sized matrices - * of same type it is enough to swap the data pointers. - */ - template - void swap(MatrixBase const & other) - { this->_swap(other.derived()); } + : Base(other.derived()) + { } - inline Index innerStride() const { return 1; } - inline Index outerStride() const { return this->innerSize(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return 1; } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return this->innerSize(); } /////////// Geometry module /////////// template + EIGEN_DEVICE_FUNC explicit Matrix(const RotationBase& r); template + EIGEN_DEVICE_FUNC Matrix& operator=(const RotationBase& r); - #ifdef EIGEN2_SUPPORT - template - explicit Matrix(const eigen2_RotationBase& r); - template - Matrix& operator=(const eigen2_RotationBase& r); - #endif - // allow to extend Matrix outside Eigen #ifdef EIGEN_MATRIX_PLUGIN #include EIGEN_MATRIX_PLUGIN diff --git a/nuparu/include/Eigen/src/Core/MatrixBase.h b/nuparu/include/Eigen/src/Core/MatrixBase.h index 9193b6ab..9d612c85 100644 --- a/nuparu/include/Eigen/src/Core/MatrixBase.h +++ b/nuparu/include/Eigen/src/Core/MatrixBase.h @@ -52,7 +52,7 @@ template class MatrixBase #ifndef EIGEN_PARSED_BY_DOXYGEN typedef MatrixBase StorageBaseType; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; + typedef typename internal::traits::StorageIndex StorageIndex; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; @@ -66,8 +66,7 @@ template class MatrixBase using Base::MaxSizeAtCompileTime; using Base::IsVectorAtCompileTime; using Base::Flags; - using Base::CoeffReadCost; - + using Base::derived; using Base::const_cast_derived; using Base::rows; @@ -81,6 +80,8 @@ template class MatrixBase using Base::operator-=; using Base::operator*=; using Base::operator/=; + using Base::operator*; + using Base::operator/; typedef typename Base::CoeffReturnType CoeffReturnType; typedef typename Base::ConstTransposeReturnType ConstTransposeReturnType; @@ -98,25 +99,14 @@ template class MatrixBase /** \returns the size of the main diagonal, which is min(rows(),cols()). * \sa rows(), cols(), SizeAtCompileTime. */ + EIGEN_DEVICE_FUNC inline Index diagonalSize() const { return (std::min)(rows(),cols()); } - /** \brief The plain matrix type corresponding to this expression. - * - * This is not necessarily exactly the return type of eval(). In the case of plain matrices, - * the return type of eval() is a const reference to a matrix, not a matrix! It is however guaranteed - * that the return type of eval() is either PlainObject or const PlainObject&. - */ - typedef Matrix::Scalar, - internal::traits::RowsAtCompileTime, - internal::traits::ColsAtCompileTime, - AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), - internal::traits::MaxRowsAtCompileTime, - internal::traits::MaxColsAtCompileTime - > PlainObject; + typedef typename Base::PlainObject PlainObject; #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal Represents a matrix with all coefficients equal to one another*/ - typedef CwiseNullaryOp,Derived> ConstantReturnType; + typedef CwiseNullaryOp,PlainObject> ConstantReturnType; /** \internal the return type of MatrixBase::adjoint() */ typedef typename internal::conditional::IsComplex, CwiseUnaryOp, ConstTransposeReturnType>, @@ -125,7 +115,7 @@ template class MatrixBase /** \internal Return type of eigenvalues() */ typedef Matrix, internal::traits::ColsAtCompileTime, 1, ColMajor> EigenvaluesReturnType; /** \internal the return type of identity */ - typedef CwiseNullaryOp,Derived> IdentityReturnType; + typedef CwiseNullaryOp,PlainObject> IdentityReturnType; /** \internal the return type of unit vectors */ typedef Block, SquareMatrixType>, internal::traits::RowsAtCompileTime, @@ -145,39 +135,48 @@ template class MatrixBase /** Special case of the template operator=, in order to prevent the compiler * from generating a default operator= (issue hit with g++ 4.1) */ + EIGEN_DEVICE_FUNC Derived& operator=(const MatrixBase& other); // We cannot inherit here via Base::operator= since it is causing // trouble with MSVC. template + EIGEN_DEVICE_FUNC Derived& operator=(const DenseBase& other); template + EIGEN_DEVICE_FUNC Derived& operator=(const EigenBase& other); template + EIGEN_DEVICE_FUNC Derived& operator=(const ReturnByValue& other); -#ifndef EIGEN_PARSED_BY_DOXYGEN - template - Derived& lazyAssign(const ProductBase& other); - - template - Derived& lazyAssign(const MatrixPowerProduct& other); -#endif // not EIGEN_PARSED_BY_DOXYGEN - template + EIGEN_DEVICE_FUNC Derived& operator+=(const MatrixBase& other); template + EIGEN_DEVICE_FUNC Derived& operator-=(const MatrixBase& other); +#ifdef __CUDACC__ template - const typename ProductReturnType::Type + EIGEN_DEVICE_FUNC + const Product + operator*(const MatrixBase &other) const + { return this->lazyProduct(other); } +#else + + template + const Product operator*(const MatrixBase &other) const; +#endif + template - const typename LazyProductReturnType::Type + EIGEN_DEVICE_FUNC + const Product lazyProduct(const MatrixBase &other) const; template @@ -190,88 +189,91 @@ template class MatrixBase void applyOnTheRight(const EigenBase& other); template - const DiagonalProduct + EIGEN_DEVICE_FUNC + const Product operator*(const DiagonalBase &diagonal) const; template + EIGEN_DEVICE_FUNC typename internal::scalar_product_traits::Scalar,typename internal::traits::Scalar>::ReturnType dot(const MatrixBase& other) const; - #ifdef EIGEN2_SUPPORT - template - Scalar eigen2_dot(const MatrixBase& other) const; - #endif - - RealScalar squaredNorm() const; - RealScalar norm() const; + EIGEN_DEVICE_FUNC RealScalar squaredNorm() const; + EIGEN_DEVICE_FUNC RealScalar norm() const; RealScalar stableNorm() const; RealScalar blueNorm() const; RealScalar hypotNorm() const; - const PlainObject normalized() const; - void normalize(); + EIGEN_DEVICE_FUNC const PlainObject normalized() const; + EIGEN_DEVICE_FUNC void normalize(); - const AdjointReturnType adjoint() const; - void adjointInPlace(); + EIGEN_DEVICE_FUNC const AdjointReturnType adjoint() const; + EIGEN_DEVICE_FUNC void adjointInPlace(); typedef Diagonal DiagonalReturnType; + EIGEN_DEVICE_FUNC DiagonalReturnType diagonal(); - typedef typename internal::add_const >::type ConstDiagonalReturnType; + + typedef typename internal::add_const >::type ConstDiagonalReturnType; + EIGEN_DEVICE_FUNC ConstDiagonalReturnType diagonal() const; template struct DiagonalIndexReturnType { typedef Diagonal Type; }; template struct ConstDiagonalIndexReturnType { typedef const Diagonal Type; }; - template typename DiagonalIndexReturnType::Type diagonal(); - template typename ConstDiagonalIndexReturnType::Type diagonal() const; - - // Note: The "MatrixBase::" prefixes are added to help MSVC9 to match these declarations with the later implementations. - // On the other hand they confuse MSVC8... - #if (defined _MSC_VER) && (_MSC_VER >= 1500) // 2008 or later - typename MatrixBase::template DiagonalIndexReturnType::Type diagonal(Index index); - typename MatrixBase::template ConstDiagonalIndexReturnType::Type diagonal(Index index) const; - #else - typename DiagonalIndexReturnType::Type diagonal(Index index); - typename ConstDiagonalIndexReturnType::Type diagonal(Index index) const; - #endif - - #ifdef EIGEN2_SUPPORT - template typename internal::eigen2_part_return_type::type part(); - template const typename internal::eigen2_part_return_type::type part() const; + template + EIGEN_DEVICE_FUNC + typename DiagonalIndexReturnType::Type diagonal(); + + template + EIGEN_DEVICE_FUNC + typename ConstDiagonalIndexReturnType::Type diagonal() const; - // huuuge hack. make Eigen2's matrix.part() work in eigen3. Problem: Diagonal is now a class template instead - // of an integer constant. Solution: overload the part() method template wrt template parameters list. - template class U> - const DiagonalWrapper part() const - { return diagonal().asDiagonal(); } - #endif // EIGEN2_SUPPORT + typedef Diagonal DiagonalDynamicIndexReturnType; + typedef typename internal::add_const >::type ConstDiagonalDynamicIndexReturnType; + + EIGEN_DEVICE_FUNC + DiagonalDynamicIndexReturnType diagonal(Index index); + EIGEN_DEVICE_FUNC + ConstDiagonalDynamicIndexReturnType diagonal(Index index) const; template struct TriangularViewReturnType { typedef TriangularView Type; }; template struct ConstTriangularViewReturnType { typedef const TriangularView Type; }; - template typename TriangularViewReturnType::Type triangularView(); - template typename ConstTriangularViewReturnType::Type triangularView() const; + template + EIGEN_DEVICE_FUNC + typename TriangularViewReturnType::Type triangularView(); + template + EIGEN_DEVICE_FUNC + typename ConstTriangularViewReturnType::Type triangularView() const; template struct SelfAdjointViewReturnType { typedef SelfAdjointView Type; }; template struct ConstSelfAdjointViewReturnType { typedef const SelfAdjointView Type; }; - template typename SelfAdjointViewReturnType::Type selfadjointView(); - template typename ConstSelfAdjointViewReturnType::Type selfadjointView() const; + template + EIGEN_DEVICE_FUNC + typename SelfAdjointViewReturnType::Type selfadjointView(); + template + EIGEN_DEVICE_FUNC + typename ConstSelfAdjointViewReturnType::Type selfadjointView() const; const SparseView sparseView(const Scalar& m_reference = Scalar(0), const typename NumTraits::Real& m_epsilon = NumTraits::dummy_precision()) const; - static const IdentityReturnType Identity(); - static const IdentityReturnType Identity(Index rows, Index cols); - static const BasisReturnType Unit(Index size, Index i); - static const BasisReturnType Unit(Index i); - static const BasisReturnType UnitX(); - static const BasisReturnType UnitY(); - static const BasisReturnType UnitZ(); - static const BasisReturnType UnitW(); - + EIGEN_DEVICE_FUNC static const IdentityReturnType Identity(); + EIGEN_DEVICE_FUNC static const IdentityReturnType Identity(Index rows, Index cols); + EIGEN_DEVICE_FUNC static const BasisReturnType Unit(Index size, Index i); + EIGEN_DEVICE_FUNC static const BasisReturnType Unit(Index i); + EIGEN_DEVICE_FUNC static const BasisReturnType UnitX(); + EIGEN_DEVICE_FUNC static const BasisReturnType UnitY(); + EIGEN_DEVICE_FUNC static const BasisReturnType UnitZ(); + EIGEN_DEVICE_FUNC static const BasisReturnType UnitW(); + + EIGEN_DEVICE_FUNC const DiagonalWrapper asDiagonal() const; const PermutationWrapper asPermutation() const; + EIGEN_DEVICE_FUNC Derived& setIdentity(); + EIGEN_DEVICE_FUNC Derived& setIdentity(Index rows, Index cols); bool isIdentity(const RealScalar& prec = NumTraits::dummy_precision()) const; @@ -303,59 +305,49 @@ template class MatrixBase NoAlias noalias(); - inline const ForceAlignedAccess forceAlignedAccess() const; - inline ForceAlignedAccess forceAlignedAccess(); - template inline typename internal::add_const_on_value_type,Derived&>::type>::type forceAlignedAccessIf() const; - template inline typename internal::conditional,Derived&>::type forceAlignedAccessIf(); + // TODO forceAlignedAccess is temporarily disabled + // Need to find a nicer workaround. + inline const Derived& forceAlignedAccess() const { return derived(); } + inline Derived& forceAlignedAccess() { return derived(); } + template inline const Derived& forceAlignedAccessIf() const { return derived(); } + template inline Derived& forceAlignedAccessIf() { return derived(); } - Scalar trace() const; + EIGEN_DEVICE_FUNC Scalar trace() const; -/////////// Array module /////////// + template EIGEN_DEVICE_FUNC RealScalar lpNorm() const; - template RealScalar lpNorm() const; - - MatrixBase& matrix() { return *this; } - const MatrixBase& matrix() const { return *this; } + EIGEN_DEVICE_FUNC MatrixBase& matrix() { return *this; } + EIGEN_DEVICE_FUNC const MatrixBase& matrix() const { return *this; } /** \returns an \link Eigen::ArrayBase Array \endlink expression of this matrix * \sa ArrayBase::matrix() */ - ArrayWrapper array() { return derived(); } - const ArrayWrapper array() const { return derived(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ArrayWrapper array() { return ArrayWrapper(derived()); } + /** \returns a const \link Eigen::ArrayBase Array \endlink expression of this matrix + * \sa ArrayBase::matrix() */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const ArrayWrapper array() const { return ArrayWrapper(derived()); } /////////// LU module /////////// - const FullPivLU fullPivLu() const; - const PartialPivLU partialPivLu() const; + EIGEN_DEVICE_FUNC + inline const FullPivLU fullPivLu() const; + EIGEN_DEVICE_FUNC + inline const PartialPivLU partialPivLu() const; - #if EIGEN2_SUPPORT_STAGE < STAGE20_RESOLVE_API_CONFLICTS - const LU lu() const; - #endif + EIGEN_DEVICE_FUNC + inline const PartialPivLU lu() const; - #ifdef EIGEN2_SUPPORT - const LU eigen2_lu() const; - #endif - - #if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS - const PartialPivLU lu() const; - #endif + EIGEN_DEVICE_FUNC + inline const Inverse inverse() const; - #ifdef EIGEN2_SUPPORT template - void computeInverse(MatrixBase *result) const { - *result = this->inverse(); - } - #endif - - const internal::inverse_impl inverse() const; - template - void computeInverseAndDetWithCheck( + inline void computeInverseAndDetWithCheck( ResultType& inverse, typename ResultType::Scalar& determinant, bool& invertible, const RealScalar& absDeterminantThreshold = NumTraits::dummy_precision() ) const; template - void computeInverseWithCheck( + inline void computeInverseWithCheck( ResultType& inverse, bool& invertible, const RealScalar& absDeterminantThreshold = NumTraits::dummy_precision() @@ -364,29 +356,24 @@ template class MatrixBase /////////// Cholesky module /////////// - const LLT llt() const; - const LDLT ldlt() const; + inline const LLT llt() const; + inline const LDLT ldlt() const; /////////// QR module /////////// - const HouseholderQR householderQr() const; - const ColPivHouseholderQR colPivHouseholderQr() const; - const FullPivHouseholderQR fullPivHouseholderQr() const; - - #ifdef EIGEN2_SUPPORT - const QR qr() const; - #endif + inline const HouseholderQR householderQr() const; + inline const ColPivHouseholderQR colPivHouseholderQr() const; + inline const FullPivHouseholderQR fullPivHouseholderQr() const; - EigenvaluesReturnType eigenvalues() const; - RealScalar operatorNorm() const; +/////////// Eigenvalues module /////////// -/////////// SVD module /////////// + inline EigenvaluesReturnType eigenvalues() const; + inline RealScalar operatorNorm() const; - JacobiSVD jacobiSvd(unsigned int computationOptions = 0) const; +/////////// SVD module /////////// - #ifdef EIGEN2_SUPPORT - SVD svd() const; - #endif + inline JacobiSVD jacobiSvd(unsigned int computationOptions = 0) const; + inline BDCSVD bdcSvd(unsigned int computationOptions = 0) const; /////////// Geometry module /////////// @@ -398,20 +385,25 @@ template class MatrixBase }; #endif // EIGEN_PARSED_BY_DOXYGEN template - typename cross_product_return_type::type + EIGEN_DEVICE_FUNC + inline typename cross_product_return_type::type cross(const MatrixBase& other) const; + template - PlainObject cross3(const MatrixBase& other) const; - PlainObject unitOrthogonal(void) const; - Matrix eulerAngles(Index a0, Index a1, Index a2) const; + EIGEN_DEVICE_FUNC + inline PlainObject cross3(const MatrixBase& other) const; + + EIGEN_DEVICE_FUNC + inline PlainObject unitOrthogonal(void) const; - #if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS - ScalarMultipleReturnType operator*(const UniformScaling& s) const; + inline Matrix eulerAngles(Index a0, Index a1, Index a2) const; + + inline ScalarMultipleReturnType operator*(const UniformScaling& s) const; // put this as separate enum value to work around possible GCC 4.3 bug (?) - enum { HomogeneousReturnTypeDirection = ColsAtCompileTime==1?Vertical:Horizontal }; + enum { HomogeneousReturnTypeDirection = ColsAtCompileTime==1&&RowsAtCompileTime==1 ? ((internal::traits::Flags&RowMajorBit)==RowMajorBit ? Horizontal : Vertical) + : ColsAtCompileTime==1 ? Vertical : Horizontal }; typedef Homogeneous HomogeneousReturnType; - HomogeneousReturnType homogeneous() const; - #endif + inline HomogeneousReturnType homogeneous() const; enum { SizeMinusOne = SizeAtCompileTime==Dynamic ? Dynamic : SizeAtCompileTime-1 @@ -422,7 +414,7 @@ template class MatrixBase typedef CwiseUnaryOp::Scalar>, const ConstStartMinusOne > HNormalizedReturnType; - const HNormalizedReturnType hnormalized() const; + inline const HNormalizedReturnType hnormalized() const; ////////// Householder module /////////// @@ -446,6 +438,15 @@ template class MatrixBase template void applyOnTheRight(Index p, Index q, const JacobiRotation& j); +///////// SparseCore module ///////// + + template + EIGEN_STRONG_INLINE const typename SparseMatrixBase::template CwiseProductDenseReturnType::Type + cwiseProduct(const SparseMatrixBase &other) const + { + return other.cwiseProduct(derived()); + } + ///////// MatrixFunctions module ///////// typedef typename internal::stem_function::type StemFunction; @@ -458,49 +459,15 @@ template class MatrixBase const MatrixSquareRootReturnValue sqrt() const; const MatrixLogarithmReturnValue log() const; const MatrixPowerReturnValue pow(const RealScalar& p) const; - -#ifdef EIGEN2_SUPPORT - template - Derived& operator+=(const Flagged, 0, - EvalBeforeAssigningBit>& other); - - template - Derived& operator-=(const Flagged, 0, - EvalBeforeAssigningBit>& other); - - /** \deprecated because .lazy() is deprecated - * Overloaded for cache friendly product evaluation */ - template - Derived& lazyAssign(const Flagged& other) - { return lazyAssign(other._expression()); } - - template - const Flagged marked() const; - const Flagged lazy() const; - - inline const Cwise cwise() const; - inline Cwise cwise(); - - VectorBlock start(Index size); - const VectorBlock start(Index size) const; - VectorBlock end(Index size); - const VectorBlock end(Index size) const; - template VectorBlock start(); - template const VectorBlock start() const; - template VectorBlock end(); - template const VectorBlock end() const; - - Minor minor(Index row, Index col); - const Minor minor(Index row, Index col) const; -#endif + const MatrixComplexPowerReturnValue pow(const std::complex& p) const; protected: - MatrixBase() : Base() {} + EIGEN_DEVICE_FUNC MatrixBase() : Base() {} private: - explicit MatrixBase(int); - MatrixBase(int,int); - template explicit MatrixBase(const MatrixBase&); + EIGEN_DEVICE_FUNC explicit MatrixBase(int); + EIGEN_DEVICE_FUNC MatrixBase(int,int); + template EIGEN_DEVICE_FUNC explicit MatrixBase(const MatrixBase&); protected: // mixing arrays and matrices is not legal template Derived& operator+=(const ArrayBase& ) @@ -510,6 +477,51 @@ template class MatrixBase {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} }; + +/*************************************************************************** +* Implementation of matrix base methods +***************************************************************************/ + +/** replaces \c *this by \c *this * \a other. + * + * \returns a reference to \c *this + * + * Example: \include MatrixBase_applyOnTheRight.cpp + * Output: \verbinclude MatrixBase_applyOnTheRight.out + */ +template +template +inline Derived& +MatrixBase::operator*=(const EigenBase &other) +{ + other.derived().applyThisOnTheRight(derived()); + return derived(); +} + +/** replaces \c *this by \c *this * \a other. It is equivalent to MatrixBase::operator*=(). + * + * Example: \include MatrixBase_applyOnTheRight.cpp + * Output: \verbinclude MatrixBase_applyOnTheRight.out + */ +template +template +inline void MatrixBase::applyOnTheRight(const EigenBase &other) +{ + other.derived().applyThisOnTheRight(derived()); +} + +/** replaces \c *this by \a other * \c *this. + * + * Example: \include MatrixBase_applyOnTheLeft.cpp + * Output: \verbinclude MatrixBase_applyOnTheLeft.out + */ +template +template +inline void MatrixBase::applyOnTheLeft(const EigenBase &other) +{ + other.derived().applyThisOnTheLeft(derived()); +} + } // end namespace Eigen #endif // EIGEN_MATRIXBASE_H diff --git a/nuparu/include/Eigen/src/Core/NestByValue.h b/nuparu/include/Eigen/src/Core/NestByValue.h index a893b176..9aeaf8d1 100644 --- a/nuparu/include/Eigen/src/Core/NestByValue.h +++ b/nuparu/include/Eigen/src/Core/NestByValue.h @@ -40,29 +40,29 @@ template class NestByValue typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(NestByValue) - inline NestByValue(const ExpressionType& matrix) : m_expression(matrix) {} + EIGEN_DEVICE_FUNC explicit inline NestByValue(const ExpressionType& matrix) : m_expression(matrix) {} - inline Index rows() const { return m_expression.rows(); } - inline Index cols() const { return m_expression.cols(); } - inline Index outerStride() const { return m_expression.outerStride(); } - inline Index innerStride() const { return m_expression.innerStride(); } + EIGEN_DEVICE_FUNC inline Index rows() const { return m_expression.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_expression.cols(); } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_expression.outerStride(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_expression.innerStride(); } - inline const CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index row, Index col) const { return m_expression.coeff(row, col); } - inline Scalar& coeffRef(Index row, Index col) + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index col) { return m_expression.const_cast_derived().coeffRef(row, col); } - inline const CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index index) const { return m_expression.coeff(index); } - inline Scalar& coeffRef(Index index) + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index index) { return m_expression.const_cast_derived().coeffRef(index); } @@ -91,7 +91,7 @@ template class NestByValue m_expression.const_cast_derived().template writePacket(index, x); } - operator const ExpressionType&() const { return m_expression; } + EIGEN_DEVICE_FUNC operator const ExpressionType&() const { return m_expression; } protected: const ExpressionType m_expression; diff --git a/nuparu/include/Eigen/src/Core/NoAlias.h b/nuparu/include/Eigen/src/Core/NoAlias.h index 768bfb18..0ade7525 100644 --- a/nuparu/include/Eigen/src/Core/NoAlias.h +++ b/nuparu/include/Eigen/src/Core/NoAlias.h @@ -30,62 +30,36 @@ namespace Eigen { template class StorageBase> class NoAlias { - typedef typename ExpressionType::Scalar Scalar; public: - NoAlias(ExpressionType& expression) : m_expression(expression) {} - - /** Behaves like MatrixBase::lazyAssign(other) - * \sa MatrixBase::lazyAssign() */ + typedef typename ExpressionType::Scalar Scalar; + + explicit NoAlias(ExpressionType& expression) : m_expression(expression) {} + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ExpressionType& operator=(const StorageBase& other) - { return internal::assign_selector::run(m_expression,other.derived()); } - - /** \sa MatrixBase::operator+= */ + { + call_assignment_no_alias(m_expression, other.derived(), internal::assign_op()); + return m_expression; + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ExpressionType& operator+=(const StorageBase& other) { - typedef SelfCwiseBinaryOp, ExpressionType, OtherDerived> SelfAdder; - SelfAdder tmp(m_expression); - typedef typename internal::nested::type OtherDerivedNested; - typedef typename internal::remove_all::type _OtherDerivedNested; - internal::assign_selector::run(tmp,OtherDerivedNested(other.derived())); + call_assignment_no_alias(m_expression, other.derived(), internal::add_assign_op()); return m_expression; } - - /** \sa MatrixBase::operator-= */ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ExpressionType& operator-=(const StorageBase& other) { - typedef SelfCwiseBinaryOp, ExpressionType, OtherDerived> SelfAdder; - SelfAdder tmp(m_expression); - typedef typename internal::nested::type OtherDerivedNested; - typedef typename internal::remove_all::type _OtherDerivedNested; - internal::assign_selector::run(tmp,OtherDerivedNested(other.derived())); + call_assignment_no_alias(m_expression, other.derived(), internal::sub_assign_op()); return m_expression; } -#ifndef EIGEN_PARSED_BY_DOXYGEN - template - EIGEN_STRONG_INLINE ExpressionType& operator+=(const ProductBase& other) - { other.derived().addTo(m_expression); return m_expression; } - - template - EIGEN_STRONG_INLINE ExpressionType& operator-=(const ProductBase& other) - { other.derived().subTo(m_expression); return m_expression; } - - template - EIGEN_STRONG_INLINE ExpressionType& operator+=(const CoeffBasedProduct& other) - { return m_expression.derived() += CoeffBasedProduct(other.lhs(), other.rhs()); } - - template - EIGEN_STRONG_INLINE ExpressionType& operator-=(const CoeffBasedProduct& other) - { return m_expression.derived() -= CoeffBasedProduct(other.lhs(), other.rhs()); } - - template - ExpressionType& operator=(const ReturnByValue& func) - { return m_expression = func; } -#endif - + EIGEN_DEVICE_FUNC ExpressionType& expression() const { return m_expression; @@ -126,7 +100,7 @@ class NoAlias template NoAlias MatrixBase::noalias() { - return derived(); + return NoAlias(derived()); } } // end namespace Eigen diff --git a/nuparu/include/Eigen/src/Core/NumTraits.h b/nuparu/include/Eigen/src/Core/NumTraits.h index bac9e50b..1d85dec7 100644 --- a/nuparu/include/Eigen/src/Core/NumTraits.h +++ b/nuparu/include/Eigen/src/Core/NumTraits.h @@ -68,21 +68,40 @@ template struct GenericNumTraits >::type NonInteger; typedef T Nested; - static inline Real epsilon() { return std::numeric_limits::epsilon(); } + EIGEN_DEVICE_FUNC + static inline Real epsilon() + { + #if defined(__CUDA_ARCH__) + return internal::device::numeric_limits::epsilon(); + #else + return std::numeric_limits::epsilon(); + #endif + } + EIGEN_DEVICE_FUNC static inline Real dummy_precision() { // make sure to override this for floating-point types return Real(0); } - static inline T highest() { return (std::numeric_limits::max)(); } - static inline T lowest() { return IsInteger ? (std::numeric_limits::min)() : (-(std::numeric_limits::max)()); } - -#ifdef EIGEN2_SUPPORT - enum { - HasFloatingPoint = !IsInteger - }; - typedef NonInteger FloatingPoint; + + + EIGEN_DEVICE_FUNC + static inline T highest() { +#if defined(__CUDA_ARCH__) + return (internal::device::numeric_limits::max)(); +#else + return (std::numeric_limits::max)(); #endif + } + + EIGEN_DEVICE_FUNC + static inline T lowest() { +#if defined(__CUDA_ARCH__) + return IsInteger ? (internal::device::numeric_limits::min)() : (-(internal::device::numeric_limits::max)()); +#else + return IsInteger ? (std::numeric_limits::min)() : (-(std::numeric_limits::max)()); +#endif + } }; template struct NumTraits : GenericNumTraits @@ -91,11 +110,13 @@ template struct NumTraits : GenericNumTraits template<> struct NumTraits : GenericNumTraits { + EIGEN_DEVICE_FUNC static inline float dummy_precision() { return 1e-5f; } }; template<> struct NumTraits : GenericNumTraits { + EIGEN_DEVICE_FUNC static inline double dummy_precision() { return 1e-12; } }; @@ -136,9 +157,9 @@ struct NumTraits > IsInteger = NumTraits::IsInteger, IsSigned = NumTraits::IsSigned, RequireInitialization = 1, - ReadCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits::ReadCost, - AddCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits::AddCost, - MulCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits::MulCost + ReadCost = ArrayType::SizeAtCompileTime==Dynamic ? HugeCost : ArrayType::SizeAtCompileTime * NumTraits::ReadCost, + AddCost = ArrayType::SizeAtCompileTime==Dynamic ? HugeCost : ArrayType::SizeAtCompileTime * NumTraits::AddCost, + MulCost = ArrayType::SizeAtCompileTime==Dynamic ? HugeCost : ArrayType::SizeAtCompileTime * NumTraits::MulCost }; static inline RealScalar epsilon() { return NumTraits::epsilon(); } diff --git a/nuparu/include/Eigen/src/Core/PermutationMatrix.h b/nuparu/include/Eigen/src/Core/PermutationMatrix.h index 4fc5dd31..90e1df23 100644 --- a/nuparu/include/Eigen/src/Core/PermutationMatrix.h +++ b/nuparu/include/Eigen/src/Core/PermutationMatrix.h @@ -2,7 +2,7 @@ // for linear algebra. // // Copyright (C) 2009 Benoit Jacob -// Copyright (C) 2009-2011 Gael Guennebaud +// Copyright (C) 2009-2015 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -13,8 +13,6 @@ namespace Eigen { -template class PermutedImpl; - /** \class PermutationBase * \ingroup Core_Module * @@ -41,10 +39,6 @@ template -struct permut_matrix_product_retval; -template -struct permut_sparsematrix_product_retval; enum PermPermProduct_t {PermPermProduct}; } // end namespace internal @@ -60,19 +54,20 @@ class PermutationBase : public EigenBase typedef typename Traits::IndicesType IndicesType; enum { Flags = Traits::Flags, - CoeffReadCost = Traits::CoeffReadCost, RowsAtCompileTime = Traits::RowsAtCompileTime, ColsAtCompileTime = Traits::ColsAtCompileTime, MaxRowsAtCompileTime = Traits::MaxRowsAtCompileTime, MaxColsAtCompileTime = Traits::MaxColsAtCompileTime }; - typedef typename Traits::Scalar Scalar; - typedef typename Traits::Index Index; - typedef Matrix + typedef typename Traits::StorageIndex StorageIndex; + typedef Matrix DenseMatrixType; - typedef PermutationMatrix + typedef PermutationMatrix PlainPermutationType; + typedef PlainPermutationType PlainObject; using Base::derived; + typedef Inverse InverseReturnType; + typedef void Scalar; #endif /** Copies the other permutation into *this */ @@ -118,7 +113,7 @@ class PermutationBase : public EigenBase void evalTo(MatrixBase& other) const { other.setZero(); - for (int i=0; i /** Sets *this to be the identity permutation matrix */ void setIdentity() { - for(Index i = 0; i < size(); ++i) + StorageIndex n = StorageIndex(size()); + for(StorageIndex i = 0; i < n; ++i) indices().coeffRef(i) = i; } @@ -163,18 +159,18 @@ class PermutationBase : public EigenBase * * \returns a reference to *this. * - * \warning This is much slower than applyTranspositionOnTheRight(int,int): + * \warning This is much slower than applyTranspositionOnTheRight(Index,Index): * this has linear complexity and requires a lot of branching. * - * \sa applyTranspositionOnTheRight(int,int) + * \sa applyTranspositionOnTheRight(Index,Index) */ Derived& applyTranspositionOnTheLeft(Index i, Index j) { eigen_assert(i>=0 && j>=0 && i * * This is a fast operation, it only consists in swapping two indices. * - * \sa applyTranspositionOnTheLeft(int,int) + * \sa applyTranspositionOnTheLeft(Index,Index) */ Derived& applyTranspositionOnTheRight(Index i, Index j) { @@ -198,14 +194,14 @@ class PermutationBase : public EigenBase * * \note \note_try_to_help_rvo */ - inline Transpose inverse() const - { return derived(); } + inline InverseReturnType inverse() const + { return InverseReturnType(derived()); } /** \returns the tranpose permutation matrix. * * \note \note_try_to_help_rvo */ - inline Transpose transpose() const - { return derived(); } + inline InverseReturnType transpose() const + { return InverseReturnType(derived()); } /**** multiplication helpers to hopefully get RVO ****/ @@ -215,13 +211,13 @@ class PermutationBase : public EigenBase template void assignTranspose(const PermutationBase& other) { - for (int i=0; i void assignProduct(const Lhs& lhs, const Rhs& rhs) { eigen_assert(lhs.cols() == rhs.rows()); - for (int i=0; i * \note \note_try_to_help_rvo */ template - inline PlainPermutationType operator*(const Transpose >& other) const + inline PlainPermutationType operator*(const InverseImpl& other) const { return PlainPermutationType(internal::PermPermProduct, *this, other.eval()); } /** \returns the product of an inverse permutation with another permutation. @@ -248,8 +244,37 @@ class PermutationBase : public EigenBase * \note \note_try_to_help_rvo */ template friend - inline PlainPermutationType operator*(const Transpose >& other, const PermutationBase& perm) + inline PlainPermutationType operator*(const InverseImpl& other, const PermutationBase& perm) { return PlainPermutationType(internal::PermPermProduct, other.eval(), perm); } + + /** \returns the determinant of the permutation matrix, which is either 1 or -1 depending on the parity of the permutation. + * + * This function is O(\c n) procedure allocating a buffer of \c n booleans. + */ + Index determinant() const + { + Index res = 1; + Index n = size(); + Matrix mask(n); + mask.fill(false); + Index r = 0; + while(r < n) + { + // search for the next seed + while(r=n) + break; + // we got one, let's follow it until we are back to the seed + Index k0 = r++; + mask.coeffRef(k0) = true; + for(Index k=indices().coeff(k0); k!=k0; k=indices().coeff(k)) + { + mask.coeffRef(k) = true; + res = -res; + } + } + return res; + } protected: @@ -262,7 +287,7 @@ class PermutationBase : public EigenBase * * \param SizeAtCompileTime the number of rows/cols, or Dynamic * \param MaxSizeAtCompileTime the maximum number of rows/cols, or Dynamic. This optional parameter defaults to SizeAtCompileTime. Most of the time, you should not have to specify it. - * \param IndexType the interger type of the indices + * \param StorageIndex the integer type of the indices * * This class represents a permutation matrix, internally stored as a vector of integers. * @@ -270,24 +295,29 @@ class PermutationBase : public EigenBase */ namespace internal { -template -struct traits > - : traits > +template +struct traits > + : traits > { - typedef IndexType Index; - typedef Matrix IndicesType; + typedef PermutationStorage StorageKind; + typedef Matrix<_StorageIndex, SizeAtCompileTime, 1, 0, MaxSizeAtCompileTime, 1> IndicesType; + typedef _StorageIndex StorageIndex; + typedef void Scalar; }; } -template -class PermutationMatrix : public PermutationBase > +template +class PermutationMatrix : public PermutationBase > { typedef PermutationBase Base; typedef internal::traits Traits; public: + typedef const PermutationMatrix& Nested; + #ifndef EIGEN_PARSED_BY_DOXYGEN typedef typename Traits::IndicesType IndicesType; + typedef typename Traits::StorageIndex StorageIndex; #endif inline PermutationMatrix() @@ -295,8 +325,10 @@ class PermutationMatrix : public PermutationBase::highest()); + } /** Copy constructor. */ template @@ -317,7 +349,7 @@ class PermutationMatrix : public PermutationBase - explicit inline PermutationMatrix(const MatrixBase& a_indices) : m_indices(a_indices) + explicit inline PermutationMatrix(const MatrixBase& indices) : m_indices(indices) {} /** Convert the Transpositions \a tr to a permutation matrix */ @@ -364,10 +396,13 @@ class PermutationMatrix : public PermutationBase - PermutationMatrix(const Transpose >& other) - : m_indices(other.nestedPermutation().size()) + PermutationMatrix(const InverseImpl& other) + : m_indices(other.derived().nestedExpression().size()) { - for (int i=0; i::highest()); + StorageIndex end = StorageIndex(m_indices.size()); + for (StorageIndex i=0; i PermutationMatrix(internal::PermPermProduct_t, const Lhs& lhs, const Rhs& rhs) @@ -384,18 +419,20 @@ class PermutationMatrix : public PermutationBase -struct traits,_PacketAccess> > - : traits > +template +struct traits,_PacketAccess> > + : traits > { - typedef IndexType Index; - typedef Map, _PacketAccess> IndicesType; + typedef PermutationStorage StorageKind; + typedef Map, _PacketAccess> IndicesType; + typedef _StorageIndex StorageIndex; + typedef void Scalar; }; } -template -class Map,_PacketAccess> - : public PermutationBase,_PacketAccess> > +template +class Map,_PacketAccess> + : public PermutationBase,_PacketAccess> > { typedef PermutationBase Base; typedef internal::traits Traits; @@ -403,14 +440,14 @@ class Map, #ifndef EIGEN_PARSED_BY_DOXYGEN typedef typename Traits::IndicesType IndicesType; - typedef typename IndicesType::Scalar Index; + typedef typename IndicesType::Scalar StorageIndex; #endif - inline Map(const Index* indicesPtr) + inline Map(const StorageIndex* indicesPtr) : m_indices(indicesPtr) {} - inline Map(const Index* indicesPtr, Index size) + inline Map(const StorageIndex* indicesPtr, Index size) : m_indices(indicesPtr,size) {} @@ -457,24 +494,21 @@ class Map, * \sa class PermutationBase, class PermutationMatrix */ -struct PermutationStorage {}; - template class TranspositionsWrapper; namespace internal { template struct traits > { typedef PermutationStorage StorageKind; - typedef typename _IndicesType::Scalar Scalar; - typedef typename _IndicesType::Scalar Index; + typedef void Scalar; + typedef typename _IndicesType::Scalar StorageIndex; typedef _IndicesType IndicesType; enum { RowsAtCompileTime = _IndicesType::SizeAtCompileTime, ColsAtCompileTime = _IndicesType::SizeAtCompileTime, - MaxRowsAtCompileTime = IndicesType::MaxRowsAtCompileTime, - MaxColsAtCompileTime = IndicesType::MaxColsAtCompileTime, - Flags = 0, - CoeffReadCost = _IndicesType::CoeffReadCost + MaxRowsAtCompileTime = IndicesType::MaxSizeAtCompileTime, + MaxColsAtCompileTime = IndicesType::MaxSizeAtCompileTime, + Flags = 0 }; }; } @@ -490,8 +524,8 @@ class PermutationWrapper : public PermutationBase -inline const internal::permut_matrix_product_retval -operator*(const MatrixBase& matrix, - const PermutationBase &permutation) +template +EIGEN_DEVICE_FUNC +const Product +operator*(const MatrixBase &matrix, + const PermutationBase& permutation) { - return internal::permut_matrix_product_retval - - (permutation.derived(), matrix.derived()); + return Product + (matrix.derived(), permutation.derived()); } /** \returns the matrix with the permutation applied to the rows. */ -template -inline const internal::permut_matrix_product_retval - +template +EIGEN_DEVICE_FUNC +const Product operator*(const PermutationBase &permutation, - const MatrixBase& matrix) + const MatrixBase& matrix) { - return internal::permut_matrix_product_retval - - (permutation.derived(), matrix.derived()); + return Product + (permutation.derived(), matrix.derived()); } -namespace internal { - -template -struct traits > -{ - typedef typename MatrixType::PlainObject ReturnType; -}; -template -struct permut_matrix_product_retval - : public ReturnByValue > +template +class InverseImpl + : public EigenBase > { - typedef typename remove_all::type MatrixTypeNestedCleaned; - typedef typename MatrixType::Index Index; - - permut_matrix_product_retval(const PermutationType& perm, const MatrixType& matrix) - : m_permutation(perm), m_matrix(matrix) - {} - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - - template inline void evalTo(Dest& dst) const - { - const Index n = Side==OnTheLeft ? rows() : cols(); - - if(is_same::value && extract_data(dst) == extract_data(m_matrix)) - { - // apply the permutation inplace - Matrix mask(m_permutation.size()); - mask.fill(false); - Index r = 0; - while(r < m_permutation.size()) - { - // search for the next seed - while(r=m_permutation.size()) - break; - // we got one, let's follow it until we are back to the seed - Index k0 = r++; - Index kPrev = k0; - mask.coeffRef(k0) = true; - for(Index k=m_permutation.indices().coeff(k0); k!=k0; k=m_permutation.indices().coeff(k)) - { - Block(dst, k) - .swap(Block - (dst,((Side==OnTheLeft) ^ Transposed) ? k0 : kPrev)); - - mask.coeffRef(k) = true; - kPrev = k; - } - } - } - else - { - for(int i = 0; i < n; ++i) - { - Block - (dst, ((Side==OnTheLeft) ^ Transposed) ? m_permutation.indices().coeff(i) : i) - - = - - Block - (m_matrix, ((Side==OnTheRight) ^ Transposed) ? m_permutation.indices().coeff(i) : i); - } - } - } - - protected: - const PermutationType& m_permutation; - typename MatrixType::Nested m_matrix; -}; - -/* Template partial specialization for transposed/inverse permutations */ - -template -struct traits > > - : traits -{}; - -} // end namespace internal - -template -class Transpose > - : public EigenBase > > -{ - typedef Derived PermutationType; - typedef typename PermutationType::IndicesType IndicesType; typedef typename PermutationType::PlainPermutationType PlainPermutationType; + typedef internal::traits PermTraits; + protected: + InverseImpl() {} public: + typedef Inverse InverseType; + using EigenBase >::derived; #ifndef EIGEN_PARSED_BY_DOXYGEN - typedef internal::traits Traits; - typedef typename Derived::DenseMatrixType DenseMatrixType; + typedef typename PermutationType::DenseMatrixType DenseMatrixType; enum { - Flags = Traits::Flags, - CoeffReadCost = Traits::CoeffReadCost, - RowsAtCompileTime = Traits::RowsAtCompileTime, - ColsAtCompileTime = Traits::ColsAtCompileTime, - MaxRowsAtCompileTime = Traits::MaxRowsAtCompileTime, - MaxColsAtCompileTime = Traits::MaxColsAtCompileTime + RowsAtCompileTime = PermTraits::RowsAtCompileTime, + ColsAtCompileTime = PermTraits::ColsAtCompileTime, + MaxRowsAtCompileTime = PermTraits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = PermTraits::MaxColsAtCompileTime }; - typedef typename Traits::Scalar Scalar; #endif - Transpose(const PermutationType& p) : m_permutation(p) {} - - inline int rows() const { return m_permutation.rows(); } - inline int cols() const { return m_permutation.cols(); } - #ifndef EIGEN_PARSED_BY_DOXYGEN template void evalTo(MatrixBase& other) const { other.setZero(); - for (int i=0; i friend - inline const internal::permut_matrix_product_retval - operator*(const MatrixBase& matrix, const Transpose& trPerm) + const Product + operator*(const MatrixBase& matrix, const InverseType& trPerm) { - return internal::permut_matrix_product_retval(trPerm.m_permutation, matrix.derived()); + return Product(matrix.derived(), trPerm.derived()); } /** \returns the matrix with the inverse permutation applied to the rows. */ template - inline const internal::permut_matrix_product_retval + const Product operator*(const MatrixBase& matrix) const { - return internal::permut_matrix_product_retval(m_permutation, matrix.derived()); + return Product(derived(), matrix.derived()); } - - const PermutationType& nestedPermutation() const { return m_permutation; } - - protected: - const PermutationType& m_permutation; }; template @@ -683,6 +625,12 @@ const PermutationWrapper MatrixBase::asPermutation() con return derived(); } +namespace internal { + +template<> struct AssignmentKind { typedef EigenBase2EigenBase Kind; }; + +} // end namespace internal + } // end namespace Eigen #endif // EIGEN_PERMUTATIONMATRIX_H diff --git a/nuparu/include/Eigen/src/Core/PlainObjectBase.h b/nuparu/include/Eigen/src/Core/PlainObjectBase.h index af0a479c..1225e85b 100644 --- a/nuparu/include/Eigen/src/Core/PlainObjectBase.h +++ b/nuparu/include/Eigen/src/Core/PlainObjectBase.h @@ -28,6 +28,7 @@ namespace internal { template struct check_rows_cols_for_overflow { template + EIGEN_DEVICE_FUNC static EIGEN_ALWAYS_INLINE void run(Index, Index) { } @@ -35,6 +36,7 @@ template struct check_rows_cols_for_overflow { template<> struct check_rows_cols_for_overflow { template + EIGEN_DEVICE_FUNC static EIGEN_ALWAYS_INLINE void run(Index rows, Index cols) { // http://hg.mozilla.org/mozilla-central/file/6c8a909977d3/xpcom/ds/CheckedInt.h#l242 @@ -47,7 +49,10 @@ template<> struct check_rows_cols_for_overflow { } }; -template struct conservative_resize_like_impl; +template +struct conservative_resize_like_impl; template struct matrix_swap_impl; @@ -64,8 +69,9 @@ template struct m #ifdef EIGEN_PARSED_BY_DOXYGEN namespace internal { -// this is a warkaround to doxygen not being able to understand the inheritence logic +// this is a workaround to doxygen not being able to understand the inheritance logic // when it is hidden by the dense_xpr_base helper struct. +/** This class is just a workaround for Doxygen and it does not not actually exist. */ template struct dense_xpr_base_dispatcher_for_doxygen;// : public MatrixBase {}; /** This class is just a workaround for Doxygen and it does not not actually exist. */ template @@ -90,8 +96,8 @@ class PlainObjectBase : public internal::dense_xpr_base::type typedef typename internal::dense_xpr_base::type Base; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; + typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; typedef Derived DenseType; @@ -110,28 +116,36 @@ class PlainObjectBase : public internal::dense_xpr_base::type typedef Eigen::Map MapType; friend class Eigen::Map; typedef const Eigen::Map ConstMapType; - friend class Eigen::Map; - typedef Eigen::Map AlignedMapType; - friend class Eigen::Map; - typedef const Eigen::Map ConstAlignedMapType; +#if EIGEN_MAX_ALIGN_BYTES>0 + // for EIGEN_MAX_ALIGN_BYTES==0, AlignedMax==Unaligned, and many compilers generate warnings for friend-ing a class twice. + friend class Eigen::Map; + friend class Eigen::Map; +#endif + typedef Eigen::Map AlignedMapType; + typedef const Eigen::Map ConstAlignedMapType; template struct StridedMapType { typedef Eigen::Map type; }; template struct StridedConstMapType { typedef Eigen::Map type; }; - template struct StridedAlignedMapType { typedef Eigen::Map type; }; - template struct StridedConstAlignedMapType { typedef Eigen::Map type; }; + template struct StridedAlignedMapType { typedef Eigen::Map type; }; + template struct StridedConstAlignedMapType { typedef Eigen::Map type; }; protected: DenseStorage m_storage; public: - enum { NeedsToAlign = SizeAtCompileTime != Dynamic && (internal::traits::Flags & AlignedBit) != 0 }; + enum { NeedsToAlign = (SizeAtCompileTime != Dynamic) && (internal::traits::Alignment>0) }; EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) + EIGEN_DEVICE_FUNC Base& base() { return *static_cast(this); } + EIGEN_DEVICE_FUNC const Base& base() const { return *static_cast(this); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { return m_storage.rows(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { return m_storage.cols(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(Index rowId, Index colId) const { if(Flags & RowMajorBit) @@ -140,11 +154,13 @@ class PlainObjectBase : public internal::dense_xpr_base::type return m_storage.data()[rowId + colId * m_storage.rows()]; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(Index index) const { return m_storage.data()[index]; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index rowId, Index colId) { if(Flags & RowMajorBit) @@ -153,11 +169,13 @@ class PlainObjectBase : public internal::dense_xpr_base::type return m_storage.data()[rowId + colId * m_storage.rows()]; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) { return m_storage.data()[index]; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeffRef(Index rowId, Index colId) const { if(Flags & RowMajorBit) @@ -166,6 +184,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type return m_storage.data()[rowId + colId * m_storage.rows()]; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeffRef(Index index) const { return m_storage.data()[index]; @@ -206,11 +225,11 @@ class PlainObjectBase : public internal::dense_xpr_base::type } /** \returns a const pointer to the data array of this matrix */ - EIGEN_STRONG_INLINE const Scalar *data() const + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar *data() const { return m_storage.data(); } /** \returns a pointer to the data array of this matrix */ - EIGEN_STRONG_INLINE Scalar *data() + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar *data() { return m_storage.data(); } /** Resizes \c *this to a \a rows x \a cols matrix. @@ -229,22 +248,22 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * \sa resize(Index) for vectors, resize(NoChange_t, Index), resize(Index, NoChange_t) */ - EIGEN_STRONG_INLINE void resize(Index nbRows, Index nbCols) - { - eigen_assert( EIGEN_IMPLIES(RowsAtCompileTime!=Dynamic,nbRows==RowsAtCompileTime) - && EIGEN_IMPLIES(ColsAtCompileTime!=Dynamic,nbCols==ColsAtCompileTime) - && EIGEN_IMPLIES(RowsAtCompileTime==Dynamic && MaxRowsAtCompileTime!=Dynamic,nbRows<=MaxRowsAtCompileTime) - && EIGEN_IMPLIES(ColsAtCompileTime==Dynamic && MaxColsAtCompileTime!=Dynamic,nbCols<=MaxColsAtCompileTime) - && nbRows>=0 && nbCols>=0 && "Invalid sizes when resizing a matrix or array."); - internal::check_rows_cols_for_overflow::run(nbRows, nbCols); + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void resize(Index rows, Index cols) + { + eigen_assert( EIGEN_IMPLIES(RowsAtCompileTime!=Dynamic,rows==RowsAtCompileTime) + && EIGEN_IMPLIES(ColsAtCompileTime!=Dynamic,cols==ColsAtCompileTime) + && EIGEN_IMPLIES(RowsAtCompileTime==Dynamic && MaxRowsAtCompileTime!=Dynamic,rows<=MaxRowsAtCompileTime) + && EIGEN_IMPLIES(ColsAtCompileTime==Dynamic && MaxColsAtCompileTime!=Dynamic,cols<=MaxColsAtCompileTime) + && rows>=0 && cols>=0 && "Invalid sizes when resizing a matrix or array."); + internal::check_rows_cols_for_overflow::run(rows, cols); #ifdef EIGEN_INITIALIZE_COEFFS - Index size = nbRows*nbCols; + Index size = rows*cols; bool size_changed = size != this->size(); - m_storage.resize(size, nbRows, nbCols); + m_storage.resize(size, rows, cols); if(size_changed) EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED #else - internal::check_rows_cols_for_overflow::run(nbRows, nbCols); - m_storage.resize(nbRows*nbCols, nbRows, nbCols); + m_storage.resize(rows*cols, rows, cols); #endif } @@ -259,6 +278,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * \sa resize(Index,Index), resize(NoChange_t, Index), resize(Index, NoChange_t) */ + EIGEN_DEVICE_FUNC inline void resize(Index size) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(PlainObjectBase) @@ -283,9 +303,10 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * \sa resize(Index,Index) */ - inline void resize(NoChange_t, Index nbCols) + EIGEN_DEVICE_FUNC + inline void resize(NoChange_t, Index cols) { - resize(rows(), nbCols); + resize(rows(), cols); } /** Resizes the matrix, changing only the number of rows. For the parameter of type NoChange_t, just pass the special value \c NoChange @@ -296,9 +317,10 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * \sa resize(Index,Index) */ - inline void resize(Index nbRows, NoChange_t) + EIGEN_DEVICE_FUNC + inline void resize(Index rows, NoChange_t) { - resize(nbRows, cols()); + resize(rows, cols()); } /** Resizes \c *this to have the same dimensions as \a other. @@ -309,6 +331,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type * remain row-vectors and vectors remain vectors. */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resizeLike(const EigenBase& _other) { const OtherDerived& other = _other.derived(); @@ -336,9 +359,10 @@ class PlainObjectBase : public internal::dense_xpr_base::type * Matrices are resized relative to the top-left element. In case values need to be * appended to the matrix they will be uninitialized. */ - EIGEN_STRONG_INLINE void conservativeResize(Index nbRows, Index nbCols) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void conservativeResize(Index rows, Index cols) { - internal::conservative_resize_like_impl::run(*this, nbRows, nbCols); + internal::conservative_resize_like_impl::run(*this, rows, cols); } /** Resizes the matrix to \a rows x \a cols while leaving old values untouched. @@ -348,10 +372,11 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * In case the matrix is growing, new rows will be uninitialized. */ - EIGEN_STRONG_INLINE void conservativeResize(Index nbRows, NoChange_t) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void conservativeResize(Index rows, NoChange_t) { // Note: see the comment in conservativeResize(Index,Index) - conservativeResize(nbRows, cols()); + conservativeResize(rows, cols()); } /** Resizes the matrix to \a rows x \a cols while leaving old values untouched. @@ -361,10 +386,11 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * In case the matrix is growing, new columns will be uninitialized. */ - EIGEN_STRONG_INLINE void conservativeResize(NoChange_t, Index nbCols) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void conservativeResize(NoChange_t, Index cols) { // Note: see the comment in conservativeResize(Index,Index) - conservativeResize(rows(), nbCols); + conservativeResize(rows(), cols); } /** Resizes the vector to \a size while retaining old values. @@ -375,6 +401,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * When values are appended, they will be uninitialized. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void conservativeResize(Index size) { internal::conservative_resize_like_impl::run(*this, size); @@ -390,6 +417,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type * appended to the matrix they will copied from \c other. */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void conservativeResizeLike(const DenseBase& other) { internal::conservative_resize_like_impl::run(*this, other); @@ -398,6 +426,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const PlainObjectBase& other) { return _set(other); @@ -405,6 +434,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type /** \sa MatrixBase::lazyAssign() */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& lazyAssign(const DenseBase& other) { _resize_to_match(other); @@ -412,12 +442,18 @@ class PlainObjectBase : public internal::dense_xpr_base::type } template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const ReturnByValue& func) { resize(func.rows(), func.cols()); return Base::operator=(func); } + // Prevent user from trying to instantiate PlainObjectBase objects + // by making all its constructor protected. See bug 1074. + protected: + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PlainObjectBase() : m_storage() { // _check_template_params(); @@ -427,38 +463,85 @@ class PlainObjectBase : public internal::dense_xpr_base::type #ifndef EIGEN_PARSED_BY_DOXYGEN // FIXME is it still needed ? /** \internal */ - PlainObjectBase(internal::constructor_without_unaligned_array_assert) + EIGEN_DEVICE_FUNC + explicit PlainObjectBase(internal::constructor_without_unaligned_array_assert) : m_storage(internal::constructor_without_unaligned_array_assert()) { // _check_template_params(); EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED } #endif - EIGEN_STRONG_INLINE PlainObjectBase(Index a_size, Index nbRows, Index nbCols) - : m_storage(a_size, nbRows, nbCols) +#ifdef EIGEN_HAVE_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + PlainObjectBase(PlainObjectBase&& other) + : m_storage( std::move(other.m_storage) ) + { + } + + EIGEN_DEVICE_FUNC + PlainObjectBase& operator=(PlainObjectBase&& other) + { + using std::swap; + swap(m_storage, other.m_storage); + return *this; + } +#endif + + /** Copy constructor */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE PlainObjectBase(const PlainObjectBase& other) + : Base(), m_storage(other.m_storage) { } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE PlainObjectBase(Index size, Index rows, Index cols) + : m_storage(size, rows, cols) { // _check_template_params(); // EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED } - /** \copydoc MatrixBase::operator=(const EigenBase&) - */ + /** \sa PlainObjectBase::operator=(const EigenBase&) */ template - EIGEN_STRONG_INLINE Derived& operator=(const EigenBase &other) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE PlainObjectBase(const DenseBase &other) + : m_storage() { - _resize_to_match(other); - Base::operator=(other.derived()); - return this->derived(); + _check_template_params(); + resizeLike(other); + _set_noalias(other); } - /** \sa MatrixBase::operator=(const EigenBase&) */ + /** \sa PlainObjectBase::operator=(const EigenBase&) */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PlainObjectBase(const EigenBase &other) - : m_storage(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols()) + : m_storage() { _check_template_params(); - internal::check_rows_cols_for_overflow::run(other.derived().rows(), other.derived().cols()); + resizeLike(other); + *this = other.derived(); + } + /** \brief Copy constructor with in-place evaluation */ + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE PlainObjectBase(const ReturnByValue& other) + { + _check_template_params(); + // FIXME this does not automatically transpose vectors if necessary + resize(other.rows(), other.cols()); + other.evalTo(this->derived()); + } + + public: + + /** \copydoc MatrixBase::operator=(const EigenBase&) + */ + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Derived& operator=(const EigenBase &other) + { + _resize_to_match(other); Base::operator=(other.derived()); + return this->derived(); } /** \name Map @@ -535,16 +618,16 @@ class PlainObjectBase : public internal::dense_xpr_base::type //@} using Base::setConstant; - Derived& setConstant(Index size, const Scalar& value); - Derived& setConstant(Index rows, Index cols, const Scalar& value); + EIGEN_DEVICE_FUNC Derived& setConstant(Index size, const Scalar& value); + EIGEN_DEVICE_FUNC Derived& setConstant(Index rows, Index cols, const Scalar& value); using Base::setZero; - Derived& setZero(Index size); - Derived& setZero(Index rows, Index cols); + EIGEN_DEVICE_FUNC Derived& setZero(Index size); + EIGEN_DEVICE_FUNC Derived& setZero(Index rows, Index cols); using Base::setOnes; - Derived& setOnes(Index size); - Derived& setOnes(Index rows, Index cols); + EIGEN_DEVICE_FUNC Derived& setOnes(Index size); + EIGEN_DEVICE_FUNC Derived& setOnes(Index rows, Index cols); using Base::setRandom; Derived& setRandom(Index size); @@ -563,6 +646,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type * remain row-vectors and vectors remain vectors. */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _resize_to_match(const EigenBase& other) { #ifdef EIGEN_NO_AUTOMATIC_RESIZING @@ -589,25 +673,23 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * \internal */ + // aliasing is dealt once in internall::call_assignment + // so at this stage we have to assume aliasing... and resising has to be done later. template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& _set(const DenseBase& other) { - _set_selector(other.derived(), typename internal::conditional(int(OtherDerived::Flags) & EvalBeforeAssigningBit), internal::true_type, internal::false_type>::type()); + internal::call_assignment(this->derived(), other.derived()); return this->derived(); } - template - EIGEN_STRONG_INLINE void _set_selector(const OtherDerived& other, const internal::true_type&) { _set_noalias(other.eval()); } - - template - EIGEN_STRONG_INLINE void _set_selector(const OtherDerived& other, const internal::false_type&) { _set_noalias(other); } - /** \internal Like _set() but additionally makes the assumption that no aliasing effect can happen (which * is the case when creating a new matrix) so one can enforce lazy evaluation. * * \sa operator=(const MatrixBase&), _set() */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& _set_noalias(const DenseBase& other) { // I don't think we need this resize call since the lazyAssign will anyways resize @@ -615,40 +697,166 @@ class PlainObjectBase : public internal::dense_xpr_base::type //_resize_to_match(other); // the 'false' below means to enforce lazy evaluation. We don't use lazyAssign() because // it wouldn't allow to copy a row-vector into a column-vector. - return internal::assign_selector::run(this->derived(), other.derived()); + internal::call_assignment_no_alias(this->derived(), other.derived(), internal::assign_op()); + return this->derived(); } template - EIGEN_STRONG_INLINE void _init2(Index nbRows, Index nbCols, typename internal::enable_if::type* = 0) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init2(Index rows, Index cols, typename internal::enable_if::type* = 0) { EIGEN_STATIC_ASSERT(bool(NumTraits::IsInteger) && bool(NumTraits::IsInteger), FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED) - resize(nbRows,nbCols); + resize(rows,cols); } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _init2(const Scalar& val0, const Scalar& val1, typename internal::enable_if::type* = 0) { EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 2) m_storage.data()[0] = val0; m_storage.data()[1] = val1; } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init2(const Index& val0, const Index& val1, + typename internal::enable_if< (!internal::is_same::value) + && (internal::is_same::value) + && (internal::is_same::value) + && Base::SizeAtCompileTime==2,T1>::type* = 0) + { + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 2) + m_storage.data()[0] = Scalar(val0); + m_storage.data()[1] = Scalar(val1); + } + + // The argument is convertible to the Index type and we either have a non 1x1 Matrix, or a dynamic-sized Array, + // then the argument is meant to be the size of the object. + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(Index size, typename internal::enable_if< (Base::SizeAtCompileTime!=1 || !internal::is_convertible::value) + && ((!internal::is_same::XprKind,ArrayXpr>::value || Base::SizeAtCompileTime==Dynamic)),T>::type* = 0) + { + // NOTE MSVC 2008 complains if we directly put bool(NumTraits::IsInteger) as the EIGEN_STATIC_ASSERT argument. + const bool is_integer = NumTraits::IsInteger; + EIGEN_STATIC_ASSERT(is_integer, + FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED) + resize(size); + } + + // We have a 1x1 matrix/array => the argument is interpreted as the value of the unique coefficient (case where scalar type can be implicitely converted) + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Scalar& val0, typename internal::enable_if::value,T>::type* = 0) + { + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 1) + m_storage.data()[0] = val0; + } + + // We have a 1x1 matrix/array => the argument is interpreted as the value of the unique coefficient (case where scalar type match the index type) + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Index& val0, + typename internal::enable_if< (!internal::is_same::value) + && (internal::is_same::value) + && Base::SizeAtCompileTime==1 + && internal::is_convertible::value,T*>::type* = 0) + { + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 1) + m_storage.data()[0] = Scalar(val0); + } + + // Initialize a fixed size matrix from a pointer to raw data + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Scalar* data){ + this->_set_noalias(ConstMapType(data)); + } + + // Initialize an arbitrary matrix from a dense expression + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const DenseBase& other){ + this->_set_noalias(other); + } + + // Initialize an arbitrary matrix from a generic Eigen expression + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const EigenBase& other){ + this->derived() = other; + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const ReturnByValue& other) + { + resize(other.rows(), other.cols()); + other.evalTo(this->derived()); + } + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const RotationBase& r) + { + this->derived() = r; + } + + // For fixed -size arrays: + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Scalar& val0, + typename internal::enable_if< Base::SizeAtCompileTime!=Dynamic + && Base::SizeAtCompileTime!=1 + && internal::is_convertible::value + && internal::is_same::XprKind,ArrayXpr>::value,T>::type* = 0) + { + Base::setConstant(val0); + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Index& val0, + typename internal::enable_if< (!internal::is_same::value) + && (internal::is_same::value) + && Base::SizeAtCompileTime!=Dynamic + && Base::SizeAtCompileTime!=1 + && internal::is_convertible::value + && internal::is_same::XprKind,ArrayXpr>::value,T*>::type* = 0) + { + Base::setConstant(val0); + } + template friend struct internal::matrix_swap_impl; - /** \internal generic implementation of swap for dense storage since for dynamic-sized matrices of same type it is enough to swap the - * data pointers. + public: + +#ifndef EIGEN_PARSED_BY_DOXYGEN + /** \internal + * \brief Override DenseBase::swap() since for dynamic-sized matrices + * of same type it is enough to swap the data pointers. */ template - void _swap(DenseBase const & other) + EIGEN_DEVICE_FUNC + void swap(DenseBase & other) { enum { SwapPointers = internal::is_same::value && Base::SizeAtCompileTime==Dynamic }; - internal::matrix_swap_impl::run(this->derived(), other.const_cast_derived()); + internal::matrix_swap_impl::run(this->derived(), other.derived()); } - - public: -#ifndef EIGEN_PARSED_BY_DOXYGEN + + /** \internal + * \brief const version forwarded to DenseBase::swap + */ + template + EIGEN_DEVICE_FUNC + void swap(DenseBase const & other) + { Base::swap(other.derived()); } + + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void _check_template_params() { EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, (Options&RowMajor)==RowMajor) @@ -662,16 +870,16 @@ class PlainObjectBase : public internal::dense_xpr_base::type && (Options & (DontAlign|RowMajor)) == Options), INVALID_MATRIX_TEMPLATE_PARAMETERS) } -#endif -private: - enum { ThisConstantIsPrivateInPlainObjectBase }; + enum { IsPlainObjectBase = 1 }; +#endif }; +namespace internal { + template -struct internal::conservative_resize_like_impl +struct conservative_resize_like_impl { - typedef typename Derived::Index Index; static void run(DenseBase& _this, Index rows, Index cols) { if (_this.rows() == rows && _this.cols() == cols) return; @@ -729,12 +937,14 @@ struct internal::conservative_resize_like_impl } }; -namespace internal { - +// Here, the specialization for vectors inherits from the general matrix case +// to allow calling .conservativeResize(rows,cols) on vectors. template struct conservative_resize_like_impl + : conservative_resize_like_impl { - typedef typename Derived::Index Index; + using conservative_resize_like_impl::run; + static void run(DenseBase& _this, Index size) { const Index new_rows = Derived::RowsAtCompileTime==1 ? 1 : size; @@ -760,6 +970,7 @@ struct conservative_resize_like_impl template struct matrix_swap_impl { + EIGEN_DEVICE_FUNC static inline void run(MatrixTypeA& a, MatrixTypeB& b) { a.base().swap(b); @@ -769,6 +980,7 @@ struct matrix_swap_impl template struct matrix_swap_impl { + EIGEN_DEVICE_FUNC static inline void run(MatrixTypeA& a, MatrixTypeB& b) { static_cast(a).m_storage.swap(static_cast(b).m_storage); diff --git a/nuparu/include/Eigen/src/Core/Product.h b/nuparu/include/Eigen/src/Core/Product.h new file mode 100644 index 00000000..fdd2fed3 --- /dev/null +++ b/nuparu/include/Eigen/src/Core/Product.h @@ -0,0 +1,222 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2011 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_PRODUCT_H +#define EIGEN_PRODUCT_H + +namespace Eigen { + +template class ProductImpl; + +/** \class Product + * \ingroup Core_Module + * + * \brief Expression of the product of two arbitrary matrices or vectors + * + * \param Lhs the type of the left-hand side expression + * \param Rhs the type of the right-hand side expression + * + * This class represents an expression of the product of two arbitrary matrices. + * + * The other template parameters are: + * \tparam Option can be DefaultProduct, AliasFreeProduct, or LazyProduct + * + */ + + +namespace internal { + +// Determine the scalar of Product. This is normally the same as Lhs::Scalar times +// Rhs::Scalar, but product with permutation matrices inherit the scalar of the other factor. +template::Shape, + typename RhsShape = typename evaluator_traits::Shape > +struct product_result_scalar +{ + typedef typename scalar_product_traits::ReturnType Scalar; +}; + +template +struct product_result_scalar +{ + typedef typename Rhs::Scalar Scalar; +}; + +template + struct product_result_scalar +{ + typedef typename Lhs::Scalar Scalar; +}; + +template +struct product_result_scalar +{ + typedef typename Rhs::Scalar Scalar; +}; + +template + struct product_result_scalar +{ + typedef typename Lhs::Scalar Scalar; +}; + +template +struct traits > +{ + typedef typename remove_all::type LhsCleaned; + typedef typename remove_all::type RhsCleaned; + typedef traits LhsTraits; + typedef traits RhsTraits; + + typedef MatrixXpr XprKind; + + typedef typename product_result_scalar::Scalar Scalar; + typedef typename product_promote_storage_type::ret>::ret StorageKind; + typedef typename promote_index_type::type StorageIndex; + + enum { + RowsAtCompileTime = LhsTraits::RowsAtCompileTime, + ColsAtCompileTime = RhsTraits::ColsAtCompileTime, + MaxRowsAtCompileTime = LhsTraits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = RhsTraits::MaxColsAtCompileTime, + + // FIXME: only needed by GeneralMatrixMatrixTriangular + InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(LhsTraits::ColsAtCompileTime, RhsTraits::RowsAtCompileTime), + + // The storage order is somewhat arbitrary here. The correct one will be determined through the evaluator. + Flags = (MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1) ? RowMajorBit + : (MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1) ? 0 + : ( ((LhsTraits::Flags&NoPreferredStorageOrderBit) && (RhsTraits::Flags&RowMajorBit)) + || ((RhsTraits::Flags&NoPreferredStorageOrderBit) && (LhsTraits::Flags&RowMajorBit)) ) ? RowMajorBit + : NoPreferredStorageOrderBit + }; +}; + +} // end namespace internal + + +template +class Product : public ProductImpl<_Lhs,_Rhs,Option, + typename internal::product_promote_storage_type::StorageKind, + typename internal::traits<_Rhs>::StorageKind, + internal::product_type<_Lhs,_Rhs>::ret>::ret> +{ + public: + + typedef _Lhs Lhs; + typedef _Rhs Rhs; + + typedef typename ProductImpl< + Lhs, Rhs, Option, + typename internal::product_promote_storage_type::StorageKind, + typename internal::traits::StorageKind, + internal::product_type::ret>::ret>::Base Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(Product) + + typedef typename internal::ref_selector::type LhsNested; + typedef typename internal::ref_selector::type RhsNested; + typedef typename internal::remove_all::type LhsNestedCleaned; + typedef typename internal::remove_all::type RhsNestedCleaned; + + EIGEN_DEVICE_FUNC Product(const Lhs& lhs, const Rhs& rhs) : m_lhs(lhs), m_rhs(rhs) + { + eigen_assert(lhs.cols() == rhs.rows() + && "invalid matrix product" + && "if you wanted a coeff-wise or a dot product use the respective explicit functions"); + } + + EIGEN_DEVICE_FUNC inline Index rows() const { return m_lhs.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_rhs.cols(); } + + EIGEN_DEVICE_FUNC const LhsNestedCleaned& lhs() const { return m_lhs; } + EIGEN_DEVICE_FUNC const RhsNestedCleaned& rhs() const { return m_rhs; } + + protected: + + LhsNested m_lhs; + RhsNested m_rhs; +}; + +namespace internal { + +template::ret> +class dense_product_base + : public internal::dense_xpr_base >::type +{}; + +/** Convertion to scalar for inner-products */ +template +class dense_product_base + : public internal::dense_xpr_base >::type +{ + typedef Product ProductXpr; + typedef typename internal::dense_xpr_base::type Base; +public: + using Base::derived; + typedef typename Base::Scalar Scalar; + + operator const Scalar() const + { + return internal::evaluator(derived()).coeff(0,0); + } +}; + +} // namespace internal + +// Generic API dispatcher +template +class ProductImpl : public internal::generic_xpr_base, MatrixXpr, StorageKind>::type +{ + public: + typedef typename internal::generic_xpr_base, MatrixXpr, StorageKind>::type Base; +}; + +template +class ProductImpl + : public internal::dense_product_base +{ + typedef Product Derived; + + public: + + typedef typename internal::dense_product_base Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Derived) + protected: + enum { + IsOneByOne = (RowsAtCompileTime == 1 || RowsAtCompileTime == Dynamic) && + (ColsAtCompileTime == 1 || ColsAtCompileTime == Dynamic), + EnableCoeff = IsOneByOne || Option==LazyProduct + }; + + public: + + EIGEN_DEVICE_FUNC Scalar coeff(Index row, Index col) const + { + EIGEN_STATIC_ASSERT(EnableCoeff, THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS); + eigen_assert( (Option==LazyProduct) || (this->rows() == 1 && this->cols() == 1) ); + + return internal::evaluator(derived()).coeff(row,col); + } + + EIGEN_DEVICE_FUNC Scalar coeff(Index i) const + { + EIGEN_STATIC_ASSERT(EnableCoeff, THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS); + eigen_assert( (Option==LazyProduct) || (this->rows() == 1 && this->cols() == 1) ); + + return internal::evaluator(derived()).coeff(i); + } + + +}; + +} // end namespace Eigen + +#endif // EIGEN_PRODUCT_H diff --git a/nuparu/include/Eigen/src/Core/ProductBase.h b/nuparu/include/Eigen/src/Core/ProductBase.h deleted file mode 100644 index a494b5f8..00000000 --- a/nuparu/include/Eigen/src/Core/ProductBase.h +++ /dev/null @@ -1,278 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_PRODUCTBASE_H -#define EIGEN_PRODUCTBASE_H - -namespace Eigen { - -/** \class ProductBase - * \ingroup Core_Module - * - */ - -namespace internal { -template -struct traits > -{ - typedef MatrixXpr XprKind; - typedef typename remove_all<_Lhs>::type Lhs; - typedef typename remove_all<_Rhs>::type Rhs; - typedef typename scalar_product_traits::ReturnType Scalar; - typedef typename promote_storage_type::StorageKind, - typename traits::StorageKind>::ret StorageKind; - typedef typename promote_index_type::Index, - typename traits::Index>::type Index; - enum { - RowsAtCompileTime = traits::RowsAtCompileTime, - ColsAtCompileTime = traits::ColsAtCompileTime, - MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, - MaxColsAtCompileTime = traits::MaxColsAtCompileTime, - Flags = (MaxRowsAtCompileTime==1 ? RowMajorBit : 0) - | EvalBeforeNestingBit | EvalBeforeAssigningBit | NestByRefBit, - // Note that EvalBeforeNestingBit and NestByRefBit - // are not used in practice because nested is overloaded for products - CoeffReadCost = 0 // FIXME why is it needed ? - }; -}; -} - -#define EIGEN_PRODUCT_PUBLIC_INTERFACE(Derived) \ - typedef ProductBase Base; \ - EIGEN_DENSE_PUBLIC_INTERFACE(Derived) \ - typedef typename Base::LhsNested LhsNested; \ - typedef typename Base::_LhsNested _LhsNested; \ - typedef typename Base::LhsBlasTraits LhsBlasTraits; \ - typedef typename Base::ActualLhsType ActualLhsType; \ - typedef typename Base::_ActualLhsType _ActualLhsType; \ - typedef typename Base::RhsNested RhsNested; \ - typedef typename Base::_RhsNested _RhsNested; \ - typedef typename Base::RhsBlasTraits RhsBlasTraits; \ - typedef typename Base::ActualRhsType ActualRhsType; \ - typedef typename Base::_ActualRhsType _ActualRhsType; \ - using Base::m_lhs; \ - using Base::m_rhs; - -template -class ProductBase : public MatrixBase -{ - public: - typedef MatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(ProductBase) - - typedef typename Lhs::Nested LhsNested; - typedef typename internal::remove_all::type _LhsNested; - typedef internal::blas_traits<_LhsNested> LhsBlasTraits; - typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; - typedef typename internal::remove_all::type _ActualLhsType; - typedef typename internal::traits::Scalar LhsScalar; - - typedef typename Rhs::Nested RhsNested; - typedef typename internal::remove_all::type _RhsNested; - typedef internal::blas_traits<_RhsNested> RhsBlasTraits; - typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; - typedef typename internal::remove_all::type _ActualRhsType; - typedef typename internal::traits::Scalar RhsScalar; - - // Diagonal of a product: no need to evaluate the arguments because they are going to be evaluated only once - typedef CoeffBasedProduct FullyLazyCoeffBaseProductType; - - public: - - typedef typename Base::PlainObject PlainObject; - - ProductBase(const Lhs& a_lhs, const Rhs& a_rhs) - : m_lhs(a_lhs), m_rhs(a_rhs) - { - eigen_assert(a_lhs.cols() == a_rhs.rows() - && "invalid matrix product" - && "if you wanted a coeff-wise or a dot product use the respective explicit functions"); - } - - inline Index rows() const { return m_lhs.rows(); } - inline Index cols() const { return m_rhs.cols(); } - - template - inline void evalTo(Dest& dst) const { dst.setZero(); scaleAndAddTo(dst,Scalar(1)); } - - template - inline void addTo(Dest& dst) const { scaleAndAddTo(dst,Scalar(1)); } - - template - inline void subTo(Dest& dst) const { scaleAndAddTo(dst,Scalar(-1)); } - - template - inline void scaleAndAddTo(Dest& dst, const Scalar& alpha) const { derived().scaleAndAddTo(dst,alpha); } - - const _LhsNested& lhs() const { return m_lhs; } - const _RhsNested& rhs() const { return m_rhs; } - - // Implicit conversion to the nested type (trigger the evaluation of the product) - operator const PlainObject& () const - { - m_result.resize(m_lhs.rows(), m_rhs.cols()); - derived().evalTo(m_result); - return m_result; - } - - const Diagonal diagonal() const - { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs); } - - template - const Diagonal diagonal() const - { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs); } - - const Diagonal diagonal(Index index) const - { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs).diagonal(index); } - - // restrict coeff accessors to 1x1 expressions. No need to care about mutators here since this isnt a Lvalue expression - typename Base::CoeffReturnType coeff(Index row, Index col) const - { -#ifdef EIGEN2_SUPPORT - return lhs().row(row).cwiseProduct(rhs().col(col).transpose()).sum(); -#else - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); - Matrix result = *this; - return result.coeff(row,col); -#endif - } - - typename Base::CoeffReturnType coeff(Index i) const - { - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); - Matrix result = *this; - return result.coeff(i); - } - - const Scalar& coeffRef(Index row, Index col) const - { - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); - return derived().coeffRef(row,col); - } - - const Scalar& coeffRef(Index i) const - { - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); - return derived().coeffRef(i); - } - - protected: - - LhsNested m_lhs; - RhsNested m_rhs; - - mutable PlainObject m_result; -}; - -// here we need to overload the nested rule for products -// such that the nested type is a const reference to a plain matrix -namespace internal { -template -struct nested, N, PlainObject> -{ - typedef PlainObject const& type; -}; -} - -template -class ScaledProduct; - -// Note that these two operator* functions are not defined as member -// functions of ProductBase, because, otherwise we would have to -// define all overloads defined in MatrixBase. Furthermore, Using -// "using Base::operator*" would not work with MSVC. -// -// Also note that here we accept any compatible scalar types -template -const ScaledProduct -operator*(const ProductBase& prod, const typename Derived::Scalar& x) -{ return ScaledProduct(prod.derived(), x); } - -template -typename internal::enable_if::value, - const ScaledProduct >::type -operator*(const ProductBase& prod, const typename Derived::RealScalar& x) -{ return ScaledProduct(prod.derived(), x); } - - -template -const ScaledProduct -operator*(const typename Derived::Scalar& x,const ProductBase& prod) -{ return ScaledProduct(prod.derived(), x); } - -template -typename internal::enable_if::value, - const ScaledProduct >::type -operator*(const typename Derived::RealScalar& x,const ProductBase& prod) -{ return ScaledProduct(prod.derived(), x); } - -namespace internal { -template -struct traits > - : traits, - typename NestedProduct::_LhsNested, - typename NestedProduct::_RhsNested> > -{ - typedef typename traits::StorageKind StorageKind; -}; -} - -template -class ScaledProduct - : public ProductBase, - typename NestedProduct::_LhsNested, - typename NestedProduct::_RhsNested> -{ - public: - typedef ProductBase, - typename NestedProduct::_LhsNested, - typename NestedProduct::_RhsNested> Base; - typedef typename Base::Scalar Scalar; - typedef typename Base::PlainObject PlainObject; -// EIGEN_PRODUCT_PUBLIC_INTERFACE(ScaledProduct) - - ScaledProduct(const NestedProduct& prod, const Scalar& x) - : Base(prod.lhs(),prod.rhs()), m_prod(prod), m_alpha(x) {} - - template - inline void evalTo(Dest& dst) const { dst.setZero(); scaleAndAddTo(dst, Scalar(1)); } - - template - inline void addTo(Dest& dst) const { scaleAndAddTo(dst, Scalar(1)); } - - template - inline void subTo(Dest& dst) const { scaleAndAddTo(dst, Scalar(-1)); } - - template - inline void scaleAndAddTo(Dest& dst, const Scalar& a_alpha) const { m_prod.derived().scaleAndAddTo(dst,a_alpha * m_alpha); } - - const Scalar& alpha() const { return m_alpha; } - - protected: - const NestedProduct& m_prod; - Scalar m_alpha; -}; - -/** \internal - * Overloaded to perform an efficient C = (A*B).lazy() */ -template -template -Derived& MatrixBase::lazyAssign(const ProductBase& other) -{ - other.derived().evalTo(derived()); - return derived(); -} - -} // end namespace Eigen - -#endif // EIGEN_PRODUCTBASE_H diff --git a/nuparu/include/Eigen/src/Core/ProductEvaluators.h b/nuparu/include/Eigen/src/Core/ProductEvaluators.h new file mode 100755 index 00000000..794038a2 --- /dev/null +++ b/nuparu/include/Eigen/src/Core/ProductEvaluators.h @@ -0,0 +1,1061 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2008 Benoit Jacob +// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2011 Jitse Niesen +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +#ifndef EIGEN_PRODUCTEVALUATORS_H +#define EIGEN_PRODUCTEVALUATORS_H + +namespace Eigen { + +namespace internal { + +/** \internal + * Evaluator of a product expression. + * Since products require special treatments to handle all possible cases, + * we simply deffer the evaluation logic to a product_evaluator class + * which offers more partial specialization possibilities. + * + * \sa class product_evaluator + */ +template +struct evaluator > + : public product_evaluator > +{ + typedef Product XprType; + typedef product_evaluator Base; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : Base(xpr) {} +}; + +// Catch scalar * ( A * B ) and transform it to (A*scalar) * B +// TODO we should apply that rule only if that's really helpful +template +struct evaluator_traits, const Product > > + : evaluator_traits_base, const Product > > +{ + enum { AssumeAliasing = 1 }; +}; +template +struct evaluator, const Product > > + : public evaluator,const Lhs>, Rhs, DefaultProduct> > +{ + typedef CwiseUnaryOp, const Product > XprType; + typedef evaluator,const Lhs>, Rhs, DefaultProduct> > Base; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) + : Base(xpr.functor().m_other * xpr.nestedExpression().lhs() * xpr.nestedExpression().rhs()) + {} +}; + + +template +struct evaluator, DiagIndex> > + : public evaluator, DiagIndex> > +{ + typedef Diagonal, DiagIndex> XprType; + typedef evaluator, DiagIndex> > Base; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) + : Base(Diagonal, DiagIndex>( + Product(xpr.nestedExpression().lhs(), xpr.nestedExpression().rhs()), + xpr.index() )) + {} +}; + + +// Helper class to perform a matrix product with the destination at hand. +// Depending on the sizes of the factors, there are different evaluation strategies +// as controlled by internal::product_type. +template< typename Lhs, typename Rhs, + typename LhsShape = typename evaluator_traits::Shape, + typename RhsShape = typename evaluator_traits::Shape, + int ProductType = internal::product_type::value> +struct generic_product_impl; + +template +struct evaluator_traits > + : evaluator_traits_base > +{ + enum { AssumeAliasing = 1 }; +}; + +template +struct evaluator_traits > + : evaluator_traits_base > +{ + enum { AssumeAliasing = 0 }; +}; + +// This is the default evaluator implementation for products: +// It creates a temporary and call generic_product_impl +template +struct product_evaluator, ProductTag, LhsShape, RhsShape> + : public evaluator::PlainObject> +{ + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef evaluator Base; + enum { + Flags = Base::Flags | EvalBeforeNestingBit + }; + + EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + +// FIXME shall we handle nested_eval here?, +// if so, then we must take care at removing the call to nested_eval in the specializations (e.g., in permutation_matrix_product, transposition_matrix_product, etc.) +// typedef typename internal::nested_eval::type LhsNested; +// typedef typename internal::nested_eval::type RhsNested; +// typedef typename internal::remove_all::type LhsNestedCleaned; +// typedef typename internal::remove_all::type RhsNestedCleaned; +// +// const LhsNested lhs(xpr.lhs()); +// const RhsNested rhs(xpr.rhs()); +// +// generic_product_impl::evalTo(m_result, lhs, rhs); + + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; +}; + +// Dense = Product +template< typename DstXprType, typename Lhs, typename Rhs, int Options, typename Scalar> +struct Assignment, internal::assign_op, Dense2Dense, + typename enable_if<(Options==DefaultProduct || Options==AliasFreeProduct),Scalar>::type> +{ + typedef Product SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + // FIXME shall we handle nested_eval here? + generic_product_impl::evalTo(dst, src.lhs(), src.rhs()); + } +}; + +// Dense += Product +template< typename DstXprType, typename Lhs, typename Rhs, int Options, typename Scalar> +struct Assignment, internal::add_assign_op, Dense2Dense, + typename enable_if<(Options==DefaultProduct || Options==AliasFreeProduct),Scalar>::type> +{ + typedef Product SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &) + { + // FIXME shall we handle nested_eval here? + generic_product_impl::addTo(dst, src.lhs(), src.rhs()); + } +}; + +// Dense -= Product +template< typename DstXprType, typename Lhs, typename Rhs, int Options, typename Scalar> +struct Assignment, internal::sub_assign_op, Dense2Dense, + typename enable_if<(Options==DefaultProduct || Options==AliasFreeProduct),Scalar>::type> +{ + typedef Product SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &) + { + // FIXME shall we handle nested_eval here? + generic_product_impl::subTo(dst, src.lhs(), src.rhs()); + } +}; + + +// Dense ?= scalar * Product +// TODO we should apply that rule if that's really helpful +// for instance, this is not good for inner products +template< typename DstXprType, typename Lhs, typename Rhs, typename AssignFunc, typename Scalar, typename ScalarBis> +struct Assignment, + const Product >, AssignFunc, Dense2Dense, Scalar> +{ + typedef CwiseUnaryOp, + const Product > SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const AssignFunc& func) + { + call_assignment_no_alias(dst, (src.functor().m_other * src.nestedExpression().lhs())*src.nestedExpression().rhs(), func); + } +}; + +//---------------------------------------- +// Catch "Dense ?= xpr + Product<>" expression to save one temporary +// FIXME we could probably enable these rules for any product, i.e., not only Dense and DefaultProduct + +template +struct assignment_from_xpr_plus_product +{ + typedef CwiseBinaryOp, const OtherXpr, const ProductType> SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const Func1& func) + { + call_assignment_no_alias(dst, src.lhs(), func); + call_assignment_no_alias(dst, src.rhs(), Func2()); + } +}; + +template< typename DstXprType, typename OtherXpr, typename Lhs, typename Rhs, typename Scalar> +struct Assignment, const OtherXpr, + const Product >, internal::assign_op, Dense2Dense> + : assignment_from_xpr_plus_product, Scalar, internal::assign_op, internal::add_assign_op > +{}; +template< typename DstXprType, typename OtherXpr, typename Lhs, typename Rhs, typename Scalar> +struct Assignment, const OtherXpr, + const Product >, internal::add_assign_op, Dense2Dense> + : assignment_from_xpr_plus_product, Scalar, internal::add_assign_op, internal::add_assign_op > +{}; +template< typename DstXprType, typename OtherXpr, typename Lhs, typename Rhs, typename Scalar> +struct Assignment, const OtherXpr, + const Product >, internal::sub_assign_op, Dense2Dense> + : assignment_from_xpr_plus_product, Scalar, internal::sub_assign_op, internal::sub_assign_op > +{}; +//---------------------------------------- + +template +struct generic_product_impl +{ + template + static inline void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + dst.coeffRef(0,0) = (lhs.transpose().cwiseProduct(rhs)).sum(); + } + + template + static inline void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + dst.coeffRef(0,0) += (lhs.transpose().cwiseProduct(rhs)).sum(); + } + + template + static void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { dst.coeffRef(0,0) -= (lhs.transpose().cwiseProduct(rhs)).sum(); } +}; + + +/*********************************************************************** +* Implementation of outer dense * dense vector product +***********************************************************************/ + +// Column major result +template +EIGEN_DONT_INLINE void outer_product_selector_run(Dst& dst, const Lhs &lhs, const Rhs &rhs, const Func& func, const false_type&) +{ + evaluator rhsEval(rhs); + typename nested_eval::type actual_lhs(lhs); + // FIXME if cols is large enough, then it might be useful to make sure that lhs is sequentially stored + // FIXME not very good if rhs is real and lhs complex while alpha is real too + const Index cols = dst.cols(); + for (Index j=0; j +EIGEN_DONT_INLINE void outer_product_selector_run(Dst& dst, const Lhs &lhs, const Rhs &rhs, const Func& func, const true_type&) +{ + evaluator lhsEval(lhs); + typename nested_eval::type actual_rhs(rhs); + // FIXME if rows is large enough, then it might be useful to make sure that rhs is sequentially stored + // FIXME not very good if lhs is real and rhs complex while alpha is real too + const Index rows = dst.rows(); + for (Index i=0; i +struct generic_product_impl +{ + template struct is_row_major : internal::conditional<(int(T::Flags)&RowMajorBit), internal::true_type, internal::false_type>::type {}; + typedef typename Product::Scalar Scalar; + + // TODO it would be nice to be able to exploit our *_assign_op functors for that purpose + struct set { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() = src; } }; + struct add { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() += src; } }; + struct sub { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() -= src; } }; + struct adds { + Scalar m_scale; + explicit adds(const Scalar& s) : m_scale(s) {} + template void operator()(const Dst& dst, const Src& src) const { + dst.const_cast_derived() += m_scale * src; + } + }; + + template + static inline void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + internal::outer_product_selector_run(dst, lhs, rhs, set(), is_row_major()); + } + + template + static inline void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + internal::outer_product_selector_run(dst, lhs, rhs, add(), is_row_major()); + } + + template + static inline void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + internal::outer_product_selector_run(dst, lhs, rhs, sub(), is_row_major()); + } + + template + static inline void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + internal::outer_product_selector_run(dst, lhs, rhs, adds(alpha), is_row_major()); + } + +}; + + +// This base class provides default implementations for evalTo, addTo, subTo, in terms of scaleAndAddTo +template +struct generic_product_impl_base +{ + typedef typename Product::Scalar Scalar; + + template + static void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { dst.setZero(); scaleAndAddTo(dst, lhs, rhs, Scalar(1)); } + + template + static void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { scaleAndAddTo(dst,lhs, rhs, Scalar(1)); } + + template + static void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { scaleAndAddTo(dst, lhs, rhs, Scalar(-1)); } + + template + static void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { Derived::scaleAndAddTo(dst,lhs,rhs,alpha); } + +}; + +template +struct generic_product_impl + : generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight }; + typedef typename internal::conditional::type MatrixType; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + internal::gemv_dense_selector::HasUsableDirectAccess) + >::run(lhs, rhs, dst, alpha); + } +}; + +template +struct generic_product_impl +{ + typedef typename Product::Scalar Scalar; + + template + static inline void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + // Same as: dst.noalias() = lhs.lazyProduct(rhs); + // but easier on the compiler side + call_assignment_no_alias(dst, lhs.lazyProduct(rhs), internal::assign_op()); + } + + template + static inline void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + // dst.noalias() += lhs.lazyProduct(rhs); + call_assignment_no_alias(dst, lhs.lazyProduct(rhs), internal::add_assign_op()); + } + + template + static inline void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + // dst.noalias() -= lhs.lazyProduct(rhs); + call_assignment_no_alias(dst, lhs.lazyProduct(rhs), internal::sub_assign_op()); + } + +// template +// static inline void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) +// { dst.noalias() += alpha * lhs.lazyProduct(rhs); } +}; + +// This specialization enforces the use of a coefficient-based evaluation strategy +template +struct generic_product_impl + : generic_product_impl {}; + +// Case 2: Evaluate coeff by coeff +// +// This is mostly taken from CoeffBasedProduct.h +// The main difference is that we add an extra argument to the etor_product_*_impl::run() function +// for the inner dimension of the product, because evaluator object do not know their size. + +template +struct etor_product_coeff_impl; + +template +struct etor_product_packet_impl; + +template +struct product_evaluator, ProductTag, DenseShape, DenseShape> + : evaluator_base > +{ + typedef Product XprType; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename XprType::PacketScalar PacketScalar; + typedef typename XprType::PacketReturnType PacketReturnType; + + EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr) + : m_lhs(xpr.lhs()), + m_rhs(xpr.rhs()), + m_lhsImpl(m_lhs), // FIXME the creation of the evaluator objects should result in a no-op, but check that! + m_rhsImpl(m_rhs), // Moreover, they are only useful for the packet path, so we could completely disable them when not needed, + // or perhaps declare them on the fly on the packet method... We have experiment to check what's best. + m_innerDim(xpr.lhs().cols()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits::MulCost); + EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits::AddCost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + // Everything below here is taken from CoeffBasedProduct.h + + typedef typename internal::nested_eval::type LhsNested; + typedef typename internal::nested_eval::type RhsNested; + + typedef typename internal::remove_all::type LhsNestedCleaned; + typedef typename internal::remove_all::type RhsNestedCleaned; + + typedef evaluator LhsEtorType; + typedef evaluator RhsEtorType; + + enum { + RowsAtCompileTime = LhsNestedCleaned::RowsAtCompileTime, + ColsAtCompileTime = RhsNestedCleaned::ColsAtCompileTime, + InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(LhsNestedCleaned::ColsAtCompileTime, RhsNestedCleaned::RowsAtCompileTime), + MaxRowsAtCompileTime = LhsNestedCleaned::MaxRowsAtCompileTime, + MaxColsAtCompileTime = RhsNestedCleaned::MaxColsAtCompileTime, + + PacketSize = packet_traits::size, + + LhsCoeffReadCost = LhsEtorType::CoeffReadCost, + RhsCoeffReadCost = RhsEtorType::CoeffReadCost, + CoeffReadCost = InnerSize==0 ? NumTraits::ReadCost + : InnerSize == Dynamic ? HugeCost + : InnerSize * (NumTraits::MulCost + LhsCoeffReadCost + RhsCoeffReadCost) + + (InnerSize - 1) * NumTraits::AddCost, + + Unroll = CoeffReadCost <= EIGEN_UNROLLING_LIMIT, + + LhsFlags = LhsEtorType::Flags, + RhsFlags = RhsEtorType::Flags, + + LhsAlignment = LhsEtorType::Alignment, + RhsAlignment = RhsEtorType::Alignment, + + LhsRowMajor = LhsFlags & RowMajorBit, + RhsRowMajor = RhsFlags & RowMajorBit, + + SameType = is_same::value, + + CanVectorizeRhs = RhsRowMajor && (RhsFlags & PacketAccessBit) + && (ColsAtCompileTime == Dynamic || ((ColsAtCompileTime % PacketSize) == 0) ), + + CanVectorizeLhs = (!LhsRowMajor) && (LhsFlags & PacketAccessBit) + && (RowsAtCompileTime == Dynamic || ((RowsAtCompileTime % PacketSize) == 0) ), + + EvalToRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 + : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 + : (RhsRowMajor && !CanVectorizeLhs), + + Flags = ((unsigned int)(LhsFlags | RhsFlags) & HereditaryBits & ~RowMajorBit) + | (EvalToRowMajor ? RowMajorBit : 0) + // TODO enable vectorization for mixed types + | (SameType && (CanVectorizeLhs || CanVectorizeRhs) ? PacketAccessBit : 0) + | (XprType::IsVectorAtCompileTime ? LinearAccessBit : 0), + + LhsOuterStrideBytes = int(LhsNestedCleaned::OuterStrideAtCompileTime) * int(sizeof(typename LhsNestedCleaned::Scalar)), + RhsOuterStrideBytes = int(RhsNestedCleaned::OuterStrideAtCompileTime) * int(sizeof(typename RhsNestedCleaned::Scalar)), + + Alignment = CanVectorizeLhs ? (LhsOuterStrideBytes<0 || (int(LhsOuterStrideBytes) % EIGEN_PLAIN_ENUM_MAX(1,LhsAlignment))!=0 ? 0 : LhsAlignment) + : CanVectorizeRhs ? (RhsOuterStrideBytes<0 || (int(RhsOuterStrideBytes) % EIGEN_PLAIN_ENUM_MAX(1,RhsAlignment))!=0 ? 0 : RhsAlignment) + : 0, + + /* CanVectorizeInner deserves special explanation. It does not affect the product flags. It is not used outside + * of Product. If the Product itself is not a packet-access expression, there is still a chance that the inner + * loop of the product might be vectorized. This is the meaning of CanVectorizeInner. Since it doesn't affect + * the Flags, it is safe to make this value depend on ActualPacketAccessBit, that doesn't affect the ABI. + */ + CanVectorizeInner = SameType + && LhsRowMajor + && (!RhsRowMajor) + && (LhsFlags & RhsFlags & ActualPacketAccessBit) + && (InnerSize % packet_traits::size == 0) + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CoeffReturnType coeff(Index row, Index col) const + { + return (m_lhs.row(row).transpose().cwiseProduct( m_rhs.col(col) )).sum(); + } + + /* Allow index-based non-packet access. It is impossible though to allow index-based packed access, + * which is why we don't set the LinearAccessBit. + * TODO: this seems possible when the result is a vector + */ + EIGEN_DEVICE_FUNC const CoeffReturnType coeff(Index index) const + { + const Index row = RowsAtCompileTime == 1 ? 0 : index; + const Index col = RowsAtCompileTime == 1 ? index : 0; + return (m_lhs.row(row).transpose().cwiseProduct( m_rhs.col(col) )).sum(); + } + + template + const PacketType packet(Index row, Index col) const + { + PacketType res; + typedef etor_product_packet_impl PacketImpl; + PacketImpl::run(row, col, m_lhsImpl, m_rhsImpl, m_innerDim, res); + return res; + } + + template + const PacketType packet(Index index) const + { + const Index row = RowsAtCompileTime == 1 ? 0 : index; + const Index col = RowsAtCompileTime == 1 ? index : 0; + return packet(row,col); + } + +protected: + const LhsNested m_lhs; + const RhsNested m_rhs; + + LhsEtorType m_lhsImpl; + RhsEtorType m_rhsImpl; + + // TODO: Get rid of m_innerDim if known at compile time + Index m_innerDim; +}; + +template +struct product_evaluator, LazyCoeffBasedProductMode, DenseShape, DenseShape> + : product_evaluator, CoeffBasedProductMode, DenseShape, DenseShape> +{ + typedef Product XprType; + typedef Product BaseProduct; + typedef product_evaluator Base; + enum { + Flags = Base::Flags | EvalBeforeNestingBit + }; + EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr) + : Base(BaseProduct(xpr.lhs(),xpr.rhs())) + {} +}; + +/**************************************** +*** Coeff based product, Packet path *** +****************************************/ + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet &res) + { + etor_product_packet_impl::run(row, col, lhs, rhs, innerDim, res); + res = pmadd(pset1(lhs.coeff(row, UnrollingIndex-1)), rhs.template packet(UnrollingIndex-1, col), res); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet &res) + { + etor_product_packet_impl::run(row, col, lhs, rhs, innerDim, res); + res = pmadd(lhs.template packet(row, UnrollingIndex-1), pset1(rhs.coeff(UnrollingIndex-1, col)), res); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index /*innerDim*/, Packet &res) + { + res = pmul(pset1(lhs.coeff(row, 0)),rhs.template packet(0, col)); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index /*innerDim*/, Packet &res) + { + res = pmul(lhs.template packet(row, 0), pset1(rhs.coeff(0, col))); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Index /*innerDim*/, Packet &res) + { + res = pset1(0); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Index /*innerDim*/, Packet &res) + { + res = pset1(0); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet& res) + { + res = pset1(0); + for(Index i = 0; i < innerDim; ++i) + res = pmadd(pset1(lhs.coeff(row, i)), rhs.template packet(i, col), res); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet& res) + { + res = pset1(0); + for(Index i = 0; i < innerDim; ++i) + res = pmadd(lhs.template packet(row, i), pset1(rhs.coeff(i, col)), res); + } +}; + + +/*************************************************************************** +* Triangular products +***************************************************************************/ +template +struct triangular_product_impl; + +template +struct generic_product_impl + : generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + triangular_product_impl + ::run(dst, lhs.nestedExpression(), rhs, alpha); + } +}; + +template +struct generic_product_impl +: generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + triangular_product_impl::run(dst, lhs, rhs.nestedExpression(), alpha); + } +}; + + +/*************************************************************************** +* SelfAdjoint products +***************************************************************************/ +template +struct selfadjoint_product_impl; + +template +struct generic_product_impl + : generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + selfadjoint_product_impl::run(dst, lhs.nestedExpression(), rhs, alpha); + } +}; + +template +struct generic_product_impl +: generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + selfadjoint_product_impl::run(dst, lhs, rhs.nestedExpression(), alpha); + } +}; + + +/*************************************************************************** +* Diagonal products +***************************************************************************/ + +template +struct diagonal_product_evaluator_base + : evaluator_base +{ + typedef typename scalar_product_traits::ReturnType Scalar; +public: + enum { + CoeffReadCost = NumTraits::MulCost + evaluator::CoeffReadCost + evaluator::CoeffReadCost, + + MatrixFlags = evaluator::Flags, + DiagFlags = evaluator::Flags, + _StorageOrder = MatrixFlags & RowMajorBit ? RowMajor : ColMajor, + _ScalarAccessOnDiag = !((int(_StorageOrder) == ColMajor && int(ProductOrder) == OnTheLeft) + ||(int(_StorageOrder) == RowMajor && int(ProductOrder) == OnTheRight)), + _SameTypes = is_same::value, + // FIXME currently we need same types, but in the future the next rule should be the one + //_Vectorizable = bool(int(MatrixFlags)&PacketAccessBit) && ((!_PacketOnDiag) || (_SameTypes && bool(int(DiagFlags)&PacketAccessBit))), + _Vectorizable = bool(int(MatrixFlags)&PacketAccessBit) && _SameTypes && (_ScalarAccessOnDiag || (bool(int(DiagFlags)&PacketAccessBit))), + _LinearAccessMask = (MatrixType::RowsAtCompileTime==1 || MatrixType::ColsAtCompileTime==1) ? LinearAccessBit : 0, + Flags = ((HereditaryBits|_LinearAccessMask) & (unsigned int)(MatrixFlags)) | (_Vectorizable ? PacketAccessBit : 0), + Alignment = evaluator::Alignment + }; + + diagonal_product_evaluator_base(const MatrixType &mat, const DiagonalType &diag) + : m_diagImpl(diag), m_matImpl(mat) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits::MulCost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index idx) const + { + return m_diagImpl.coeff(idx) * m_matImpl.coeff(idx); + } + +protected: + template + EIGEN_STRONG_INLINE PacketType packet_impl(Index row, Index col, Index id, internal::true_type) const + { + return internal::pmul(m_matImpl.template packet(row, col), + internal::pset1(m_diagImpl.coeff(id))); + } + + template + EIGEN_STRONG_INLINE PacketType packet_impl(Index row, Index col, Index id, internal::false_type) const + { + enum { + InnerSize = (MatrixType::Flags & RowMajorBit) ? MatrixType::ColsAtCompileTime : MatrixType::RowsAtCompileTime, + DiagonalPacketLoadMode = EIGEN_PLAIN_ENUM_MIN(LoadMode,((InnerSize%16) == 0) ? int(Aligned16) : int(evaluator::Alignment)) // FIXME hardcoded 16!! + }; + return internal::pmul(m_matImpl.template packet(row, col), + m_diagImpl.template packet(id)); + } + + evaluator m_diagImpl; + evaluator m_matImpl; +}; + +// diagonal * dense +template +struct product_evaluator, ProductTag, DiagonalShape, DenseShape> + : diagonal_product_evaluator_base, OnTheLeft> +{ + typedef diagonal_product_evaluator_base, OnTheLeft> Base; + using Base::m_diagImpl; + using Base::m_matImpl; + using Base::coeff; + typedef typename Base::Scalar Scalar; + + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + + enum { + StorageOrder = int(Rhs::Flags) & RowMajorBit ? RowMajor : ColMajor + }; + + EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr) + : Base(xpr.rhs(), xpr.lhs().diagonal()) + { + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const + { + return m_diagImpl.coeff(row) * m_matImpl.coeff(row, col); + } + +#ifndef __CUDACC__ + template + EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const + { + // FIXME: NVCC used to complain about the template keyword, but we have to check whether this is still the case. + // See also similar calls below. + return this->template packet_impl(row,col, row, + typename internal::conditional::type()); + } + + template + EIGEN_STRONG_INLINE PacketType packet(Index idx) const + { + return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); + } +#endif +}; + +// dense * diagonal +template +struct product_evaluator, ProductTag, DenseShape, DiagonalShape> + : diagonal_product_evaluator_base, OnTheRight> +{ + typedef diagonal_product_evaluator_base, OnTheRight> Base; + using Base::m_diagImpl; + using Base::m_matImpl; + using Base::coeff; + typedef typename Base::Scalar Scalar; + + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + + enum { StorageOrder = int(Lhs::Flags) & RowMajorBit ? RowMajor : ColMajor }; + + EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr) + : Base(xpr.lhs(), xpr.rhs().diagonal()) + { + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const + { + return m_matImpl.coeff(row, col) * m_diagImpl.coeff(col); + } + +#ifndef __CUDACC__ + template + EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const + { + return this->template packet_impl(row,col, col, + typename internal::conditional::type()); + } + + template + EIGEN_STRONG_INLINE PacketType packet(Index idx) const + { + return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); + } +#endif +}; + +/*************************************************************************** +* Products with permutation matrices +***************************************************************************/ + +/** \internal + * \class permutation_matrix_product + * Internal helper class implementing the product between a permutation matrix and a matrix. + * This class is specialized for DenseShape below and for SparseShape in SparseCore/SparsePermutation.h + */ +template +struct permutation_matrix_product; + +template +struct permutation_matrix_product +{ + typedef typename nested_eval::type MatrixType; + typedef typename remove_all::type MatrixTypeCleaned; + + template + static inline void run(Dest& dst, const PermutationType& perm, const ExpressionType& xpr) + { + MatrixType mat(xpr); + const Index n = Side==OnTheLeft ? mat.rows() : mat.cols(); + // FIXME we need an is_same for expression that is not sensitive to constness. For instance + // is_same_xpr, Block >::value should be true. + //if(is_same::value && extract_data(dst) == extract_data(mat)) + if(is_same_dense(dst, mat)) + { + // apply the permutation inplace + Matrix mask(perm.size()); + mask.fill(false); + Index r = 0; + while(r < perm.size()) + { + // search for the next seed + while(r=perm.size()) + break; + // we got one, let's follow it until we are back to the seed + Index k0 = r++; + Index kPrev = k0; + mask.coeffRef(k0) = true; + for(Index k=perm.indices().coeff(k0); k!=k0; k=perm.indices().coeff(k)) + { + Block(dst, k) + .swap(Block + (dst,((Side==OnTheLeft) ^ Transposed) ? k0 : kPrev)); + + mask.coeffRef(k) = true; + kPrev = k; + } + } + } + else + { + for(Index i = 0; i < n; ++i) + { + Block + (dst, ((Side==OnTheLeft) ^ Transposed) ? perm.indices().coeff(i) : i) + + = + + Block + (mat, ((Side==OnTheRight) ^ Transposed) ? perm.indices().coeff(i) : i); + } + } + } +}; + +template +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + permutation_matrix_product::run(dst, lhs, rhs); + } +}; + +template +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + permutation_matrix_product::run(dst, rhs, lhs); + } +}; + +template +struct generic_product_impl, Rhs, PermutationShape, MatrixShape, ProductTag> +{ + template + static void evalTo(Dest& dst, const Inverse& lhs, const Rhs& rhs) + { + permutation_matrix_product::run(dst, lhs.nestedExpression(), rhs); + } +}; + +template +struct generic_product_impl, MatrixShape, PermutationShape, ProductTag> +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Inverse& rhs) + { + permutation_matrix_product::run(dst, rhs.nestedExpression(), lhs); + } +}; + + +/*************************************************************************** +* Products with transpositions matrices +***************************************************************************/ + +// FIXME could we unify Transpositions and Permutation into a single "shape"?? + +/** \internal + * \class transposition_matrix_product + * Internal helper class implementing the product between a permutation matrix and a matrix. + */ +template +struct transposition_matrix_product +{ + typedef typename nested_eval::type MatrixType; + typedef typename remove_all::type MatrixTypeCleaned; + + template + static inline void run(Dest& dst, const TranspositionType& tr, const ExpressionType& xpr) + { + MatrixType mat(xpr); + typedef typename TranspositionType::StorageIndex StorageIndex; + const Index size = tr.size(); + StorageIndex j = 0; + + if(!(is_same::value && extract_data(dst) == extract_data(mat))) + dst = mat; + + for(Index k=(Transposed?size-1:0) ; Transposed?k>=0:k +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + transposition_matrix_product::run(dst, lhs, rhs); + } +}; + +template +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + transposition_matrix_product::run(dst, rhs, lhs); + } +}; + + +template +struct generic_product_impl, Rhs, TranspositionsShape, MatrixShape, ProductTag> +{ + template + static void evalTo(Dest& dst, const Transpose& lhs, const Rhs& rhs) + { + transposition_matrix_product::run(dst, lhs.nestedExpression(), rhs); + } +}; + +template +struct generic_product_impl, MatrixShape, TranspositionsShape, ProductTag> +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Transpose& rhs) + { + transposition_matrix_product::run(dst, rhs.nestedExpression(), lhs); + } +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_PRODUCT_EVALUATORS_H diff --git a/nuparu/include/Eigen/src/Core/Random.h b/nuparu/include/Eigen/src/Core/Random.h index 480fea40..02038e9e 100644 --- a/nuparu/include/Eigen/src/Core/Random.h +++ b/nuparu/include/Eigen/src/Core/Random.h @@ -28,12 +28,18 @@ struct functor_traits > /** \returns a random matrix expression * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this MatrixBase type. * + * \not_reentrant + * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, * it is redundant to pass \a rows and \a cols as arguments, so Random() should be used * instead. + * * * Example: \include MatrixBase_random_int_int.cpp * Output: \verbinclude MatrixBase_random_int_int.out @@ -41,22 +47,28 @@ struct functor_traits > * This expression has the "evaluate before nesting" flag so that it will be evaluated into * a temporary matrix whenever it is nested in a larger expression. This prevents unexpected * behavior with expressions involving random matrices. + * + * See DenseBase::NullaryExpr(Index, const CustomNullaryOp&) for an example using C++11 random generators. * - * \sa MatrixBase::setRandom(), MatrixBase::Random(Index), MatrixBase::Random() + * \sa DenseBase::setRandom(), DenseBase::Random(Index), DenseBase::Random() */ template -inline const CwiseNullaryOp::Scalar>, Derived> +inline const typename DenseBase::RandomReturnType DenseBase::Random(Index rows, Index cols) { return NullaryExpr(rows, cols, internal::scalar_random_op()); } /** \returns a random vector expression + * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. * * The parameter \a size is the size of the returned vector. * Must be compatible with this MatrixBase type. * * \only_for_vectors + * \not_reentrant * * This variant is meant to be used for dynamic-size vector types. For fixed-size types, * it is redundant to pass \a size as argument, so Random() should be used @@ -69,10 +81,10 @@ DenseBase::Random(Index rows, Index cols) * a temporary vector whenever it is nested in a larger expression. This prevents unexpected * behavior with expressions involving random matrices. * - * \sa MatrixBase::setRandom(), MatrixBase::Random(Index,Index), MatrixBase::Random() + * \sa DenseBase::setRandom(), DenseBase::Random(Index,Index), DenseBase::Random() */ template -inline const CwiseNullaryOp::Scalar>, Derived> +inline const typename DenseBase::RandomReturnType DenseBase::Random(Index size) { return NullaryExpr(size, internal::scalar_random_op()); @@ -80,6 +92,9 @@ DenseBase::Random(Index size) /** \returns a fixed-size random matrix or vector expression * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you * need to use the variants taking size arguments. * @@ -89,11 +104,13 @@ DenseBase::Random(Index size) * This expression has the "evaluate before nesting" flag so that it will be evaluated into * a temporary matrix whenever it is nested in a larger expression. This prevents unexpected * behavior with expressions involving random matrices. + * + * \not_reentrant * - * \sa MatrixBase::setRandom(), MatrixBase::Random(Index,Index), MatrixBase::Random(Index) + * \sa DenseBase::setRandom(), DenseBase::Random(Index,Index), DenseBase::Random(Index) */ template -inline const CwiseNullaryOp::Scalar>, Derived> +inline const typename DenseBase::RandomReturnType DenseBase::Random() { return NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_random_op()); @@ -101,6 +118,11 @@ DenseBase::Random() /** Sets all coefficients in this expression to random values. * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * + * \not_reentrant + * * Example: \include MatrixBase_setRandom.cpp * Output: \verbinclude MatrixBase_setRandom.out * @@ -114,12 +136,16 @@ inline Derived& DenseBase::setRandom() /** Resizes to the given \a newSize, and sets all coefficients in this expression to random values. * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * * \only_for_vectors + * \not_reentrant * * Example: \include Matrix_setRandom_int.cpp * Output: \verbinclude Matrix_setRandom_int.out * - * \sa MatrixBase::setRandom(), setRandom(Index,Index), class CwiseNullaryOp, MatrixBase::Random() + * \sa DenseBase::setRandom(), setRandom(Index,Index), class CwiseNullaryOp, DenseBase::Random() */ template EIGEN_STRONG_INLINE Derived& @@ -131,19 +157,24 @@ PlainObjectBase::setRandom(Index newSize) /** Resizes to the given size, and sets all coefficients in this expression to random values. * - * \param nbRows the new number of rows - * \param nbCols the new number of columns + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * + * \not_reentrant + * + * \param rows the new number of rows + * \param cols the new number of columns * * Example: \include Matrix_setRandom_int_int.cpp * Output: \verbinclude Matrix_setRandom_int_int.out * - * \sa MatrixBase::setRandom(), setRandom(Index), class CwiseNullaryOp, MatrixBase::Random() + * \sa DenseBase::setRandom(), setRandom(Index), class CwiseNullaryOp, DenseBase::Random() */ template EIGEN_STRONG_INLINE Derived& -PlainObjectBase::setRandom(Index nbRows, Index nbCols) +PlainObjectBase::setRandom(Index rows, Index cols) { - resize(nbRows, nbCols); + resize(rows, cols); return setRandom(); } diff --git a/nuparu/include/Eigen/src/Core/Redux.h b/nuparu/include/Eigen/src/Core/Redux.h index 50548fa9..d170cae2 100644 --- a/nuparu/include/Eigen/src/Core/Redux.h +++ b/nuparu/include/Eigen/src/Core/Redux.h @@ -50,21 +50,34 @@ struct redux_traits public: enum { - Cost = ( Derived::SizeAtCompileTime == Dynamic - || Derived::CoeffReadCost == Dynamic - || (Derived::SizeAtCompileTime!=1 && functor_traits::Cost == Dynamic) - ) ? Dynamic - : Derived::SizeAtCompileTime * Derived::CoeffReadCost - + (Derived::SizeAtCompileTime-1) * functor_traits::Cost, + Cost = Derived::SizeAtCompileTime == Dynamic ? HugeCost + : Derived::SizeAtCompileTime * Derived::CoeffReadCost + (Derived::SizeAtCompileTime-1) * functor_traits::Cost, UnrollingLimit = EIGEN_UNROLLING_LIMIT * (int(Traversal) == int(DefaultTraversal) ? 1 : int(PacketSize)) }; public: enum { - Unrolling = Cost != Dynamic && Cost <= UnrollingLimit - ? CompleteUnrolling - : NoUnrolling + Unrolling = Cost <= UnrollingLimit ? CompleteUnrolling : NoUnrolling }; + +#ifdef EIGEN_DEBUG_ASSIGN + static void debug() + { + std::cerr << "Xpr: " << typeid(typename Derived::XprType).name() << std::endl; + std::cerr.setf(std::ios::hex, std::ios::basefield); + EIGEN_DEBUG_VAR(Derived::Flags) + std::cerr.unsetf(std::ios::hex); + EIGEN_DEBUG_VAR(InnerMaxSize) + EIGEN_DEBUG_VAR(PacketSize) + EIGEN_DEBUG_VAR(MightVectorize) + EIGEN_DEBUG_VAR(MayLinearVectorize) + EIGEN_DEBUG_VAR(MaySliceVectorize) + EIGEN_DEBUG_VAR(Traversal) + EIGEN_DEBUG_VAR(UnrollingLimit) + EIGEN_DEBUG_VAR(Unrolling) + std::cerr << std::endl; + } +#endif }; /*************************************************************************** @@ -82,6 +95,7 @@ struct redux_novec_unroller typedef typename Derived::Scalar Scalar; + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func& func) { return func(redux_novec_unroller::run(mat,func), @@ -99,6 +113,7 @@ struct redux_novec_unroller typedef typename Derived::Scalar Scalar; + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func&) { return mat.coeffByOuterInner(outer, inner); @@ -112,6 +127,7 @@ template struct redux_novec_unroller { typedef typename Derived::Scalar Scalar; + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Scalar run(const Derived&, const Func&) { return Scalar(); } }; @@ -143,7 +159,7 @@ struct redux_vec_unroller index = Start * packet_traits::size, outer = index / int(Derived::InnerSizeAtCompileTime), inner = index % int(Derived::InnerSizeAtCompileTime), - alignment = (Derived::Flags & AlignedBit) ? Aligned : Unaligned + alignment = Derived::Alignment }; typedef typename Derived::Scalar Scalar; @@ -151,7 +167,7 @@ struct redux_vec_unroller static EIGEN_STRONG_INLINE PacketScalar run(const Derived &mat, const Func&) { - return mat.template packetByOuterInner(outer, inner); + return mat.template packetByOuterInner(outer, inner); } }; @@ -169,8 +185,8 @@ template struct redux_impl { typedef typename Derived::Scalar Scalar; - typedef typename Derived::Index Index; - static EIGEN_STRONG_INLINE Scalar run(const Derived& mat, const Func& func) + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func& func) { eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); Scalar res; @@ -194,18 +210,18 @@ struct redux_impl { typedef typename Derived::Scalar Scalar; typedef typename packet_traits::type PacketScalar; - typedef typename Derived::Index Index; - static Scalar run(const Derived& mat, const Func& func) + static Scalar run(const Derived &mat, const Func& func) { const Index size = mat.size(); - eigen_assert(size && "you are using an empty matrix"); + const Index packetSize = packet_traits::size; - const Index alignedStart = internal::first_aligned(mat); + const int packetAlignment = unpacket_traits::alignment; enum { - alignment = bool(Derived::Flags & DirectAccessBit) || bool(Derived::Flags & AlignedBit) - ? Aligned : Unaligned + alignment0 = (bool(Derived::Flags & DirectAccessBit) && bool(packet_traits::AlignedOnScalar)) ? int(packetAlignment) : int(Unaligned), + alignment = EIGEN_PLAIN_ENUM_MAX(alignment0, Derived::Alignment) }; + const Index alignedStart = internal::first_default_aligned(mat.nestedExpression()); const Index alignedSize2 = ((size-alignedStart)/(2*packetSize))*(2*packetSize); const Index alignedSize = ((size-alignedStart)/(packetSize))*(packetSize); const Index alignedEnd2 = alignedStart + alignedSize2; @@ -213,19 +229,19 @@ struct redux_impl Scalar res; if(alignedSize) { - PacketScalar packet_res0 = mat.template packet(alignedStart); + PacketScalar packet_res0 = mat.template packet(alignedStart); if(alignedSize>packetSize) // we have at least two packets to partly unroll the loop { - PacketScalar packet_res1 = mat.template packet(alignedStart+packetSize); + PacketScalar packet_res1 = mat.template packet(alignedStart+packetSize); for(Index index = alignedStart + 2*packetSize; index < alignedEnd2; index += 2*packetSize) { - packet_res0 = func.packetOp(packet_res0, mat.template packet(index)); - packet_res1 = func.packetOp(packet_res1, mat.template packet(index+packetSize)); + packet_res0 = func.packetOp(packet_res0, mat.template packet(index)); + packet_res1 = func.packetOp(packet_res1, mat.template packet(index+packetSize)); } packet_res0 = func.packetOp(packet_res0,packet_res1); if(alignedEnd>alignedEnd2) - packet_res0 = func.packetOp(packet_res0, mat.template packet(alignedEnd2)); + packet_res0 = func.packetOp(packet_res0, mat.template packet(alignedEnd2)); } res = func.predux(packet_res0); @@ -247,14 +263,14 @@ struct redux_impl } }; -template -struct redux_impl +// NOTE: for SliceVectorizedTraversal we simply bypass unrolling +template +struct redux_impl { typedef typename Derived::Scalar Scalar; - typedef typename packet_traits::type PacketScalar; - typedef typename Derived::Index Index; + typedef typename packet_traits::type PacketType; - static Scalar run(const Derived& mat, const Func& func) + EIGEN_DEVICE_FUNC static Scalar run(const Derived &mat, const Func& func) { eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); const Index innerSize = mat.innerSize(); @@ -266,10 +282,10 @@ struct redux_impl Scalar res; if(packetedInnerSize) { - PacketScalar packet_res = mat.template packet(0,0); + PacketType packet_res = mat.template packet(0,0); for(Index j=0; j(j,i)); + packet_res = func.packetOp(packet_res, mat.template packetByOuterInner(j,i)); res = func.predux(packet_res); for(Index j=0; j Size = Derived::SizeAtCompileTime, VectorizedSize = (Size / PacketSize) * PacketSize }; - static EIGEN_STRONG_INLINE Scalar run(const Derived& mat, const Func& func) + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func& func) { eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); - Scalar res = func.predux(redux_vec_unroller::run(mat,func)); - if (VectorizedSize != Size) - res = func(res,redux_novec_unroller::run(mat,func)); - return res; + if (VectorizedSize > 0) { + Scalar res = func.predux(redux_vec_unroller::run(mat,func)); + if (VectorizedSize != Size) + res = func(res,redux_novec_unroller::run(mat,func)); + return res; + } + else { + return redux_novec_unroller::run(mat,func); + } } }; +// evaluator adaptor +template +class redux_evaluator +{ +public: + typedef _XprType XprType; + EIGEN_DEVICE_FUNC explicit redux_evaluator(const XprType &xpr) : m_evaluator(xpr), m_xpr(xpr) {} + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename XprType::PacketScalar PacketScalar; + typedef typename XprType::PacketReturnType PacketReturnType; + + enum { + MaxRowsAtCompileTime = XprType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = XprType::MaxColsAtCompileTime, + // TODO we should not remove DirectAccessBit and rather find an elegant way to query the alignment offset at runtime from the evaluator + Flags = evaluator::Flags & ~DirectAccessBit, + IsRowMajor = XprType::IsRowMajor, + SizeAtCompileTime = XprType::SizeAtCompileTime, + InnerSizeAtCompileTime = XprType::InnerSizeAtCompileTime, + CoeffReadCost = evaluator::CoeffReadCost, + Alignment = evaluator::Alignment + }; + + EIGEN_DEVICE_FUNC Index rows() const { return m_xpr.rows(); } + EIGEN_DEVICE_FUNC Index cols() const { return m_xpr.cols(); } + EIGEN_DEVICE_FUNC Index size() const { return m_xpr.size(); } + EIGEN_DEVICE_FUNC Index innerSize() const { return m_xpr.innerSize(); } + EIGEN_DEVICE_FUNC Index outerSize() const { return m_xpr.outerSize(); } + + EIGEN_DEVICE_FUNC + CoeffReturnType coeff(Index row, Index col) const + { return m_evaluator.coeff(row, col); } + + EIGEN_DEVICE_FUNC + CoeffReturnType coeff(Index index) const + { return m_evaluator.coeff(index); } + + template + PacketReturnType packet(Index row, Index col) const + { return m_evaluator.template packet(row, col); } + + template + PacketReturnType packet(Index index) const + { return m_evaluator.template packet(index); } + + EIGEN_DEVICE_FUNC + CoeffReturnType coeffByOuterInner(Index outer, Index inner) const + { return m_evaluator.coeff(IsRowMajor ? outer : inner, IsRowMajor ? inner : outer); } + + template + PacketReturnType packetByOuterInner(Index outer, Index inner) const + { return m_evaluator.template packet(IsRowMajor ? outer : inner, IsRowMajor ? inner : outer); } + + const XprType & nestedExpression() const { return m_xpr; } + +protected: + internal::evaluator m_evaluator; + const XprType &m_xpr; +}; + } // end namespace internal /*************************************************************************** @@ -316,18 +399,21 @@ struct redux_impl /** \returns the result of a full redux operation on the whole matrix or vector using \a func * * The template parameter \a BinaryOp is the type of the functor \a func which must be - * an associative operator. Both current STL and TR1 functor styles are handled. + * an associative operator. Both current C++98 and C++11 functor styles are handled. * * \sa DenseBase::sum(), DenseBase::minCoeff(), DenseBase::maxCoeff(), MatrixBase::colwise(), MatrixBase::rowwise() */ template template -EIGEN_STRONG_INLINE typename internal::result_of::Scalar)>::type +typename internal::traits::Scalar DenseBase::redux(const Func& func) const { - typedef typename internal::remove_all::type ThisNested; - return internal::redux_impl - ::run(derived(), func); + eigen_assert(this->rows()>0 && this->cols()>0 && "you are using an empty matrix"); + + typedef typename internal::redux_evaluator ThisEvaluator; + ThisEvaluator thisEval(derived()); + + return internal::redux_impl::run(thisEval, func); } /** \returns the minimum of all coefficients of \c *this. @@ -337,7 +423,7 @@ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::minCoeff() const { - return this->redux(Eigen::internal::scalar_min_op()); + return derived().redux(Eigen::internal::scalar_min_op()); } /** \returns the maximum of all coefficients of \c *this. @@ -347,7 +433,7 @@ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::maxCoeff() const { - return this->redux(Eigen::internal::scalar_max_op()); + return derived().redux(Eigen::internal::scalar_max_op()); } /** \returns the sum of all coefficients of *this @@ -360,7 +446,7 @@ DenseBase::sum() const { if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0)) return Scalar(0); - return this->redux(Eigen::internal::scalar_sum_op()); + return derived().redux(Eigen::internal::scalar_sum_op()); } /** \returns the mean of all coefficients of *this @@ -371,7 +457,7 @@ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::mean() const { - return Scalar(this->redux(Eigen::internal::scalar_sum_op())) / Scalar(this->size()); + return Scalar(derived().redux(Eigen::internal::scalar_sum_op())) / Scalar(this->size()); } /** \returns the product of all coefficients of *this @@ -387,7 +473,7 @@ DenseBase::prod() const { if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0)) return Scalar(1); - return this->redux(Eigen::internal::scalar_product_op()); + return derived().redux(Eigen::internal::scalar_product_op()); } /** \returns the trace of \c *this, i.e. the sum of the coefficients on the main diagonal. diff --git a/nuparu/include/Eigen/src/Core/Ref.h b/nuparu/include/Eigen/src/Core/Ref.h index aba795bd..61de5ed1 100644 --- a/nuparu/include/Eigen/src/Core/Ref.h +++ b/nuparu/include/Eigen/src/Core/Ref.h @@ -12,24 +12,20 @@ namespace Eigen { -template class RefBase; -template,OuterStride<> >::type > class Ref; - /** \class Ref * \ingroup Core_Module * - * \brief A matrix or vector expression mapping an existing expressions + * \brief A matrix or vector expression mapping an existing expression * * \tparam PlainObjectType the equivalent matrix type of the mapped data - * \tparam Options specifies whether the pointer is \c #Aligned, or \c #Unaligned. + * \tparam MapOptions specifies the pointer alignment in bytes. It can be: \c #Aligned128, , \c #Aligned64, \c #Aligned32, \c #Aligned16, \c #Aligned8 or \c #Unaligned. * The default is \c #Unaligned. * \tparam StrideType optionally specifies strides. By default, Ref implies a contiguous storage along the inner dimension (inner stride==1), - * but accept a variable outer stride (leading dimension). + * but accepts a variable outer stride (leading dimension). * This can be overridden by specifying strides. * The type passed here must be a specialization of the Stride template, see examples below. * - * This class permits to write non template functions taking Eigen's object as parameters while limiting the number of copies. + * This class provides a way to write non-template functions taking Eigen objects as parameters while limiting the number of copies. * A Ref<> object can represent either a const expression or a l-value: * \code * // in-out argument: @@ -39,10 +35,10 @@ template& x); * \endcode * - * In the in-out case, the input argument must satisfies the constraints of the actual Ref<> type, otherwise a compilation issue will be triggered. + * In the in-out case, the input argument must satisfy the constraints of the actual Ref<> type, otherwise a compilation issue will be triggered. * By default, a Ref can reference any dense vector expression of float having a contiguous memory layout. - * Likewise, a Ref can reference any column major dense matrix expression of float whose column's elements are contiguously stored with - * the possibility to have a constant space inbetween each column, i.e.: the inner stride mmust be equal to 1, but the outer-stride (or leading dimension), + * Likewise, a Ref can reference any column-major dense matrix expression of float whose column's elements are contiguously stored with + * the possibility to have a constant space in-between each column, i.e. the inner stride must be equal to 1, but the outer stride (or leading dimension) * can be greater than the number of rows. * * In the const case, if the input expression does not match the above requirement, then it is evaluated into a temporary before being passed to the function. @@ -52,21 +48,22 @@ template > x); * foo3(A.row()); // OK * \endcode - * The downside here is that the function foo3 might be significantly slower than foo1 because it won't be able to exploit vectorization, and will involved more - * expensive address computations even if the input is contiguously stored in memory. To overcome this issue, one might propose to overloads internally calling a + * The downside here is that the function foo3 might be significantly slower than foo1 because it won't be able to exploit vectorization, and will involve more + * expensive address computations even if the input is contiguously stored in memory. To overcome this issue, one might propose to overload internally calling a * template function, e.g.: * \code * // in the .h: @@ -94,24 +91,27 @@ struct traits > typedef _PlainObjectType PlainObjectType; typedef _StrideType StrideType; enum { - Options = _Options + Options = _Options, + Flags = traits >::Flags | NestByRefBit, + Alignment = traits >::Alignment }; template struct match { enum { HasDirectAccess = internal::has_direct_access::ret, - StorageOrderMatch = PlainObjectType::IsVectorAtCompileTime || ((PlainObjectType::Flags&RowMajorBit)==(Derived::Flags&RowMajorBit)), + StorageOrderMatch = PlainObjectType::IsVectorAtCompileTime || Derived::IsVectorAtCompileTime || ((PlainObjectType::Flags&RowMajorBit)==(Derived::Flags&RowMajorBit)), InnerStrideMatch = int(StrideType::InnerStrideAtCompileTime)==int(Dynamic) || int(StrideType::InnerStrideAtCompileTime)==int(Derived::InnerStrideAtCompileTime) || (int(StrideType::InnerStrideAtCompileTime)==0 && int(Derived::InnerStrideAtCompileTime)==1), OuterStrideMatch = Derived::IsVectorAtCompileTime || int(StrideType::OuterStrideAtCompileTime)==int(Dynamic) || int(StrideType::OuterStrideAtCompileTime)==int(Derived::OuterStrideAtCompileTime), - AlignmentMatch = (_Options!=Aligned) || ((PlainObjectType::Flags&AlignedBit)==0) || ((traits::Flags&AlignedBit)==AlignedBit), - MatchAtCompileTime = HasDirectAccess && StorageOrderMatch && InnerStrideMatch && OuterStrideMatch && AlignmentMatch + AlignmentMatch = (int(traits::Alignment)==int(Unaligned)) || (int(evaluator::Alignment) >= int(Alignment)), // FIXME the first condition is not very clear, it should be replaced by the required alignment + ScalarTypeMatch = internal::is_same::value, + MatchAtCompileTime = HasDirectAccess && StorageOrderMatch && InnerStrideMatch && OuterStrideMatch && AlignmentMatch && ScalarTypeMatch }; typedef typename internal::conditional::type type; }; - + }; template @@ -130,12 +130,12 @@ template class RefBase typedef MapBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(RefBase) - inline Index innerStride() const + EIGEN_DEVICE_FUNC inline Index innerStride() const { return StrideType::InnerStrideAtCompileTime != 0 ? m_stride.inner() : 1; } - inline Index outerStride() const + EIGEN_DEVICE_FUNC inline Index outerStride() const { return StrideType::OuterStrideAtCompileTime != 0 ? m_stride.outer() : IsVectorAtCompileTime ? this->size() @@ -143,7 +143,7 @@ template class RefBase : this->rows(); } - RefBase() + EIGEN_DEVICE_FUNC RefBase() : Base(0,RowsAtCompileTime==Dynamic?0:RowsAtCompileTime,ColsAtCompileTime==Dynamic?0:ColsAtCompileTime), // Stride<> does not allow default ctor for Dynamic strides, so let' initialize it with dummy values: m_stride(StrideType::OuterStrideAtCompileTime==Dynamic?0:StrideType::OuterStrideAtCompileTime, @@ -157,7 +157,7 @@ template class RefBase typedef Stride StrideBase; template - void construct(Expression& expr) + EIGEN_DEVICE_FUNC void construct(Expression& expr) { if(PlainObjectType::RowsAtCompileTime==1) { @@ -171,8 +171,12 @@ template class RefBase } else ::new (static_cast(this)) Base(expr.data(), expr.rows(), expr.cols()); - ::new (&m_stride) StrideBase(StrideType::OuterStrideAtCompileTime==0?0:expr.outerStride(), - StrideType::InnerStrideAtCompileTime==0?0:expr.innerStride()); + + if(Expression::IsVectorAtCompileTime && (!PlainObjectType::IsVectorAtCompileTime) && ((Expression::Flags&RowMajorBit)!=(PlainObjectType::Flags&RowMajorBit))) + ::new (&m_stride) StrideBase(expr.innerStride(), StrideType::InnerStrideAtCompileTime==0?0:1); + else + ::new (&m_stride) StrideBase(StrideType::OuterStrideAtCompileTime==0?0:expr.outerStride(), + StrideType::InnerStrideAtCompileTime==0?0:expr.innerStride()); } StrideBase m_stride; @@ -182,7 +186,11 @@ template class RefBase template class Ref : public RefBase > { + private: typedef internal::traits Traits; + template + EIGEN_DEVICE_FUNC inline Ref(const PlainObjectBase& expr, + typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0); public: typedef RefBase Base; @@ -191,20 +199,23 @@ template class Ref #ifndef EIGEN_PARSED_BY_DOXYGEN template - inline Ref(PlainObjectBase& expr, - typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) + EIGEN_DEVICE_FUNC inline Ref(PlainObjectBase& expr, + typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) { - Base::construct(expr); + EIGEN_STATIC_ASSERT(bool(Traits::template match::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); + Base::construct(expr.derived()); } template - inline Ref(const DenseBase& expr, - typename internal::enable_if::value&&bool(Traits::template match::MatchAtCompileTime)),Derived>::type* = 0, - int = Derived::ThisConstantIsPrivateInPlainObjectBase) + EIGEN_DEVICE_FUNC inline Ref(const DenseBase& expr, + typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) #else template inline Ref(DenseBase& expr) #endif { + EIGEN_STATIC_ASSERT(bool(internal::is_lvalue::value), THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); + EIGEN_STATIC_ASSERT(bool(Traits::template match::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); + EIGEN_STATIC_ASSERT(!Derived::IsPlainObjectBase,THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); Base::construct(expr.const_cast_derived()); } @@ -223,7 +234,8 @@ template class Ref< EIGEN_DENSE_PUBLIC_INTERFACE(Ref) template - inline Ref(const DenseBase& expr) + EIGEN_DEVICE_FUNC inline Ref(const DenseBase& expr, + typename internal::enable_if::ScalarTypeMatch),Derived>::type* = 0) { // std::cout << match_helper::HasDirectAccess << "," << match_helper::OuterStrideMatch << "," << match_helper::InnerStrideMatch << "\n"; // std::cout << int(StrideType::OuterStrideAtCompileTime) << " - " << int(Derived::OuterStrideAtCompileTime) << "\n"; @@ -231,18 +243,27 @@ template class Ref< construct(expr.derived(), typename Traits::template match::type()); } + EIGEN_DEVICE_FUNC inline Ref(const Ref& other) : Base(other) { + // copy constructor shall not copy the m_object, to avoid unnecessary malloc and copy + } + + template + EIGEN_DEVICE_FUNC inline Ref(const RefBase& other) { + construct(other.derived(), typename Traits::template match::type()); + } + protected: template - void construct(const Expression& expr,internal::true_type) + EIGEN_DEVICE_FUNC void construct(const Expression& expr,internal::true_type) { Base::construct(expr); } template - void construct(const Expression& expr, internal::false_type) + EIGEN_DEVICE_FUNC void construct(const Expression& expr, internal::false_type) { - m_object.lazyAssign(expr); + internal::call_assignment_no_alias(m_object,expr,internal::assign_op()); Base::construct(m_object); } diff --git a/nuparu/include/Eigen/src/Core/Replicate.h b/nuparu/include/Eigen/src/Core/Replicate.h index dde86a83..bec59831 100644 --- a/nuparu/include/Eigen/src/Core/Replicate.h +++ b/nuparu/include/Eigen/src/Core/Replicate.h @@ -35,10 +35,7 @@ struct traits > typedef typename MatrixType::Scalar Scalar; typedef typename traits::StorageKind StorageKind; typedef typename traits::XprKind XprKind; - enum { - Factor = (RowFactor==Dynamic || ColFactor==Dynamic) ? Dynamic : RowFactor*ColFactor - }; - typedef typename nested::type MatrixTypeNested; + typedef typename ref_selector::type MatrixTypeNested; typedef typename remove_reference::type _MatrixTypeNested; enum { RowsAtCompileTime = RowFactor==Dynamic || int(MatrixType::RowsAtCompileTime)==Dynamic @@ -53,8 +50,9 @@ struct traits > IsRowMajor = MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1 ? 1 : MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1 ? 0 : (MatrixType::Flags & RowMajorBit) ? 1 : 0, - Flags = (_MatrixTypeNested::Flags & HereditaryBits & ~RowMajorBit) | (IsRowMajor ? RowMajorBit : 0), - CoeffReadCost = _MatrixTypeNested::CoeffReadCost + + // FIXME enable DirectAccess with negative strides? + Flags = IsRowMajor ? RowMajorBit : 0 }; }; } @@ -68,10 +66,12 @@ template class Replicate typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Replicate) + typedef typename internal::remove_all::type NestedExpression; template - inline explicit Replicate(const OriginalMatrixType& a_matrix) - : m_matrix(a_matrix), m_rowFactor(RowFactor), m_colFactor(ColFactor) + EIGEN_DEVICE_FUNC + inline explicit Replicate(const OriginalMatrixType& matrix) + : m_matrix(matrix), m_rowFactor(RowFactor), m_colFactor(ColFactor) { EIGEN_STATIC_ASSERT((internal::is_same::type,OriginalMatrixType>::value), THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE) @@ -79,41 +79,20 @@ template class Replicate } template - inline Replicate(const OriginalMatrixType& a_matrix, Index rowFactor, Index colFactor) - : m_matrix(a_matrix), m_rowFactor(rowFactor), m_colFactor(colFactor) + EIGEN_DEVICE_FUNC + inline Replicate(const OriginalMatrixType& matrix, Index rowFactor, Index colFactor) + : m_matrix(matrix), m_rowFactor(rowFactor), m_colFactor(colFactor) { EIGEN_STATIC_ASSERT((internal::is_same::type,OriginalMatrixType>::value), THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE) } + EIGEN_DEVICE_FUNC inline Index rows() const { return m_matrix.rows() * m_rowFactor.value(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_matrix.cols() * m_colFactor.value(); } - inline Scalar coeff(Index rowId, Index colId) const - { - // try to avoid using modulo; this is a pure optimization strategy - const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 - : RowFactor==1 ? rowId - : rowId%m_matrix.rows(); - const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 - : ColFactor==1 ? colId - : colId%m_matrix.cols(); - - return m_matrix.coeff(actual_row, actual_col); - } - template - inline PacketScalar packet(Index rowId, Index colId) const - { - const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 - : RowFactor==1 ? rowId - : rowId%m_matrix.rows(); - const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 - : ColFactor==1 ? colId - : colId%m_matrix.cols(); - - return m_matrix.template packet(actual_row, actual_col); - } - + EIGEN_DEVICE_FUNC const _MatrixTypeNested& nestedExpression() const { return m_matrix; @@ -135,27 +114,12 @@ template class Replicate */ template template -inline const Replicate +const Replicate DenseBase::replicate() const { return Replicate(derived()); } -/** - * \return an expression of the replication of \c *this - * - * Example: \include MatrixBase_replicate_int_int.cpp - * Output: \verbinclude MatrixBase_replicate_int_int.out - * - * \sa VectorwiseOp::replicate(), DenseBase::replicate(), class Replicate - */ -template -inline const Replicate -DenseBase::replicate(Index rowFactor,Index colFactor) const -{ - return Replicate(derived(),rowFactor,colFactor); -} - /** * \return an expression of the replication of each column (or row) of \c *this * diff --git a/nuparu/include/Eigen/src/Core/ReturnByValue.h b/nuparu/include/Eigen/src/Core/ReturnByValue.h index d66c24ba..7feb6e01 100644 --- a/nuparu/include/Eigen/src/Core/ReturnByValue.h +++ b/nuparu/include/Eigen/src/Core/ReturnByValue.h @@ -38,9 +38,10 @@ struct traits > * So internal::nested always gives the plain return matrix type. * * FIXME: I don't understand why we need this specialization: isn't this taken care of by the EvalBeforeNestingBit ?? + * Answer: EvalBeforeNestingBit should be deprecated since we have the evaluators */ template -struct nested, n, PlainObject> +struct nested_eval, n, PlainObject> { typedef typename traits::ReturnType type; }; @@ -48,7 +49,7 @@ struct nested, n, PlainObject> } // end namespace internal template class ReturnByValue - : internal::no_assignment_operator, public internal::dense_xpr_base< ReturnByValue >::type + : public internal::dense_xpr_base< ReturnByValue >::type, internal::no_assignment_operator { public: typedef typename internal::traits::ReturnType ReturnType; @@ -57,10 +58,11 @@ template class ReturnByValue EIGEN_DENSE_PUBLIC_INTERFACE(ReturnByValue) template + EIGEN_DEVICE_FUNC inline void evalTo(Dest& dst) const { static_cast(this)->evalTo(dst); } - inline Index rows() const { return static_cast(this)->rows(); } - inline Index cols() const { return static_cast(this)->cols(); } + EIGEN_DEVICE_FUNC inline Index rows() const { return static_cast(this)->rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return static_cast(this)->cols(); } #ifndef EIGEN_PARSED_BY_DOXYGEN #define Unusable YOU_ARE_TRYING_TO_ACCESS_A_SINGLE_COEFFICIENT_IN_A_SPECIAL_EXPRESSION_WHERE_THAT_IS_NOT_ALLOWED_BECAUSE_THAT_WOULD_BE_INEFFICIENT @@ -72,6 +74,7 @@ template class ReturnByValue const Unusable& coeff(Index,Index) const { return *reinterpret_cast(this); } Unusable& coeffRef(Index) { return *reinterpret_cast(this); } Unusable& coeffRef(Index,Index) { return *reinterpret_cast(this); } +#undef Unusable #endif }; @@ -83,6 +86,33 @@ Derived& DenseBase::operator=(const ReturnByValue& other) return derived(); } +namespace internal { + +// Expression is evaluated in a temporary; default implementation of Assignment is bypassed so that +// when a ReturnByValue expression is assigned, the evaluator is not constructed. +// TODO: Finalize port to new regime; ReturnByValue should not exist in the expression world + +template +struct evaluator > + : public evaluator::ReturnType> +{ + typedef ReturnByValue XprType; + typedef typename internal::traits::ReturnType PlainObject; + typedef evaluator Base; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + xpr.evalTo(m_result); + } + +protected: + PlainObject m_result; +}; + +} // end namespace internal + } // end namespace Eigen #endif // EIGEN_RETURNBYVALUE_H diff --git a/nuparu/include/Eigen/src/Core/Reverse.h b/nuparu/include/Eigen/src/Core/Reverse.h index e30ae3d2..d7c380c7 100644 --- a/nuparu/include/Eigen/src/Core/Reverse.h +++ b/nuparu/include/Eigen/src/Core/Reverse.h @@ -37,32 +37,25 @@ struct traits > typedef typename MatrixType::Scalar Scalar; typedef typename traits::StorageKind StorageKind; typedef typename traits::XprKind XprKind; - typedef typename nested::type MatrixTypeNested; + typedef typename ref_selector::type MatrixTypeNested; typedef typename remove_reference::type _MatrixTypeNested; enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, - - // let's enable LinearAccess only with vectorization because of the product overhead - LinearAccess = ( (Direction==BothDirections) && (int(_MatrixTypeNested::Flags)&PacketAccessBit) ) - ? LinearAccessBit : 0, - - Flags = int(_MatrixTypeNested::Flags) & (HereditaryBits | LvalueBit | PacketAccessBit | LinearAccess), - - CoeffReadCost = _MatrixTypeNested::CoeffReadCost + Flags = _MatrixTypeNested::Flags & (RowMajorBit | LvalueBit) }; }; -template struct reverse_packet_cond +template struct reverse_packet_cond { - static inline PacketScalar run(const PacketScalar& x) { return preverse(x); } + static inline PacketType run(const PacketType& x) { return preverse(x); } }; -template struct reverse_packet_cond +template struct reverse_packet_cond { - static inline PacketScalar run(const PacketScalar& x) { return x; } + static inline PacketType run(const PacketType& x) { return x; } }; } // end namespace internal @@ -74,12 +67,9 @@ template class Reverse typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Reverse) + typedef typename internal::remove_all::type NestedExpression; using Base::IsRowMajor; - // next line is necessary because otherwise const version of operator() - // is hidden by non-const version defined in this file - using Base::operator(); - protected: enum { PacketSize = internal::packet_traits::size, @@ -95,82 +85,19 @@ template class Reverse typedef internal::reverse_packet_cond reverse_packet; public: - inline Reverse(const MatrixType& matrix) : m_matrix(matrix) { } + EIGEN_DEVICE_FUNC explicit inline Reverse(const MatrixType& matrix) : m_matrix(matrix) { } EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Reverse) - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } + EIGEN_DEVICE_FUNC inline Index rows() const { return m_matrix.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_matrix.cols(); } - inline Index innerStride() const + EIGEN_DEVICE_FUNC inline Index innerStride() const { return -m_matrix.innerStride(); } - inline Scalar& operator()(Index row, Index col) - { - eigen_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); - return coeffRef(row, col); - } - - inline Scalar& coeffRef(Index row, Index col) - { - return m_matrix.const_cast_derived().coeffRef(ReverseRow ? m_matrix.rows() - row - 1 : row, - ReverseCol ? m_matrix.cols() - col - 1 : col); - } - - inline CoeffReturnType coeff(Index row, Index col) const - { - return m_matrix.coeff(ReverseRow ? m_matrix.rows() - row - 1 : row, - ReverseCol ? m_matrix.cols() - col - 1 : col); - } - - inline CoeffReturnType coeff(Index index) const - { - return m_matrix.coeff(m_matrix.size() - index - 1); - } - - inline Scalar& coeffRef(Index index) - { - return m_matrix.const_cast_derived().coeffRef(m_matrix.size() - index - 1); - } - - inline Scalar& operator()(Index index) - { - eigen_assert(index >= 0 && index < m_matrix.size()); - return coeffRef(index); - } - - template - inline const PacketScalar packet(Index row, Index col) const - { - return reverse_packet::run(m_matrix.template packet( - ReverseRow ? m_matrix.rows() - row - OffsetRow : row, - ReverseCol ? m_matrix.cols() - col - OffsetCol : col)); - } - - template - inline void writePacket(Index row, Index col, const PacketScalar& x) - { - m_matrix.const_cast_derived().template writePacket( - ReverseRow ? m_matrix.rows() - row - OffsetRow : row, - ReverseCol ? m_matrix.cols() - col - OffsetCol : col, - reverse_packet::run(x)); - } - - template - inline const PacketScalar packet(Index index) const - { - return internal::preverse(m_matrix.template packet( m_matrix.size() - index - PacketSize )); - } - - template - inline void writePacket(Index index, const PacketScalar& x) - { - m_matrix.const_cast_derived().template writePacket(m_matrix.size() - index - PacketSize, internal::preverse(x)); - } - - const typename internal::remove_all::type& + EIGEN_DEVICE_FUNC const typename internal::remove_all::type& nestedExpression() const { return m_matrix; @@ -190,33 +117,93 @@ template inline typename DenseBase::ReverseReturnType DenseBase::reverse() { - return derived(); + return ReverseReturnType(derived()); } -/** This is the const version of reverse(). */ -template -inline const typename DenseBase::ConstReverseReturnType -DenseBase::reverse() const -{ - return derived(); -} + +//reverse const overload moved DenseBase.h due to a CUDA compiler bug /** This is the "in place" version of reverse: it reverses \c *this. * * In most cases it is probably better to simply use the reversed expression * of a matrix. However, when reversing the matrix data itself is really needed, * then this "in-place" version is probably the right choice because it provides - * the following additional features: + * the following additional benefits: * - less error prone: doing the same operation with .reverse() requires special care: * \code m = m.reverse().eval(); \endcode - * - this API allows to avoid creating a temporary (the current implementation creates a temporary, but that could be avoided using swap) + * - this API enables reverse operations without the need for a temporary * - it allows future optimizations (cache friendliness, etc.) * - * \sa reverse() */ + * \sa VectorwiseOp::reverseInPlace(), reverse() */ template inline void DenseBase::reverseInPlace() { - derived() = derived().reverse().eval(); + if(cols()>rows()) + { + Index half = cols()/2; + leftCols(half).swap(rightCols(half).reverse()); + if((cols()%2)==1) + { + Index half2 = rows()/2; + col(half).head(half2).swap(col(half).tail(half2).reverse()); + } + } + else + { + Index half = rows()/2; + topRows(half).swap(bottomRows(half).reverse()); + if((rows()%2)==1) + { + Index half2 = cols()/2; + row(half).head(half2).swap(row(half).tail(half2).reverse()); + } + } +} + +namespace internal { + +template +struct vectorwise_reverse_inplace_impl; + +template<> +struct vectorwise_reverse_inplace_impl +{ + template + static void run(ExpressionType &xpr) + { + Index half = xpr.rows()/2; + xpr.topRows(half).swap(xpr.bottomRows(half).colwise().reverse()); + } +}; + +template<> +struct vectorwise_reverse_inplace_impl +{ + template + static void run(ExpressionType &xpr) + { + Index half = xpr.cols()/2; + xpr.leftCols(half).swap(xpr.rightCols(half).rowwise().reverse()); + } +}; + +} // end namespace internal + +/** This is the "in place" version of VectorwiseOp::reverse: it reverses each column or row of \c *this. + * + * In most cases it is probably better to simply use the reversed expression + * of a matrix. However, when reversing the matrix data itself is really needed, + * then this "in-place" version is probably the right choice because it provides + * the following additional benefits: + * - less error prone: doing the same operation with .reverse() requires special care: + * \code m = m.reverse().eval(); \endcode + * - this API enables reverse operations without the need for a temporary + * + * \sa DenseBase::reverseInPlace(), reverse() */ +template +void VectorwiseOp::reverseInPlace() +{ + internal::vectorwise_reverse_inplace_impl::run(_expression().const_cast_derived()); } } // end namespace Eigen diff --git a/nuparu/include/Eigen/src/Core/Select.h b/nuparu/include/Eigen/src/Core/Select.h index 87993bbb..79eec1b5 100644 --- a/nuparu/include/Eigen/src/Core/Select.h +++ b/nuparu/include/Eigen/src/Core/Select.h @@ -43,23 +43,21 @@ struct traits > ColsAtCompileTime = ConditionMatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = ConditionMatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = ConditionMatrixType::MaxColsAtCompileTime, - Flags = (unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & HereditaryBits, - CoeffReadCost = traits::type>::CoeffReadCost - + EIGEN_SIZE_MAX(traits::type>::CoeffReadCost, - traits::type>::CoeffReadCost) + Flags = (unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & RowMajorBit }; }; } template -class Select : internal::no_assignment_operator, - public internal::dense_xpr_base< Select >::type +class Select : public internal::dense_xpr_base< Select >::type, + internal::no_assignment_operator { public: typedef typename internal::dense_xpr_base