1
1

Compare commits

..

84 Commits

Author SHA1 Message Date
Dalai Felinto
f87036e8a7 the maxz and minz shaders were not being compiled 2016-11-02 19:52:15 +01:00
Dalai Felinto
f8a1255464 Fix left over from merge
Linux did not mind with them, but luckily Linux is more strict
2016-11-01 22:00:47 +01:00
Dalai Felinto
0497b012a3 Cleanups to make the patch lean 2016-10-21 12:59:03 +00:00
Dalai Felinto
669c2801c0 'gmon.out' should have never been here 2016-10-21 12:51:27 +00:00
Dalai Felinto
d26de5c907 Merge remote-tracking branch 'origin/blender2.8' into pbr-viewport 2016-10-21 12:50:28 +00:00
Dalai Felinto
1640ea89e5 Merge remote-tracking branch 'origin/blender2.8' into pbr-viewport
Conflicts:
	source/blender/blenloader/intern/versioning_270.c
	source/blender/editors/space_view3d/drawobject.c
2016-10-21 12:29:08 +00:00
Dalai Felinto
d74f6b2204 Merge remote-tracking branch 'origin/blender2.8' into pbr-merge
Conflicts:
	source/blender/blenloader/intern/versioning_defaults.c
	source/blender/editors/space_view3d/drawobject.c
	source/blender/editors/space_view3d/space_view3d.c
	source/blender/editors/space_view3d/view3d_draw.c
	source/blender/gpu/CMakeLists.txt
	source/blender/gpu/GPU_framebuffer.h
	source/blender/gpu/GPU_material.h
	source/blender/gpu/GPU_shader.h
	source/blender/gpu/intern/gpu_codegen.c
	source/blender/gpu/intern/gpu_draw.c
	source/blender/gpu/intern/gpu_framebuffer.c
	source/blender/gpu/intern/gpu_material.c
	source/blender/gpu/intern/gpu_shader.c
	source/blender/makesdna/DNA_view3d_types.h
2016-10-20 21:40:30 +00:00
Dalai Felinto
4948b6e226 Merge remote-tracking branch 'origin/master' into pbr-merge
Conflicts:
	source/blender/editors/space_view3d/view3d_draw.c
2016-10-20 19:37:36 +00:00
Dalai Felinto
feff6b4df3 Merge commit 'e5c32844678e292a084d6d97eb2d4ba6affc217d' into pbr-merge
Conflicts:
	source/blender/gpu/shaders/gpu_shader_material.glsl
2016-10-20 18:29:32 +00:00
Dalai Felinto
12c0394a4f Merge commit '4b046c530d3e14d7737c4770b9ae07942f4c6047' into pbr-merge
Conflicts:
	source/blender/nodes/shader/nodes/node_shader_fresnel.c
2016-10-20 18:23:17 +00:00
Dalai Felinto
06b5508073 Merge commit '4b046c530d3e14d7737c4770b9ae07942f4c6047^' into pbr-merge 2016-10-20 18:16:24 +00:00
Dalai Felinto
6f81e808e3 Merge commit '2b240b0430787814316f3b3166453c6d85b017f3' into pbr-merge
Conflicts:
	release/datafiles/splash.png
	release/datafiles/splash_2x.png
	source/blender/gpu/CMakeLists.txt
	source/blender/gpu/intern/gpu_shader.c
2016-10-20 17:44:51 +00:00
Dalai Felinto
d0989e538e Merge commit '7830ec54186e8b05a366775e02c6457eb83814a3' into pbr-merge
Conflicts:
	source/blender/nodes/shader/nodes/node_shader_texture.c
2016-10-20 17:26:16 +00:00
Dalai Felinto
418b24551e Merge commit '9269574089a742130f02c0a1184a19d94f0e665d' into pbr-online
Merge conflicts fixes include fix on ob->reflectionplane for write and
read, and a few manual fixes to account for the ID remap changes

Conflicts:
	source/blender/blenkernel/intern/object.c
	source/blender/blenkernel/intern/world.c
	source/blender/blenloader/intern/writefile.c
	source/blender/editors/space_view3d/view3d_draw.c
	source/blender/gpu/GPU_draw.h
	source/blender/gpu/intern/gpu_draw.c
	source/blender/gpu/intern/gpu_material.c
	source/blender/gpu/intern/gpu_texture.c
	source/blender/gpu/shaders/gpu_shader_vertex_world.glsl
2016-10-20 17:00:49 +00:00
Clément Fukhaut
a84794b399 Worked on HiZRaytracing 2016-09-04 18:56:03 +02:00
Clément Fukhaut
20fa91bd47 Early Hi-Z raytrace implementation (not functional yet) 2016-07-05 23:56:22 +02:00
Clément Fukhaut
ddfae3d2e1 I should sleep sometimes 2016-06-16 19:02:10 +02:00
turjuque
4cae0cb418 Fix texelFetch for older opengl version. 2016-06-16 01:47:07 +02:00
turjuque
22c83011a9 Fix Crash. 2016-06-16 01:46:36 +02:00
turjuque
d2ec40b8f5 Fixed crash with no material meshes 2016-06-06 18:29:46 +02:00
Clément Fukhaut
31d65359e8 Fix compilation error 2016-06-06 11:57:49 +02:00
Clément Fukhaut
554952d114 Remove SSR distance
Fixed Vertex shader not compiling for world nodetree
2016-06-05 19:45:50 +02:00
Clément Fukhaut
d85b6b86cf Fixed Planar reflection
Added Thickness parameter to SSR
2016-06-05 19:13:21 +02:00
Clément Fukhaut
db461850d7 Merge branch 'master' of git://git.blender.org/blender
# Conflicts:
#	source/blender/gpu/shaders/gpu_shader_material.glsl
2016-06-05 16:29:41 +02:00
Clément Fukhaut
d28c4d4a7c Polishing UI and added new splash 2016-06-05 15:59:05 +02:00
Clément Fukhaut
96f6372a07 Added closest filtering.
This may not be compatible with all hardware but it's texture binding independant.
2016-06-05 15:58:09 +02:00
Clément Fukhaut
9c8fbd9813 Fix transparent renders. 2016-06-05 15:56:39 +02:00
Clément Fukhaut
fbf7e5acfb -Finished SSR Integration
-Added HiZ bufffer generation for future HiZ raytracing
-Rewritten probe choosing code
-Fixed glossy aniso mistakes
2016-06-04 21:38:03 +02:00
Clément Fukhaut
d7d0166386 -Fixed SSR : Using depth buffer for increased precision but using another slot
-Fixed some typos
2016-05-31 18:08:18 +02:00
Clément Fukhaut
6ebbef4724 Merge branch 'master' of git://git.blender.org/blender
# Conflicts:
#	source/blender/gpu/intern/gpu_draw.c
#	source/blender/gpu/shaders/gpu_shader_material.glsl
#	source/blender/makesdna/DNA_view3d_types.h
#	source/blender/nodes/shader/nodes/node_shader_normal_map.c
#	source/blender/nodes/shader/nodes/node_shader_tex_environment.c
#	source/blender/nodes/shader/nodes/node_shader_tex_image.c
#	source/blender/nodes/shader/nodes/node_shader_tex_noise.c
#	source/blender/nodes/shader/nodes/node_shader_texture.c
2016-05-30 20:09:02 +02:00
Clément Fukhaut
bcf5e1c7f5 -Added Material Layer Override
-Unified SSAO settings
-Added GPU_ltc.h to hold the luts
-Simplier SSR Settings
-Reworked Anisotropic shaders (now matching Cycles)
-Finished adding other distributions
-Added Specular AO
2016-05-30 17:45:17 +02:00
Clément Fukhaut
4841e60261 Added ambient occlusion support in material
Algorithm is slow but high quality
Added backface buffer to compute per pixel thickness
Sampling quality is passed via uniforms and not via constants : this is a little slower but it does not need to recompile shader every time
Moved some code for organisation.
2016-05-25 19:12:13 +02:00
Clément Fukhaut
7e4d937718 Started adding beckmann distribution.
Improved Sun disk equations.
Adde Tried Ray aligned disk intersection to match cycles
but it's not working on microfacet bsdf for now.
2016-05-21 12:58:39 +02:00
Clément Fukhaut
579d16714f Fixing area light orientation. 2016-05-15 17:37:12 +02:00
Clément Fukhaut
d949b28199 Fixes Bug with invalid framebuffer operation in solid mode. 2016-05-15 00:04:24 +02:00
Clément Fukhaut
e54385f059 Implemented Linearly Transformed Cosines for area light.
Used for Glossy GGX and Diffuse only for now.
2016-05-07 03:28:28 +02:00
Clément Fukhaut
b372028836 Optimisation. Only run the shadow calculation and light color once per light per material.
Compared to once per light per bsdfs. Only for cycles material mode.
2016-05-06 19:34:46 +02:00
Clément Fukhaut
105a1d84c4 Huge codebase changes :
- Made ssfx "module" to manage screen space effects applied at material stage
- Moved probe functions to their own module
- Divided Shading glsl file into bits that are gathered when making glsl_material_library making files shorter and more organized
- Moved function generating luts and random texture to gpu_luts.c that will contains all textures needed to acheive some effects.
- GPU_PBR in GPUBuiltin is just a placeholder to trigger the uniform binding

Optimisation / correction :
- GLSL : Number of bsdf sample is now passed via an uniform instead of a #define. This means changing quality settings will no longer recompute every shaders in the scene. But this has a small perf cost.
- GLSL : Hammersley numbers are precalculated and stored inside a texture. This may have a performance impact and I will change it to a static table.
- GLSL : Random per pixel numbers are done using a texture like SSAO.
- GLSL : Lots of parameters (only for pbr) are now defined as uniform and passed at binding stage (this minimize the use of GPU_builtin).
- GLSL : most variables used in sampling algorythm are defined as global variables.
- Bsdf sampling is now using the real algorithm and not the split sum approximation (which was unecessary).

Features :
- Added toon shader support (only point light support).
- Added holdout.
2016-05-06 15:55:15 +02:00
Clément Fukhaut
80f03704e7 Fix Opengl problem on OSX 2016-05-06 15:13:30 +02:00
Clément Fukhaut
655cfca452 Implemented SSR :
- Still pretty rough implementation does only works with sharp glossy shader
- No Glossy reflection
- 2 algorithm but only one acheive decent results the other needs to be debuged.

Changed pbr settings location :
- They are now stored in structs like the FX options
2016-05-03 19:41:41 +02:00
Clément Fukhaut
7c777fe038 Oren-nayar Diffuse & Velvet Shader Environment lighting support. 2016-04-16 12:54:40 +02:00
Clément Fukhaut
81737e6cca Fix bug when capturing object with planar reflections. 2016-04-16 12:53:22 +02:00
Clément Fukhaut
515be07dd4 Merge branch 'master' of git://git.blender.org/blender
# Conflicts:
#	source/blender/gpu/shaders/gpu_shader_material.glsl
2016-04-11 21:24:12 +02:00
Clément Fukhaut
7750dea70e Last minute changes :
- Changed splash
- Added bypass for lamps diffuse and specular contribution
- Added probe related operators

Signed-off-by: Clément Foucault <foucault.clem@gmail.com>
2016-04-11 19:59:29 +02:00
Clément Fukhaut
f50bf4f110 Fixed color correction post process.
Signed-off-by: Clément Foucault <foucault.clem@gmail.com>
2016-04-11 19:54:39 +02:00
Clément Fukhaut
c1580b9cd4 Fixed Probe unlinking on refresh. 2016-04-05 22:24:31 +02:00
Clément Fukhaut
c112a54d2a Fix crash with world preview & icons. 2016-04-05 22:14:25 +02:00
Clément Fukhaut
1cd2d7b744 Merge branch 'master' of git://git.blender.org/blender
# Conflicts:
#	source/blender/gpu/intern/gpu_material.c
#	source/blender/gpu/intern/gpu_shader.c
2016-04-05 00:15:30 +02:00
Clément Fukhaut
798357ca57 Planar Probe, Probe options, Probe Parallax :
- Added Planar Reflections and Refractions:
Rough planar reflection/refraction are roughly approximated by blurring with the microfacet normal direction. We blend to a fallback cubemap for high roughness. They are also displaced using the viewnormals. This last deformation is divided by the distance to the shaded point and multiplied by the distance to the reflection plane to get contact reflections.

- Added options to probes.
Probe can now only render their layers. Diffuse can be disabled (in case of use with a lightmap). Added Operator to manualy update probes.

- Probe parallax:
Correct the rays to project it to the chosen volume (unit cube or sphere) after being corrected by the obj mat (either own or external).

- Probe updates are a bit more consistent.

- Moved PBR light UI from Cycles to Blender sources.

- Added versioning code to update old file with non breaking defaults.

Signed-off-by: Clément Foucault <foucault.clem@gmail.com>
2016-04-04 21:46:20 +02:00
Clément Fukhaut
b818de11df Fixed crash when world is absent. 2016-03-21 22:13:58 +01:00
turjuque
ef01bfd53d Fix compilation issue on linux. 2016-03-20 21:49:36 +01:00
Clément Fukhaut
bb9d7491e8 Changed Splash version number 2016-03-20 17:04:30 +01:00
Clément Fukhaut
37300f3307 Fix #3 : Clamp mix factor. 2016-03-20 16:12:46 +01:00
Clément Fukhaut
ed3a8ae7b3 Removing some debug printf 2016-03-20 15:42:22 +01:00
Clément Fukhaut
9a0e6c1883 Merge branch 'master' of git://git.blender.org/blender
# Conflicts:
#	release/datafiles/splash.png
#	release/datafiles/splash_2x.png
#	source/blender/gpu/GPU_material.h
#	source/blender/gpu/shaders/gpu_shader_material.glsl
#	source/blender/makesrna/intern/rna_image_api.c
#	source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
#	source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c
#	source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c
#	source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
#	source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c
#	source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c
#	source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c
#	source/blender/nodes/shader/nodes/node_shader_fresnel.c
#	source/blender/nodes/shader/nodes/node_shader_layer_weight.c
#	source/blender/nodes/shader/nodes/node_shader_normal_map.c
2016-03-20 15:25:02 +01:00
Clément Fukhaut
b6d97ce425 Viewport Probe capture for bsdf preview:
- Added a GPUProbe generated by either the world or objects in the scene.
Updating is done by tagging the GPUProbe and waiting the gpu_update_probes call.
All probes are updated if the world changes and all objects probes are updated if an object in the scene changes. This must be optimize to ensure good performance with lots of probes.
For the moment no settings are available.

- Separated bsdf sampling code inside a new file.

- Spherical harmonic computation is now done on the GPU. Using only 64*64*6 samples for now.

- Lots of code cleaning and formating.
2016-03-20 15:08:30 +01:00
Clément Fukhaut
1eb5ff3bbd Exclude Translucent surfaces from shadows. 2016-02-21 23:01:22 +01:00
Clément Fukhaut
240e995062 Merge branch 'master' of git://git.blender.org/blender 2016-02-21 22:38:57 +01:00
Clément Fukhaut
7e0cb40b48 Giving user more control over the shadows. Enabling shadows for Area lamps. 2016-02-21 21:09:27 +01:00
Clément Fukhaut
9974ada602 Merge branch 'master' of git://git.blender.org/blender 2016-02-17 22:27:20 +01:00
Clément Fukhaut
b3c3275dad Merge branch 'master' of git://git.blender.org/blender
# Conflicts:
#	source/blender/gpu/shaders/gpu_shader_material.glsl
2016-02-17 22:24:29 +01:00
Clément Fukhaut
8de5664a60 Added support for custom number of samples for brdfs. 2016-02-14 22:42:20 +01:00
Clément Fukhaut
52cb2981c4 Fix layer weight and light's geometry nodes 2016-02-14 22:32:30 +01:00
Clément Fukhaut
4b08c4d0ae Merge branch 'master' of git://git.blender.org/blender
# Conflicts:
#	source/blender/gpu/intern/gpu_material.c
#	source/blender/gpu/shaders/gpu_shader_material.glsl
2016-02-14 14:53:40 +01:00
Clément Fukhaut
bec580b0f9 Tangent node support in GLSL (only with selected uv) 2016-02-02 00:27:11 +01:00
Clément Fukhaut
e217b66505 Merge branch 'master' of git://git.blender.org/blender
# Conflicts:
#	source/blender/gpu/GPU_texture.h
2016-02-01 23:23:30 +01:00
Clément Fukhaut
6d33b1031a Fix bug #1 2016-01-31 21:40:19 +01:00
Clément Fukhaut
051c9c39d4 Make use of new direction_transform_m4v3. Add restriction to the display of show_world_sh. 2016-01-28 16:31:35 +01:00
Clément Fukhaut
20afa77324 Merge branch 'master' of git://git.blender.org/blender
# Conflicts:
#	source/blender/editors/space_view3d/drawmesh.c
#	source/blender/gpu/CMakeLists.txt
#	source/blender/gpu/GPU_draw.h
#	source/blender/gpu/GPU_material.h
#	source/blender/gpu/GPU_texture.h
#	source/blender/gpu/intern/gpu_codegen.c
#	source/blender/gpu/intern/gpu_draw.c
#	source/blender/gpu/intern/gpu_material.c
#	source/blender/gpu/intern/gpu_shader.c
#	source/blender/gpu/intern/gpu_texture.c
#	source/blender/makesrna/intern/rna_image_api.c
#	source/blender/nodes/shader/nodes/node_shader_vectTransform.c
2016-01-28 14:44:58 +01:00
Clément Fukhaut
371c289af8 Made these changes, all relative to the viewport Material mode.
-Lamp sizes are now binded with dynamic uniforms
-Added support of Anisotropic Bsdf
-Added support of Glossy Refraction Bsdf
-Added support of Glossy Glass Bsdf
-Texture noise uses the same default coordinates as cycles.
-Vector transform now works with translations (point mode).
-Vector transform now works with translations.
-Transparency for transparent Bsdf now uses the alpha input.
-Lots of code formating
-Default tangent space inside Geometry node
-Added support for Tangent node
-Object Info now output object location correctly
2016-01-28 00:46:08 +01:00
Clément Fukhaut
59295b9126 Fixing problems with macOSX opengl. Thanks to Marcelo Varanda. 2016-01-20 01:36:27 +01:00
Clément Fukhaut
f0f398c0dd Fix sun intensity and fix a bug for some graphics cards. 2016-01-18 22:18:53 +01:00
Clément Fukhaut
a3a0220d57 Using the brdf path for default material. And fixing stuff. 2016-01-08 04:06:41 +01:00
Clément Fukhaut
df63042d8f Fixing Glass shader color. 2016-01-08 03:09:32 +01:00
Clément Fukhaut
3155b440bf Fix backward compatibility. 2016-01-08 02:30:34 +01:00
Clément Fukhaut
01a258f829 Started Velvet support in viewport code. 2016-01-07 02:42:18 +01:00
turjuque
a30e73bf67 Making things work again 2016-01-06 23:29:23 +01:00
turjuque
c326d403d8 Merge branch 'master' of github.com:Hypersomniac/blender-shader
# Conflicts:
#	source/blender/gpu/GPU_material.h
#	source/blender/gpu/SConscript
#	source/blender/gpu/intern/gpu_compositing.c
#	source/blender/gpu/intern/gpu_extensions.c
#	source/blender/gpu/intern/gpu_material.c
#	source/blender/gpu/shaders/gpu_shader_material.glsl
#	source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c
#	source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
#	source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp
2016-01-06 22:19:37 +01:00
turjuque
44aeca9023 Merge branch 'master' of git://git.blender.org/blender
# Conflicts:
#	source/blender/editors/space_view3d/drawmesh.c
#	source/blender/gpu/GPU_extensions.h
#	source/blender/gpu/SConscript
#	source/blender/gpu/intern/gpu_compositing.c
#	source/blender/gpu/intern/gpu_extensions.c
#	source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp
2016-01-06 22:14:30 +01:00
turjuque
c89ced47bb PRB viewport : Adding lamp support and post effects. and lots of gpu stuff.
No more leaks.
2016-01-06 21:38:06 +01:00
turjuque
83aeba94c7 PRB viewport : Adding lamp support and post effects. and lots of gpu stuff. 2015-12-23 23:48:23 +01:00
turjuque
4aebb28e60 Added checkboxes for display options 2015-11-26 02:50:33 +01:00
turjuque
863923d3d0 Merge branch 'master' of git://git.blender.org/blender
# Conflicts:
#	source/blender/gpu/intern/gpu_material.c
#	source/blender/makesdna/DNA_node_types.h
2015-11-25 19:02:14 +01:00
turjuque
83a54dc2a8 PBR Implementation 2015-11-25 18:43:12 +01:00
1074 changed files with 31638 additions and 72750 deletions

View File

