Fix type-related issues in dependent code. Remove hardcoded mjUSEDOUBLE. Add mjUSESINGLE compiler flag.

This CL does not change the default build behavior of MuJoCo. To use single-precision floating-point, build MuJoCo with `-DmjUSESINGLE`.

PiperOrigin-RevId: 644782648
Change-Id: Ie815df9916798ca8054306437b39a33f84ce9e08
This commit is contained in:
Yuval Tassa
2024-06-19 10:51:17 -07:00
committed by Copybara-Service
parent 7bd7065e0e
commit 3f3b39bbb1
14 changed files with 62 additions and 44 deletions
+8
View File
@@ -534,6 +534,14 @@ shown in the table below. Their names are in the format ``mjKEY_XXX``. They corr
Macros
^^^^^^
.. _mjUSESINGLE:
mjUSESINGLE
~~~~~~~~~~~
Compile-time flag, see :ref:`mjtNum`.
.. _mjDISABLED:
mjDISABLED
+15 -11
View File
@@ -54,24 +54,28 @@ The two types below are defined in `mjtnum.h <https://github.com/google-deepmind
mjtNum
^^^^^^
This is the floating-point type used throughout the simulator. If the symbol ``mjUSEDOUBLE`` is defined in
``mjmodel.h``, this type is defined as ``double``, otherwise it is defined as ``float``. Currently only the
double-precision version of MuJoCo is distributed, although the entire code base works with single-precision as well.
We may release the single-precision version in the future for efficiency reasons, but the double-precision version
will always be available. Thus it is safe to write user code assuming double precision. However, our preference is to
write code that works with either single or double precision. To this end we provide math utility functions that are
always defined with the correct floating-point type.
This is the floating-point type used throughout the simulator. When using the default build configuration, ``mjtNum`` is
defined as ``double``. If the symbol ``mjUSESINGLE`` is defined, ``mjtNum`` is defined as ``float``.
Note that changing ``mjUSEDOUBLE`` in ``mjtnum.h`` will not change how the library was compiled, and instead will
Currently only the double-precision version of MuJoCo is distributed, although the entire code base works with
single-precision as well. We may release the single-precision version in the future, but the
double-precision version will always be available. Thus it is safe to write user code assuming double precision.
However, our preference is to write code that works with either single or double precision. To this end we provide math
utility functions that are always defined with the correct floating-point type.
Note that changing ``mjUSESINGLE`` in ``mjtnum.h`` will not change how the library was compiled, and instead will
result in numerous link errors. In general, the header files distributed with precompiled MuJoCo should never be
changed by the user.
.. code-block:: C
#ifdef mjUSEDOUBLE
typedef double mjtNum;
// floating point data type and minval
#ifndef mjUSESINGLE
typedef double mjtNum;
#define mjMINVAL 1E-15 // minimum value in any denominator
#else
typedef float mjtNum;
typedef float mjtNum;
#define mjMINVAL 1E-15f
#endif
+11 -5
View File
@@ -25,12 +25,18 @@ General
5. Added support for ``ball`` joints in the URDF parser ("spherical" in URDF).
6. Deprecated :ref:`mju_rotVecMat` and :ref:`mju_rotVecMatT` in favor of :ref:`mju_mulMatVec3` and
:ref:`mju_mulMatTVec3`. These functions names and argument ordering are more consistent with the rest of the API.
7. Replaced ``mjUSEDOUBLE`` which was previously hard-coded in
`mjtnum.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjtnum.h>`__
with the build-time flag ``mjUSESINGLE``. If this symbol is not defined, MuJoCo will use double-precision floating
point, as usual. If ``mjUSESINGLE`` is defined, MuJoCo will use single-precision floating point. See :ref:`mjtNum`.
Relatedly, fixed various type errors that prevented building with single-precision.
MJX
~~~
7. Added support for :ref:`elliptic friction cones<option-cone>`.
8. Fixed a bug that resulted in less-optimal linesearch solutions for some difficult constraint settings.
9. Fixed a bug in the Newton solver that sometimes resulted in less-optimal gradients.
8. Added support for :ref:`elliptic friction cones<option-cone>`.
9. Fixed a bug that resulted in less-optimal linesearch solutions for some difficult constraint settings.
10. Fixed a bug in the Newton solver that sometimes resulted in less-optimal gradients.
.. youtube:: P83tKA1iz2Y
@@ -39,8 +45,8 @@ MJX
Simulate
^^^^^^^^
10. Added improved tutorial video.
11. Improved the Brownian noise generator.
11. Added improved tutorial video.
12. Improved the Brownian noise generator.
|br| |br| |br| |br|
+1 -5
View File
@@ -17,12 +17,8 @@
//---------------------------------- floating-point definition -------------------------------------
// compile-time configuration options
#define mjUSEDOUBLE // single or double precision for mjtNum
// floating point data type and minval
#ifdef mjUSEDOUBLE
#ifndef mjUSESINGLE
typedef double mjtNum;
#define mjMINVAL 1E-15 // minimum value in any denominator
#else
+1 -1
View File
@@ -893,7 +893,7 @@ MJAPI int mjs_isWarning(mjSpec* s);
//---------------------------------- Standard math -------------------------------------------------
#ifdef mjUSEDOUBLE
#if !defined(mjUSESINGLE)
#define mju_sqrt sqrt
#define mju_exp exp
#define mju_sin sin
+12 -10
View File
@@ -34,18 +34,17 @@ mjData* d[maxthread];
// per-thread statistics
int contacts[maxthread];
int constraints[maxthread];
double simtime[maxthread];
mjtNum simtime[maxthread];
// timer
std::chrono::steady_clock::time_point tm_start;
mjtNum gettm(void) {
std::chrono::duration<double, std::micro> elapsed;
elapsed = std::chrono::steady_clock::now() - tm_start;
using std::chrono::steady_clock;
using Microseconds = std::chrono::duration<double, std::micro>;
static steady_clock::time_point tm_start = steady_clock::now();
auto elapsed = Microseconds(steady_clock::now() - tm_start);
return elapsed.count();
}
// deallocate and print message
int finish(const char* msg = NULL, mjModel* m = NULL) {
// deallocate model
@@ -87,7 +86,7 @@ void simulate(int id, int nstep, mjtNum* ctrl) {
constraints[id] = 0;
// run and time
double start = gettm();
mjtNum start = gettm();
for (int i=0; i < nstep; i++) {
// inject pseudo-random control noise
mju_copy(d[id]->ctrl, ctrl + i*m->nu, m->nu);
@@ -126,7 +125,7 @@ int main(int argc, char** argv) {
// read arguments
int nstep = 10000, nthread = 0, npoolthread = 0;
// inject small noise by default, to avoid fixed contact state
mjtNum ctrlnoise = 0.01;
double ctrlnoise = 0.01;
if (argc > 2 && (std::sscanf(argv[2], "%d", &nstep) != 1 || nstep <= 0)) {
return finish("Invalid nstep argument");
}
@@ -149,7 +148,7 @@ int main(int argc, char** argv) {
// get filename, determine file type
std::string filename(argv[1]);
bool binary = (filename.find(".mjb") != std::string::npos);
bool binary = (filename.find(".mjb") != std::string::npos); // NOLINT
// load model
char error[1000] = "Could not load binary model";
@@ -191,8 +190,11 @@ int main(int argc, char** argv) {
nstep,
nthread > 1 ? " per thread" : "",
m->opt.timestep);
if (sizeof(mjtNum) == 4) {
std::printf(", using single-precision");
}
if (npoolthread > 1) {
std::printf(", using %d threads for engine-internal threadpool", npoolthread);
std::printf(", using %d threads", npoolthread);
}
std::printf("...\n\n");
+2 -1
View File
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cerrno>
#include <chrono>
#include <cstdint>
#include <cstdio>
@@ -334,7 +335,7 @@ void PhysicsLoop(mj::Simulate& sim) {
// misalignment condition: distance from target sim time is bigger than syncmisalign
bool misaligned =
mju_abs(Seconds(elapsedCPU).count()/slowdown - elapsedSim) > syncMisalign;
std::abs(Seconds(elapsedCPU).count()/slowdown - elapsedSim) > syncMisalign;
// out-of-sync (for any reason): reset sync times, step
if (elapsedSim < 0 || elapsedCPU.count() < 0 || syncCPU.time_since_epoch().count() == 0 ||
+3 -1
View File
@@ -1165,7 +1165,9 @@ void CopyPose(mj::Simulate* sim, const mjModel* m, const mjData* d) {
// millisecond timer, for MuJoCo built-in profiler
mjtNum Timer() {
return Milliseconds(mj::Simulate::Clock::now().time_since_epoch()).count();
static auto start = mj::Simulate::Clock::now();
auto elapsed = Milliseconds(mj::Simulate::Clock::now() - start);
return elapsed.count();
}
// clear all times
+2 -2
View File
@@ -35,9 +35,9 @@
#endif
#ifdef mjUSEPLATFORMSIMD
#if defined(__AVX__) && defined(mjUSEDOUBLE)
#if defined(__AVX__) && !defined(mjUSESINGLE)
#define mjUSEAVX
#endif // defined(__AVX__) && defined(mjUSEDOUBLE)
#endif // defined(__AVX__) && !defined(mjUSESINGLE)
#endif // mjUSEPLATFORMSIMD
+1 -1
View File
@@ -31,7 +31,7 @@
#include "engine/engine_util_spatial.h"
#ifdef mjUSEPLATFORMSIMD
#if defined(__AVX__) && defined(mjUSEDOUBLE)
#if defined(__AVX__) && !defined(mjUSESINGLE)
#define mjUSEAVX
#include "immintrin.h"
#endif
+2 -2
View File
@@ -19,7 +19,7 @@
#include <mujoco/mjtnum.h>
#ifdef mjUSEPLATFORMSIMD
#if defined(__AVX__) && defined(mjUSEDOUBLE)
#if defined(__AVX__) && !defined(mjUSESINGLE)
#define mjUSEAVX
#include "immintrin.h"
#endif
@@ -609,7 +609,7 @@ void mju_addToScl(mjtNum* res, const mjtNum* vec, mjtNum scl, int n) {
void mju_addScl(mjtNum* res, const mjtNum* vec1, const mjtNum* vec2, mjtNum scl, int n) {
int i = 0;
#if defined(__AVX__) && defined(mjUSEAVX) && defined(mjUSEDOUBLE)
#if defined(__AVX__) && defined(mjUSEAVX) && !defined(mjUSESINGLE)
int n_4 = n - 4;
// vector part
+2 -2
View File
@@ -26,7 +26,7 @@ extern "C" {
//------------------------------ standard library functions ----------------------------------------
#ifdef mjUSEDOUBLE
#if !defined(mjUSESINGLE)
#define mju_sqrt sqrt
#define mju_exp exp
#define mju_sin sin
@@ -59,7 +59,7 @@ extern "C" {
#define mju_log10 log10f
#define mju_floor floorf
#define mju_ceil ceilf
#endif
#endif // !defined(mjUSESINGLE)
//------------------------------ 3D vector and matrix-vector operations ----------------------------
+2 -2
View File
@@ -16,7 +16,7 @@
#define MUJOCO_SRC_ENGINE_ENGINE_UTIL_SPARSE_AVX_H_
#ifdef mjUSEPLATFORMSIMD
#if defined(__AVX__) && defined(mjUSEDOUBLE)
#if defined(__AVX__) && !defined(mjUSESINGLE)
#define mjUSEAVX
@@ -315,7 +315,7 @@ int mju_compare_avx(const int* vec1, const int* vec2, int n) {
return !memcmp(vec1+i, vec2+i, (n-i)*sizeof(int));
}
#endif // defined(__AVX__) && defined(mjUSEDOUBLE)
#endif // defined(__AVX__) && !defined(mjUSESINGLE)
#endif // mjUSEPLATFORMSIMD
-1
View File
@@ -61,7 +61,6 @@ public const bool THIRD_PARTY_MUJOCO_INCLUDE_MJSPEC_H_ = true;
public const bool THIRD_PARTY_MUJOCO_INCLUDE_MJTHREAD_H_ = true;
public const int mjMAXTHREAD = 128;
public const bool THIRD_PARTY_MUJOCO_INCLUDE_MJTNUM_H_ = true;
public const bool mjUSEDOUBLE = true;
public const double mjMINVAL = 1e-15;
public const bool THIRD_PARTY_MUJOCO_MJUI_H_ = true;
public const int mjMAXUISECT = 10;