@@ -333,7 +333,7 @@ option(WITH_ALEMBIC "Enable Alembic Support" OFF)
option(WITH_ALEMBIC_HDF5 "Enable Legacy Alembic Support (not officially supported)" OFF)
if(APPLE)
option(WITH_CODEC_QUICKTIME "Enable Quicktime Support" OFF)
option(WITH_CODEC_QUICKTIME "Enable Quicktime Support" ON)
endif()
# 3D format support
@@ -343,9 +343,9 @@ option(WITH_OPENCOLLADA "Enable OpenCollada Support (http://www.opencollada.or
# Sound output
option(WITH_SDL "Enable SDL for sound and joystick support" ${_init_SDL})
option(WITH_OPENAL "Enable OpenAL Support (http://www.openal.org)" ON)
option(WITH_JACK "Enable JACK Support (http://www.jackaudio.org)" ${_init_JACK})
option(WITH_JACK "Enable Jack Support (http://www.jackaudio.org)" ${_init_JACK})
if(UNIX AND NOT APPLE)
option(WITH_JACK_DYNLOAD "Enable runtime dynamic JACK libraries loading" OFF)
option(WITH_JACK_DYNLOAD "Enable runtime dynamic Jack libraries loading" OFF)
endif()
if(UNIX AND NOT APPLE)
option(WITH_SDL_DYNLOAD "Enable runtime dynamic SDL libraries loading" OFF)
@@ -497,22 +497,17 @@ endif()
# We default options to whatever default standard in the current compiler.
if(CMAKE_COMPILER_IS_GNUCC AND (NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "6.0") AND (NOT WITH_CXX11))
set(_c11_init ON)
set(_cxx11_init ON)
else()
set(_c11_init OFF)
set(_cxx11_init OFF)
endif()
set(_cxx11_init ON)
option(WITH_C11 "Build with C11 standard enabled, for development use only!" ${_c11_init})
mark_as_advanced(WITH_C11)
option(WITH_CXX11 "Build with C++11 standard enabled, for development use only!" ${_cxx11_init})
mark_as_advanced(WITH_CXX11)
# Compiler toolchain
if(CMAKE_COMPILER_IS_GNUCC)
option(WITH_LINKER_GOLD "Use ld.gold linker which is usually faster than ld.bfd" ON)
mark_as_advanced(WITH_LINKER_GOLD)
endif()
# Dependency graph
option(WITH_LEGACY_DEPSGRAPH "Build Blender with legacy dependency graph" ON)
mark_as_advanced(WITH_LEGACY_DEPSGRAPH)
@@ -627,12 +622,6 @@ if(APPLE)
# to silence sdk not found warning, just overrides CMAKE_OSX_SYSROOT
set(CMAKE_XCODE_ATTRIBUTE_SDKROOT macosx${OSX_SYSTEM})
endif()
# QuickTime framework is no longer available in SDK 10.12+
if(WITH_CODEC_QUICKTIME AND ${OSX_SYSTEM} VERSION_GREATER 10.11)
set(WITH_CODEC_QUICKTIME OFF)
message(STATUS "QuickTime not supported by SDK ${OSX_SYSTEM}, disabling WITH_CODEC_QUICKTIME")
endif()
endif()
if(OSX_SYSTEM MATCHES 10.9)
@@ -742,7 +731,7 @@ elseif(WITH_CYCLES OR WITH_OPENIMAGEIO OR WITH_AUDASPACE OR WITH_INTERNATIONAL O
# Keep enabled
else()
# New dependency graph needs either Boost or C++11 for function bindings.
if(NOT WITH_CXX11)
if(NOT USE_CXX11)
# Enabled but we don't need it
set(WITH_BOOST OFF)
endif()
@@ -866,7 +855,7 @@ endif()
# linux only, not cached
set(WITH_BINRELOC OFF)
# MACOSX only, set to avoid uninitialized
# MAXOSX only, set to avoid uninitialized
set(EXETYPE "")
# C/C++ flags
@@ -1572,7 +1561,7 @@ if(WITH_CXX11)
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
# TODO(sergey): Do we want c++11 or gnu-c++11 here?
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(MSVC)
elseif(MSVC12)
# Nothing special is needed, C++11 features are available by default.
else()
message(FATAL_ERROR "Compiler ${CMAKE_C_COMPILER_ID} is not supported for C++11 build yet")

View File

@@ -284,7 +284,7 @@ NO_BUILD=false
NO_CONFIRM=false
USE_CXX11=true # Mandatory in blender2.8
PYTHON_VERSION="3.5.2"
PYTHON_VERSION="3.5.1"
PYTHON_VERSION_MIN="3.5"
PYTHON_FORCE_BUILD=false
PYTHON_FORCE_REBUILD=false
@@ -317,7 +317,7 @@ OPENEXR_FORCE_REBUILD=false
OPENEXR_SKIP=false
_with_built_openexr=false
OIIO_VERSION="1.7.8"
OIIO_VERSION="1.6.9"
OIIO_VERSION_MIN="1.6.0"
OIIO_VERSION_MAX="1.9.0" # UNKNOWN currently # Not supported by current OSL...
OIIO_FORCE_BUILD=false
@@ -332,14 +332,14 @@ LLVM_FORCE_REBUILD=false
LLVM_SKIP=false
# OSL needs to be compiled for now!
OSL_VERSION="1.7.5"
OSL_VERSION="1.7.3"
OSL_VERSION_MIN=$OSL_VERSION
OSL_FORCE_BUILD=false
OSL_FORCE_REBUILD=false
OSL_SKIP=false
# OpenSubdiv needs to be compiled for now
OSD_VERSION="3.1.1"
OSD_VERSION="3.0.5"
OSD_VERSION_MIN=$OSD_VERSION
OSD_FORCE_BUILD=false
OSD_FORCE_REBUILD=false
@@ -367,7 +367,7 @@ OPENCOLLADA_FORCE_BUILD=false
OPENCOLLADA_FORCE_REBUILD=false
OPENCOLLADA_SKIP=false
FFMPEG_VERSION="3.2.1"
FFMPEG_VERSION="2.8.4"
FFMPEG_VERSION_MIN="2.8.4"
FFMPEG_FORCE_BUILD=false
FFMPEG_FORCE_REBUILD=false
@@ -705,21 +705,6 @@ if [ "$WITH_ALL" = true -a "$OPENCOLLADA_SKIP" = false ]; then
fi
WARNING "****WARNING****"
PRINT "If you are experiencing issues building Blender, _*TRY A FRESH, CLEAN BUILD FIRST*_!"
PRINT "The same goes for install_deps itself, if you encounter issues, please first erase everything in $SRC and $INST"
PRINT "(provided obviously you did not add anything yourself in those dirs!), and run install_deps.sh again!"
PRINT "Often, changes in the libs built by this script, or in your distro package, cannot be handled simply, so..."
PRINT ""
PRINT "You may also try to use the '--build-foo' options to bypass your distribution's packages"
PRINT "for some troublesome/buggy libraries..."
PRINT ""
PRINT ""
PRINT "Ran with:"
PRINT " install_deps.sh $COMMANDLINE"
PRINT ""
PRINT ""
# This has to be done here, because user might force some versions...
PYTHON_SOURCE=( "https://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tgz" )
@@ -792,8 +777,6 @@ However, if you are experiencing linking errors (also when building Blender itse
Please note that until the transition to C++11-built libraries if completed in your distribution, situation will
remain fuzzy and incompatibilities may happen..."
PRINT ""
PRINT ""
CXXFLAGS="$CXXFLAGS -std=c++11"
export CXXFLAGS
fi
@@ -1867,9 +1850,6 @@ compile_OSL() {
cmake_d="$cmake_d -D OSL_BUILD_PLUGINS=OFF"
cmake_d="$cmake_d -D OSL_BUILD_TESTS=OFF"
cmake_d="$cmake_d -D USE_SIMD=sse2"
if [ "$USE_CXX11" = true ]; then
cmake_d="$cmake_d -D OSL_BUILD_CPP11=1"
fi
#~ cmake_d="$cmake_d -D ILMBASE_VERSION=$ILMBASE_VERSION"
@@ -2472,7 +2452,7 @@ compile_FFmpeg() {
--enable-avfilter --disable-vdpau \
--disable-bzlib --disable-libgsm --disable-libspeex \
--enable-pthreads --enable-zlib --enable-stripping --enable-runtime-cpudetect \
--disable-vaapi --disable-nonfree --enable-gpl \
--disable-vaapi --disable-libfaac --disable-nonfree --enable-gpl \
--disable-postproc --disable-librtmp --disable-libopencore-amrnb \
--disable-libopencore-amrwb --disable-libdc1394 --disable-version3 --disable-outdev=sdl \
--disable-libxcb \
@@ -4035,6 +4015,9 @@ install_OTHER() {
fi
if [ "$_do_compile_llvm" = true ]; then
install_packages_DEB libffi-dev
# LLVM can't find the debian ffi header dir
_FFI_INCLUDE_DIR=`dpkg -L libffi-dev | grep -e ".*/ffi.h" | sed -r 's/(.*)\/ffi.h/\1/'`
PRINT ""
compile_LLVM
have_llvm=true
@@ -4053,6 +4036,7 @@ install_OTHER() {
if [ "$_do_compile_osl" = true ]; then
if [ "$have_llvm" = true ]; then
install_packages_DEB flex bison libtbb-dev
PRINT ""
compile_OSL
else
@@ -4071,6 +4055,7 @@ install_OTHER() {
fi
if [ "$_do_compile_osd" = true ]; then
install_packages_DEB flex bison libtbb-dev
PRINT ""
compile_OSD
fi
@@ -4087,6 +4072,10 @@ install_OTHER() {
fi
if [ "$_do_compile_collada" = true ]; then
install_packages_DEB libpcre3-dev
# Find path to libxml shared lib...
_XML2_LIB=`dpkg -L libxml2-dev | grep -e ".*/libxml2.so"`
# No package
PRINT ""
compile_OpenCOLLADA
fi
@@ -4171,6 +4160,16 @@ print_info_ffmpeglink() {
}
print_info() {
PRINT ""
PRINT ""
WARNING "****WARNING****"
PRINT "If you are experiencing issues building Blender, _*TRY A FRESH, CLEAN BUILD FIRST*_!"
PRINT "The same goes for install_deps itself, if you encounter issues, please first erase everything in $SRC and $INST"
PRINT "(provided obviously you did not add anything yourself in those dirs!), and run install_deps.sh again!"
PRINT "Often, changes in the libs built by this script, or in your distro package, cannot be handled simply, so..."
PRINT ""
PRINT "You may also try to use the '--build-foo' options to bypass your distribution's packages"
PRINT "for some troublesome/buggy libraries..."
PRINT ""
PRINT ""
PRINT "Ran with:"

View File

@@ -94,7 +94,6 @@ all_repositories = {
r'git://git.blender.org/blender-translations.git': 'blender-translations',
r'git://git.blender.org/blender-addons.git': 'blender-addons',
r'git://git.blender.org/blender-addons-contrib.git': 'blender-addons-contrib',
r'git://git.blender.org/blender-dev-tools.git': 'blender-dev-tools',
r'https://svn.blender.org/svnroot/bf-blender/': 'lib svn',
}
@@ -129,7 +128,6 @@ def schedule_force_build(name):
forcesched.CodebaseParameter(hide=True, codebase="blender-translations"),
forcesched.CodebaseParameter(hide=True, codebase="blender-addons"),
forcesched.CodebaseParameter(hide=True, codebase="blender-addons-contrib"),
forcesched.CodebaseParameter(hide=True, codebase="blender-dev-tools"),
forcesched.CodebaseParameter(hide=True, codebase="lib svn")],
properties=[]))
@@ -145,7 +143,6 @@ def schedule_build(name, hour, minute=0):
"blender-translations": {"repository": "", "branch": "master"},
"blender-addons": {"repository": "", "branch": "master"},
"blender-addons-contrib": {"repository": "", "branch": "master"},
"blender-dev-tools": {"repository": "", "branch": "master"},
"lib svn": {"repository": "", "branch": "trunk"}},
branch=current_branch,
builderNames=[name],
@@ -267,8 +264,7 @@ def generic_builder(id, libdir='', branch='', rsync=False):
for submodule in ('blender-translations',
'blender-addons',
'blender-addons-contrib',
'blender-dev-tools'):
'blender-addons-contrib'):
f.addStep(git_submodule_step(submodule))
f.addStep(git_step(branch))
@@ -297,14 +293,13 @@ def generic_builder(id, libdir='', branch='', rsync=False):
# Builders
add_builder(c, 'mac_x86_64_10_6_cmake', 'darwin-9.x.universal', generic_builder, hour=5)
# add_builder(c, 'linux_glibc211_i686_cmake', '', generic_builder, hour=1)
# add_builder(c, 'linux_glibc211_x86_64_cmake', '', generic_builder, hour=2)
add_builder(c, 'linux_glibc211_i686_cmake', '', generic_builder, hour=1)
add_builder(c, 'linux_glibc211_x86_64_cmake', '', generic_builder, hour=2)
add_builder(c, 'linux_glibc219_i686_cmake', '', generic_builder, hour=3)
add_builder(c, 'linux_glibc219_x86_64_cmake', '', generic_builder, hour=4)
add_builder(c, 'win32_cmake_vc2013', 'windows_vc12', generic_builder, hour=3)
add_builder(c, 'win64_cmake_vc2013', 'win64_vc12', generic_builder, hour=4)
add_builder(c, 'win32_cmake_vc2015', 'windows_vc14', generic_builder, hour=5)
add_builder(c, 'win64_cmake_vc2015', 'win64_vc14', generic_builder, hour=6)
add_builder(c, 'win64_cmake_vc2015', 'win64_vc14', generic_builder, hour=5)
# STATUS TARGETS
#

View File

@@ -183,8 +183,10 @@ if 'cmake' in builder:
print('Condifuration FAILED!')
sys.exit(retcode)
if 'win32' in builder or 'win64' in builder:
command = ['cmake', '--build', '.', '--target', target_name, '--config', 'Release']
if 'win32' in builder:
command = ['msbuild', 'INSTALL.vcxproj', '/Property:PlatformToolset=v120_xp', '/p:Configuration=Release']
elif 'win64' in builder:
command = ['msbuild', 'INSTALL.vcxproj', '/p:Configuration=Release']
else:
command = target_chroot_prefix + ['make', '-s', '-j2', target_name]

View File

@@ -1,15 +1,15 @@
# - Find JACK library
# Find the native JACK includes and library
# - Find Jack library
# Find the native Jack includes and library
# This module defines
# JACK_INCLUDE_DIRS, where to find jack.h, Set when
# JACK_INCLUDE_DIR is found.
# JACK_LIBRARIES, libraries to link against to use JACK.
# JACK_ROOT_DIR, The base directory to search for JACK.
# JACK_LIBRARIES, libraries to link against to use Jack.
# JACK_ROOT_DIR, The base directory to search for Jack.
# This can also be an environment variable.
# JACK_FOUND, If false, do not try to use JACK.
# JACK_FOUND, If false, do not try to use Jack.
#
# also defined, but not for general use are
# JACK_LIBRARY, where to find the JACK library.
# JACK_LIBRARY, where to find the Jack library.
#=============================================================================
# Copyright 2011 Blender Foundation.

View File

@@ -518,8 +518,7 @@ function(setup_liblinks
target_link_libraries(${target}
${BLENDER_GL_LIBRARIES})
#target_link_libraries(${target} ${PLATFORM_LINKLIBS} ${CMAKE_DL_LIBS})
target_link_libraries(${target} ${PLATFORM_LINKLIBS})
target_link_libraries(${target} ${PLATFORM_LINKLIBS} ${CMAKE_DL_LIBS})
endfunction()

View File

@@ -158,7 +158,7 @@ if(WITH_CODEC_FFMPEG)
mp3lame swscale x264 xvidcore theora theoradec theoraenc vorbis vorbisenc vorbisfile ogg
)
if(WITH_CXX11)
set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} schroedinger orc vpx webp swresample)
set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} schroedinger orc vpx)
endif()
set(FFMPEG_LIBPATH ${FFMPEG}/lib)
endif()
@@ -316,9 +316,6 @@ if(WITH_OPENIMAGEIO)
${OPENEXR_LIBRARIES}
${ZLIB_LIBRARIES}
)
if(WITH_CXX11)
set(OPENIMAGEIO_LIBRARIES ${OPENIMAGEIO_LIBRARIES} ${LIBDIR}/ffmpeg/lib/libwebp.a)
endif()
set(OPENIMAGEIO_LIBPATH
${OPENIMAGEIO}/lib
${JPEG_LIBPATH}

View File

@@ -384,18 +384,17 @@ add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
if(CMAKE_COMPILER_IS_GNUCC)
set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing")
if(WITH_LINKER_GOLD)
execute_process(
COMMAND ${CMAKE_C_COMPILER} -fuse-ld=gold -Wl,--version
ERROR_QUIET OUTPUT_VARIABLE LD_VERSION)
if("${LD_VERSION}" MATCHES "GNU gold")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fuse-ld=gold")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=gold")
else()
message(STATUS "GNU gold linker isn't available, using the default system linker.")
endif()
unset(LD_VERSION)
# use ld.gold linker if available, could make optional
execute_process(
COMMAND ${CMAKE_C_COMPILER} -fuse-ld=gold -Wl,--version
ERROR_QUIET OUTPUT_VARIABLE LD_VERSION)
if("${LD_VERSION}" MATCHES "GNU gold")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fuse-ld=gold")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=gold")
else()
message(STATUS "GNU gold linker isn't available, using the default system linker.")
endif()
unset(LD_VERSION)
# CLang is the same as GCC for now.
elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")

View File

@@ -112,7 +112,7 @@ set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221")
# MSVC only, Mingw doesnt need
if(CMAKE_CL_64)
set(PLATFORM_LINKFLAGS "/MACHINE:X64 ${PLATFORM_LINKFLAGS}")
set(PLATFORM_LINKFLAGS "/MACHINE:X64 /OPT:NOREF ${PLATFORM_LINKFLAGS}")
else()
set(PLATFORM_LINKFLAGS "/MACHINE:IX86 /LARGEADDRESSAWARE ${PLATFORM_LINKFLAGS}")
endif()
@@ -129,10 +129,8 @@ if(NOT DEFINED LIBDIR)
message(STATUS "32 bit compiler detected.")
set(LIBDIR_BASE "windows")
endif()
if(MSVC_VERSION EQUAL 1910)
message(STATUS "Visual Studio 2017 detected.")
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc14)
elseif(MSVC_VERSION EQUAL 1900)
if(MSVC_VERSION EQUAL 1900)
message(STATUS "Visual Studio 2015 detected.")
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc14)
else()
@@ -238,14 +236,14 @@ if(WITH_CODEC_FFMPEG)
windows_find_package(FFMPEG)
if(NOT FFMPEG_FOUND)
warn_hardcoded_paths(ffmpeg)
set(FFMPEG_LIBRARY_VERSION 57)
set(FFMPEG_LIBRARY_VERSION_AVU 55)
set(FFMPEG_LIBRARY_VERSION 55)
set(FFMPEG_LIBRARY_VERSION_AVU 52)
set(FFMPEG_LIBRARIES
${LIBDIR}/ffmpeg/lib/avcodec.lib
${LIBDIR}/ffmpeg/lib/avformat.lib
${LIBDIR}/ffmpeg/lib/avdevice.lib
${LIBDIR}/ffmpeg/lib/avutil.lib
${LIBDIR}/ffmpeg/lib/swscale.lib
${LIBDIR}/ffmpeg/lib/avcodec-${FFMPEG_LIBRARY_VERSION}.lib
${LIBDIR}/ffmpeg/lib/avformat-${FFMPEG_LIBRARY_VERSION}.lib
${LIBDIR}/ffmpeg/lib/avdevice-${FFMPEG_LIBRARY_VERSION}.lib
${LIBDIR}/ffmpeg/lib/avutil-${FFMPEG_LIBRARY_VERSION_AVU}.lib
${LIBDIR}/ffmpeg/lib/swscale-2.lib
)
endif()
endif()
@@ -380,7 +378,6 @@ if(WITH_OPENIMAGEIO)
set(OPENCOLORIO_DEFINITIONS "-DOCIO_STATIC_BUILD")
set(OPENIMAGEIO_IDIFF "${OPENIMAGEIO}/bin/idiff.exe")
add_definitions(-DOIIO_STATIC_BUILD)
add_definitions(-DOIIO_NO_SSE=1)
endif()
if(WITH_LLVM)

View File

@@ -187,7 +187,7 @@ The next table describes the information in the file-header.
</table>
<p>
<a href="https://en.wikipedia.org/wiki/Endianness">Endianness</a> addresses the way values are ordered in a sequence of bytes(see the <a href="#example-endianess">example</a> below):
<a href="http://en.wikipedia.org/wiki/Endianness">Endianness</a> addresses the way values are ordered in a sequence of bytes(see the <a href="#example-endianess">example</a> below):
</p>
<ul>

View File

@@ -699,7 +699,7 @@ LAYOUT_FILE =
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
# the reference definitions. This must be a list of .bib files. The .bib
# extension is automatically appended if omitted. This requires the bibtex tool
# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
# For LaTeX the style of the bibliography can be controlled using
# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
# search path. See also \cite for info how to create references.
@@ -1145,7 +1145,7 @@ HTML_EXTRA_FILES =
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the style sheet and background images according to
# this color. Hue is specified as an angle on a colorwheel, see
# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
# purple, and 360 is red again.
# Minimum value: 0, maximum value: 359, default value: 220.
@@ -1752,7 +1752,7 @@ LATEX_SOURCE_CODE = NO
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
# bibliography, e.g. plainnat, or ieeetr. See
# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
# The default value is: plain.
# This tag requires that the tag GENERATE_LATEX is set to YES.

View File

@@ -24,8 +24,8 @@ Then, call ``bpy.app.translations.register(__name__, your_dict)`` in your ``regi
The ``Manage UI translations`` add-on has several functions to help you collect strings to translate, and
generate the needed python code (the translation dictionary), as well as optional intermediary po files
if you want some... See
`How to Translate Blender <https://wiki.blender.org/index.php/Dev:Doc/Process/Translate_Blender>`_ and
`Using i18n in Blender Code <https://wiki.blender.org/index.php/Dev:Source/Interface/Internationalization>`_
`How to Translate Blender <http://wiki.blender.org/index.php/Dev:Doc/Process/Translate_Blender>`_ and
`Using i18n in Blender Code <http://wiki.blender.org/index.php/Dev:Source/Interface/Internationalization>`_
for more info.
Module References

View File

@@ -49,7 +49,7 @@ vec2d[:] = vec3d[:2]
# Vectors support 'swizzle' operations
# See https://en.wikipedia.org/wiki/Swizzling_(computer_graphics)
# See http://en.wikipedia.org/wiki/Swizzling_(computer_graphics)
vec.xyz = vec.zyx
vec.xy = vec4d.zw
vec.xyz = vec4d.wzz

View File

@@ -405,7 +405,7 @@ base class --- :class:`SCA_IObject`
.. note::
This attribute is experimental and may be removed (but probably wont be).
This attribute is experemental and may be removed (but probably wont be).
.. note::
@@ -419,7 +419,7 @@ base class --- :class:`SCA_IObject`
.. note::
This attribute is experimental and may be removed (but probably wont be).
This attribute is experemental and may be removed (but probably wont be).
.. note::
@@ -453,7 +453,7 @@ base class --- :class:`SCA_IObject`
.. attribute:: childrenRecursive
all children of this object including children's children, (read-only).
all children of this object including childrens children, (read-only).
:type: :class:`CListValue` of :class:`KX_GameObject`'s
@@ -536,7 +536,7 @@ base class --- :class:`SCA_IObject`
.. method:: getAxisVect(vect)
Returns the axis vector rotates by the object's worldspace orientation.
Returns the axis vector rotates by the objects worldspace orientation.
This is the equivalent of multiplying the vector by the orientation matrix.
:arg vect: a vector to align the axis.
@@ -596,7 +596,7 @@ base class --- :class:`SCA_IObject`
Gets the game object's linear velocity.
This method returns the game object's velocity through it's center of mass, ie no angular velocity component.
This method returns the game object's velocity through it's centre of mass, ie no angular velocity component.
:arg local:
* False: you get the "global" velocity ie: relative to world orientation.
@@ -609,7 +609,7 @@ base class --- :class:`SCA_IObject`
Sets the game object's linear velocity.
This method sets game object's velocity through it's center of mass,
This method sets game object's velocity through it's centre of mass,
ie no angular velocity component.
This requires a dynamic object.
@@ -814,7 +814,7 @@ base class --- :class:`SCA_IObject`
# do something
pass
The face parameter determines the orientation of the normal.
The face paremeter determines the orientation of the normal.
* 0 => hit normal is always oriented towards the ray origin (as if you casted the ray from outside)
* 1 => hit normal is the real face normal (only for mesh object, otherwise face has no effect)
@@ -911,7 +911,7 @@ base class --- :class:`SCA_IObject`
.. note::
The gameObject argument has an advantage that it can convert from a mesh with modifiers applied (such as the Subdivision Surface modifier).
The gameObject argument has an advantage that it can convert from a mesh with modifiers applied (such as subsurf).
.. warning::
@@ -919,7 +919,7 @@ base class --- :class:`SCA_IObject`
.. warning::
If the object is a part of a compound object it will fail (parent or child)
If the object is a part of a combound object it will fail (parent or child)
.. warning::

File diff suppressed because it is too large Load Diff

View File

@@ -23,7 +23,7 @@ The features exposed closely follow the C API,
giving python access to the functions used by blenders own mesh editing tools.
For an overview of BMesh data types and how they reference each other see:
`BMesh Design Document <https://wiki.blender.org/index.php/Dev:Source/Modeling/BMesh/Design>`_ .
`BMesh Design Document <http://wiki.blender.org/index.php/Dev:2.6/Source/Modeling/BMesh/Design>`_ .
.. note::
@@ -31,12 +31,13 @@ For an overview of BMesh data types and how they reference each other see:
**Disk** and **Radial** data is not exposed by the python api since this is for internal use only.
.. warning:: TODO items are...
.. warning::
TODO items are...
* add access to BMesh **walkers**
* add custom-data manipulation functions add/remove/rename.
Example Script
--------------

View File

@@ -204,7 +204,7 @@ Lets say we want to access the texture of a brush via Python, to adjust its ``co
- Start in the default scene and enable 'Sculpt' mode from the 3D-View header.
- From the toolbar expand the **Texture** panel and add a new texture.
*Notice the texture button its self doesn't have very useful links (you can check the tooltips).*
*Notice the texture button its self doesn't have very useful links (you can check the tool-tips).*
- The contrast setting isn't exposed in the sculpt toolbar, so view the texture in the properties panel...
- In the properties button select the Texture context.

View File

@@ -18,7 +18,7 @@ amongst our own scripts and make it easier to use python scripts from other proj
Using our style guide for your own scripts makes it easier if you eventually want to contribute them to blender.
This style guide is known as pep8 and can be found `here <https://www.python.org/dev/peps/pep-0008/>`_
This style guide is known as pep8 and can be found `here <http://www.python.org/dev/peps/pep-0008>`_
A brief listing of pep8 criteria.
@@ -316,7 +316,7 @@ use to join a list of strings (the list may be temporary). In the following exam
Join is fastest on many strings,
`string formatting <https://wiki.blender.org/index.php/Dev:Source/Modeling/BMesh/Design>`__
`string formatting <http://docs.python.org/py3k/library/string.html#string-formatting>`__
is quite fast too (better for converting data types). String arithmetic is slowest.

View File

@@ -1,4 +1,3 @@
*******
Gotchas
*******
@@ -39,6 +38,7 @@ but some operators are more picky about when they run.
In most cases you can figure out what context an operator needs
simply be seeing how it's used in Blender and thinking about what it does.
Unfortunately if you're still stuck - the only way to **really** know
whats going on is to read the source code for the poll function and see what its checking.
@@ -82,6 +82,7 @@ it should be reported to the bug tracker.
Stale Data
==========
No updates after setting values
-------------------------------
@@ -173,8 +174,8 @@ In this situation you can...
.. _info_gotcha_mesh_faces:
N-Gons and Tessellation Faces
=============================
NGons and Tessellation Faces
============================
Since 2.63 NGons are supported, this adds some complexity
since in some cases you need to access triangles/quads still (some exporters for example).
@@ -508,7 +509,7 @@ Unicode Problems
Python supports many different encodings so there is nothing stopping you from
writing a script in ``latin1`` or ``iso-8859-15``.
See `pep-0263 <https://www.python.org/dev/peps/pep-0263/>`_
See `pep-0263 <http://www.python.org/dev/peps/pep-0263/>`_
However this complicates matters for Blender's Python API because ``.blend`` files don't have an explicit encoding.
@@ -656,7 +657,7 @@ Here are some general hints to avoid running into these problems.
.. note::
To find the line of your script that crashes you can use the ``faulthandler`` module.
See the `faulthandler docs <https://docs.python.org/dev/library/faulthandler.html>`_.
See `faulthandler docs <http://docs.python.org/dev/library/faulthandler.html>`_.
While the crash may be in Blenders C/C++ code,
this can help a lot to track down the area of the script that causes the crash.

View File

@@ -19,7 +19,7 @@ This is a typical Python environment so tutorials on how to write Python scripts
will work running the scripts in Blender too.
Blender provides the :mod:`bpy` module to the Python interpreter.
This module can be imported in a script and gives access to Blender data, classes, and functions.
Scripts that deal with Blender data will need to import this module.
Scripts that deal with Blender data will need to import this module.
Here is a simple example of moving a vertex of the object named **Cube**:
@@ -43,7 +43,8 @@ scene manipulation, automation, defining your own toolset and customization.
On startup Blender scans the ``scripts/startup/`` directory for Python modules and imports them.
The exact location of this directory depends on your installation.
See the :ref:`directory layout docs <blender_manual:getting-started_installing-config-directories>`.
`See the directory layout docs
<https://www.blender.org/manual/getting_started/installing_blender/directorylayout.html>`__
Script Loading
@@ -80,7 +81,7 @@ To run as modules:
Add-ons
-------
------
Some of Blenders functionality is best kept optional,
alongside scripts loaded at startup we have add-ons which are kept in their own directory ``scripts/addons``,
@@ -91,7 +92,7 @@ variable which Blender uses to read metadata such as name, author, category and
The User Preferences add-on listing uses **bl_info** to display information about each add-on.
`See Add-ons <https://wiki.blender.org/index.php/Dev:Py/Scripts/Guidelines/Addons>`__
`See Add-ons <http://wiki.blender.org/index.php/Dev:2.5/Py/Scripts/Guidelines/Addons>`__
for details on the ``bl_info`` dictionary.
@@ -213,7 +214,7 @@ A simple Blender/Python module can look like this:
bpy.utils.register_class(SimpleOperator)
def unregister():
bpy.utils.unregister_class(SimpleOperator)
bpy.utils.unregister_class(SimpleOperator)
if __name__ == "__main__":
register()
@@ -327,7 +328,7 @@ Say you want to store material settings for a custom engine.
.. note::
*The class must be registered before being used in a property, failing to do so will raise an error:*
``ValueError: bpy_struct "Material" registration error: my_custom_props could not register``
@@ -429,3 +430,4 @@ Calling these operators:
>>> bpy.ops.object.operator_2()
Hello World OBJECT_OT_operator_2
{'FINISHED'}

View File

@@ -51,7 +51,8 @@ A quick list of helpful things to know before starting:
| ``scripts/startup/bl_operators`` for operators.
Exact location depends on platform, see:
:ref:`Configuration and Data Paths <blender_manual:getting-started_installing-config-directories>`.
`Configuration and Data Paths
<https://www.blender.org/manual/getting_started/installing_blender/directorylayout.html>`__.
Running Scripts

View File

@@ -27,7 +27,7 @@ There are 3 main uses for the terminal, these are:
.. note::
For Linux and macOS users this means starting the terminal first, then running Blender from within it.
For Linux and OSX users this means starting the terminal first, then running Blender from within it.
On Windows the terminal can be enabled from the help menu.
@@ -306,7 +306,7 @@ Advantages include:
This is marked advanced because to run Blender as a Python module requires a special build option.
For instructions on building see
`Building Blender as a Python module <https://wiki.blender.org/index.php/User:Ideasman42/BlenderAsPyModule>`_
`Building Blender as a Python module <http://wiki.blender.org/index.php/User:Ideasman42/BlenderAsPyModule>`_
Python Safety (Build Option)

View File

@@ -121,8 +121,14 @@ Add the following script to the text editor in Blender.
obj.location.x += 1.0
Click the :ref:`Run Script button <blender_manual:editors-text-run-script>`,
all objects in the active scene are moved by 1.0 Blender unit.
.. image:: run_script.png
:width: 924px
:align: center
:height: 574px
:alt: Run Script button
Click the Run Script button, all objects in the active scene are moved by 1.0 Blender unit.
Next we will make this script into an add-on.
Write the Add-on (Simple)
@@ -232,7 +238,7 @@ if you want it to be enabled on restart, press *Save as Default*.
print(addon_utils.paths())
More is written on this topic here:
:ref:`Directory Layout <blender_manual:getting-started_installing-config-directories>`.
`Directory Layout <https://www.blender.org/manual/getting_started/installing_blender/directorylayout.html>`_
Your Second Add-on
@@ -630,6 +636,6 @@ Here are some sites you might like to check on after completing this tutorial.
*Great info for those who are still learning Python.*
- `Blender Development (Wiki) <https://wiki.blender.org/index.php/Dev:Contents>`_ -
*Blender Development, general information and helpful links.*
- `Blender Artists (Coding Section) <https://blenderartists.org/forum/forumdisplay.php?47-Coding>`_ -
- `Blender Artists (Coding Section) <http://blenderartists.org/forum/forumdisplay.php?47-Coding>`_ -
*forum where people ask Python development questions*

View File

@@ -1565,9 +1565,9 @@ def pyrna2sphinx(basepath):
# operators
def write_ops():
API_BASEURL = "https://developer.blender.org/diffusion/B/browse/master/release/scripts "
API_BASEURL_ADDON = "https://developer.blender.org/diffusion/BA"
API_BASEURL_ADDON_CONTRIB = "https://developer.blender.org/diffusion/BAC"
API_BASEURL = "https://developer.blender.org/diffusion/B/browse/master/release/scripts/ "
API_BASEURL_ADDON = "https://developer.blender.org/diffusion/BA/"
API_BASEURL_ADDON_CONTRIB = "https://developer.blender.org/diffusion/BAC/"
op_modules = {}
for op in ops.values():
@@ -1632,9 +1632,6 @@ def write_sphinx_conf_py(basepath):
file = open(filepath, "w", encoding="utf-8")
fw = file.write
fw("import sys, os\n\n")
fw("extensions = ['sphinx.ext.intersphinx']\n\n")
fw("intersphinx_mapping = {'blender_manual': ('https://docs.blender.org/manual/en/dev/', None)}\n\n")
fw("project = 'Blender'\n")
# fw("master_doc = 'index'\n")
fw("copyright = u'Blender Foundation'\n")
@@ -1651,16 +1648,11 @@ def write_sphinx_conf_py(basepath):
# not helpful since the source is generated, adds to upload size.
fw("html_copy_source = False\n")
fw("html_show_sphinx = False\n")
fw("html_split_index = True\n")
fw("\n")
# needed for latex, pdf gen
fw("latex_elements = {\n")
fw(" 'papersize': 'a4paper',\n")
fw("}\n\n")
fw("latex_documents = [ ('contents', 'contents.tex', 'Blender Index', 'Blender Foundation', 'manual'), ]\n")
fw("latex_paper_size = 'a4paper'\n")
file.close()

View File

@@ -41,9 +41,9 @@ import tempfile
import zipfile
DEFAULT_RSYNC_SERVER = "docs.blender.org"
DEFAULT_RSYNC_SERVER = "www.blender.org"
DEFAULT_RSYNC_ROOT = "/api/"
DEFAULT_SYMLINK_ROOT = "/data/www/vhosts/docs.blender.org/api"
DEFAULT_SYMLINK_ROOT = "/data/www/vhosts/www.blender.org/api"
def argparse_create():
@@ -142,11 +142,8 @@ def main():
zip_name = "blender_python_reference_%s" % blenver_zip # We can't use 'release' postfix here...
zip_path = os.path.join(args.mirror_dir, zip_name)
with zipfile.ZipFile(zip_path, 'w') as zf:
for dirname, _, filenames in os.walk(api_dir):
for filename in filenames:
filepath = os.path.join(dirname, filename)
zip_filepath = os.path.join(zip_name, os.path.relpath(filepath, api_dir))
zf.write(filepath, arcname=zip_filepath)
for de in os.scandir(api_dir):
zf.write(de.path, arcname=os.path.join(zip_name, de.name))
os.rename(zip_path, os.path.join(api_dir, "%s.zip" % zip_name))
# VII) Create symlinks and html redirects.

View File

@@ -77,7 +77,7 @@ namespace std {
void resize(size_type new_size)
{ resize(new_size, T()); }
#if defined(_VECTOR_) && (_MSC_VER<1910)
#if defined(_VECTOR_)
// workaround MSVC std::vector implementation
void resize(size_type new_size, const value_type& x)
{
@@ -110,7 +110,7 @@ namespace std {
vector_base::insert(vector_base::end(), new_size - vector_base::size(), x);
}
#else
// either GCC 4.1, MSVC2017 or non-GCC
// either GCC 4.1 or non-GCC
// default implementation which should always work.
void resize(size_type new_size, const value_type& x)
{

View File

@@ -73,12 +73,10 @@ set(SRC
internal/ceres/file.cc
internal/ceres/generated/partitioned_matrix_view_d_d_d.cc
internal/ceres/generated/schur_eliminator_d_d_d.cc
internal/ceres/gradient_checker.cc
internal/ceres/gradient_checking_cost_function.cc
internal/ceres/gradient_problem.cc
internal/ceres/gradient_problem_solver.cc
internal/ceres/implicit_schur_complement.cc
internal/ceres/is_close.cc
internal/ceres/iterative_schur_complement_solver.cc
internal/ceres/lapack.cc
internal/ceres/levenberg_marquardt_strategy.cc
@@ -118,7 +116,6 @@ set(SRC
internal/ceres/triplet_sparse_matrix.cc
internal/ceres/trust_region_minimizer.cc
internal/ceres/trust_region_preprocessor.cc
internal/ceres/trust_region_step_evaluator.cc
internal/ceres/trust_region_strategy.cc
internal/ceres/types.cc
internal/ceres/wall_time.cc
@@ -207,7 +204,6 @@ set(SRC
internal/ceres/householder_vector.h
internal/ceres/implicit_schur_complement.h
internal/ceres/integral_types.h
internal/ceres/is_close.h
internal/ceres/iterative_schur_complement_solver.h
internal/ceres/lapack.h
internal/ceres/levenberg_marquardt_strategy.h
@@ -252,7 +248,6 @@ set(SRC
internal/ceres/triplet_sparse_matrix.h
internal/ceres/trust_region_minimizer.h
internal/ceres/trust_region_preprocessor.h
internal/ceres/trust_region_step_evaluator.h
internal/ceres/trust_region_strategy.h
internal/ceres/visibility_based_preconditioner.h
internal/ceres/wall_time.h

1091
extern/ceres/ChangeLog vendored

File diff suppressed because it is too large Load Diff

View File

@@ -173,5 +173,26 @@ if(WITH_OPENMP)
)
endif()
TEST_UNORDERED_MAP_SUPPORT()
if(HAVE_STD_UNORDERED_MAP_HEADER)
if(HAVE_UNORDERED_MAP_IN_STD_NAMESPACE)
add_definitions(-DCERES_STD_UNORDERED_MAP)
else()
if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
add_definitions(-DCERES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
else()
add_definitions(-DCERES_NO_UNORDERED_MAP)
message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)")
endif()
endif()
else()
if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
add_definitions(-DCERES_TR1_UNORDERED_MAP)
else()
add_definitions(-DCERES_NO_UNORDERED_MAP)
message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)")
endif()
endif()
blender_add_lib(extern_ceres "\${SRC}" "\${INC}" "\${INC_SYS}")
EOF

View File

@@ -149,7 +149,6 @@ internal/ceres/generated/schur_eliminator_4_4_d.cc
internal/ceres/generated/schur_eliminator_d_d_d.cc
internal/ceres/generate_eliminator_specialization.py
internal/ceres/generate_partitioned_matrix_view_specializations.py
internal/ceres/gradient_checker.cc
internal/ceres/gradient_checking_cost_function.cc
internal/ceres/gradient_checking_cost_function.h
internal/ceres/gradient_problem.cc
@@ -161,8 +160,6 @@ internal/ceres/householder_vector.h
internal/ceres/implicit_schur_complement.cc
internal/ceres/implicit_schur_complement.h
internal/ceres/integral_types.h
internal/ceres/is_close.cc
internal/ceres/is_close.h
internal/ceres/iterative_schur_complement_solver.cc
internal/ceres/iterative_schur_complement_solver.h
internal/ceres/lapack.cc
@@ -246,8 +243,6 @@ internal/ceres/trust_region_minimizer.cc
internal/ceres/trust_region_minimizer.h
internal/ceres/trust_region_preprocessor.cc
internal/ceres/trust_region_preprocessor.h
internal/ceres/trust_region_step_evaluator.cc
internal/ceres/trust_region_step_evaluator.h
internal/ceres/trust_region_strategy.cc
internal/ceres/trust_region_strategy.h
internal/ceres/types.cc

View File

@@ -130,8 +130,7 @@ class CostFunctionToFunctor {
const int num_parameter_blocks =
(N0 > 0) + (N1 > 0) + (N2 > 0) + (N3 > 0) + (N4 > 0) +
(N5 > 0) + (N6 > 0) + (N7 > 0) + (N8 > 0) + (N9 > 0);
CHECK_EQ(static_cast<int>(parameter_block_sizes.size()),
num_parameter_blocks);
CHECK_EQ(parameter_block_sizes.size(), num_parameter_blocks);
CHECK_EQ(N0, parameter_block_sizes[0]);
if (parameter_block_sizes.size() > 1) CHECK_EQ(N1, parameter_block_sizes[1]); // NOLINT

View File

@@ -357,28 +357,6 @@ class CERES_EXPORT Covariance {
const double*> >& covariance_blocks,
Problem* problem);
// Compute a part of the covariance matrix.
//
// The vector parameter_blocks contains the parameter blocks that
// are used for computing the covariance matrix. From this vector
// all covariance pairs are generated. This allows the covariance
// estimation algorithm to only compute and store these blocks.
//
// parameter_blocks cannot contain duplicates. Bad things will
// happen if they do.
//
// Note that the list of covariance_blocks is only used to determine
// what parts of the covariance matrix are computed. The full
// Jacobian is used to do the computation, i.e. they do not have an
// impact on what part of the Jacobian is used for computation.
//
// The return value indicates the success or failure of the
// covariance computation. Please see the documentation for
// Covariance::Options for more on the conditions under which this
// function returns false.
bool Compute(const std::vector<const double*>& parameter_blocks,
Problem* problem);
// Return the block of the cross-covariance matrix corresponding to
// parameter_block1 and parameter_block2.
//
@@ -416,40 +394,6 @@ class CERES_EXPORT Covariance {
const double* parameter_block2,
double* covariance_block) const;
// Return the covariance matrix corresponding to all parameter_blocks.
//
// Compute must be called before calling GetCovarianceMatrix and all
// parameter_blocks must have been present in the vector
// parameter_blocks when Compute was called. Otherwise
// GetCovarianceMatrix returns false.
//
// covariance_matrix must point to a memory location that can store
// the size of the covariance matrix. The covariance matrix will be
// a square matrix whose row and column count is equal to the sum of
// the sizes of the individual parameter blocks. The covariance
// matrix will be a row-major matrix.
bool GetCovarianceMatrix(const std::vector<const double *> &parameter_blocks,
double *covariance_matrix);
// Return the covariance matrix corresponding to parameter_blocks
// in the tangent space if a local parameterization is associated
// with one of the parameter blocks else returns the covariance
// matrix in the ambient space.
//
// Compute must be called before calling GetCovarianceMatrix and all
// parameter_blocks must have been present in the vector
// parameters_blocks when Compute was called. Otherwise
// GetCovarianceMatrix returns false.
//
// covariance_matrix must point to a memory location that can store
// the size of the covariance matrix. The covariance matrix will be
// a square matrix whose row and column count is equal to the sum of
// the sizes of the tangent spaces of the individual parameter
// blocks. The covariance matrix will be a row-major matrix.
bool GetCovarianceMatrixInTangentSpace(
const std::vector<const double*>& parameter_blocks,
double* covariance_matrix);
private:
internal::scoped_ptr<internal::CovarianceImpl> impl_;
};

View File

@@ -85,6 +85,22 @@ class DynamicNumericDiffCostFunction : public CostFunction {
options_(options) {
}
// Deprecated. New users should avoid using this constructor. Instead, use the
// constructor with NumericDiffOptions.
DynamicNumericDiffCostFunction(
const CostFunctor* functor,
Ownership ownership,
double relative_step_size)
: functor_(functor),
ownership_(ownership),
options_() {
LOG(WARNING) << "This constructor is deprecated and will be removed in "
"a future version. Please use the NumericDiffOptions "
"constructor instead.";
options_.relative_step_size = relative_step_size;
}
virtual ~DynamicNumericDiffCostFunction() {
if (ownership_ != TAKE_OWNERSHIP) {
functor_.release();
@@ -122,19 +138,19 @@ class DynamicNumericDiffCostFunction : public CostFunction {
std::vector<double> parameters_copy(parameters_size);
std::vector<double*> parameters_references_copy(block_sizes.size());
parameters_references_copy[0] = &parameters_copy[0];
for (size_t block = 1; block < block_sizes.size(); ++block) {
for (int block = 1; block < block_sizes.size(); ++block) {
parameters_references_copy[block] = parameters_references_copy[block - 1]
+ block_sizes[block - 1];
}
// Copy the parameters into the local temp space.
for (size_t block = 0; block < block_sizes.size(); ++block) {
for (int block = 0; block < block_sizes.size(); ++block) {
memcpy(parameters_references_copy[block],
parameters[block],
block_sizes[block] * sizeof(*parameters[block]));
}
for (size_t block = 0; block < block_sizes.size(); ++block) {
for (int block = 0; block < block_sizes.size(); ++block) {
if (jacobians[block] != NULL &&
!NumericDiff<CostFunctor, method, DYNAMIC,
DYNAMIC, DYNAMIC, DYNAMIC, DYNAMIC, DYNAMIC,

View File

@@ -27,121 +27,194 @@
// POSSIBILITY OF SUCH DAMAGE.
// Copyright 2007 Google Inc. All Rights Reserved.
//
// Authors: wjr@google.com (William Rucklidge),
// keir@google.com (Keir Mierle),
// dgossow@google.com (David Gossow)
// Author: wjr@google.com (William Rucklidge)
//
// This file contains a class that exercises a cost function, to make sure
// that it is computing reasonable derivatives. It compares the Jacobians
// computed by the cost function with those obtained by finite
// differences.
#ifndef CERES_PUBLIC_GRADIENT_CHECKER_H_
#define CERES_PUBLIC_GRADIENT_CHECKER_H_
#include <cstddef>
#include <algorithm>
#include <vector>
#include <string>
#include "ceres/cost_function.h"
#include "ceres/dynamic_numeric_diff_cost_function.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/fixed_array.h"
#include "ceres/internal/macros.h"
#include "ceres/internal/scoped_ptr.h"
#include "ceres/local_parameterization.h"
#include "ceres/numeric_diff_cost_function.h"
#include "glog/logging.h"
namespace ceres {
// GradientChecker compares the Jacobians returned by a cost function against
// derivatives estimated using finite differencing.
// An object that exercises a cost function, to compare the answers that it
// gives with derivatives estimated using finite differencing.
//
// The condition enforced is that
//
// (J_actual(i, j) - J_numeric(i, j))
// ------------------------------------ < relative_precision
// max(J_actual(i, j), J_numeric(i, j))
//
// where J_actual(i, j) is the jacobian as computed by the supplied cost
// function (by the user) multiplied by the local parameterization Jacobian
// and J_numeric is the jacobian as computed by finite differences, multiplied
// by the local parameterization Jacobian as well.
// The only likely usage of this is for testing.
//
// How to use: Fill in an array of pointers to parameter blocks for your
// CostFunction, and then call Probe(). Check that the return value is 'true'.
// CostFunction, and then call Probe(). Check that the return value is
// 'true'. See prober_test.cc for an example.
//
// This is templated similarly to NumericDiffCostFunction, as it internally
// uses that.
template <typename CostFunctionToProbe,
int M = 0, int N0 = 0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0>
class GradientChecker {
public:
// This will not take ownership of the cost function or local
// parameterizations.
//
// function: The cost function to probe.
// local_parameterization: A vector of local parameterizations for each
// parameter. May be NULL or contain NULL pointers to indicate that the
// respective parameter does not have a local parameterization.
// options: Options to use for numerical differentiation.
GradientChecker(
const CostFunction* function,
const std::vector<const LocalParameterization*>* local_parameterizations,
const NumericDiffOptions& options);
// Here we stash some results from the probe, for later
// inspection.
struct GradientCheckResults {
// Computed cost.
Vector cost;
// Contains results from a call to Probe for later inspection.
struct ProbeResults {
// The return value of the cost function.
bool return_value;
// Computed residual vector.
Vector residuals;
// The sizes of the Jacobians below are dictated by the cost function's
// parameter block size and residual block sizes. If a parameter block
// has a local parameterization associated with it, the size of the "local"
// Jacobian will be determined by the local parameterization dimension and
// residual block size, otherwise it will be identical to the regular
// Jacobian.
// The sizes of these matrices are dictated by the cost function's
// parameter and residual block sizes. Each vector's length will
// term->parameter_block_sizes().size(), and each matrix is the
// Jacobian of the residual with respect to the corresponding parameter
// block.
// Derivatives as computed by the cost function.
std::vector<Matrix> jacobians;
std::vector<Matrix> term_jacobians;
// Derivatives as computed by the cost function in local space.
std::vector<Matrix> local_jacobians;
// Derivatives as computed by finite differencing.
std::vector<Matrix> finite_difference_jacobians;
// Derivatives as computed by nuerical differentiation in local space.
std::vector<Matrix> numeric_jacobians;
// Derivatives as computed by nuerical differentiation in local space.
std::vector<Matrix> local_numeric_jacobians;
// Contains the maximum relative error found in the local Jacobians.
double maximum_relative_error;
// If an error was detected, this will contain a detailed description of
// that error.
std::string error_log;
// Infinity-norm of term_jacobians - finite_difference_jacobians.
double error_jacobians;
};
// Call the cost function, compute alternative Jacobians using finite
// differencing and compare results. If local parameterizations are given,
// the Jacobians will be multiplied by the local parameterization Jacobians
// before performing the check, which effectively means that all errors along
// the null space of the local parameterization will be ignored.
// Returns false if the Jacobians don't match, the cost function return false,
// or if the cost function returns different residual when called with a
// Jacobian output argument vs. calling it without. Otherwise returns true.
// Checks the Jacobian computed by a cost function.
//
// parameters: The parameter values at which to probe.
// relative_precision: A threshold for the relative difference between the
// Jacobians. If the Jacobians differ by more than this amount, then the
// probe fails.
// results: On return, the Jacobians (and other information) will be stored
// here. May be NULL.
// probe_point: The parameter values at which to probe.
// error_tolerance: A threshold for the infinity-norm difference
// between the Jacobians. If the Jacobians differ by more than
// this amount, then the probe fails.
//
// term: The cost function to test. Not retained after this call returns.
//
// results: On return, the two Jacobians (and other information)
// will be stored here. May be NULL.
//
// Returns true if no problems are detected and the difference between the
// Jacobians is less than error_tolerance.
bool Probe(double const* const* parameters,
double relative_precision,
ProbeResults* results) const;
static bool Probe(double const* const* probe_point,
double error_tolerance,
CostFunctionToProbe *term,
GradientCheckResults* results) {
CHECK_NOTNULL(probe_point);
CHECK_NOTNULL(term);
LOG(INFO) << "-------------------- Starting Probe() --------------------";
// We need a GradientCheckeresults, whether or not they supplied one.
internal::scoped_ptr<GradientCheckResults> owned_results;
if (results == NULL) {
owned_results.reset(new GradientCheckResults);
results = owned_results.get();
}
// Do a consistency check between the term and the template parameters.
CHECK_EQ(M, term->num_residuals());
const int num_residuals = M;
const std::vector<int32>& block_sizes = term->parameter_block_sizes();
const int num_blocks = block_sizes.size();
CHECK_LE(num_blocks, 5) << "Unable to test functions that take more "
<< "than 5 parameter blocks";
if (N0) {
CHECK_EQ(N0, block_sizes[0]);
CHECK_GE(num_blocks, 1);
} else {
CHECK_LT(num_blocks, 1);
}
if (N1) {
CHECK_EQ(N1, block_sizes[1]);
CHECK_GE(num_blocks, 2);
} else {
CHECK_LT(num_blocks, 2);
}
if (N2) {
CHECK_EQ(N2, block_sizes[2]);
CHECK_GE(num_blocks, 3);
} else {
CHECK_LT(num_blocks, 3);
}
if (N3) {
CHECK_EQ(N3, block_sizes[3]);
CHECK_GE(num_blocks, 4);
} else {
CHECK_LT(num_blocks, 4);
}
if (N4) {
CHECK_EQ(N4, block_sizes[4]);
CHECK_GE(num_blocks, 5);
} else {
CHECK_LT(num_blocks, 5);
}
results->term_jacobians.clear();
results->term_jacobians.resize(num_blocks);
results->finite_difference_jacobians.clear();
results->finite_difference_jacobians.resize(num_blocks);
internal::FixedArray<double*> term_jacobian_pointers(num_blocks);
internal::FixedArray<double*>
finite_difference_jacobian_pointers(num_blocks);
for (int i = 0; i < num_blocks; i++) {
results->term_jacobians[i].resize(num_residuals, block_sizes[i]);
term_jacobian_pointers[i] = results->term_jacobians[i].data();
results->finite_difference_jacobians[i].resize(
num_residuals, block_sizes[i]);
finite_difference_jacobian_pointers[i] =
results->finite_difference_jacobians[i].data();
}
results->cost.resize(num_residuals, 1);
CHECK(term->Evaluate(probe_point, results->cost.data(),
term_jacobian_pointers.get()));
NumericDiffCostFunction<CostFunctionToProbe, CENTRAL, M, N0, N1, N2, N3, N4>
numeric_term(term, DO_NOT_TAKE_OWNERSHIP);
CHECK(numeric_term.Evaluate(probe_point, results->cost.data(),
finite_difference_jacobian_pointers.get()));
results->error_jacobians = 0;
for (int i = 0; i < num_blocks; i++) {
Matrix jacobian_difference = results->term_jacobians[i] -
results->finite_difference_jacobians[i];
results->error_jacobians =
std::max(results->error_jacobians,
jacobian_difference.lpNorm<Eigen::Infinity>());
}
LOG(INFO) << "========== term-computed derivatives ==========";
for (int i = 0; i < num_blocks; i++) {
LOG(INFO) << "term_computed block " << i;
LOG(INFO) << "\n" << results->term_jacobians[i];
}
LOG(INFO) << "========== finite-difference derivatives ==========";
for (int i = 0; i < num_blocks; i++) {
LOG(INFO) << "finite_difference block " << i;
LOG(INFO) << "\n" << results->finite_difference_jacobians[i];
}
LOG(INFO) << "========== difference ==========";
for (int i = 0; i < num_blocks; i++) {
LOG(INFO) << "difference block " << i;
LOG(INFO) << (results->term_jacobians[i] -
results->finite_difference_jacobians[i]);
}
LOG(INFO) << "||difference|| = " << results->error_jacobians;
return results->error_jacobians < error_tolerance;
}
private:
CERES_DISALLOW_IMPLICIT_CONSTRUCTORS(GradientChecker);
std::vector<const LocalParameterization*> local_parameterizations_;
const CostFunction* function_;
internal::scoped_ptr<CostFunction> finite_diff_cost_function_;
};
} // namespace ceres

View File

@@ -33,8 +33,9 @@
// This file needs to compile as c code.
#ifdef __cplusplus
#include <cstddef>
#include "ceres/internal/config.h"
#if defined(CERES_TR1_MEMORY_HEADER)
#include <tr1/memory>
#else
@@ -49,25 +50,6 @@ using std::tr1::shared_ptr;
using std::shared_ptr;
#endif
// We allocate some Eigen objects on the stack and other places they
// might not be aligned to 16-byte boundaries. If we have C++11, we
// can specify their alignment anyway, and thus can safely enable
// vectorization on those matrices; in C++99, we are out of luck. Figure out
// what case we're in and write macros that do the right thing.
#ifdef CERES_USE_CXX11
namespace port_constants {
static constexpr size_t kMaxAlignBytes =
// Work around a GCC 4.8 bug
// (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56019) where
// std::max_align_t is misplaced.
#if defined (__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 8
alignof(::max_align_t);
#else
alignof(std::max_align_t);
#endif
} // namespace port_constants
#endif
} // namespace ceres
#endif // __cplusplus

View File

@@ -69,7 +69,7 @@ struct CERES_EXPORT IterationSummary {
// Step was numerically valid, i.e., all values are finite and the
// step reduces the value of the linearized model.
//
// Note: step_is_valid is always true when iteration = 0.
// Note: step_is_valid is false when iteration = 0.
bool step_is_valid;
// Step did not reduce the value of the objective function
@@ -77,7 +77,7 @@ struct CERES_EXPORT IterationSummary {
// acceptance criterion used by the non-monotonic trust region
// algorithm.
//
// Note: step_is_nonmonotonic is always false when iteration = 0;
// Note: step_is_nonmonotonic is false when iteration = 0;
bool step_is_nonmonotonic;
// Whether or not the minimizer accepted this step or not. If the
@@ -89,7 +89,7 @@ struct CERES_EXPORT IterationSummary {
// relative decrease is not sufficient, the algorithm may accept the
// step and the step is declared successful.
//
// Note: step_is_successful is always true when iteration = 0.
// Note: step_is_successful is false when iteration = 0.
bool step_is_successful;
// Value of the objective function.

View File

@@ -164,7 +164,6 @@
#include "Eigen/Core"
#include "ceres/fpclassify.h"
#include "ceres/internal/port.h"
namespace ceres {
@@ -228,23 +227,21 @@ struct Jet {
T a;
// The infinitesimal part.
// We allocate Jets on the stack and other places they
// might not be aligned to 16-byte boundaries. If we have C++11, we
// can specify their alignment anyway, and thus can safely enable
// vectorization on those matrices; in C++99, we are out of luck. Figure out
// what case we're in and do the right thing.
#ifndef CERES_USE_CXX11
// fall back to safe version:
//
// Note the Eigen::DontAlign bit is needed here because this object
// gets allocated on the stack and as part of other arrays and
// structs. Forcing the right alignment there is the source of much
// pain and suffering. Even if that works, passing Jets around to
// functions by value has problems because the C++ ABI does not
// guarantee alignment for function arguments.
//
// Setting the DontAlign bit prevents Eigen from using SSE for the
// various operations on Jets. This is a small performance penalty
// since the AutoDiff code will still expose much of the code as
// statically sized loops to the compiler. But given the subtle
// issues that arise due to alignment, especially when dealing with
// multiple platforms, it seems to be a trade off worth making.
Eigen::Matrix<T, N, 1, Eigen::DontAlign> v;
#else
static constexpr bool kShouldAlignMatrix =
16 <= ::ceres::port_constants::kMaxAlignBytes;
static constexpr int kAlignHint = kShouldAlignMatrix ?
Eigen::AutoAlign : Eigen::DontAlign;
static constexpr size_t kAlignment = kShouldAlignMatrix ? 16 : 1;
alignas(kAlignment) Eigen::Matrix<T, N, 1, kAlignHint> v;
#endif
};
// Unary +
@@ -391,8 +388,6 @@ inline double atan (double x) { return std::atan(x); }
inline double sinh (double x) { return std::sinh(x); }
inline double cosh (double x) { return std::cosh(x); }
inline double tanh (double x) { return std::tanh(x); }
inline double floor (double x) { return std::floor(x); }
inline double ceil (double x) { return std::ceil(x); }
inline double pow (double x, double y) { return std::pow(x, y); }
inline double atan2(double y, double x) { return std::atan2(y, x); }
@@ -487,51 +482,10 @@ Jet<T, N> tanh(const Jet<T, N>& f) {
return Jet<T, N>(tanh_a, tmp * f.v);
}
// The floor function should be used with extreme care as this operation will
// result in a zero derivative which provides no information to the solver.
//
// floor(a + h) ~= floor(a) + 0
template <typename T, int N> inline
Jet<T, N> floor(const Jet<T, N>& f) {
return Jet<T, N>(floor(f.a));
}
// The ceil function should be used with extreme care as this operation will
// result in a zero derivative which provides no information to the solver.
//
// ceil(a + h) ~= ceil(a) + 0
template <typename T, int N> inline
Jet<T, N> ceil(const Jet<T, N>& f) {
return Jet<T, N>(ceil(f.a));
}
// Bessel functions of the first kind with integer order equal to 0, 1, n.
//
// Microsoft has deprecated the j[0,1,n]() POSIX Bessel functions in favour of
// _j[0,1,n](). Where available on MSVC, use _j[0,1,n]() to avoid deprecated
// function errors in client code (the specific warning is suppressed when
// Ceres itself is built).
inline double BesselJ0(double x) {
#if defined(_MSC_VER) && defined(_j0)
return _j0(x);
#else
return j0(x);
#endif
}
inline double BesselJ1(double x) {
#if defined(_MSC_VER) && defined(_j1)
return _j1(x);
#else
return j1(x);
#endif
}
inline double BesselJn(int n, double x) {
#if defined(_MSC_VER) && defined(_jn)
return _jn(n, x);
#else
return jn(n, x);
#endif
}
inline double BesselJ0(double x) { return j0(x); }
inline double BesselJ1(double x) { return j1(x); }
inline double BesselJn(int n, double x) { return jn(n, x); }
// For the formulae of the derivatives of the Bessel functions see the book:
// Olver, Lozier, Boisvert, Clark, NIST Handbook of Mathematical Functions,
@@ -789,15 +743,7 @@ template<typename T, int N> inline Jet<T, N> ei_pow (const Jet<T, N>& x,
// strange compile errors.
template <typename T, int N>
inline std::ostream &operator<<(std::ostream &s, const Jet<T, N>& z) {
s << "[" << z.a << " ; ";
for (int i = 0; i < N; ++i) {
s << z.v[i];
if (i != N - 1) {
s << ", ";
}
}
s << "]";
return s;
return s << "[" << z.a << " ; " << z.v.transpose() << "]";
}
} // namespace ceres
@@ -811,7 +757,6 @@ struct NumTraits<ceres::Jet<T, N> > {
typedef ceres::Jet<T, N> Real;
typedef ceres::Jet<T, N> NonInteger;
typedef ceres::Jet<T, N> Nested;
typedef ceres::Jet<T, N> Literal;
static typename ceres::Jet<T, N> dummy_precision() {
return ceres::Jet<T, N>(1e-12);
@@ -832,21 +777,6 @@ struct NumTraits<ceres::Jet<T, N> > {
HasFloatingPoint = 1,
RequireInitialization = 1
};
template<bool Vectorized>
struct Div {
enum {
#if defined(EIGEN_VECTORIZE_AVX)
AVX = true,
#else
AVX = false,
#endif
// Assuming that for Jets, division is as expensive as
// multiplication.
Cost = 3
};
};
};
} // namespace Eigen

View File

@@ -211,28 +211,6 @@ class CERES_EXPORT QuaternionParameterization : public LocalParameterization {
virtual int LocalSize() const { return 3; }
};
// Implements the quaternion local parameterization for Eigen's representation
// of the quaternion. Eigen uses a different internal memory layout for the
// elements of the quaternion than what is commonly used. Specifically, Eigen
// stores the elements in memory as [x, y, z, w] where the real part is last
// whereas it is typically stored first. Note, when creating an Eigen quaternion
// through the constructor the elements are accepted in w, x, y, z order. Since
// Ceres operates on parameter blocks which are raw double pointers this
// difference is important and requires a different parameterization.
//
// Plus(x, delta) = [sin(|delta|) delta / |delta|, cos(|delta|)] * x
// with * being the quaternion multiplication operator.
class EigenQuaternionParameterization : public ceres::LocalParameterization {
public:
virtual ~EigenQuaternionParameterization() {}
virtual bool Plus(const double* x,
const double* delta,
double* x_plus_delta) const;
virtual bool ComputeJacobian(const double* x,
double* jacobian) const;
virtual int GlobalSize() const { return 4; }
virtual int LocalSize() const { return 3; }
};
// This provides a parameterization for homogeneous vectors which are commonly
// used in Structure for Motion problems. One example where they are used is

View File

@@ -206,6 +206,29 @@ class NumericDiffCostFunction
}
}
// Deprecated. New users should avoid using this constructor. Instead, use the
// constructor with NumericDiffOptions.
NumericDiffCostFunction(CostFunctor* functor,
Ownership ownership,
int num_residuals,
const double relative_step_size)
:functor_(functor),
ownership_(ownership),
options_() {
LOG(WARNING) << "This constructor is deprecated and will be removed in "
"a future version. Please use the NumericDiffOptions "
"constructor instead.";
if (kNumResiduals == DYNAMIC) {
SizedCostFunction<kNumResiduals,
N0, N1, N2, N3, N4,
N5, N6, N7, N8, N9>
::set_num_residuals(num_residuals);
}
options_.relative_step_size = relative_step_size;
}
~NumericDiffCostFunction() {
if (ownership_ != TAKE_OWNERSHIP) {
functor_.release();

View File

@@ -309,9 +309,6 @@ class CERES_EXPORT Problem {
// Allow the indicated parameter block to vary during optimization.
void SetParameterBlockVariable(double* values);
// Returns true if a parameter block is set constant, and false otherwise.
bool IsParameterBlockConstant(double* values) const;
// Set the local parameterization for one of the parameter blocks.
// The local_parameterization is owned by the Problem by default. It
// is acceptable to set the same parameterization for multiple
@@ -464,10 +461,6 @@ class CERES_EXPORT Problem {
// parameter block has a local parameterization, then it contributes
// "LocalSize" entries to the gradient vector (and the number of
// columns in the jacobian).
//
// Note 3: This function cannot be called while the problem is being
// solved, for example it cannot be called from an IterationCallback
// at the end of an iteration during a solve.
bool Evaluate(const EvaluateOptions& options,
double* cost,
std::vector<double>* residuals,

View File

@@ -48,6 +48,7 @@
#include <algorithm>
#include <cmath>
#include <limits>
#include "glog/logging.h"
namespace ceres {
@@ -417,6 +418,7 @@ template <typename T>
inline void EulerAnglesToRotationMatrix(const T* euler,
const int row_stride_parameter,
T* R) {
CHECK_EQ(row_stride_parameter, 3);
EulerAnglesToRotationMatrix(euler, RowMajorAdapter3x3(R));
}
@@ -494,6 +496,7 @@ void QuaternionToRotation(const T q[4],
QuaternionToScaledRotation(q, R);
T normalizer = q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3];
CHECK_NE(normalizer, T(0));
normalizer = T(1) / normalizer;
for (int i = 0; i < 3; ++i) {

View File

@@ -134,7 +134,7 @@ class CERES_EXPORT Solver {
trust_region_problem_dump_format_type = TEXTFILE;
check_gradients = false;
gradient_check_relative_precision = 1e-8;
gradient_check_numeric_derivative_relative_step_size = 1e-6;
numeric_derivative_relative_step_size = 1e-6;
update_state_every_iteration = false;
}
@@ -701,22 +701,12 @@ class CERES_EXPORT Solver {
// this number, then the jacobian for that cost term is dumped.
double gradient_check_relative_precision;
// WARNING: This option only applies to the to the numeric
// differentiation used for checking the user provided derivatives
// when when Solver::Options::check_gradients is true. If you are
// using NumericDiffCostFunction and are interested in changing
// the step size for numeric differentiation in your cost
// function, please have a look at
// include/ceres/numeric_diff_options.h.
// Relative shift used for taking numeric derivatives. For finite
// differencing, each dimension is evaluated at slightly shifted
// values; for the case of central difference, this is what gets
// evaluated:
//
// Relative shift used for taking numeric derivatives when
// Solver::Options::check_gradients is true.
//
// For finite differencing, each dimension is evaluated at
// slightly shifted values; for the case of central difference,
// this is what gets evaluated:
//
// delta = gradient_check_numeric_derivative_relative_step_size;
// delta = numeric_derivative_relative_step_size;
// f_initial = f(x)
// f_forward = f((1 + delta) * x)
// f_backward = f((1 - delta) * x)
@@ -733,7 +723,7 @@ class CERES_EXPORT Solver {
// theory a good choice is sqrt(eps) * x, which for doubles means
// about 1e-8 * x. However, I have found this number too
// optimistic. This number should be exposed for users to change.
double gradient_check_numeric_derivative_relative_step_size;
double numeric_derivative_relative_step_size;
// If true, the user's parameter blocks are updated at the end of
// every Minimizer iteration, otherwise they are updated when the
@@ -811,13 +801,6 @@ class CERES_EXPORT Solver {
// Number of times inner iterations were performed.
int num_inner_iteration_steps;
// Total number of iterations inside the line search algorithm
// across all invocations. We call these iterations "steps" to
// distinguish them from the outer iterations of the line search
// and trust region minimizer algorithms which call the line
// search algorithm as a subroutine.
int num_line_search_steps;
// All times reported below are wall times.
// When the user calls Solve, before the actual optimization

View File

@@ -32,7 +32,7 @@
#define CERES_PUBLIC_VERSION_H_
#define CERES_VERSION_MAJOR 1
#define CERES_VERSION_MINOR 12
#define CERES_VERSION_MINOR 11
#define CERES_VERSION_REVISION 0
// Classic CPP stringifcation; the extra level of indirection allows the

View File

@@ -46,7 +46,6 @@ namespace internal {
using std::make_pair;
using std::pair;
using std::vector;
using std::adjacent_find;
void CompressedRowJacobianWriter::PopulateJacobianRowAndColumnBlockVectors(
const Program* program, CompressedRowSparseMatrix* jacobian) {
@@ -141,21 +140,12 @@ SparseMatrix* CompressedRowJacobianWriter::CreateJacobian() const {
// Sort the parameters by their position in the state vector.
sort(parameter_indices.begin(), parameter_indices.end());
if (adjacent_find(parameter_indices.begin(), parameter_indices.end()) !=
parameter_indices.end()) {
std::string parameter_block_description;
for (int j = 0; j < num_parameter_blocks; ++j) {
ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
parameter_block_description +=
parameter_block->ToString() + "\n";
}
LOG(FATAL) << "Ceres internal error: "
<< "Duplicate parameter blocks detected in a cost function. "
<< "This should never happen. Please report this to "
<< "the Ceres developers.\n"
<< "Residual Block: " << residual_block->ToString() << "\n"
<< "Parameter Blocks: " << parameter_block_description;
}
CHECK(unique(parameter_indices.begin(), parameter_indices.end()) ==
parameter_indices.end())
<< "Ceres internal error: "
<< "Duplicate parameter blocks detected in a cost function. "
<< "This should never happen. Please report this to "
<< "the Ceres developers.";
// Update the row indices.
const int num_residuals = residual_block->NumResiduals();

View File

@@ -38,7 +38,6 @@
namespace ceres {
using std::make_pair;
using std::pair;
using std::vector;
@@ -55,12 +54,6 @@ bool Covariance::Compute(
return impl_->Compute(covariance_blocks, problem->problem_impl_.get());
}
bool Covariance::Compute(
const vector<const double*>& parameter_blocks,
Problem* problem) {
return impl_->Compute(parameter_blocks, problem->problem_impl_.get());
}
bool Covariance::GetCovarianceBlock(const double* parameter_block1,
const double* parameter_block2,
double* covariance_block) const {
@@ -80,20 +73,4 @@ bool Covariance::GetCovarianceBlockInTangentSpace(
covariance_block);
}
bool Covariance::GetCovarianceMatrix(
const vector<const double*>& parameter_blocks,
double* covariance_matrix) {
return impl_->GetCovarianceMatrixInTangentOrAmbientSpace(parameter_blocks,
true, // ambient
covariance_matrix);
}
bool Covariance::GetCovarianceMatrixInTangentSpace(
const std::vector<const double *>& parameter_blocks,
double *covariance_matrix) {
return impl_->GetCovarianceMatrixInTangentOrAmbientSpace(parameter_blocks,
false, // tangent
covariance_matrix);
}
} // namespace ceres

View File

@@ -36,8 +36,6 @@
#include <algorithm>
#include <cstdlib>
#include <numeric>
#include <sstream>
#include <utility>
#include <vector>
@@ -45,7 +43,6 @@
#include "Eigen/SparseQR"
#include "Eigen/SVD"
#include "ceres/collections_port.h"
#include "ceres/compressed_col_sparse_matrix_utils.h"
#include "ceres/compressed_row_sparse_matrix.h"
#include "ceres/covariance.h"
@@ -54,7 +51,6 @@
#include "ceres/map_util.h"
#include "ceres/parameter_block.h"
#include "ceres/problem_impl.h"
#include "ceres/residual_block.h"
#include "ceres/suitesparse.h"
#include "ceres/wall_time.h"
#include "glog/logging.h"
@@ -65,7 +61,6 @@ namespace internal {
using std::make_pair;
using std::map;
using std::pair;
using std::sort;
using std::swap;
using std::vector;
@@ -91,38 +86,8 @@ CovarianceImpl::CovarianceImpl(const Covariance::Options& options)
CovarianceImpl::~CovarianceImpl() {
}
template <typename T> void CheckForDuplicates(vector<T> blocks) {
sort(blocks.begin(), blocks.end());
typename vector<T>::iterator it =
std::adjacent_find(blocks.begin(), blocks.end());
if (it != blocks.end()) {
// In case there are duplicates, we search for their location.
map<T, vector<int> > blocks_map;
for (int i = 0; i < blocks.size(); ++i) {
blocks_map[blocks[i]].push_back(i);
}
std::ostringstream duplicates;
while (it != blocks.end()) {
duplicates << "(";
for (int i = 0; i < blocks_map[*it].size() - 1; ++i) {
duplicates << blocks_map[*it][i] << ", ";
}
duplicates << blocks_map[*it].back() << ")";
it = std::adjacent_find(it + 1, blocks.end());
if (it < blocks.end()) {
duplicates << " and ";
}
}
LOG(FATAL) << "Covariance::Compute called with duplicate blocks at "
<< "indices " << duplicates.str();
}
}
bool CovarianceImpl::Compute(const CovarianceBlocks& covariance_blocks,
ProblemImpl* problem) {
CheckForDuplicates<pair<const double*, const double*> >(covariance_blocks);
problem_ = problem;
parameter_block_to_row_index_.clear();
covariance_matrix_.reset(NULL);
@@ -132,20 +97,6 @@ bool CovarianceImpl::Compute(const CovarianceBlocks& covariance_blocks,
return is_valid_;
}
bool CovarianceImpl::Compute(const vector<const double*>& parameter_blocks,
ProblemImpl* problem) {
CheckForDuplicates<const double*>(parameter_blocks);
CovarianceBlocks covariance_blocks;
for (int i = 0; i < parameter_blocks.size(); ++i) {
for (int j = i; j < parameter_blocks.size(); ++j) {
covariance_blocks.push_back(make_pair(parameter_blocks[i],
parameter_blocks[j]));
}
}
return Compute(covariance_blocks, problem);
}
bool CovarianceImpl::GetCovarianceBlockInTangentOrAmbientSpace(
const double* original_parameter_block1,
const double* original_parameter_block2,
@@ -169,17 +120,9 @@ bool CovarianceImpl::GetCovarianceBlockInTangentOrAmbientSpace(
ParameterBlock* block2 =
FindOrDie(parameter_map,
const_cast<double*>(original_parameter_block2));
const int block1_size = block1->Size();
const int block2_size = block2->Size();
const int block1_local_size = block1->LocalSize();
const int block2_local_size = block2->LocalSize();
if (!lift_covariance_to_ambient_space) {
MatrixRef(covariance_block, block1_local_size, block2_local_size)
.setZero();
} else {
MatrixRef(covariance_block, block1_size, block2_size).setZero();
}
MatrixRef(covariance_block, block1_size, block2_size).setZero();
return true;
}
@@ -297,94 +240,6 @@ bool CovarianceImpl::GetCovarianceBlockInTangentOrAmbientSpace(
return true;
}
bool CovarianceImpl::GetCovarianceMatrixInTangentOrAmbientSpace(
const vector<const double*>& parameters,
bool lift_covariance_to_ambient_space,
double* covariance_matrix) const {
CHECK(is_computed_)
<< "Covariance::GetCovarianceMatrix called before Covariance::Compute";
CHECK(is_valid_)
<< "Covariance::GetCovarianceMatrix called when Covariance::Compute "
<< "returned false.";
const ProblemImpl::ParameterMap& parameter_map = problem_->parameter_map();
// For OpenMP compatibility we need to define these vectors in advance
const int num_parameters = parameters.size();
vector<int> parameter_sizes;
vector<int> cum_parameter_size;
parameter_sizes.reserve(num_parameters);
cum_parameter_size.resize(num_parameters + 1);
cum_parameter_size[0] = 0;
for (int i = 0; i < num_parameters; ++i) {
ParameterBlock* block =
FindOrDie(parameter_map, const_cast<double*>(parameters[i]));
if (lift_covariance_to_ambient_space) {
parameter_sizes.push_back(block->Size());
} else {
parameter_sizes.push_back(block->LocalSize());
}
}
std::partial_sum(parameter_sizes.begin(), parameter_sizes.end(),
cum_parameter_size.begin() + 1);
const int max_covariance_block_size =
*std::max_element(parameter_sizes.begin(), parameter_sizes.end());
const int covariance_size = cum_parameter_size.back();
// Assemble the blocks in the covariance matrix.
MatrixRef covariance(covariance_matrix, covariance_size, covariance_size);
const int num_threads = options_.num_threads;
scoped_array<double> workspace(
new double[num_threads * max_covariance_block_size *
max_covariance_block_size]);
bool success = true;
// The collapse() directive is only supported in OpenMP 3.0 and higher. OpenMP
// 3.0 was released in May 2008 (hence the version number).
#if _OPENMP >= 200805
# pragma omp parallel for num_threads(num_threads) schedule(dynamic) collapse(2)
#else
# pragma omp parallel for num_threads(num_threads) schedule(dynamic)
#endif
for (int i = 0; i < num_parameters; ++i) {
for (int j = 0; j < num_parameters; ++j) {
// The second loop can't start from j = i for compatibility with OpenMP
// collapse command. The conditional serves as a workaround
if (j >= i) {
int covariance_row_idx = cum_parameter_size[i];
int covariance_col_idx = cum_parameter_size[j];
int size_i = parameter_sizes[i];
int size_j = parameter_sizes[j];
#ifdef CERES_USE_OPENMP
int thread_id = omp_get_thread_num();
#else
int thread_id = 0;
#endif
double* covariance_block =
workspace.get() +
thread_id * max_covariance_block_size * max_covariance_block_size;
if (!GetCovarianceBlockInTangentOrAmbientSpace(
parameters[i], parameters[j], lift_covariance_to_ambient_space,
covariance_block)) {
success = false;
}
covariance.block(covariance_row_idx, covariance_col_idx,
size_i, size_j) =
MatrixRef(covariance_block, size_i, size_j);
if (i != j) {
covariance.block(covariance_col_idx, covariance_row_idx,
size_j, size_i) =
MatrixRef(covariance_block, size_i, size_j).transpose();
}
}
}
}
return success;
}
// Determine the sparsity pattern of the covariance matrix based on
// the block pairs requested by the user.
bool CovarianceImpl::ComputeCovarianceSparsity(
@@ -397,28 +252,18 @@ bool CovarianceImpl::ComputeCovarianceSparsity(
vector<double*> all_parameter_blocks;
problem->GetParameterBlocks(&all_parameter_blocks);
const ProblemImpl::ParameterMap& parameter_map = problem->parameter_map();
HashSet<ParameterBlock*> parameter_blocks_in_use;
vector<ResidualBlock*> residual_blocks;
problem->GetResidualBlocks(&residual_blocks);
for (int i = 0; i < residual_blocks.size(); ++i) {
ResidualBlock* residual_block = residual_blocks[i];
parameter_blocks_in_use.insert(residual_block->parameter_blocks(),
residual_block->parameter_blocks() +
residual_block->NumParameterBlocks());
}
constant_parameter_blocks_.clear();
vector<double*>& active_parameter_blocks =
evaluate_options_.parameter_blocks;
active_parameter_blocks.clear();
for (int i = 0; i < all_parameter_blocks.size(); ++i) {
double* parameter_block = all_parameter_blocks[i];
ParameterBlock* block = FindOrDie(parameter_map, parameter_block);
if (!block->IsConstant() && (parameter_blocks_in_use.count(block) > 0)) {
active_parameter_blocks.push_back(parameter_block);
} else {
if (block->IsConstant()) {
constant_parameter_blocks_.insert(parameter_block);
} else {
active_parameter_blocks.push_back(parameter_block);
}
}
@@ -541,8 +386,8 @@ bool CovarianceImpl::ComputeCovarianceValues() {
switch (options_.algorithm_type) {
case DENSE_SVD:
return ComputeCovarianceValuesUsingDenseSVD();
case SUITE_SPARSE_QR:
#ifndef CERES_NO_SUITESPARSE
case SUITE_SPARSE_QR:
return ComputeCovarianceValuesUsingSuiteSparseQR();
#else
LOG(ERROR) << "SuiteSparse is required to use the "
@@ -779,10 +624,7 @@ bool CovarianceImpl::ComputeCovarianceValuesUsingDenseSVD() {
if (automatic_truncation) {
break;
} else {
LOG(ERROR) << "Error: Covariance matrix is near rank deficient "
<< "and the user did not specify a non-zero"
<< "Covariance::Options::null_space_rank "
<< "to enable the computation of a Pseudo-Inverse. "
LOG(ERROR) << "Cholesky factorization of J'J is not reliable. "
<< "Reciprocal condition number: "
<< singular_value_ratio * singular_value_ratio << " "
<< "min_reciprocal_condition_number: "

View File

@@ -55,21 +55,12 @@ class CovarianceImpl {
const double*> >& covariance_blocks,
ProblemImpl* problem);
bool Compute(
const std::vector<const double*>& parameter_blocks,
ProblemImpl* problem);
bool GetCovarianceBlockInTangentOrAmbientSpace(
const double* parameter_block1,
const double* parameter_block2,
bool lift_covariance_to_ambient_space,
double* covariance_block) const;
bool GetCovarianceMatrixInTangentOrAmbientSpace(
const std::vector<const double*>& parameters,
bool lift_covariance_to_ambient_space,
double *covariance_matrix) const;
bool ComputeCovarianceSparsity(
const std::vector<std::pair<const double*,
const double*> >& covariance_blocks,

View File

@@ -1,276 +0,0 @@
// Ceres Solver - A fast non-linear least squares minimizer
// Copyright 2016 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// 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 Google Inc. 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.
//
// Authors: wjr@google.com (William Rucklidge),
// keir@google.com (Keir Mierle),
// dgossow@google.com (David Gossow)
#include "ceres/gradient_checker.h"
#include <algorithm>
#include <cmath>
#include <numeric>
#include <string>
#include <vector>
#include "ceres/is_close.h"
#include "ceres/stringprintf.h"
#include "ceres/types.h"
namespace ceres {
using internal::IsClose;
using internal::StringAppendF;
using internal::StringPrintf;
using std::string;
using std::vector;
namespace {
// Evaluate the cost function and transform the returned Jacobians to
// the local space of the respective local parameterizations.
bool EvaluateCostFunction(
const ceres::CostFunction* function,
double const* const * parameters,
const std::vector<const ceres::LocalParameterization*>&
local_parameterizations,
Vector* residuals,
std::vector<Matrix>* jacobians,
std::vector<Matrix>* local_jacobians) {
CHECK_NOTNULL(residuals);
CHECK_NOTNULL(jacobians);
CHECK_NOTNULL(local_jacobians);
const vector<int32>& block_sizes = function->parameter_block_sizes();
const int num_parameter_blocks = block_sizes.size();
// Allocate Jacobian matrices in local space.
local_jacobians->resize(num_parameter_blocks);
vector<double*> local_jacobian_data(num_parameter_blocks);
for (int i = 0; i < num_parameter_blocks; ++i) {
int block_size = block_sizes.at(i);
if (local_parameterizations.at(i) != NULL) {
block_size = local_parameterizations.at(i)->LocalSize();
}
local_jacobians->at(i).resize(function->num_residuals(), block_size);
local_jacobians->at(i).setZero();
local_jacobian_data.at(i) = local_jacobians->at(i).data();
}
// Allocate Jacobian matrices in global space.
jacobians->resize(num_parameter_blocks);
vector<double*> jacobian_data(num_parameter_blocks);
for (int i = 0; i < num_parameter_blocks; ++i) {
jacobians->at(i).resize(function->num_residuals(), block_sizes.at(i));
jacobians->at(i).setZero();
jacobian_data.at(i) = jacobians->at(i).data();
}
// Compute residuals & jacobians.
CHECK_NE(0, function->num_residuals());
residuals->resize(function->num_residuals());
residuals->setZero();
if (!function->Evaluate(parameters, residuals->data(),
jacobian_data.data())) {
return false;
}
// Convert Jacobians from global to local space.
for (size_t i = 0; i < local_jacobians->size(); ++i) {
if (local_parameterizations.at(i) == NULL) {
local_jacobians->at(i) = jacobians->at(i);
} else {
int global_size = local_parameterizations.at(i)->GlobalSize();
int local_size = local_parameterizations.at(i)->LocalSize();
CHECK_EQ(jacobians->at(i).cols(), global_size);
Matrix global_J_local(global_size, local_size);
local_parameterizations.at(i)->ComputeJacobian(
parameters[i], global_J_local.data());
local_jacobians->at(i) = jacobians->at(i) * global_J_local;
}
}
return true;
}
} // namespace
GradientChecker::GradientChecker(
const CostFunction* function,
const vector<const LocalParameterization*>* local_parameterizations,
const NumericDiffOptions& options) :
function_(function) {
CHECK_NOTNULL(function);
if (local_parameterizations != NULL) {
local_parameterizations_ = *local_parameterizations;
} else {
local_parameterizations_.resize(function->parameter_block_sizes().size(),
NULL);
}
DynamicNumericDiffCostFunction<CostFunction, CENTRAL>*
finite_diff_cost_function =
new DynamicNumericDiffCostFunction<CostFunction, CENTRAL>(
function, DO_NOT_TAKE_OWNERSHIP, options);
finite_diff_cost_function_.reset(finite_diff_cost_function);
const vector<int32>& parameter_block_sizes =
function->parameter_block_sizes();
const int num_parameter_blocks = parameter_block_sizes.size();
for (int i = 0; i < num_parameter_blocks; ++i) {
finite_diff_cost_function->AddParameterBlock(parameter_block_sizes[i]);
}
finite_diff_cost_function->SetNumResiduals(function->num_residuals());
}
bool GradientChecker::Probe(double const* const * parameters,
double relative_precision,
ProbeResults* results_param) const {
int num_residuals = function_->num_residuals();
// Make sure that we have a place to store results, no matter if the user has
// provided an output argument.
ProbeResults* results;
ProbeResults results_local;
if (results_param != NULL) {
results = results_param;
results->residuals.resize(0);
results->jacobians.clear();
results->numeric_jacobians.clear();
results->local_jacobians.clear();
results->local_numeric_jacobians.clear();
results->error_log.clear();
} else {
results = &results_local;
}
results->maximum_relative_error = 0.0;
results->return_value = true;
// Evaluate the derivative using the user supplied code.
vector<Matrix>& jacobians = results->jacobians;
vector<Matrix>& local_jacobians = results->local_jacobians;
if (!EvaluateCostFunction(function_, parameters, local_parameterizations_,
&results->residuals, &jacobians, &local_jacobians)) {
results->error_log = "Function evaluation with Jacobians failed.";
results->return_value = false;
}
// Evaluate the derivative using numeric derivatives.
vector<Matrix>& numeric_jacobians = results->numeric_jacobians;
vector<Matrix>& local_numeric_jacobians = results->local_numeric_jacobians;
Vector finite_diff_residuals;
if (!EvaluateCostFunction(finite_diff_cost_function_.get(), parameters,
local_parameterizations_, &finite_diff_residuals,
&numeric_jacobians, &local_numeric_jacobians)) {
results->error_log += "\nFunction evaluation with numerical "
"differentiation failed.";
results->return_value = false;
}
if (!results->return_value) {
return false;
}
for (int i = 0; i < num_residuals; ++i) {
if (!IsClose(
results->residuals[i],
finite_diff_residuals[i],
relative_precision,
NULL,
NULL)) {
results->error_log = "Function evaluation with and without Jacobians "
"resulted in different residuals.";
LOG(INFO) << results->residuals.transpose();
LOG(INFO) << finite_diff_residuals.transpose();
return false;
}
}
// See if any elements have relative error larger than the threshold.
int num_bad_jacobian_components = 0;
double& worst_relative_error = results->maximum_relative_error;
worst_relative_error = 0;
// Accumulate the error message for all the jacobians, since it won't get
// output if there are no bad jacobian components.
string error_log;
for (int k = 0; k < function_->parameter_block_sizes().size(); k++) {
StringAppendF(&error_log,
"========== "
"Jacobian for " "block %d: (%ld by %ld)) "
"==========\n",
k,
static_cast<long>(local_jacobians[k].rows()),
static_cast<long>(local_jacobians[k].cols()));
// The funny spacing creates appropriately aligned column headers.
error_log +=
" block row col user dx/dy num diff dx/dy "
"abs error relative error parameter residual\n";
for (int i = 0; i < local_jacobians[k].rows(); i++) {
for (int j = 0; j < local_jacobians[k].cols(); j++) {
double term_jacobian = local_jacobians[k](i, j);
double finite_jacobian = local_numeric_jacobians[k](i, j);
double relative_error, absolute_error;
bool bad_jacobian_entry =
!IsClose(term_jacobian,
finite_jacobian,
relative_precision,
&relative_error,
&absolute_error);
worst_relative_error = std::max(worst_relative_error, relative_error);
StringAppendF(&error_log,
"%6d %4d %4d %17g %17g %17g %17g %17g %17g",
k, i, j,
term_jacobian, finite_jacobian,
absolute_error, relative_error,
parameters[k][j],
results->residuals[i]);
if (bad_jacobian_entry) {
num_bad_jacobian_components++;
StringAppendF(
&error_log,
" ------ (%d,%d,%d) Relative error worse than %g",
k, i, j, relative_precision);
}
error_log += "\n";
}
}
}
// Since there were some bad errors, dump comprehensive debug info.
if (num_bad_jacobian_components) {
string header = StringPrintf("\nDetected %d bad Jacobian component(s). "
"Worst relative error was %g.\n",
num_bad_jacobian_components,
worst_relative_error);
results->error_log = header + "\n" + error_log;
return false;
}
return true;
}
} // namespace ceres

View File

@@ -26,8 +26,7 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Authors: keir@google.com (Keir Mierle),
// dgossow@google.com (David Gossow)
// Author: keir@google.com (Keir Mierle)
#include "ceres/gradient_checking_cost_function.h"
@@ -37,7 +36,7 @@
#include <string>
#include <vector>
#include "ceres/gradient_checker.h"
#include "ceres/cost_function.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/scoped_ptr.h"
#include "ceres/parameter_block.h"
@@ -60,25 +59,55 @@ using std::vector;
namespace {
// True if x and y have an absolute relative difference less than
// relative_precision and false otherwise. Stores the relative and absolute
// difference in relative/absolute_error if non-NULL.
bool IsClose(double x, double y, double relative_precision,
double *relative_error,
double *absolute_error) {
double local_absolute_error;
double local_relative_error;
if (!absolute_error) {
absolute_error = &local_absolute_error;
}
if (!relative_error) {
relative_error = &local_relative_error;
}
*absolute_error = abs(x - y);
*relative_error = *absolute_error / max(abs(x), abs(y));
if (x == 0 || y == 0) {
// If x or y is exactly zero, then relative difference doesn't have any
// meaning. Take the absolute difference instead.
*relative_error = *absolute_error;
}
return abs(*relative_error) < abs(relative_precision);
}
class GradientCheckingCostFunction : public CostFunction {
public:
GradientCheckingCostFunction(
const CostFunction* function,
const std::vector<const LocalParameterization*>* local_parameterizations,
const NumericDiffOptions& options,
double relative_precision,
const string& extra_info,
GradientCheckingIterationCallback* callback)
GradientCheckingCostFunction(const CostFunction* function,
const NumericDiffOptions& options,
double relative_precision,
const string& extra_info)
: function_(function),
gradient_checker_(function, local_parameterizations, options),
relative_precision_(relative_precision),
extra_info_(extra_info),
callback_(callback) {
CHECK_NOTNULL(callback_);
extra_info_(extra_info) {
DynamicNumericDiffCostFunction<CostFunction, CENTRAL>*
finite_diff_cost_function =
new DynamicNumericDiffCostFunction<CostFunction, CENTRAL>(
function,
DO_NOT_TAKE_OWNERSHIP,
options);
const vector<int32>& parameter_block_sizes =
function->parameter_block_sizes();
for (int i = 0; i < parameter_block_sizes.size(); ++i) {
finite_diff_cost_function->AddParameterBlock(parameter_block_sizes[i]);
}
*mutable_parameter_block_sizes() = parameter_block_sizes;
set_num_residuals(function->num_residuals());
finite_diff_cost_function->SetNumResiduals(num_residuals());
finite_diff_cost_function_.reset(finite_diff_cost_function);
}
virtual ~GradientCheckingCostFunction() { }
@@ -91,92 +120,133 @@ class GradientCheckingCostFunction : public CostFunction {
return function_->Evaluate(parameters, residuals, NULL);
}
GradientChecker::ProbeResults results;
bool okay = gradient_checker_.Probe(parameters,
relative_precision_,
&results);
int num_residuals = function_->num_residuals();
// If the cost function returned false, there's nothing we can say about
// the gradients.
if (results.return_value == false) {
// Make space for the jacobians of the two methods.
const vector<int32>& block_sizes = function_->parameter_block_sizes();
vector<Matrix> term_jacobians(block_sizes.size());
vector<Matrix> finite_difference_jacobians(block_sizes.size());
vector<double*> term_jacobian_pointers(block_sizes.size());
vector<double*> finite_difference_jacobian_pointers(block_sizes.size());
for (int i = 0; i < block_sizes.size(); i++) {
term_jacobians[i].resize(num_residuals, block_sizes[i]);
term_jacobian_pointers[i] = term_jacobians[i].data();
finite_difference_jacobians[i].resize(num_residuals, block_sizes[i]);
finite_difference_jacobian_pointers[i] =
finite_difference_jacobians[i].data();
}
// Evaluate the derivative using the user supplied code.
if (!function_->Evaluate(parameters,
residuals,
&term_jacobian_pointers[0])) {
LOG(WARNING) << "Function evaluation failed.";
return false;
}
// Copy the residuals.
const int num_residuals = function_->num_residuals();
MatrixRef(residuals, num_residuals, 1) = results.residuals;
// Evaluate the derivative using numeric derivatives.
finite_diff_cost_function_->Evaluate(
parameters,
residuals,
&finite_difference_jacobian_pointers[0]);
// Copy the original jacobian blocks into the jacobians array.
const vector<int32>& block_sizes = function_->parameter_block_sizes();
// See if any elements have relative error larger than the threshold.
int num_bad_jacobian_components = 0;
double worst_relative_error = 0;
// Accumulate the error message for all the jacobians, since it won't get
// output if there are no bad jacobian components.
string m;
for (int k = 0; k < block_sizes.size(); k++) {
// Copy the original jacobian blocks into the jacobians array.
if (jacobians[k] != NULL) {
MatrixRef(jacobians[k],
results.jacobians[k].rows(),
results.jacobians[k].cols()) = results.jacobians[k];
term_jacobians[k].rows(),
term_jacobians[k].cols()) = term_jacobians[k];
}
StringAppendF(&m,
"========== "
"Jacobian for " "block %d: (%ld by %ld)) "
"==========\n",
k,
static_cast<long>(term_jacobians[k].rows()),
static_cast<long>(term_jacobians[k].cols()));
// The funny spacing creates appropriately aligned column headers.
m += " block row col user dx/dy num diff dx/dy "
"abs error relative error parameter residual\n";
for (int i = 0; i < term_jacobians[k].rows(); i++) {
for (int j = 0; j < term_jacobians[k].cols(); j++) {
double term_jacobian = term_jacobians[k](i, j);
double finite_jacobian = finite_difference_jacobians[k](i, j);
double relative_error, absolute_error;
bool bad_jacobian_entry =
!IsClose(term_jacobian,
finite_jacobian,
relative_precision_,
&relative_error,
&absolute_error);
worst_relative_error = max(worst_relative_error, relative_error);
StringAppendF(&m, "%6d %4d %4d %17g %17g %17g %17g %17g %17g",
k, i, j,
term_jacobian, finite_jacobian,
absolute_error, relative_error,
parameters[k][j],
residuals[i]);
if (bad_jacobian_entry) {
num_bad_jacobian_components++;
StringAppendF(
&m, " ------ (%d,%d,%d) Relative error worse than %g",
k, i, j, relative_precision_);
}
m += "\n";
}
}
}
if (!okay) {
std::string error_log = "Gradient Error detected!\nExtra info for "
"this residual: " + extra_info_ + "\n" + results.error_log;
callback_->SetGradientErrorDetected(error_log);
// Since there were some bad errors, dump comprehensive debug info.
if (num_bad_jacobian_components) {
string header = StringPrintf("Detected %d bad jacobian component(s). "
"Worst relative error was %g.\n",
num_bad_jacobian_components,
worst_relative_error);
if (!extra_info_.empty()) {
header += "Extra info for this residual: " + extra_info_ + "\n";
}
LOG(WARNING) << "\n" << header << m;
}
return true;
}
private:
const CostFunction* function_;
GradientChecker gradient_checker_;
internal::scoped_ptr<CostFunction> finite_diff_cost_function_;
double relative_precision_;
string extra_info_;
GradientCheckingIterationCallback* callback_;
};
} // namespace
GradientCheckingIterationCallback::GradientCheckingIterationCallback()
: gradient_error_detected_(false) {
}
CallbackReturnType GradientCheckingIterationCallback::operator()(
const IterationSummary& summary) {
if (gradient_error_detected_) {
LOG(ERROR)<< "Gradient error detected. Terminating solver.";
return SOLVER_ABORT;
}
return SOLVER_CONTINUE;
}
void GradientCheckingIterationCallback::SetGradientErrorDetected(
std::string& error_log) {
mutex_.Lock();
gradient_error_detected_ = true;
error_log_ += "\n" + error_log;
mutex_.Unlock();
}
CostFunction* CreateGradientCheckingCostFunction(
const CostFunction* cost_function,
const std::vector<const LocalParameterization*>* local_parameterizations,
CostFunction *CreateGradientCheckingCostFunction(
const CostFunction *cost_function,
double relative_step_size,
double relative_precision,
const std::string& extra_info,
GradientCheckingIterationCallback* callback) {
const string& extra_info) {
NumericDiffOptions numeric_diff_options;
numeric_diff_options.relative_step_size = relative_step_size;
return new GradientCheckingCostFunction(cost_function,
local_parameterizations,
numeric_diff_options,
relative_precision, extra_info,
callback);
relative_precision,
extra_info);
}
ProblemImpl* CreateGradientCheckingProblemImpl(
ProblemImpl* problem_impl,
double relative_step_size,
double relative_precision,
GradientCheckingIterationCallback* callback) {
CHECK_NOTNULL(callback);
ProblemImpl* CreateGradientCheckingProblemImpl(ProblemImpl* problem_impl,
double relative_step_size,
double relative_precision) {
// We create new CostFunctions by wrapping the original CostFunction
// in a gradient checking CostFunction. So its okay for the
// ProblemImpl to take ownership of it and destroy it. The
@@ -190,9 +260,6 @@ ProblemImpl* CreateGradientCheckingProblemImpl(
gradient_checking_problem_options.local_parameterization_ownership =
DO_NOT_TAKE_OWNERSHIP;
NumericDiffOptions numeric_diff_options;
numeric_diff_options.relative_step_size = relative_step_size;
ProblemImpl* gradient_checking_problem_impl = new ProblemImpl(
gradient_checking_problem_options);
@@ -227,26 +294,19 @@ ProblemImpl* CreateGradientCheckingProblemImpl(
string extra_info = StringPrintf(
"Residual block id %d; depends on parameters [", i);
vector<double*> parameter_blocks;
vector<const LocalParameterization*> local_parameterizations;
parameter_blocks.reserve(residual_block->NumParameterBlocks());
local_parameterizations.reserve(residual_block->NumParameterBlocks());
for (int j = 0; j < residual_block->NumParameterBlocks(); ++j) {
ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
parameter_blocks.push_back(parameter_block->mutable_user_state());
StringAppendF(&extra_info, "%p", parameter_block->mutable_user_state());
extra_info += (j < residual_block->NumParameterBlocks() - 1) ? ", " : "]";
local_parameterizations.push_back(problem_impl->GetParameterization(
parameter_block->mutable_user_state()));
}
// Wrap the original CostFunction in a GradientCheckingCostFunction.
CostFunction* gradient_checking_cost_function =
new GradientCheckingCostFunction(residual_block->cost_function(),
&local_parameterizations,
numeric_diff_options,
relative_precision,
extra_info,
callback);
CreateGradientCheckingCostFunction(residual_block->cost_function(),
relative_step_size,
relative_precision,
extra_info);
// The const_cast is necessary because
// ProblemImpl::AddResidualBlock can potentially take ownership of

View File

@@ -26,8 +26,7 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Authors: keir@google.com (Keir Mierle),
// dgossow@google.com (David Gossow)
// Author: keir@google.com (Keir Mierle)
#ifndef CERES_INTERNAL_GRADIENT_CHECKING_COST_FUNCTION_H_
#define CERES_INTERNAL_GRADIENT_CHECKING_COST_FUNCTION_H_
@@ -35,76 +34,50 @@
#include <string>
#include "ceres/cost_function.h"
#include "ceres/iteration_callback.h"
#include "ceres/local_parameterization.h"
#include "ceres/mutex.h"
namespace ceres {
namespace internal {
class ProblemImpl;
// Callback that collects information about gradient checking errors, and
// will abort the solve as soon as an error occurs.
class GradientCheckingIterationCallback : public IterationCallback {
public:
GradientCheckingIterationCallback();
// Will return SOLVER_CONTINUE until a gradient error has been detected,
// then return SOLVER_ABORT.
virtual CallbackReturnType operator()(const IterationSummary& summary);
// Notify this that a gradient error has occurred (thread safe).
void SetGradientErrorDetected(std::string& error_log);
// Retrieve error status (not thread safe).
bool gradient_error_detected() const { return gradient_error_detected_; }
const std::string& error_log() const { return error_log_; }
private:
bool gradient_error_detected_;
std::string error_log_;
// Mutex protecting member variables.
ceres::internal::Mutex mutex_;
};
// Creates a CostFunction that checks the Jacobians that cost_function computes
// with finite differences. This API is only intended for unit tests that intend
// to check the functionality of the GradientCheckingCostFunction
// implementation directly.
CostFunction* CreateGradientCheckingCostFunction(
const CostFunction* cost_function,
const std::vector<const LocalParameterization*>* local_parameterizations,
double relative_step_size,
double relative_precision,
const std::string& extra_info,
GradientCheckingIterationCallback* callback);
// Create a new ProblemImpl object from the input problem_impl, where all
// cost functions are wrapped so that each time their Evaluate method is called,
// an additional check is performed that compares the Jacobians computed by
// the original cost function with alternative Jacobians computed using
// numerical differentiation. If local parameterizations are given for any
// parameters, the Jacobians will be compared in the local space instead of the
// ambient space. For details on the gradient checking procedure, see the
// documentation of the GradientChecker class. If an error is detected in any
// iteration, the respective cost function will notify the
// GradientCheckingIterationCallback.
// Creates a CostFunction that checks the jacobians that cost_function computes
// with finite differences. Bad results are logged; required precision is
// controlled by relative_precision and the numeric differentiation step size is
// controlled with relative_step_size. See solver.h for a better explanation of
// relative_step_size. Caller owns result.
//
// The caller owns the returned ProblemImpl object.
// The condition enforced is that
//
// (J_actual(i, j) - J_numeric(i, j))
// ------------------------------------ < relative_precision
// max(J_actual(i, j), J_numeric(i, j))
//
// where J_actual(i, j) is the jacobian as computed by the supplied cost
// function (by the user) and J_numeric is the jacobian as computed by finite
// differences.
//
// Note: This is quite inefficient and is intended only for debugging.
CostFunction* CreateGradientCheckingCostFunction(
const CostFunction* cost_function,
double relative_step_size,
double relative_precision,
const std::string& extra_info);
// Create a new ProblemImpl object from the input problem_impl, where
// each CostFunctions in problem_impl are wrapped inside a
// GradientCheckingCostFunctions. This gives us a ProblemImpl object
// which checks its derivatives against estimates from numeric
// differentiation everytime a ResidualBlock is evaluated.
//
// relative_step_size and relative_precision are parameters to control
// the numeric differentiation and the relative tolerance between the
// jacobian computed by the CostFunctions in problem_impl and
// jacobians obtained by numerically differentiating them. See the
// documentation of 'numeric_derivative_relative_step_size' in solver.h for a
// better explanation.
ProblemImpl* CreateGradientCheckingProblemImpl(
ProblemImpl* problem_impl,
double relative_step_size,
double relative_precision,
GradientCheckingIterationCallback* callback);
// jacobians obtained by numerically differentiating them. For more
// details see the documentation for
// CreateGradientCheckingCostFunction above.
ProblemImpl* CreateGradientCheckingProblemImpl(ProblemImpl* problem_impl,
double relative_step_size,
double relative_precision);
} // namespace internal
} // namespace ceres

View File

@@ -84,12 +84,6 @@ Solver::Options GradientProblemSolverOptionsToSolverOptions(
} // namespace
bool GradientProblemSolver::Options::IsValid(std::string* error) const {
const Solver::Options solver_options =
GradientProblemSolverOptionsToSolverOptions(*this);
return solver_options.IsValid(error);
}
GradientProblemSolver::~GradientProblemSolver() {
}
@@ -105,6 +99,8 @@ void GradientProblemSolver::Solve(const GradientProblemSolver::Options& options,
using internal::SetSummaryFinalCost;
double start_time = WallTimeInSeconds();
Solver::Options solver_options =
GradientProblemSolverOptionsToSolverOptions(options);
*CHECK_NOTNULL(summary) = Summary();
summary->num_parameters = problem.NumParameters();
@@ -116,16 +112,14 @@ void GradientProblemSolver::Solve(const GradientProblemSolver::Options& options,
summary->nonlinear_conjugate_gradient_type = options.nonlinear_conjugate_gradient_type; // NOLINT
// Check validity
if (!options.IsValid(&summary->message)) {
if (!solver_options.IsValid(&summary->message)) {
LOG(ERROR) << "Terminating: " << summary->message;
return;
}
// TODO(sameeragarwal): This is a bit convoluted, we should be able
// to convert to minimizer options directly, but this will do for
// now.
Minimizer::Options minimizer_options =
Minimizer::Options(GradientProblemSolverOptionsToSolverOptions(options));
// Assuming that the parameter blocks in the program have been
Minimizer::Options minimizer_options;
minimizer_options = Minimizer::Options(solver_options);
minimizer_options.evaluator.reset(new GradientProblemEvaluator(problem));
scoped_ptr<IterationCallback> logging_callback;

View File

@@ -1,59 +0,0 @@
// Ceres Solver - A fast non-linear least squares minimizer
// Copyright 2016 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// 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 Google Inc. 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.
//
// Authors: keir@google.com (Keir Mierle), dgossow@google.com (David Gossow)
#include "ceres/is_close.h"
#include <algorithm>
#include <cmath>
namespace ceres {
namespace internal {
bool IsClose(double x, double y, double relative_precision,
double *relative_error,
double *absolute_error) {
double local_absolute_error;
double local_relative_error;
if (!absolute_error) {
absolute_error = &local_absolute_error;
}
if (!relative_error) {
relative_error = &local_relative_error;
}
*absolute_error = std::fabs(x - y);
*relative_error = *absolute_error / std::max(std::fabs(x), std::fabs(y));
if (x == 0 || y == 0) {
// If x or y is exactly zero, then relative difference doesn't have any
// meaning. Take the absolute difference instead.
*relative_error = *absolute_error;
}
return *relative_error < std::fabs(relative_precision);
}
} // namespace internal
} // namespace ceres

View File

@@ -1,51 +0,0 @@
// Ceres Solver - A fast non-linear least squares minimizer
// Copyright 2016 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// 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 Google Inc. 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.
//
// Authors: keir@google.com (Keir Mierle), dgossow@google.com (David Gossow)
//
// Utility routine for comparing two values.
#ifndef CERES_INTERNAL_IS_CLOSE_H_
#define CERES_INTERNAL_IS_CLOSE_H_
namespace ceres {
namespace internal {
// Returns true if x and y have a relative (unsigned) difference less than
// relative_precision and false otherwise. Stores the relative and absolute
// difference in relative/absolute_error if non-NULL. If one of the two values
// is exactly zero, the absolute difference will be compared, and relative_error
// will be set to the absolute difference.
bool IsClose(double x,
double y,
double relative_precision,
double *relative_error,
double *absolute_error);
} // namespace internal
} // namespace ceres
#endif // CERES_INTERNAL_IS_CLOSE_H_

View File

@@ -191,7 +191,6 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
options.line_search_sufficient_curvature_decrease;
line_search_options.max_step_expansion =
options.max_line_search_step_expansion;
line_search_options.is_silent = options.is_silent;
line_search_options.function = &line_search_function;
scoped_ptr<LineSearch>
@@ -342,12 +341,10 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
"as the step was valid when it was selected by the line search.";
LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
break;
}
if (!Evaluate(evaluator,
x_plus_delta,
&current_state,
&summary->message)) {
} else if (!Evaluate(evaluator,
x_plus_delta,
&current_state,
&summary->message)) {
summary->termination_type = FAILURE;
summary->message =
"Step failed to evaluate. This should not happen as the step was "
@@ -355,17 +352,15 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
summary->message;
LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
break;
} else {
x = x_plus_delta;
}
// Compute the norm of the step in the ambient space.
iteration_summary.step_norm = (x_plus_delta - x).norm();
x = x_plus_delta;
iteration_summary.gradient_max_norm = current_state.gradient_max_norm;
iteration_summary.gradient_norm = sqrt(current_state.gradient_squared_norm);
iteration_summary.cost_change = previous_state.cost - current_state.cost;
iteration_summary.cost = current_state.cost + summary->fixed_cost;
iteration_summary.step_norm = delta.norm();
iteration_summary.step_is_valid = true;
iteration_summary.step_is_successful = true;
iteration_summary.step_size = current_state.step_size;
@@ -381,13 +376,6 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
WallTimeInSeconds() - start_time
+ summary->preprocessor_time_in_seconds;
// Iterations inside the line search algorithm are considered
// 'steps' in the broader context, to distinguish these inner
// iterations from from the outer iterations of the line search
// minimizer. The number of line search steps is the total number
// of inner line search iterations (or steps) across the entire
// minimization.
summary->num_line_search_steps += line_search_summary.num_iterations;
summary->line_search_cost_evaluation_time_in_seconds +=
line_search_summary.cost_evaluation_time_in_seconds;
summary->line_search_gradient_evaluation_time_in_seconds +=

View File

@@ -30,8 +30,6 @@
#include "ceres/local_parameterization.h"
#include <algorithm>
#include "Eigen/Geometry"
#include "ceres/householder_vector.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/fixed_array.h"
@@ -89,17 +87,28 @@ bool IdentityParameterization::MultiplyByJacobian(const double* x,
}
SubsetParameterization::SubsetParameterization(
int size, const vector<int>& constant_parameters)
: local_size_(size - constant_parameters.size()), constancy_mask_(size, 0) {
int size,
const vector<int>& constant_parameters)
: local_size_(size - constant_parameters.size()),
constancy_mask_(size, 0) {
CHECK_GT(constant_parameters.size(), 0)
<< "The set of constant parameters should contain at least "
<< "one element. If you do not wish to hold any parameters "
<< "constant, then do not use a SubsetParameterization";
vector<int> constant = constant_parameters;
std::sort(constant.begin(), constant.end());
CHECK_GE(constant.front(), 0)
<< "Indices indicating constant parameter must be greater than zero.";
CHECK_LT(constant.back(), size)
<< "Indices indicating constant parameter must be less than the size "
<< "of the parameter block.";
CHECK(std::adjacent_find(constant.begin(), constant.end()) == constant.end())
sort(constant.begin(), constant.end());
CHECK(unique(constant.begin(), constant.end()) == constant.end())
<< "The set of constant parameters cannot contain duplicates";
CHECK_LT(constant_parameters.size(), size)
<< "Number of parameters held constant should be less "
<< "than the size of the parameter block. If you wish "
<< "to hold the entire parameter block constant, then a "
<< "efficient way is to directly mark it as constant "
<< "instead of using a LocalParameterization to do so.";
CHECK_GE(*min_element(constant.begin(), constant.end()), 0);
CHECK_LT(*max_element(constant.begin(), constant.end()), size);
for (int i = 0; i < constant_parameters.size(); ++i) {
constancy_mask_[constant_parameters[i]] = 1;
}
@@ -120,10 +129,6 @@ bool SubsetParameterization::Plus(const double* x,
bool SubsetParameterization::ComputeJacobian(const double* x,
double* jacobian) const {
if (local_size_ == 0) {
return true;
}
MatrixRef m(jacobian, constancy_mask_.size(), local_size_);
m.setZero();
for (int i = 0, j = 0; i < constancy_mask_.size(); ++i) {
@@ -138,10 +143,6 @@ bool SubsetParameterization::MultiplyByJacobian(const double* x,
const int num_rows,
const double* global_matrix,
double* local_matrix) const {
if (local_size_ == 0) {
return true;
}
for (int row = 0; row < num_rows; ++row) {
for (int col = 0, j = 0; col < constancy_mask_.size(); ++col) {
if (!constancy_mask_[col]) {
@@ -183,39 +184,6 @@ bool QuaternionParameterization::ComputeJacobian(const double* x,
return true;
}
bool EigenQuaternionParameterization::Plus(const double* x_ptr,
const double* delta,
double* x_plus_delta_ptr) const {
Eigen::Map<Eigen::Quaterniond> x_plus_delta(x_plus_delta_ptr);
Eigen::Map<const Eigen::Quaterniond> x(x_ptr);
const double norm_delta =
sqrt(delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]);
if (norm_delta > 0.0) {
const double sin_delta_by_delta = sin(norm_delta) / norm_delta;
// Note, in the constructor w is first.
Eigen::Quaterniond delta_q(cos(norm_delta),
sin_delta_by_delta * delta[0],
sin_delta_by_delta * delta[1],
sin_delta_by_delta * delta[2]);
x_plus_delta = delta_q * x;
} else {
x_plus_delta = x;
}
return true;
}
bool EigenQuaternionParameterization::ComputeJacobian(const double* x,
double* jacobian) const {
jacobian[0] = x[3]; jacobian[1] = x[2]; jacobian[2] = -x[1]; // NOLINT
jacobian[3] = -x[2]; jacobian[4] = x[3]; jacobian[5] = x[0]; // NOLINT
jacobian[6] = x[1]; jacobian[7] = -x[0]; jacobian[8] = x[3]; // NOLINT
jacobian[9] = -x[0]; jacobian[10] = -x[1]; jacobian[11] = -x[2]; // NOLINT
return true;
}
HomogeneousVectorParameterization::HomogeneousVectorParameterization(int size)
: size_(size) {
CHECK_GT(size_, 1) << "The size of the homogeneous vector needs to be "
@@ -364,9 +332,9 @@ bool ProductParameterization::ComputeJacobian(const double* x,
if (!param->ComputeJacobian(x + x_cursor, buffer.get())) {
return false;
}
jacobian.block(x_cursor, delta_cursor, global_size, local_size)
= MatrixRef(buffer.get(), global_size, local_size);
delta_cursor += local_size;
x_cursor += global_size;
}

View File

@@ -67,7 +67,7 @@ FindOrDie(const Collection& collection,
// If the key is present in the map then the value associated with that
// key is returned, otherwise the value passed as a default is returned.
template <class Collection>
const typename Collection::value_type::second_type
const typename Collection::value_type::second_type&
FindWithDefault(const Collection& collection,
const typename Collection::value_type::first_type& key,
const typename Collection::value_type::second_type& value) {

View File

@@ -161,34 +161,25 @@ class ParameterBlock {
// does not take ownership of the parameterization.
void SetParameterization(LocalParameterization* new_parameterization) {
CHECK(new_parameterization != NULL) << "NULL parameterization invalid.";
// Nothing to do if the new parameterization is the same as the
// old parameterization.
if (new_parameterization == local_parameterization_) {
return;
}
CHECK(local_parameterization_ == NULL)
<< "Can't re-set the local parameterization; it leads to "
<< "ambiguous ownership. Current local parameterization is: "
<< local_parameterization_;
CHECK(new_parameterization->GlobalSize() == size_)
<< "Invalid parameterization for parameter block. The parameter block "
<< "has size " << size_ << " while the parameterization has a global "
<< "size of " << new_parameterization->GlobalSize() << ". Did you "
<< "accidentally use the wrong parameter block or parameterization?";
CHECK_GT(new_parameterization->LocalSize(), 0)
<< "Invalid parameterization. Parameterizations must have a positive "
<< "dimensional tangent space.";
local_parameterization_ = new_parameterization;
local_parameterization_jacobian_.reset(
new double[local_parameterization_->GlobalSize() *
local_parameterization_->LocalSize()]);
CHECK(UpdateLocalParameterizationJacobian())
<< "Local parameterization Jacobian computation failed for x: "
<< ConstVectorRef(state_, Size()).transpose();
if (new_parameterization != local_parameterization_) {
CHECK(local_parameterization_ == NULL)
<< "Can't re-set the local parameterization; it leads to "
<< "ambiguous ownership.";
local_parameterization_ = new_parameterization;
local_parameterization_jacobian_.reset(
new double[local_parameterization_->GlobalSize() *
local_parameterization_->LocalSize()]);
CHECK(UpdateLocalParameterizationJacobian())
<< "Local parameterization Jacobian computation failed for x: "
<< ConstVectorRef(state_, Size()).transpose();
} else {
// Ignore the case that the parameterizations match.
}
}
void SetUpperBound(int index, double upper_bound) {

View File

@@ -174,10 +174,6 @@ void Problem::SetParameterBlockVariable(double* values) {
problem_impl_->SetParameterBlockVariable(values);
}
bool Problem::IsParameterBlockConstant(double* values) const {
return problem_impl_->IsParameterBlockConstant(values);
}
void Problem::SetParameterization(
double* values,
LocalParameterization* local_parameterization) {

View File

@@ -249,11 +249,10 @@ ResidualBlock* ProblemImpl::AddResidualBlock(
// Check for duplicate parameter blocks.
vector<double*> sorted_parameter_blocks(parameter_blocks);
sort(sorted_parameter_blocks.begin(), sorted_parameter_blocks.end());
const bool has_duplicate_items =
(std::adjacent_find(sorted_parameter_blocks.begin(),
sorted_parameter_blocks.end())
!= sorted_parameter_blocks.end());
if (has_duplicate_items) {
vector<double*>::const_iterator duplicate_items =
unique(sorted_parameter_blocks.begin(),
sorted_parameter_blocks.end());
if (duplicate_items != sorted_parameter_blocks.end()) {
string blocks;
for (int i = 0; i < parameter_blocks.size(); ++i) {
blocks += StringPrintf(" %p ", parameter_blocks[i]);
@@ -573,16 +572,6 @@ void ProblemImpl::SetParameterBlockConstant(double* values) {
parameter_block->SetConstant();
}
bool ProblemImpl::IsParameterBlockConstant(double* values) const {
const ParameterBlock* parameter_block =
FindWithDefault(parameter_block_map_, values, NULL);
CHECK(parameter_block != NULL)
<< "Parameter block not found: " << values << ". You must add the "
<< "parameter block to the problem before it can be queried.";
return parameter_block->IsConstant();
}
void ProblemImpl::SetParameterBlockVariable(double* values) {
ParameterBlock* parameter_block =
FindWithDefault(parameter_block_map_, values, NULL);

View File

@@ -128,8 +128,6 @@ class ProblemImpl {
void SetParameterBlockConstant(double* values);
void SetParameterBlockVariable(double* values);
bool IsParameterBlockConstant(double* values) const;
void SetParameterization(double* values,
LocalParameterization* local_parameterization);
const LocalParameterization* GetParameterization(double* values) const;

View File

@@ -142,11 +142,6 @@ void OrderingForSparseNormalCholeskyUsingSuiteSparse(
ordering);
}
VLOG(2) << "Block ordering stats: "
<< " flops: " << ss.mutable_cc()->fl
<< " lnz : " << ss.mutable_cc()->lnz
<< " anz : " << ss.mutable_cc()->anz;
ss.Free(block_jacobian_transpose);
#endif // CERES_NO_SUITESPARSE
}

View File

@@ -127,7 +127,7 @@ class ResidualBlock {
int index() const { return index_; }
void set_index(int index) { index_ = index; }
std::string ToString() const {
std::string ToString() {
return StringPrintf("{residual block; index=%d}", index_);
}

View File

@@ -33,7 +33,6 @@
#include <algorithm>
#include <ctime>
#include <set>
#include <sstream>
#include <vector>
#include "ceres/block_random_access_dense_matrix.h"
@@ -564,12 +563,6 @@ SparseSchurComplementSolver::SolveReducedLinearSystemUsingEigen(
// worse than the one computed using the block version of the
// algorithm.
simplicial_ldlt_->analyzePattern(eigen_lhs);
if (VLOG_IS_ON(2)) {
std::stringstream ss;
simplicial_ldlt_->dumpMemory(ss);
VLOG(2) << "Symbolic Analysis\n"
<< ss.str();
}
event_logger.AddEvent("Analysis");
if (simplicial_ldlt_->info() != Eigen::Success) {
summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;

View File

@@ -94,7 +94,7 @@ bool CommonOptionsAreValid(const Solver::Options& options, string* error) {
OPTION_GT(num_linear_solver_threads, 0);
if (options.check_gradients) {
OPTION_GT(gradient_check_relative_precision, 0.0);
OPTION_GT(gradient_check_numeric_derivative_relative_step_size, 0.0);
OPTION_GT(numeric_derivative_relative_step_size, 0.0);
}
return true;
}
@@ -351,7 +351,6 @@ void PreSolveSummarize(const Solver::Options& options,
summary->dense_linear_algebra_library_type = options.dense_linear_algebra_library_type; // NOLINT
summary->dogleg_type = options.dogleg_type;
summary->inner_iteration_time_in_seconds = 0.0;
summary->num_line_search_steps = 0;
summary->line_search_cost_evaluation_time_in_seconds = 0.0;
summary->line_search_gradient_evaluation_time_in_seconds = 0.0;
summary->line_search_polynomial_minimization_time_in_seconds = 0.0;
@@ -496,28 +495,21 @@ void Solver::Solve(const Solver::Options& options,
// values provided by the user.
program->SetParameterBlockStatePtrsToUserStatePtrs();
// If gradient_checking is enabled, wrap all cost functions in a
// gradient checker and install a callback that terminates if any gradient
// error is detected.
scoped_ptr<internal::ProblemImpl> gradient_checking_problem;
internal::GradientCheckingIterationCallback gradient_checking_callback;
Solver::Options modified_options = options;
if (options.check_gradients) {
modified_options.callbacks.push_back(&gradient_checking_callback);
gradient_checking_problem.reset(
CreateGradientCheckingProblemImpl(
problem_impl,
options.gradient_check_numeric_derivative_relative_step_size,
options.gradient_check_relative_precision,
&gradient_checking_callback));
options.numeric_derivative_relative_step_size,
options.gradient_check_relative_precision));
problem_impl = gradient_checking_problem.get();
program = problem_impl->mutable_program();
}
scoped_ptr<Preprocessor> preprocessor(
Preprocessor::Create(modified_options.minimizer_type));
Preprocessor::Create(options.minimizer_type));
PreprocessedProblem pp;
const bool status = preprocessor->Preprocess(modified_options, problem_impl, &pp);
const bool status = preprocessor->Preprocess(options, problem_impl, &pp);
summary->fixed_cost = pp.fixed_cost;
summary->preprocessor_time_in_seconds = WallTimeInSeconds() - start_time;
@@ -542,13 +534,6 @@ void Solver::Solve(const Solver::Options& options,
summary->postprocessor_time_in_seconds =
WallTimeInSeconds() - postprocessor_start_time;
// If the gradient checker reported an error, we want to report FAILURE
// instead of USER_FAILURE and provide the error log.
if (gradient_checking_callback.gradient_error_detected()) {
summary->termination_type = FAILURE;
summary->message = gradient_checking_callback.error_log();
}
summary->total_time_in_seconds = WallTimeInSeconds() - start_time;
}
@@ -571,7 +556,6 @@ Solver::Summary::Summary()
num_successful_steps(-1),
num_unsuccessful_steps(-1),
num_inner_iteration_steps(-1),
num_line_search_steps(-1),
preprocessor_time_in_seconds(-1.0),
minimizer_time_in_seconds(-1.0),
postprocessor_time_in_seconds(-1.0),
@@ -712,14 +696,16 @@ string Solver::Summary::FullReport() const {
num_linear_solver_threads_given,
num_linear_solver_threads_used);
string given;
StringifyOrdering(linear_solver_ordering_given, &given);
string used;
StringifyOrdering(linear_solver_ordering_used, &used);
StringAppendF(&report,
"Linear solver ordering %22s %24s\n",
given.c_str(),
used.c_str());
if (IsSchurType(linear_solver_type_used)) {
string given;
StringifyOrdering(linear_solver_ordering_given, &given);
string used;
StringifyOrdering(linear_solver_ordering_used, &used);
StringAppendF(&report,
"Linear solver ordering %22s %24s\n",
given.c_str(),
used.c_str());
}
if (inner_iterations_given) {
StringAppendF(&report,
@@ -798,14 +784,9 @@ string Solver::Summary::FullReport() const {
num_inner_iteration_steps);
}
const bool line_search_used =
(minimizer_type == LINE_SEARCH ||
(minimizer_type == TRUST_REGION && is_constrained));
if (line_search_used) {
StringAppendF(&report, "Line search steps % 14d\n",
num_line_search_steps);
}
const bool print_line_search_timing_information =
minimizer_type == LINE_SEARCH ||
(minimizer_type == TRUST_REGION && is_constrained);
StringAppendF(&report, "\nTime (in seconds):\n");
StringAppendF(&report, "Preprocessor %25.4f\n",
@@ -813,13 +794,13 @@ string Solver::Summary::FullReport() const {
StringAppendF(&report, "\n Residual evaluation %23.4f\n",
residual_evaluation_time_in_seconds);
if (line_search_used) {
if (print_line_search_timing_information) {
StringAppendF(&report, " Line search cost evaluation %10.4f\n",
line_search_cost_evaluation_time_in_seconds);
}
StringAppendF(&report, " Jacobian evaluation %23.4f\n",
jacobian_evaluation_time_in_seconds);
if (line_search_used) {
if (print_line_search_timing_information) {
StringAppendF(&report, " Line search gradient evaluation %6.4f\n",
line_search_gradient_evaluation_time_in_seconds);
}
@@ -834,7 +815,7 @@ string Solver::Summary::FullReport() const {
inner_iteration_time_in_seconds);
}
if (line_search_used) {
if (print_line_search_timing_information) {
StringAppendF(&report, " Line search polynomial minimization %.4f\n",
line_search_polynomial_minimization_time_in_seconds);
}

View File

@@ -33,7 +33,6 @@
#include <algorithm>
#include <cstring>
#include <ctime>
#include <sstream>
#include "ceres/compressed_row_sparse_matrix.h"
#include "ceres/cxsparse.h"
@@ -72,12 +71,6 @@ LinearSolver::Summary SimplicialLDLTSolve(
if (do_symbolic_analysis) {
solver->analyzePattern(lhs);
if (VLOG_IS_ON(2)) {
std::stringstream ss;
solver->dumpMemory(ss);
VLOG(2) << "Symbolic Analysis\n"
<< ss.str();
}
event_logger->AddEvent("Analyze");
if (solver->info() != Eigen::Success) {
summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;

View File

@@ -43,27 +43,14 @@ namespace internal {
using std::string;
// va_copy() was defined in the C99 standard. However, it did not appear in the
// C++ standard until C++11. This means that if Ceres is being compiled with a
// strict pre-C++11 standard (e.g. -std=c++03), va_copy() will NOT be defined,
// as we are using the C++ compiler (it would however be defined if we were
// using the C compiler). Note however that both GCC & Clang will in fact
// define va_copy() when compiling for C++ if the C++ standard is not explicitly
// specified (i.e. no -std=c++<XX> arg), even though it should not strictly be
// defined unless -std=c++11 (or greater) was passed.
#if !defined(va_copy)
#if defined (__GNUC__)
// On GCC/Clang, if va_copy() is not defined (C++ standard < C++11 explicitly
// specified), use the internal __va_copy() version, which should be present
// in even very old GCC versions.
#define va_copy(d, s) __va_copy(d, s)
#else
// Some older versions of MSVC do not have va_copy(), in which case define it.
// Although this is required for older MSVC versions, it should also work for
// other non-GCC/Clang compilers which also do not defined va_copy().
#ifdef _MSC_VER
enum { IS_COMPILER_MSVC = 1 };
#if _MSC_VER < 1800
#define va_copy(d, s) ((d) = (s))
#endif // defined (__GNUC__)
#endif // !defined(va_copy)
#endif
#else
enum { IS_COMPILER_MSVC = 0 };
#endif
void StringAppendV(string* dst, const char* format, va_list ap) {
// First try with a small fixed size buffer
@@ -84,13 +71,13 @@ void StringAppendV(string* dst, const char* format, va_list ap) {
return;
}
#if defined (_MSC_VER)
// Error or MSVC running out of space. MSVC 8.0 and higher
// can be asked about space needed with the special idiom below:
va_copy(backup_ap, ap);
result = vsnprintf(NULL, 0, format, backup_ap);
va_end(backup_ap);
#endif
if (IS_COMPILER_MSVC) {
// Error or MSVC running out of space. MSVC 8.0 and higher
// can be asked about space needed with the special idiom below:
va_copy(backup_ap, ap);
result = vsnprintf(NULL, 0, format, backup_ap);
va_end(backup_ap);
}
if (result < 0) {
// Just an error.

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
// Copyright 2016 Google Inc. All rights reserved.
// Copyright 2015 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -31,136 +31,35 @@
#ifndef CERES_INTERNAL_TRUST_REGION_MINIMIZER_H_
#define CERES_INTERNAL_TRUST_REGION_MINIMIZER_H_
#include "ceres/internal/eigen.h"
#include "ceres/internal/scoped_ptr.h"
#include "ceres/minimizer.h"
#include "ceres/solver.h"
#include "ceres/sparse_matrix.h"
#include "ceres/trust_region_step_evaluator.h"
#include "ceres/trust_region_strategy.h"
#include "ceres/types.h"
namespace ceres {
namespace internal {
// Generic trust region minimization algorithm.
// Generic trust region minimization algorithm. The heavy lifting is
// done by a TrustRegionStrategy object passed in as part of options.
//
// For example usage, see SolverImpl::Minimize.
class TrustRegionMinimizer : public Minimizer {
public:
~TrustRegionMinimizer();
// This method is not thread safe.
~TrustRegionMinimizer() {}
virtual void Minimize(const Minimizer::Options& options,
double* parameters,
Solver::Summary* solver_summary);
Solver::Summary* summary);
private:
void Init(const Minimizer::Options& options,
double* parameters,
Solver::Summary* solver_summary);
bool IterationZero();
bool FinalizeIterationAndCheckIfMinimizerCanContinue();
bool ComputeTrustRegionStep();
bool EvaluateGradientAndJacobian();
void ComputeCandidatePointAndEvaluateCost();
void DoLineSearch(const Vector& x,
const Vector& gradient,
const double cost,
Vector* delta);
void DoInnerIterationsIfNeeded();
bool ParameterToleranceReached();
bool FunctionToleranceReached();
bool GradientToleranceReached();
bool MaxSolverTimeReached();
bool MaxSolverIterationsReached();
bool MinTrustRegionRadiusReached();
bool IsStepSuccessful();
void HandleUnsuccessfulStep();
bool HandleSuccessfulStep();
bool HandleInvalidStep();
void Init(const Minimizer::Options& options);
void EstimateScale(const SparseMatrix& jacobian, double* scale) const;
bool MaybeDumpLinearLeastSquaresProblem(const int iteration,
const SparseMatrix* jacobian,
const double* residuals,
const double* step) const;
Minimizer::Options options_;
// These pointers are shortcuts to objects passed to the
// TrustRegionMinimizer. The TrustRegionMinimizer does not own them.
double* parameters_;
Solver::Summary* solver_summary_;
Evaluator* evaluator_;
SparseMatrix* jacobian_;
TrustRegionStrategy* strategy_;
scoped_ptr<TrustRegionStepEvaluator> step_evaluator_;
bool is_not_silent_;
bool inner_iterations_are_enabled_;
bool inner_iterations_were_useful_;
// Summary of the current iteration.
IterationSummary iteration_summary_;
// Dimensionality of the problem in the ambient space.
int num_parameters_;
// Dimensionality of the problem in the tangent space. This is the
// number of columns in the Jacobian.
int num_effective_parameters_;
// Length of the residual vector, also the number of rows in the Jacobian.
int num_residuals_;
// Current point.
Vector x_;
// Residuals at x_;
Vector residuals_;
// Gradient at x_.
Vector gradient_;
// Solution computed by the inner iterations.
Vector inner_iteration_x_;
// model_residuals = J * trust_region_step
Vector model_residuals_;
Vector negative_gradient_;
// projected_gradient_step = Plus(x, -gradient), an intermediate
// quantity used to compute the projected gradient norm.
Vector projected_gradient_step_;
// The step computed by the trust region strategy. If Jacobi scaling
// is enabled, this is a vector in the scaled space.
Vector trust_region_step_;
// The current proposal for how far the trust region algorithm
// thinks we should move. In the most basic case, it is just the
// trust_region_step_ with the Jacobi scaling undone. If bounds
// constraints are present, then it is the result of the projected
// line search.
Vector delta_;
// candidate_x = Plus(x, delta)
Vector candidate_x_;
// Scaling vector to scale the columns of the Jacobian.
Vector jacobian_scaling_;
// Euclidean norm of x_.
double x_norm_;
// Cost at x_.
double x_cost_;
// Minimum cost encountered up till now.
double minimum_cost_;
// How much did the trust region strategy reduce the cost of the
// linearized Gauss-Newton model.
double model_cost_change_;
// Cost at candidate_x_.
double candidate_cost_;
// Time at which the minimizer was started.
double start_time_in_secs_;
// Time at which the current iteration was started.
double iteration_start_time_in_secs_;
// Number of consecutive steps where the minimizer loop computed a
// numerically invalid step.
int num_consecutive_invalid_steps_;
};
} // namespace internal
} // namespace ceres
#endif // CERES_INTERNAL_TRUST_REGION_MINIMIZER_H_

View File

@@ -1,107 +0,0 @@
// Ceres Solver - A fast non-linear least squares minimizer
// Copyright 2016 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// 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 Google Inc. 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.
//
// Author: sameeragarwal@google.com (Sameer Agarwal)
#include <algorithm>
#include "ceres/trust_region_step_evaluator.h"
#include "glog/logging.h"
namespace ceres {
namespace internal {
TrustRegionStepEvaluator::TrustRegionStepEvaluator(
const double initial_cost,
const int max_consecutive_nonmonotonic_steps)
: max_consecutive_nonmonotonic_steps_(max_consecutive_nonmonotonic_steps),
minimum_cost_(initial_cost),
current_cost_(initial_cost),
reference_cost_(initial_cost),
candidate_cost_(initial_cost),
accumulated_reference_model_cost_change_(0.0),
accumulated_candidate_model_cost_change_(0.0),
num_consecutive_nonmonotonic_steps_(0){
}
double TrustRegionStepEvaluator::StepQuality(
const double cost,
const double model_cost_change) const {
const double relative_decrease = (current_cost_ - cost) / model_cost_change;
const double historical_relative_decrease =
(reference_cost_ - cost) /
(accumulated_reference_model_cost_change_ + model_cost_change);
return std::max(relative_decrease, historical_relative_decrease);
}
void TrustRegionStepEvaluator::StepAccepted(
const double cost,
const double model_cost_change) {
// Algorithm 10.1.2 from Trust Region Methods by Conn, Gould &
// Toint.
//
// Step 3a
current_cost_ = cost;
accumulated_candidate_model_cost_change_ += model_cost_change;
accumulated_reference_model_cost_change_ += model_cost_change;
// Step 3b.
if (current_cost_ < minimum_cost_) {
minimum_cost_ = current_cost_;
num_consecutive_nonmonotonic_steps_ = 0;
candidate_cost_ = current_cost_;
accumulated_candidate_model_cost_change_ = 0.0;
} else {
// Step 3c.
++num_consecutive_nonmonotonic_steps_;
if (current_cost_ > candidate_cost_) {
candidate_cost_ = current_cost_;
accumulated_candidate_model_cost_change_ = 0.0;
}
}
// Step 3d.
//
// At this point we have made too many non-monotonic steps and
// we are going to reset the value of the reference iterate so
// as to force the algorithm to descend.
//
// Note: In the original algorithm by Toint, this step was only
// executed if the step was non-monotonic, but that would not handle
// the case of max_consecutive_nonmonotonic_steps = 0. The small
// modification of doing this always handles that corner case
// correctly.
if (num_consecutive_nonmonotonic_steps_ ==
max_consecutive_nonmonotonic_steps_) {
reference_cost_ = candidate_cost_;
accumulated_reference_model_cost_change_ =
accumulated_candidate_model_cost_change_;
}
}
} // namespace internal
} // namespace ceres

View File

@@ -1,122 +0,0 @@
// Ceres Solver - A fast non-linear least squares minimizer
// Copyright 2016 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// 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 Google Inc. 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.
//
// Author: sameeragarwal@google.com (Sameer Agarwal)
#ifndef CERES_INTERNAL_TRUST_REGION_STEP_EVALUATOR_H_
#define CERES_INTERNAL_TRUST_REGION_STEP_EVALUATOR_H_
namespace ceres {
namespace internal {
// The job of the TrustRegionStepEvaluator is to evaluate the quality
// of a step, i.e., how the cost of a step compares with the reduction
// in the objective of the trust region problem.
//
// Classic trust region methods are descent methods, in that they only
// accept a point if it strictly reduces the value of the objective
// function. They do this by measuring the quality of a step as
//
// cost_change / model_cost_change.
//
// Relaxing the monotonic descent requirement allows the algorithm to
// be more efficient in the long term at the cost of some local
// increase in the value of the objective function.
//
// This is because allowing for non-decreasing objective function
// values in a principled manner allows the algorithm to "jump over
// boulders" as the method is not restricted to move into narrow
// valleys while preserving its convergence properties.
//
// The parameter max_consecutive_nonmonotonic_steps controls the
// window size used by the step selection algorithm to accept
// non-monotonic steps. Setting this parameter to zero, recovers the
// classic montonic descent algorithm.
//
// Based on algorithm 10.1.2 (page 357) of "Trust Region
// Methods" by Conn Gould & Toint, or equations 33-40 of
// "Non-monotone trust-region algorithms for nonlinear
// optimization subject to convex constraints" by Phil Toint,
// Mathematical Programming, 77, 1997.
//
// Example usage:
//
// TrustRegionStepEvaluator* step_evaluator = ...
//
// cost = ... // Compute the non-linear objective function value.
// model_cost_change = ... // Change in the value of the trust region objective.
// if (step_evaluator->StepQuality(cost, model_cost_change) > threshold) {
// x = x + delta;
// step_evaluator->StepAccepted(cost, model_cost_change);
// }
class TrustRegionStepEvaluator {
public:
// initial_cost is as the name implies the cost of the starting
// state of the trust region minimizer.
//
// max_consecutive_nonmonotonic_steps controls the window size used
// by the step selection algorithm to accept non-monotonic
// steps. Setting this parameter to zero, recovers the classic
// montonic descent algorithm.
TrustRegionStepEvaluator(double initial_cost,
int max_consecutive_nonmonotonic_steps);
// Return the quality of the step given its cost and the decrease in
// the cost of the model. model_cost_change has to be positive.
double StepQuality(double cost, double model_cost_change) const;
// Inform the step evaluator that a step with the given cost and
// model_cost_change has been accepted by the trust region
// minimizer.
void StepAccepted(double cost, double model_cost_change);
private:
const int max_consecutive_nonmonotonic_steps_;
// The minimum cost encountered up till now.
double minimum_cost_;
// The current cost of the trust region minimizer as informed by the
// last call to StepAccepted.
double current_cost_;
double reference_cost_;
double candidate_cost_;
// Accumulated model cost since the last time the reference model
// cost was updated, i.e., when a step with cost less than the
// current known minimum cost is accepted.
double accumulated_reference_model_cost_change_;
// Accumulated model cost since the last time the candidate model
// cost was updated, i.e., a non-monotonic step was taken with a
// cost that was greater than the current candidate cost.
double accumulated_candidate_model_cost_change_;
// Number of steps taken since the last time minimum_cost was updated.
int num_consecutive_nonmonotonic_steps_;
};
} // namespace internal
} // namespace ceres
#endif // CERES_INTERNAL_TRUST_REGION_STEP_EVALUATOR_H_

View File

@@ -86,20 +86,20 @@ class TrustRegionStrategy {
struct PerSolveOptions {
PerSolveOptions()
: eta(0),
dump_filename_base(""),
dump_format_type(TEXTFILE) {
}
// Forcing sequence for inexact solves.
double eta;
DumpFormatType dump_format_type;
// If non-empty and dump_format_type is not CONSOLE, the trust
// regions strategy will write the linear system to file(s) with
// name starting with dump_filename_base. If dump_format_type is
// CONSOLE then dump_filename_base will be ignored and the linear
// system will be written to the standard error.
std::string dump_filename_base;
DumpFormatType dump_format_type;
};
struct Summary {

View File

@@ -369,8 +369,7 @@ typedef unsigned int cl_GLenum;
#endif
/* Define basic vector types */
/* WOrkaround for ppc64el platform: conflicts with bool from C++. */
#if defined( __VEC__ ) && !(defined(__PPC64__) && defined(__LITTLE_ENDIAN__))
#if defined( __VEC__ )
#include <altivec.h> /* may be omitted depending on compiler. AltiVec spec provides no way to detect whether the header is required. */
typedef vector unsigned char __cl_uchar16;
typedef vector signed char __cl_char16;

View File

@@ -137,7 +137,7 @@ int curve_fit_cubic_to_points_refit_db(
const double error_threshold,
const unsigned int calc_flag,
const unsigned int *corners,
const unsigned int corners_len,
unsigned int corners_len,
const double corner_angle,
double **r_cubic_array, unsigned int *r_cubic_array_len,

View File

@@ -18,8 +18,6 @@ Local modifications:
- Applied some modifications from fork https://github.com/Nazg-Gul/gflags.git
(see https://github.com/gflags/gflags/pull/129)
- Avoid attempt of acquiring mutex lock in FlagRegistry::GlobalRegistry when
- Avoid attemot of acquiring mutex lock in FlagRegistry::GlobalRegistry when
doing static flags initialization. See d81dd2d in Blender repository.
- Made `google::{anonymous}::FlagValue::ValueSize() const` inlined, so it does
not trigger strict compiler warning.

View File

@@ -218,7 +218,7 @@ class FlagValue {
bool Equal(const FlagValue& x) const;
FlagValue* New() const; // creates a new one with default value
void CopyFrom(const FlagValue& x);
inline int ValueSize() const;
int ValueSize() const;
// Calls the given validate-fn on value_buffer_, and returns
// whatever it returns. But first casts validate_fn_proto to a
@@ -443,7 +443,7 @@ void FlagValue::CopyFrom(const FlagValue& x) {
}
}
inline int FlagValue::ValueSize() const {
int FlagValue::ValueSize() const {
if (type_ > FV_MAX_INDEX) {
assert(false); // unknown type
return 0;

View File

@@ -59,8 +59,7 @@
# include <unistd.h>
#endif
// Hurd does not have SYS_write.
#if (defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H)) && !defined(__GNU__)
#if defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H)
# define safe_write(fd, s, len) syscall(SYS_write, fd, s, len)
#else
// Not so safe, but what can you do?

View File

@@ -111,7 +111,7 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
result[n++] = *(sp+2);
#elif defined(_CALL_SYSV)
result[n++] = *(sp+1);
#elif defined(__APPLE__) || ((defined(__linux) || defined(__linux__)) && defined(__PPC64__))
#elif defined(__APPLE__) || (defined(__linux) && defined(__PPC64__))
// This check is in case the compiler doesn't define _CALL_AIX/etc.
result[n++] = *(sp+2);
#elif defined(__linux)

View File

@@ -60,10 +60,6 @@
#include <string>
#include <vector>
#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
# include <type_traits>
#endif
#include "gtest/gtest-message.h"
#include "gtest/internal/gtest-string.h"
#include "gtest/internal/gtest-filepath.h"
@@ -858,7 +854,6 @@ struct AddReference<T&> { typedef T& type; }; // NOLINT
template <typename From, typename To>
class ImplicitlyConvertible {
private:
#if !((__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800))
// We need the following helper functions only for their types.
// They have no implementations.
@@ -879,7 +874,6 @@ class ImplicitlyConvertible {
// implicitly converted to type To.
static char Helper(To);
static char (&Helper(...))[2]; // NOLINT
#endif
// We have to put the 'public' section after the 'private' section,
// or MSVC refuses to compile the code.
@@ -889,8 +883,6 @@ class ImplicitlyConvertible {
// instantiation. The simplest workaround is to use its C++0x type traits
// functions (C++Builder 2009 and above only).
static const bool value = __is_convertible(From, To);
#elif (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
static const bool value = std::is_convertible<From, To>::value;
#else
// MSVC warns about implicitly converting from double to int for
// possible loss of data, so we need to temporarily disable the

View File

@@ -21,10 +21,10 @@ set(INC
)
set(SRC
range_tree.h
intern/generic_alloc_impl.h
range_tree.hh
range_tree_c_api.h
intern/range_tree.c
range_tree_c_api.cc
)
blender_add_lib(extern_rangetree "${SRC}" "${INC}" "")

View File

@@ -1,5 +1,5 @@
Project: RangeTree
URL: https://github.com/ideasman42/rangetree-c
License: Apache 2.0
Upstream version: 40ebed8aa209
URL: https://github.com/nicholasbishop/RangeTree
License: GPLv2+
Upstream version: c4ecf6bb7dfd
Local modifications: None

13
extern/rangetree/README.org vendored Normal file
View File

@@ -0,0 +1,13 @@
* Overview
Basic class for storing non-overlapping scalar ranges. Underlying
representation is a C++ STL set for fast lookups.
* License
GPL version 2 or later (see COPYING)
* Author Note
This implementation is intended for storing free unique IDs in a new
undo system for BMesh in Blender, but could be useful elsewhere.
* Website
https://github.com/nicholasbishop/RangeTree

View File

@@ -1,215 +0,0 @@
/*
* Copyright (c) 2016, Blender Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "Apache License")
* with the following modification; you may not use this file except in
* compliance with the Apache License and the following modification to it:
* Section 6. Trademarks. is deleted and replaced with:
*
* 6. Trademarks. This License does not grant permission to use the trade
* names, trademarks, service marks, or product names of the Licensor
* and its affiliates, except as required to comply with Section 4(c) of
* the License and to reproduce the content of the NOTICE file.
*
* You may obtain a copy of the Apache License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Apache License with the above modification is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the Apache License for the specific
* language governing permissions and limitations under the Apache License.
*/
/**
* Simple Memory Chunking Allocator
* ================================
*
* Defines need to be set:
* - #TPOOL_IMPL_PREFIX: Prefix to use for the API.
* - #TPOOL_ALLOC_TYPE: Struct type this pool handles.
* - #TPOOL_STRUCT: Name for pool struct name.
* - #TPOOL_CHUNK_SIZE: Chunk size (optional), use 64kb when not defined.
*
* \note #TPOOL_ALLOC_TYPE must be at least ``sizeof(void *)``.
*
* Defines the API, uses #TPOOL_IMPL_PREFIX to prefix each function.
*
* - *_pool_create()
* - *_pool_destroy()
* - *_pool_clear()
*
* - *_pool_elem_alloc()
* - *_pool_elem_calloc()
* - *_pool_elem_free()
*/
/* check we're not building directly */
#if !defined(TPOOL_IMPL_PREFIX) || \
!defined(TPOOL_ALLOC_TYPE) || \
!defined(TPOOL_STRUCT)
# error "This file can't be compiled directly, include in another source file"
#endif
#define _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1 ## MACRO_ARG2
#define _CONCAT(MACRO_ARG1, MACRO_ARG2) _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2)
#define _TPOOL_PREFIX(id) _CONCAT(TPOOL_IMPL_PREFIX, _##id)
/* local identifiers */
#define pool_create _TPOOL_PREFIX(pool_create)
#define pool_destroy _TPOOL_PREFIX(pool_destroy)
#define pool_clear _TPOOL_PREFIX(pool_clear)
#define pool_elem_alloc _TPOOL_PREFIX(pool_elem_alloc)
#define pool_elem_calloc _TPOOL_PREFIX(pool_elem_calloc)
#define pool_elem_free _TPOOL_PREFIX(pool_elem_free)
/* private identifiers (only for this file, undefine after) */
#define pool_alloc_chunk _TPOOL_PREFIX(pool_alloc_chunk)
#define TPoolChunk _TPOOL_PREFIX(TPoolChunk)
#define TPoolChunkElemFree _TPOOL_PREFIX(TPoolChunkElemFree)
#ifndef TPOOL_CHUNK_SIZE
#define TPOOL_CHUNK_SIZE (1 << 16) /* 64kb */
#define _TPOOL_CHUNK_SIZE_UNDEF
#endif
#ifndef UNLIKELY
# ifdef __GNUC__
# define UNLIKELY(x) __builtin_expect(!!(x), 0)
# else
# define UNLIKELY(x) (x)
# endif
#endif
#ifdef __GNUC__
# define MAYBE_UNUSED __attribute__((unused))
#else
# define MAYBE_UNUSED
#endif
struct TPoolChunk {
struct TPoolChunk *prev;
unsigned int size;
unsigned int bufsize;
TPOOL_ALLOC_TYPE buf[0];
};
struct TPoolChunkElemFree {
struct TPoolChunkElemFree *next;
};
struct TPOOL_STRUCT {
/* Always keep at least one chunk (never NULL) */
struct TPoolChunk *chunk;
/* when NULL, allocate a new chunk */
struct TPoolChunkElemFree *free;
};
/**
* Number of elems to include per #TPoolChunk when no reserved size is passed,
* or we allocate past the reserved number.
*
* \note Optimize number for 64kb allocs.
*/
#define _TPOOL_CHUNK_DEFAULT_NUM \
(((1 << 16) - sizeof(struct TPoolChunk)) / sizeof(TPOOL_ALLOC_TYPE))
/** \name Internal Memory Management
* \{ */
static struct TPoolChunk *pool_alloc_chunk(
unsigned int tot_elems, struct TPoolChunk *chunk_prev)
{
struct TPoolChunk *chunk = malloc(
sizeof(struct TPoolChunk) + (sizeof(TPOOL_ALLOC_TYPE) * tot_elems));
chunk->prev = chunk_prev;
chunk->bufsize = tot_elems;
chunk->size = 0;
return chunk;
}
static TPOOL_ALLOC_TYPE *pool_elem_alloc(struct TPOOL_STRUCT *pool)
{
TPOOL_ALLOC_TYPE *elem;
if (pool->free) {
elem = (TPOOL_ALLOC_TYPE *)pool->free;
pool->free = pool->free->next;
}
else {
struct TPoolChunk *chunk = pool->chunk;
if (UNLIKELY(chunk->size == chunk->bufsize)) {
chunk = pool->chunk = pool_alloc_chunk(_TPOOL_CHUNK_DEFAULT_NUM, chunk);
}
elem = &chunk->buf[chunk->size++];
}
return elem;
}
MAYBE_UNUSED
static TPOOL_ALLOC_TYPE *pool_elem_calloc(struct TPOOL_STRUCT *pool)
{
TPOOL_ALLOC_TYPE *elem = pool_elem_alloc(pool);
memset(elem, 0, sizeof(*elem));
return elem;
}
static void pool_elem_free(struct TPOOL_STRUCT *pool, TPOOL_ALLOC_TYPE *elem)
{
struct TPoolChunkElemFree *elem_free = (struct TPoolChunkElemFree *)elem;
elem_free->next = pool->free;
pool->free = elem_free;
}
static void pool_create(struct TPOOL_STRUCT *pool, unsigned int tot_reserve)
{
pool->chunk = pool_alloc_chunk((tot_reserve > 1) ? tot_reserve : _TPOOL_CHUNK_DEFAULT_NUM, NULL);
pool->free = NULL;
}
MAYBE_UNUSED
static void pool_clear(struct TPOOL_STRUCT *pool)
{
/* Remove all except the last chunk */
while (pool->chunk->prev) {
struct TPoolChunk *chunk_prev = pool->chunk->prev;
free(pool->chunk);
pool->chunk = chunk_prev;
}
pool->chunk->size = 0;
pool->free = NULL;
}
static void pool_destroy(struct TPOOL_STRUCT *pool)
{
struct TPoolChunk *chunk = pool->chunk;
do {
struct TPoolChunk *chunk_prev;
chunk_prev = chunk->prev;
free(chunk);
chunk = chunk_prev;
} while (chunk);
pool->chunk = NULL;
pool->free = NULL;
}
/** \} */
#undef _TPOOL_CHUNK_DEFAULT_NUM
#undef _CONCAT_AUX
#undef _CONCAT
#undef _TPOOL_PREFIX
#undef TPoolChunk
#undef TPoolChunkElemFree
#ifdef _TPOOL_CHUNK_SIZE_UNDEF
# undef TPOOL_CHUNK_SIZE
# undef _TPOOL_CHUNK_SIZE_UNDEF
#endif

View File

@@ -1,873 +0,0 @@
/*
* Copyright (c) 2016, Campbell Barton.
*
* Licensed under the Apache License, Version 2.0 (the "Apache License")
* with the following modification; you may not use this file except in
* compliance with the Apache License and the following modification to it:
* Section 6. Trademarks. is deleted and replaced with:
*
* 6. Trademarks. This License does not grant permission to use the trade
* names, trademarks, service marks, or product names of the Licensor
* and its affiliates, except as required to comply with Section 4(c) of
* the License and to reproduce the content of the NOTICE file.
*
* You may obtain a copy of the Apache License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Apache License with the above modification is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the Apache License for the specific
* language governing permissions and limitations under the Apache License.
*/
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include "range_tree.h"
typedef unsigned int uint;
/* Use binary-tree for lookups, else fallback to full search */
#define USE_BTREE
/* Use memory pool for nodes, else do individual allocations */
#define USE_TPOOL
/* Node representing a range in the RangeTreeUInt. */
typedef struct Node {
struct Node *next, *prev;
/* range (inclusive) */
uint min, max;
#ifdef USE_BTREE
/* Left leaning red-black tree, for reference implementation see:
* https://gitlab.com/ideasman42/btree-mini-py */
struct Node *left, *right;
/* RED/BLACK */
bool color;
#endif
} Node;
#ifdef USE_TPOOL
/* rt_pool_* pool allocator */
#define TPOOL_IMPL_PREFIX rt_node
#define TPOOL_ALLOC_TYPE Node
#define TPOOL_STRUCT ElemPool_Node
#include "generic_alloc_impl.h"
#undef TPOOL_IMPL_PREFIX
#undef TPOOL_ALLOC_TYPE
#undef TPOOL_STRUCT
#endif /* USE_TPOOL */
typedef struct LinkedList {
Node *first, *last;
} LinkedList;
typedef struct RangeTreeUInt {
uint range[2];
LinkedList list;
#ifdef USE_BTREE
Node *root;
#endif
#ifdef USE_TPOOL
struct ElemPool_Node epool;
#endif
} RangeTreeUInt;
/* ------------------------------------------------------------------------- */
/* List API */
static void list_push_front(LinkedList *list, Node *node)
{
if (list->first != NULL) {
node->next = list->first;
node->next->prev = node;
node->prev = NULL;
}
else {
list->last = node;
}
list->first = node;
}
static void list_push_back(LinkedList *list, Node *node)
{
if (list->first != NULL) {
node->prev = list->last;
node->prev->next = node;
node->next = NULL;
}
else {
list->first = node;
}
list->last = node;
}
static void list_push_after(LinkedList *list, Node *node_prev, Node *node_new)
{
/* node_new before node_next */
/* empty list */
if (list->first == NULL) {
list->first = node_new;
list->last = node_new;
return;
}
/* insert at head of list */
if (node_prev == NULL) {
node_new->prev = NULL;
node_new->next = list->first;
node_new->next->prev = node_new;
list->first = node_new;
return;
}
/* at end of list */
if (list->last == node_prev) {
list->last = node_new;
}
node_new->next = node_prev->next;
node_new->prev = node_prev;
node_prev->next = node_new;
if (node_new->next) {
node_new->next->prev = node_new;
}
}
static void list_push_before(LinkedList *list, Node *node_next, Node *node_new)
{
/* node_new before node_next */
/* empty list */
if (list->first == NULL) {
list->first = node_new;
list->last = node_new;
return;
}
/* insert at end of list */
if (node_next == NULL) {
node_new->prev = list->last;
node_new->next = NULL;
list->last->next = node_new;
list->last = node_new;
return;
}
/* at beginning of list */
if (list->first == node_next) {
list->first = node_new;
}
node_new->next = node_next;
node_new->prev = node_next->prev;
node_next->prev = node_new;
if (node_new->prev) {
node_new->prev->next = node_new;
}
}
static void list_remove(LinkedList *list, Node *node)
{
if (node->next != NULL) {
node->next->prev = node->prev;
}
if (node->prev != NULL) {
node->prev->next = node->next;
}
if (list->last == node) {
list->last = node->prev;
}
if (list->first == node) {
list->first = node->next;
}
}
static void list_clear(LinkedList *list)
{
list->first = NULL;
list->last = NULL;
}
/* end list API */
/* forward declarations */
static void rt_node_free(RangeTreeUInt *rt, Node *node);
#ifdef USE_BTREE
#ifdef DEBUG
static bool rb_is_balanced_root(const Node *root);
#endif
/* ------------------------------------------------------------------------- */
/* Internal BTree API
*
* Left-leaning red-black tree.
*/
/* use minimum, could use max too since nodes never overlap */
#define KEY(n) ((n)->min)
enum {
RED = 0,
BLACK = 1,
};
static bool is_red(const Node *node)
{
return (node && (node->color == RED));
}
static int key_cmp(uint key1, uint key2)
{
return (key1 == key2) ? 0 : ((key1 < key2) ? -1 : 1);
}
/* removed from the tree */
static void rb_node_invalidate(Node *node)
{
#ifdef DEBUG
node->left = NULL;
node->right = NULL;
node->color = false;
#else
(void)node;
#endif
}
static void rb_flip_color(Node *node)
{
node->color ^= 1;
node->left->color ^= 1;
node->right->color ^= 1;
}
static Node *rb_rotate_left(Node *left)
{
/* Make a right-leaning 3-node lean to the left. */
Node *right = left->right;
left->right = right->left;
right->left = left;
right->color = left->color;
left->color = RED;
return right;
}
static Node *rb_rotate_right(Node *right)
{
/* Make a left-leaning 3-node lean to the right. */
Node *left = right->left;
right->left = left->right;
left->right = right;
left->color = right->color;
right->color = RED;
return left;
}
/* Fixup colors when insert happened */
static Node *rb_fixup_insert(Node *node)
{
if (is_red(node->right) && !is_red(node->left)) {
node = rb_rotate_left(node);
}
if (is_red(node->left) && is_red(node->left->left)) {
node = rb_rotate_right(node);
}
if (is_red(node->left) && is_red(node->right)) {
rb_flip_color(node);
}
return node;
}
static Node *rb_insert_recursive(Node *node, Node *node_to_insert)
{
if (node == NULL) {
return node_to_insert;
}
const int cmp = key_cmp(KEY(node_to_insert), KEY(node));
if (cmp == 0) {
/* caller ensures no collisions */
assert(0);
}
else if (cmp == -1) {
node->left = rb_insert_recursive(node->left, node_to_insert);
}
else {
node->right = rb_insert_recursive(node->right, node_to_insert);
}
return rb_fixup_insert(node);
}
static Node *rb_insert_root(Node *root, Node *node_to_insert)
{
root = rb_insert_recursive(root, node_to_insert);
root->color = BLACK;
return root;
}
static Node *rb_move_red_to_left(Node *node)
{
/* Assuming that h is red and both h->left and h->left->left
* are black, make h->left or one of its children red.
*/
rb_flip_color(node);
if (node->right && is_red(node->right->left)) {
node->right = rb_rotate_right(node->right);
node = rb_rotate_left(node);
rb_flip_color(node);
}
return node;
}
static Node *rb_move_red_to_right(Node *node)
{
/* Assuming that h is red and both h->right and h->right->left
* are black, make h->right or one of its children red.
*/
rb_flip_color(node);
if (node->left && is_red(node->left->left)) {
node = rb_rotate_right(node);
rb_flip_color(node);
}
return node;
}
/* Fixup colors when remove happened */
static Node *rb_fixup_remove(Node *node)
{
if (is_red(node->right)) {
node = rb_rotate_left(node);
}
if (is_red(node->left) && is_red(node->left->left)) {
node = rb_rotate_right(node);
}
if (is_red(node->left) && is_red(node->right)) {
rb_flip_color(node);
}
return node;
}
static Node *rb_pop_min_recursive(Node *node, Node **r_node_pop)
{
if (node == NULL) {
return NULL;
}
if (node->left == NULL) {
rb_node_invalidate(node);
*r_node_pop = node;
return NULL;
}
if ((!is_red(node->left)) && (!is_red(node->left->left))) {
node = rb_move_red_to_left(node);
}
node->left = rb_pop_min_recursive(node->left, r_node_pop);
return rb_fixup_remove(node);
}
static Node *rb_remove_recursive(Node *node, const Node *node_to_remove)
{
if (node == NULL) {
return NULL;
}
if (key_cmp(KEY(node_to_remove), KEY(node)) == -1) {
if (node->left != NULL) {
if ((!is_red(node->left)) && (!is_red(node->left->left))) {
node = rb_move_red_to_left(node);
}
}
node->left = rb_remove_recursive(node->left, node_to_remove);
}
else {
if (is_red(node->left)) {
node = rb_rotate_right(node);
}
if ((node == node_to_remove) && (node->right == NULL)) {
rb_node_invalidate(node);
return NULL;
}
assert(node->right != NULL);
if ((!is_red(node->right)) && (!is_red(node->right->left))) {
node = rb_move_red_to_right(node);
}
if (node == node_to_remove) {
/* minor improvement over original method:
* no need to double lookup min */
Node *node_free; /* will always be set */
node->right = rb_pop_min_recursive(node->right, &node_free);
node_free->left = node->left;
node_free->right = node->right;
node_free->color = node->color;
rb_node_invalidate(node);
node = node_free;
}
else {
node->right = rb_remove_recursive(node->right, node_to_remove);
}
}
return rb_fixup_remove(node);
}
static Node *rb_btree_remove(Node *root, const Node *node_to_remove)
{
root = rb_remove_recursive(root, node_to_remove);
if (root != NULL) {
root->color = BLACK;
}
return root;
}
/*
* Returns the node closest to and including 'key',
* excluding anything below.
*/
static Node *rb_get_or_upper_recursive(Node *n, const uint key)
{
if (n == NULL) {
return NULL;
}
const int cmp_upper = key_cmp(KEY(n), key);
if (cmp_upper == 0) {
return n; // exact match
}
else if (cmp_upper == 1) {
assert(KEY(n) >= key);
Node *n_test = rb_get_or_upper_recursive(n->left, key);
return n_test ? n_test : n;
}
else { // cmp_upper == -1
return rb_get_or_upper_recursive(n->right, key);
}
}
/*
* Returns the node closest to and including 'key',
* excluding anything above.
*/
static Node *rb_get_or_lower_recursive(Node *n, const uint key)
{
if (n == NULL) {
return NULL;
}
const int cmp_lower = key_cmp(KEY(n), key);
if (cmp_lower == 0) {
return n; // exact match
}
else if (cmp_lower == -1) {
assert(KEY(n) <= key);
Node *n_test = rb_get_or_lower_recursive(n->right, key);
return n_test ? n_test : n;
}
else { // cmp_lower == 1
return rb_get_or_lower_recursive(n->left, key);
}
}
#ifdef DEBUG
static bool rb_is_balanced_recursive(const Node *node, int black)
{
// Does every path from the root to a leaf have the given number
// of black links?
if (node == NULL) {
return black == 0;
}
if (!is_red(node)) {
black--;
}
return rb_is_balanced_recursive(node->left, black) &&
rb_is_balanced_recursive(node->right, black);
}
static bool rb_is_balanced_root(const Node *root)
{
// Do all paths from root to leaf have same number of black edges?
int black = 0; // number of black links on path from root to min
const Node *node = root;
while (node != NULL) {
if (!is_red(node)) {
black++;
}
node = node->left;
}
return rb_is_balanced_recursive(root, black);
}
#endif // DEBUG
/* End BTree API */
#endif // USE_BTREE
/* ------------------------------------------------------------------------- */
/* Internal RangeTreeUInt API */
#ifdef _WIN32
#define inline __inline
#endif
static inline Node *rt_node_alloc(RangeTreeUInt *rt)
{
#ifdef USE_TPOOL
return rt_node_pool_elem_alloc(&rt->epool);
#else
(void)rt;
return malloc(sizeof(Node));
#endif
}
static Node *rt_node_new(RangeTreeUInt *rt, uint min, uint max)
{
Node *node = rt_node_alloc(rt);
assert(min <= max);
node->prev = NULL;
node->next = NULL;
node->min = min;
node->max = max;
#ifdef USE_BTREE
node->left = NULL;
node->right = NULL;
#endif
return node;
}
static void rt_node_free(RangeTreeUInt *rt, Node *node)
{
#ifdef USE_TPOOL
rt_node_pool_elem_free(&rt->epool, node);
#else
(void)rt;
free(node);
#endif
}
#ifdef USE_BTREE
static void rt_btree_insert(RangeTreeUInt *rt, Node *node)
{
node->color = RED;
node->left = NULL;
node->right = NULL;
rt->root = rb_insert_root(rt->root, node);
}
#endif
static void rt_node_add_back(RangeTreeUInt *rt, Node *node)
{
list_push_back(&rt->list, node);
#ifdef USE_BTREE
rt_btree_insert(rt, node);
#endif
}
static void rt_node_add_front(RangeTreeUInt *rt, Node *node)
{
list_push_front(&rt->list, node);
#ifdef USE_BTREE
rt_btree_insert(rt, node);
#endif
}
static void rt_node_add_before(RangeTreeUInt *rt, Node *node_next, Node *node)
{
list_push_before(&rt->list, node_next, node);
#ifdef USE_BTREE
rt_btree_insert(rt, node);
#endif
}
static void rt_node_add_after(RangeTreeUInt *rt, Node *node_prev, Node *node)
{
list_push_after(&rt->list, node_prev, node);
#ifdef USE_BTREE
rt_btree_insert(rt, node);
#endif
}
static void rt_node_remove(RangeTreeUInt *rt, Node *node)
{
list_remove(&rt->list, node);
#ifdef USE_BTREE
rt->root = rb_btree_remove(rt->root, node);
#endif
rt_node_free(rt, node);
}
static Node *rt_find_node_from_value(RangeTreeUInt *rt, const uint value)
{
#ifdef USE_BTREE
Node *node = rb_get_or_lower_recursive(rt->root, value);
if (node != NULL) {
if ((value >= node->min) && (value <= node->max)) {
return node;
}
}
return NULL;
#else
for (Node *node = rt->list.first; node; node = node->next) {
if ((value >= node->min) && (value <= node->max)) {
return node;
}
}
return NULL;
#endif // USE_BTREE
}
static void rt_find_node_pair_around_value(RangeTreeUInt *rt, const uint value,
Node **r_node_prev, Node **r_node_next)
{
if (value < rt->list.first->min) {
*r_node_prev = NULL;
*r_node_next = rt->list.first;
return;
}
else if (value > rt->list.last->max) {
*r_node_prev = rt->list.last;
*r_node_next = NULL;
return;
}
else {
#ifdef USE_BTREE
Node *node_next = rb_get_or_upper_recursive(rt->root, value);
if (node_next != NULL) {
Node *node_prev = node_next->prev;
if ((node_prev->max < value) && (value < node_next->min)) {
*r_node_prev = node_prev;
*r_node_next = node_next;
return;
}
}
#else
Node *node_prev = rt->list.first;
Node *node_next;
while ((node_next = node_prev->next)) {
if ((node_prev->max < value) && (value < node_next->min)) {
*r_node_prev = node_prev;
*r_node_next = node_next;
return;
}
node_prev = node_next;
}
#endif // USE_BTREE
}
*r_node_prev = NULL;
*r_node_next = NULL;
}
/* ------------------------------------------------------------------------- */
/* Public API */
static RangeTreeUInt *rt_create_empty(uint min, uint max)
{
RangeTreeUInt *rt = malloc(sizeof(*rt));
rt->range[0] = min;
rt->range[1] = max;
list_clear(&rt->list);
#ifdef USE_BTREE
rt->root = NULL;
#endif
#ifdef USE_TPOOL
rt_node_pool_create(&rt->epool, 512);
#endif
return rt;
}
RangeTreeUInt *range_tree_uint_alloc(uint min, uint max)
{
RangeTreeUInt *rt = rt_create_empty(min, max);
Node *node = rt_node_new(rt, min, max);
rt_node_add_front(rt, node);
return rt;
}
void range_tree_uint_free(RangeTreeUInt *rt)
{
#ifdef DEBUG
#ifdef USE_BTREE
assert(rb_is_balanced_root(rt->root));
#endif
#endif
#ifdef USE_TPOOL
rt_node_pool_destroy(&rt->epool);
#else
for (Node *node = rt->list.first, *node_next; node; node = node_next) {
node_next = node->next;
rt_node_free(rt, node);
}
#endif
free(rt);
}
#ifdef USE_BTREE
static Node *rt_copy_recursive(RangeTreeUInt *rt_dst, const Node *node_src)
{
if (node_src == NULL) {
return NULL;
}
Node *node_dst = rt_node_alloc(rt_dst);
*node_dst = *node_src;
node_dst->left = rt_copy_recursive(rt_dst, node_dst->left);
list_push_back(&rt_dst->list, node_dst);
node_dst->right = rt_copy_recursive(rt_dst, node_dst->right);
return node_dst;
}
#endif // USE_BTREE
RangeTreeUInt *range_tree_uint_copy(const RangeTreeUInt *rt_src)
{
RangeTreeUInt *rt_dst = rt_create_empty(rt_src->range[0], rt_src->range[1]);
#ifdef USE_BTREE
rt_dst->root = rt_copy_recursive(rt_dst, rt_src->root);
#else
for (Node *node_src = rt_src->list.first; node_src; node_src = node_src->next) {
Node *node_dst = rt_node_alloc(rt_dst);
*node_dst = *node_src;
list_push_back(&rt_dst->list, node_dst);
}
#endif
return rt_dst;
}
/**
* Return true if the tree has the value (not taken).
*/
bool range_tree_uint_has(RangeTreeUInt *rt, const uint value)
{
assert(value >= rt->range[0] && value <= rt->range[1]);
Node *node = rt_find_node_from_value(rt, value);
return (node != NULL);
}
static void range_tree_uint_take_impl(RangeTreeUInt *rt, const uint value, Node *node)
{
assert(node == rt_find_node_from_value(rt, value));
if (node->min == value) {
if (node->max != value) {
node->min += 1;
}
else {
assert(node->min == node->max);
rt_node_remove(rt, node);
}
}
else if (node->max == value) {
node->max -= 1;
}
else {
Node *node_next = rt_node_new(rt, value + 1, node->max);
node->max = value - 1;
rt_node_add_after(rt, node, node_next);
}
}
void range_tree_uint_take(RangeTreeUInt *rt, const uint value)
{
Node *node = rt_find_node_from_value(rt, value);
assert(node != NULL);
range_tree_uint_take_impl(rt, value, node);
}
bool range_tree_uint_retake(RangeTreeUInt *rt, const uint value)
{
Node *node = rt_find_node_from_value(rt, value);
if (node != NULL) {
range_tree_uint_take_impl(rt, value, node);
return true;
}
else {
return false;
}
}
uint range_tree_uint_take_any(RangeTreeUInt *rt)
{
Node *node = rt->list.first;
uint value = node->min;
if (value == node->max) {
rt_node_remove(rt, node);
}
else {
node->min += 1;
}
return value;
}
void range_tree_uint_release(RangeTreeUInt *rt, const uint value)
{
bool touch_prev, touch_next;
Node *node_prev, *node_next;
if (rt->list.first != NULL) {
rt_find_node_pair_around_value(rt, value, &node_prev, &node_next);
/* the value must have been already taken */
assert(node_prev || node_next);
/* Cases:
* 1) fill the gap between prev & next (two spans into one span).
* 2) touching prev, (grow node_prev->max up one).
* 3) touching next, (grow node_next->min down one).
* 4) touching neither, add a new segment. */
touch_prev = (node_prev != NULL && node_prev->max + 1 == value);
touch_next = (node_next != NULL && node_next->min - 1 == value);
}
else {
// we could handle this case (4) inline,
// since its not a common case - use regular logic.
node_prev = node_next = NULL;
touch_prev = false;
touch_next = false;
}
if (touch_prev && touch_next) { // 1)
node_prev->max = node_next->max;
rt_node_remove(rt, node_next);
}
else if (touch_prev) { // 2)
assert(node_prev->max + 1 == value);
node_prev->max = value;
}
else if (touch_next) { // 3)
assert(node_next->min - 1 == value);
node_next->min = value;
}
else { // 4)
Node *node_new = rt_node_new(rt, value, value);
if (node_prev != NULL) {
rt_node_add_after(rt, node_prev, node_new);
}
else if (node_next != NULL) {
rt_node_add_before(rt, node_next, node_new);
}
else {
assert(rt->list.first == NULL);
rt_node_add_back(rt, node_new);
}
}
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright (c) 2016, Campbell Barton.
*
* Licensed under the Apache License, Version 2.0 (the "Apache License")
* with the following modification; you may not use this file except in
* compliance with the Apache License and the following modification to it:
* Section 6. Trademarks. is deleted and replaced with:
*
* 6. Trademarks. This License does not grant permission to use the trade
* names, trademarks, service marks, or product names of the Licensor
* and its affiliates, except as required to comply with Section 4(c) of
* the License and to reproduce the content of the NOTICE file.
*
* You may obtain a copy of the Apache License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Apache License with the above modification is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the Apache License for the specific
* language governing permissions and limitations under the Apache License.
*/
#ifndef __RANGE_TREE_H__
#define __RANGE_TREE_H__
#ifdef __cplusplus
extern "C" {
#endif
typedef struct RangeTreeUInt RangeTreeUInt;
struct RangeTreeUInt *range_tree_uint_alloc(unsigned int min, unsigned int max);
void range_tree_uint_free(struct RangeTreeUInt *rt);
struct RangeTreeUInt *range_tree_uint_copy(const struct RangeTreeUInt *rt_src);
bool range_tree_uint_has(struct RangeTreeUInt *rt, const unsigned int value);
void range_tree_uint_take(struct RangeTreeUInt *rt, const unsigned int value);
bool range_tree_uint_retake(struct RangeTreeUInt *rt, const unsigned int value);
unsigned int range_tree_uint_take_any(struct RangeTreeUInt *rt);
void range_tree_uint_release(struct RangeTreeUInt *rt, const unsigned int value);
#ifdef __cplusplus
}
#endif
#endif /* __RANGE_TREE_H__ */

251
extern/rangetree/range_tree.hh vendored Normal file
View File

@@ -0,0 +1,251 @@
/* 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 2 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*/
#include <cassert>
#include <climits>
#include <iostream>
#include <set>
#ifndef RANGE_TREE_DEBUG_PRINT_FUNCTION
# define RANGE_TREE_DEBUG_PRINT_FUNCTION 0
#endif
template <typename T>
struct RangeTree {
struct Range {
Range(T min_, T max_)
: min(min_), max(max_), single(min_ == max_) {
assert(min_ <= max_);
}
Range(T t)
: min(t), max(t), single(true)
{}
Range& operator=(const Range& v) {
*this = v;
return *this;
}
bool operator<(const Range& v) const {
return max < v.min;
}
const T min;
const T max;
const bool single;
};
typedef std::set<Range> Tree;
typedef typename Tree::iterator TreeIter;
typedef typename Tree::reverse_iterator TreeIterReverse;
typedef typename Tree::const_iterator TreeIterConst;
/* Initialize with a single range from 'min' to 'max', inclusive. */
RangeTree(T min, T max) {
tree.insert(Range(min, max));
}
/* Initialize with a single range from 0 to 'max', inclusive. */
RangeTree(T max) {
tree.insert(Range(0, max));
}
RangeTree(const RangeTree<T>& src) {
tree = src.tree;
}
/* Remove 't' from the associated range in the tree. Precondition:
a range including 't' must exist in the tree. */
void take(T t) {
#if RANGE_TREE_DEBUG_PRINT_FUNCTION
std::cout << __func__ << "(" << t << ")\n";
#endif
/* Find the range that includes 't' and its neighbors */
TreeIter iter = tree.find(Range(t));
assert(iter != tree.end());
Range cur = *iter;
/* Remove the original range (note that this does not
invalidate the prev/next iterators) */
tree.erase(iter);
/* Construct two new ranges that together cover the original
range, except for 't' */
if (t > cur.min)
tree.insert(Range(cur.min, t - 1));
if (t + 1 <= cur.max)
tree.insert(Range(t + 1, cur.max));
}
/* clone of 'take' that checks if the item exists */
bool retake(T t) {
#if RANGE_TREE_DEBUG_PRINT_FUNCTION
std::cout << __func__ << "(" << t << ")\n";
#endif
TreeIter iter = tree.find(Range(t));
if (iter == tree.end()) {
return false;
}
Range cur = *iter;
tree.erase(iter);
if (t > cur.min)
tree.insert(Range(cur.min, t - 1));
if (t + 1 <= cur.max)
tree.insert(Range(t + 1, cur.max));
return true;
}
/* Take the first element out of the first range in the
tree. Precondition: tree must not be empty. */
T take_any() {
#if RANGE_TREE_DEBUG_PRINT_FUNCTION
std::cout << __func__ << "()\n";
#endif
/* Find the first element */
TreeIter iter = tree.begin();
assert(iter != tree.end());
T first = iter->min;
/* Take the first element */
take(first);
return first;
}
/* Return 't' to the tree, either expanding/merging existing
ranges or adding a range to cover it. Precondition: 't' cannot
be in an existing range. */
void release(T t) {
#if RANGE_TREE_DEBUG_PRINT_FUNCTION
std::cout << __func__ << "(" << t << ")\n";
#endif
/* TODO: these cases should be simplified/unified */
TreeIter right = tree.upper_bound(t);
if (right != tree.end()) {
TreeIter left = right;
if (left != tree.begin())
--left;
if (left == right) {
/* 't' lies before any existing ranges */
if (t + 1 == left->min) {
/* 't' lies directly before the first range,
resize and replace that range */
const Range r(t, left->max);
tree.erase(left);
tree.insert(r);
}
else {
/* There's a gap between 't' and the first range,
add a new range */
tree.insert(Range(t));
}
}
else if ((left->max + 1 == t) &&
(t + 1 == right->min)) {
/* 't' fills a hole. Remove left and right, and insert a
new range that covers both. */
const Range r(left->min, right->max);
tree.erase(left);
tree.erase(right);
tree.insert(r);
}
else if (left->max + 1 == t) {
/* 't' lies directly after 'left' range, resize and
replace that range */
const Range r(left->min, t);
tree.erase(left);
tree.insert(r);
}
else if (t + 1 == right->min) {
/* 't' lies directly before 'right' range, resize and
replace that range */
const Range r(t, right->max);
tree.erase(right);
tree.insert(r);
}
else {
/* There's a gap between 't' and both adjacent ranges,
add a new range */
tree.insert(Range(t));
}
}
else {
/* 't' lies after any existing ranges */
right = tree.end();
right--;
if (right->max + 1 == t) {
/* 't' lies directly after last range, resize and
replace that range */
const Range r(right->min, t);
tree.erase(right);
tree.insert(r);
}
else {
/* There's a gap between the last range and 't', add a
new range */
tree.insert(Range(t));
}
}
}
bool has(T t) const {
TreeIterConst iter = tree.find(Range(t));
return (iter != tree.end()) && (t <= iter->max);
}
bool has_range(T min, T max) const {
TreeIterConst iter = tree.find(Range(min, max));
return (iter != tree.end()) && (min == iter->min && max == iter->max);
}
bool empty() const {
return tree.empty();
}
int size() const {
return tree.size();
}
void print() const {
std::cout << "RangeTree:\n";
for (TreeIterConst iter = tree.begin(); iter != tree.end(); ++iter) {
const Range& r = *iter;
if (r.single)
std::cout << " [" << r.min << "]\n";
else
std::cout << " [" << r.min << ", " << r.max << "]\n";
}
if (empty())
std::cout << " <empty>";
std::cout << "\n";
}
unsigned int allocation_lower_bound() const {
return tree.size() * sizeof(Range);
}
private:
Tree tree;
};

92
extern/rangetree/range_tree_c_api.cc vendored Normal file
View File

@@ -0,0 +1,92 @@
/* 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 2 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*/
#include "range_tree.hh"
/* Give RangeTreeUInt a real type rather than the opaque struct type
defined for external use. */
#define RANGE_TREE_C_API_INTERNAL
typedef RangeTree<unsigned> RangeTreeUInt;
#include "range_tree_c_api.h"
RangeTreeUInt *range_tree_uint_alloc(unsigned min, unsigned max)
{
return new RangeTreeUInt(min, max);
}
RangeTreeUInt *range_tree_uint_copy(RangeTreeUInt *src)
{
return new RangeTreeUInt(*src);
}
void range_tree_uint_free(RangeTreeUInt *rt)
{
delete rt;
}
void range_tree_uint_take(RangeTreeUInt *rt, unsigned v)
{
rt->take(v);
}
bool range_tree_uint_retake(RangeTreeUInt *rt, unsigned v)
{
return rt->retake(v);
}
unsigned range_tree_uint_take_any(RangeTreeUInt *rt)
{
return rt->take_any();
}
void range_tree_uint_release(RangeTreeUInt *rt, unsigned v)
{
rt->release(v);
}
bool range_tree_uint_has(const RangeTreeUInt *rt, unsigned v)
{
return rt->has(v);
}
bool range_tree_uint_has_range(
const RangeTreeUInt *rt,
unsigned vmin,
unsigned vmax)
{
return rt->has_range(vmin, vmax);
}
bool range_tree_uint_empty(const RangeTreeUInt *rt)
{
return rt->empty();
}
unsigned range_tree_uint_size(const RangeTreeUInt *rt)
{
return rt->size();
}
void range_tree_uint_print(const RangeTreeUInt *rt)
{
rt->print();
}
unsigned int range_tree_uint_allocation_lower_bound(const RangeTreeUInt *rt)
{
return rt->allocation_lower_bound();
}

62
extern/rangetree/range_tree_c_api.h vendored Normal file
View File

@@ -0,0 +1,62 @@
/* 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 2 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*/
#ifndef __RANGE_TREE_C_API_H__
#define __RANGE_TREE_C_API_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Simple C-accessible wrapper for RangeTree<unsigned> */
#ifndef RANGE_TREE_C_API_INTERNAL
typedef struct RangeTreeUInt RangeTreeUInt;
#endif
RangeTreeUInt *range_tree_uint_alloc(unsigned min, unsigned max);
RangeTreeUInt *range_tree_uint_copy(RangeTreeUInt *src);
void range_tree_uint_free(RangeTreeUInt *rt);
void range_tree_uint_take(RangeTreeUInt *rt, unsigned v);
bool range_tree_uint_retake(RangeTreeUInt *rt, unsigned v);
unsigned range_tree_uint_take_any(RangeTreeUInt *rt);
void range_tree_uint_release(RangeTreeUInt *rt, unsigned v);
bool range_tree_uint_has(const RangeTreeUInt *rt, unsigned v);
bool range_tree_uint_has_range(
const RangeTreeUInt *rt,
unsigned vmin, unsigned vmax);
bool range_tree_uint_empty(const RangeTreeUInt *rt);
unsigned range_tree_uint_size(const RangeTreeUInt *rt);
void range_tree_uint_print(const RangeTreeUInt *rt);
unsigned int range_tree_uint_allocation_lower_bound(const RangeTreeUInt *rt);
#ifdef __cplusplus
}
#endif
#endif /* __RANGE_TREE_C_API_H__ */

View File

@@ -77,40 +77,32 @@
/* Function prototypes. */
#if (LG_SIZEOF_PTR == 8 || LG_SIZEOF_INT == 8)
ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x);
ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x);
ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x);
ATOMIC_INLINE uint64_t atomic_fetch_and_sub_uint64(uint64_t *p, uint64_t x);
ATOMIC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x);
ATOMIC_INLINE uint64_t atomic_sub_uint64(uint64_t *p, uint64_t x);
ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _new);
#endif
ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x);
ATOMIC_INLINE uint32_t atomic_sub_and_fetch_uint32(uint32_t *p, uint32_t x);
ATOMIC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x);
ATOMIC_INLINE uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x);
ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _new);
ATOMIC_INLINE uint32_t atomic_fetch_and_add_uint32(uint32_t *p, uint32_t x);
ATOMIC_INLINE uint32_t atomic_fetch_and_or_uint32(uint32_t *p, uint32_t x);
ATOMIC_INLINE uint32_t atomic_fetch_and_and_uint32(uint32_t *p, uint32_t x);
ATOMIC_INLINE uint8_t atomic_fetch_and_or_uint8(uint8_t *p, uint8_t b);
ATOMIC_INLINE uint8_t atomic_fetch_and_and_uint8(uint8_t *p, uint8_t b);
ATOMIC_INLINE size_t atomic_add_and_fetch_z(size_t *p, size_t x);
ATOMIC_INLINE size_t atomic_sub_and_fetch_z(size_t *p, size_t x);
ATOMIC_INLINE size_t atomic_fetch_and_add_z(size_t *p, size_t x);
ATOMIC_INLINE size_t atomic_fetch_and_sub_z(size_t *p, size_t x);
ATOMIC_INLINE size_t atomic_add_z(size_t *p, size_t x);
ATOMIC_INLINE size_t atomic_sub_z(size_t *p, size_t x);
ATOMIC_INLINE size_t atomic_cas_z(size_t *v, size_t old, size_t _new);
ATOMIC_INLINE unsigned atomic_add_and_fetch_u(unsigned *p, unsigned x);
ATOMIC_INLINE unsigned atomic_sub_and_fetch_u(unsigned *p, unsigned x);
ATOMIC_INLINE unsigned atomic_fetch_and_add_u(unsigned *p, unsigned x);
ATOMIC_INLINE unsigned atomic_fetch_and_sub_u(unsigned *p, unsigned x);
ATOMIC_INLINE unsigned atomic_add_u(unsigned *p, unsigned x);
ATOMIC_INLINE unsigned atomic_sub_u(unsigned *p, unsigned x);
ATOMIC_INLINE unsigned atomic_cas_u(unsigned *v, unsigned old, unsigned _new);
/* WARNING! Float 'atomics' are really faked ones, those are actually closer to some kind of spinlock-sync'ed operation,
* which means they are only efficient if collisions are highly unlikely (i.e. if probability of two threads
* working on the same pointer at the same time is very low). */
ATOMIC_INLINE float atomic_add_and_fetch_fl(float *p, const float x);
ATOMIC_INLINE float atomic_add_fl(float *p, const float x);
/******************************************************************************/
/* Include system-dependent implementations. */

View File

@@ -56,47 +56,25 @@
/******************************************************************************/
/* size_t operations. */
ATOMIC_INLINE size_t atomic_add_and_fetch_z(size_t *p, size_t x)
ATOMIC_INLINE size_t atomic_add_z(size_t *p, size_t x)
{
assert(sizeof(size_t) == LG_SIZEOF_PTR);
#if (LG_SIZEOF_PTR == 8)
return (size_t)atomic_add_and_fetch_uint64((uint64_t *)p, (uint64_t)x);
return (size_t)atomic_add_uint64((uint64_t *)p, (uint64_t)x);
#elif (LG_SIZEOF_PTR == 4)
return (size_t)atomic_add_and_fetch_uint32((uint32_t *)p, (uint32_t)x);
return (size_t)atomic_add_uint32((uint32_t *)p, (uint32_t)x);
#endif
}
ATOMIC_INLINE size_t atomic_sub_and_fetch_z(size_t *p, size_t x)
ATOMIC_INLINE size_t atomic_sub_z(size_t *p, size_t x)
{
assert(sizeof(size_t) == LG_SIZEOF_PTR);
#if (LG_SIZEOF_PTR == 8)
return (size_t)atomic_add_and_fetch_uint64((uint64_t *)p, (uint64_t)-((int64_t)x));
return (size_t)atomic_add_uint64((uint64_t *)p, (uint64_t)-((int64_t)x));
#elif (LG_SIZEOF_PTR == 4)
return (size_t)atomic_add_and_fetch_uint32((uint32_t *)p, (uint32_t)-((int32_t)x));
#endif
}
ATOMIC_INLINE size_t atomic_fetch_and_add_z(size_t *p, size_t x)
{
assert(sizeof(size_t) == LG_SIZEOF_PTR);
#if (LG_SIZEOF_PTR == 8)
return (size_t)atomic_fetch_and_add_uint64((uint64_t *)p, (uint64_t)x);
#elif (LG_SIZEOF_PTR == 4)
return (size_t)atomic_fetch_and_add_uint32((uint32_t *)p, (uint32_t)x);
#endif
}
ATOMIC_INLINE size_t atomic_fetch_and_sub_z(size_t *p, size_t x)
{
assert(sizeof(size_t) == LG_SIZEOF_PTR);
#if (LG_SIZEOF_PTR == 8)
return (size_t)atomic_fetch_and_add_uint64((uint64_t *)p, (uint64_t)-((int64_t)x));
#elif (LG_SIZEOF_PTR == 4)
return (size_t)atomic_fetch_and_add_uint32((uint32_t *)p, (uint32_t)-((int32_t)x));
return (size_t)atomic_add_uint32((uint32_t *)p, (uint32_t)-((int32_t)x));
#endif
}
@@ -113,47 +91,25 @@ ATOMIC_INLINE size_t atomic_cas_z(size_t *v, size_t old, size_t _new)
/******************************************************************************/
/* unsigned operations. */
ATOMIC_INLINE unsigned atomic_add_and_fetch_u(unsigned *p, unsigned x)
ATOMIC_INLINE unsigned atomic_add_u(unsigned *p, unsigned x)
{
assert(sizeof(unsigned) == LG_SIZEOF_INT);
#if (LG_SIZEOF_INT == 8)
return (unsigned)atomic_add_and_fetch_uint64((uint64_t *)p, (uint64_t)x);
return (unsigned)atomic_add_uint64((uint64_t *)p, (uint64_t)x);
#elif (LG_SIZEOF_INT == 4)
return (unsigned)atomic_add_and_fetch_uint32((uint32_t *)p, (uint32_t)x);
return (unsigned)atomic_add_uint32((uint32_t *)p, (uint32_t)x);
#endif
}
ATOMIC_INLINE unsigned atomic_sub_and_fetch_u(unsigned *p, unsigned x)
ATOMIC_INLINE unsigned atomic_sub_u(unsigned *p, unsigned x)
{
assert(sizeof(unsigned) == LG_SIZEOF_INT);
#if (LG_SIZEOF_INT == 8)
return (unsigned)atomic_add_and_fetch_uint64((uint64_t *)p, (uint64_t)-((int64_t)x));
return (unsigned)atomic_add_uint64((uint64_t *)p, (uint64_t)-((int64_t)x));
#elif (LG_SIZEOF_INT == 4)
return (unsigned)atomic_add_and_fetch_uint32((uint32_t *)p, (uint32_t)-((int32_t)x));
#endif
}
ATOMIC_INLINE unsigned atomic_fetch_and_add_u(unsigned *p, unsigned x)
{
assert(sizeof(unsigned) == LG_SIZEOF_INT);
#if (LG_SIZEOF_INT == 8)
return (unsigned)atomic_fetch_and_add_uint64((uint64_t *)p, (uint64_t)x);
#elif (LG_SIZEOF_INT == 4)
return (unsigned)atomic_fetch_and_add_uint32((uint32_t *)p, (uint32_t)x);
#endif
}
ATOMIC_INLINE unsigned atomic_fetch_and_sub_u(unsigned *p, unsigned x)
{
assert(sizeof(unsigned) == LG_SIZEOF_INT);
#if (LG_SIZEOF_INT == 8)
return (unsigned)atomic_fetch_and_add_uint64((uint64_t *)p, (uint64_t)-((int64_t)x));
#elif (LG_SIZEOF_INT == 4)
return (unsigned)atomic_fetch_and_add_uint32((uint32_t *)p, (uint32_t)-((int32_t)x));
return (unsigned)atomic_add_uint32((uint32_t *)p, (uint32_t)-((int32_t)x));
#endif
}
@@ -171,7 +127,7 @@ ATOMIC_INLINE unsigned atomic_cas_u(unsigned *v, unsigned old, unsigned _new)
/******************************************************************************/
/* float operations. */
ATOMIC_INLINE float atomic_add_and_fetch_fl(float *p, const float x)
ATOMIC_INLINE float atomic_add_fl(float *p, const float x)
{
assert(sizeof(float) == sizeof(uint32_t));

View File

@@ -43,12 +43,12 @@
/******************************************************************************/
/* 64-bit operations. */
#if (LG_SIZEOF_PTR == 8 || LG_SIZEOF_INT == 8)
ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x)
ATOMIC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x)
{
return InterlockedExchangeAdd64((int64_t *)p, (int64_t)x) + x;
}
ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x)
ATOMIC_INLINE uint64_t atomic_sub_uint64(uint64_t *p, uint64_t x)
{
return InterlockedExchangeAdd64((int64_t *)p, -((int64_t)x)) - x;
}
@@ -57,26 +57,16 @@ ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _ne
{
return InterlockedCompareExchange64((int64_t *)v, _new, old);
}
ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x)
{
return InterlockedExchangeAdd64((int64_t *)p, (int64_t)x);
}
ATOMIC_INLINE uint64_t atomic_fetch_and_sub_uint64(uint64_t *p, uint64_t x)
{
return InterlockedExchangeAdd64((int64_t *)p, -((int64_t)x));
}
#endif
/******************************************************************************/
/* 32-bit operations. */
ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x)
ATOMIC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x)
{
return InterlockedExchangeAdd(p, x) + x;
}
ATOMIC_INLINE uint32_t atomic_sub_and_fetch_uint32(uint32_t *p, uint32_t x)
ATOMIC_INLINE uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x)
{
return InterlockedExchangeAdd(p, -((int32_t)x)) - x;
}
@@ -91,16 +81,6 @@ ATOMIC_INLINE uint32_t atomic_fetch_and_add_uint32(uint32_t *p, uint32_t x)
return InterlockedExchangeAdd(p, x);
}
ATOMIC_INLINE uint32_t atomic_fetch_and_or_uint32(uint32_t *p, uint32_t x)
{
return InterlockedOr((long *)p, x);
}
ATOMIC_INLINE uint32_t atomic_fetch_and_and_uint32(uint32_t *p, uint32_t x)
{
return InterlockedAnd((long *)p, x);
}
/******************************************************************************/
/* 8-bit operations. */

View File

@@ -58,32 +58,22 @@
/* 64-bit operations. */
#if (LG_SIZEOF_PTR == 8 || LG_SIZEOF_INT == 8)
# if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_8))
ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x)
ATOMIC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x)
{
return __sync_add_and_fetch(p, x);
}
ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x)
ATOMIC_INLINE uint64_t atomic_sub_uint64(uint64_t *p, uint64_t x)
{
return __sync_sub_and_fetch(p, x);
}
ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x)
{
return __sync_fetch_and_add(p, x);
}
ATOMIC_INLINE uint64_t atomic_fetch_and_sub_uint64(uint64_t *p, uint64_t x)
{
return __sync_fetch_and_sub(p, x);
}
ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _new)
{
return __sync_val_compare_and_swap(v, old, _new);
}
# elif (defined(__amd64__) || defined(__x86_64__))
ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x)
ATOMIC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x)
{
asm volatile (
"lock; xaddq %0, %1;"
@@ -93,7 +83,7 @@ ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x)
return x;
}
ATOMIC_INLINE uint64_t atomic_fetch_and_sub_uint64(uint64_t *p, uint64_t x)
ATOMIC_INLINE uint64_t atomic_sub_uint64(uint64_t *p, uint64_t x)
{
x = (uint64_t)(-(int64_t)x);
asm volatile (
@@ -104,16 +94,6 @@ ATOMIC_INLINE uint64_t atomic_fetch_and_sub_uint64(uint64_t *p, uint64_t x)
return x;
}
ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x)
{
return atomic_fetch_and_add_uint64(p, x) + x;
}
ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x)
{
return atomic_fetch_and_sub_uint64(p, x) - x;
}
ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _new)
{
uint64_t ret;
@@ -132,12 +112,12 @@ ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _ne
/******************************************************************************/
/* 32-bit operations. */
#if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_4))
ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x)
ATOMIC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x)
{
return __sync_add_and_fetch(p, x);
}
ATOMIC_INLINE uint32_t atomic_sub_and_fetch_uint32(uint32_t *p, uint32_t x)
ATOMIC_INLINE uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x)
{
return __sync_sub_and_fetch(p, x);
}
@@ -147,7 +127,7 @@ ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _ne
return __sync_val_compare_and_swap(v, old, _new);
}
#elif (defined(__i386__) || defined(__amd64__) || defined(__x86_64__))
ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x)
ATOMIC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x)
{
uint32_t ret = x;
asm volatile (
@@ -158,7 +138,7 @@ ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x)
return ret+x;
}
ATOMIC_INLINE uint32_t atomic_sub_and_fetch_uint32(uint32_t *p, uint32_t x)
ATOMIC_INLINE uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x)
{
ret = (uint32_t)(-(int32_t)x);
asm volatile (
@@ -189,16 +169,6 @@ ATOMIC_INLINE uint32_t atomic_fetch_and_add_uint32(uint32_t *p, uint32_t x)
return __sync_fetch_and_add(p, x);
}
ATOMIC_INLINE uint32_t atomic_fetch_and_or_uint32(uint32_t *p, uint32_t x)
{
return __sync_fetch_and_or(p, x);
}
ATOMIC_INLINE uint32_t atomic_fetch_and_and_uint32(uint32_t *p, uint32_t x)
{
return __sync_fetch_and_and(p, x);
}
#else
# error "Missing implementation for 32-bit atomic operations"
#endif

View File

@@ -110,10 +110,10 @@ void AUD_LimiterReader::read(int& length, bool& eos, sample_t* buffer)
eos = true;
}
if(position < int(m_start * rate))
if(position < m_start * rate)
{
int len2 = length;
for(int len = int(m_start * rate) - position;
for(int len = m_start * rate - position;
len2 == length && !eos;
len -= length)
{

View File

@@ -2698,7 +2698,7 @@ Device_set_doppler_factor(Device *self, PyObject *args, void* nothing)
PyDoc_STRVAR(M_aud_Device_distance_model_doc,
"The distance model of the device.\n\n"
".. seealso:: `OpenAL documentation <https://www.openal.org/documentation>`");
".. seealso:: http://connect.creativelabs.com/openal/Documentation/OpenAL%201.1%20Specification.htm#_Toc199835864");
static PyObject *
Device_get_distance_model(Device *self, void* nothing)

View File

@@ -155,18 +155,18 @@ AUD_Device* AUD_init(const char* device, AUD_DeviceSpecs specs, int buffersize,
}
#endif
#ifdef WITH_JACK
else if(dname == "JACK")
else if(dname == "Jack")
{
#ifdef __APPLE__
struct stat st;
if (stat("/Library/Frameworks/Jackmp.framework", &st) != 0) {
printf("Warning: JACK Framework not installed\n");
printf("Warning: Jack Framework not installed\n");
return NULL;
}
else
#endif
if (!AUD_jack_supported()) {
printf("Warning: JACK cllient not installed\n");
printf("Warning: Jack cllient not installed\n");
return NULL;
}
else {

View File

@@ -61,7 +61,7 @@ typedef struct
#endif
/**
* Initializes audio routines (FFMPEG/JACK if it is enabled).
* Initializes audio rutines (FFMPEG/Jack if it is enabled).
*/
extern void AUD_initOnce(void);

View File

@@ -95,21 +95,6 @@ void AUD_Mixer::mix(sample_t* buffer, int start, int length, float volume)
out[i + start] += buffer[i] * volume;
}
void AUD_Mixer::mix(sample_t* buffer, int start, int length, float volume_to, float volume_from)
{
sample_t* out = m_buffer.getBuffer();
length = (std::min(m_length, length + start) - start);
for(int i = 0; i < length; i++)
{
float volume = volume_from * (1.0f - i / float(length)) + volume_to * (i / float(length));
for(int c = 0; c < m_specs.channels; c++)
out[(i + start) * m_specs.channels + c] += buffer[i * m_specs.channels + c] * volume;
}
}
void AUD_Mixer::read(data_t* buffer, float volume)
{
sample_t* out = m_buffer.getBuffer();

View File

@@ -95,8 +95,6 @@ public:
*/
void mix(sample_t* buffer, int start, int length, float volume);
void mix(sample_t* buffer, int start, int length, float volume_to, float volume_from);
/**
* Writes the mixing buffer into an output buffer.
* \param buffer The target buffer for superposing.

View File

@@ -89,7 +89,7 @@ bool AUD_SoftwareDevice::AUD_SoftwareHandle::pause(bool keep)
}
AUD_SoftwareDevice::AUD_SoftwareHandle::AUD_SoftwareHandle(AUD_SoftwareDevice* device, boost::shared_ptr<AUD_IReader> reader, boost::shared_ptr<AUD_PitchReader> pitch, boost::shared_ptr<AUD_ResampleReader> resampler, boost::shared_ptr<AUD_ChannelMapperReader> mapper, bool keep) :
m_reader(reader), m_pitch(pitch), m_resampler(resampler), m_mapper(mapper), m_keep(keep), m_user_pitch(1.0f), m_user_volume(1.0f), m_user_pan(0.0f), m_volume(1.0f), m_old_volume(1.0f), m_loopcount(0),
m_reader(reader), m_pitch(pitch), m_resampler(resampler), m_mapper(mapper), m_keep(keep), m_user_pitch(1.0f), m_user_volume(1.0f), m_user_pan(0.0f), m_volume(1.0f), m_loopcount(0),
m_relative(true), m_volume_max(1.0f), m_volume_min(0), m_distance_max(std::numeric_limits<float>::max()),
m_distance_reference(1.0f), m_attenuation(1.0f), m_cone_angle_outer(M_PI), m_cone_angle_inner(M_PI), m_cone_volume_outer(0),
m_flags(AUD_RENDER_CONE), m_stop(NULL), m_stop_data(NULL), m_status(AUD_STATUS_PLAYING), m_device(device)
@@ -100,8 +100,6 @@ void AUD_SoftwareDevice::AUD_SoftwareHandle::update()
{
int flags = 0;
m_old_volume = m_volume;
AUD_Vector3 SL;
if(m_relative)
SL = -m_location;
@@ -406,7 +404,7 @@ bool AUD_SoftwareDevice::AUD_SoftwareHandle::setVolume(float volume)
if(volume == 0)
{
m_old_volume = m_volume = volume;
m_volume = volume;
m_flags |= AUD_RENDER_VOLUME;
}
else
@@ -774,7 +772,7 @@ void AUD_SoftwareDevice::mix(data_t* buffer, int length)
// in case of looping
while(pos + len < length && sound->m_loopcount && eos)
{
m_mixer->mix(buf, pos, len, sound->m_volume, sound->m_old_volume);
m_mixer->mix(buf, pos, len, sound->m_volume);
pos += len;
@@ -791,7 +789,7 @@ void AUD_SoftwareDevice::mix(data_t* buffer, int length)
break;
}
m_mixer->mix(buf, pos, len, sound->m_volume, sound->m_old_volume);
m_mixer->mix(buf, pos, len, sound->m_volume);
// in case the end of the sound is reached
if(eos && !sound->m_loopcount)

View File

@@ -84,7 +84,6 @@ protected:
/// The calculated final volume of the source.
float m_volume;
float m_old_volume;
/// The loop count of the source.
int m_loopcount;

View File

@@ -41,7 +41,7 @@
typedef void (*AUD_syncFunction)(void*, int, float);
/**
* This device plays back through JACK.
* This device plays back through Jack.
*/
class AUD_JackDevice : public AUD_SoftwareDevice
{
@@ -90,7 +90,7 @@ private:
static int jack_sync(jack_transport_state_t state, jack_position_t* pos, void* data);
/**
* Next JACK Transport state (-1 if not expected to change).
* Next Jack Transport state (-1 if not expected to change).
*/
jack_transport_state_t m_nextState;
@@ -150,7 +150,7 @@ protected:
public:
/**
* Creates a JACK client for audio output.
* Creates a Jack client for audio output.
* \param name The client name.
* \param specs The wanted audio specification, where only the channel count
* is important.
@@ -160,7 +160,7 @@ public:
AUD_JackDevice(std::string name, AUD_DeviceSpecs specs, int buffersize = AUD_DEFAULT_BUFFER_SIZE);
/**
* Closes the JACK client.
* Closes the Jack client.
*/
virtual ~AUD_JackDevice();

Some files were not shown because too many files have changed in this diff Show More