<commit_before>//
//  Landscape.cpp
//
//  Created by Soso Limited on 5/26/15.
//
//

#include "Landscape.h"

#include "cinder/Log.h"
#include "Constants.h"

using namespace soso;
using namespace cinder;

namespace {

struct alignas(16) Vertex {
	vec3	position;
	vec3	normal;
	vec2	tex_coord;
	vec2	color_tex_coord;
	float deform_scaling;
	float frame_offset;
	float color_weight;
};

const auto kVertexLayout = ([] {
		auto layout = geom::BufferLayout();
		layout.append( geom::Attrib::POSITION, 3, sizeof(Vertex), offsetof(Vertex, position) );
		layout.append( geom::Attrib::NORMAL, 3, sizeof(Vertex), offsetof(Vertex, normal) );
		layout.append( geom::Attrib::TEX_COORD_0, 2, sizeof(Vertex), offsetof(Vertex, tex_coord) );
		layout.append( geom::Attrib::TEX_COORD_1, 2, sizeof(Vertex), offsetof(Vertex, color_tex_coord) );
		layout.append( geom::Attrib::CUSTOM_0, 1, sizeof(Vertex), offsetof(Vertex, deform_scaling) );
		layout.append( geom::Attrib::CUSTOM_1, 1, sizeof(Vertex), offsetof(Vertex, frame_offset) );
		layout.append( geom::Attrib::CUSTOM_2, 1, sizeof(Vertex), offsetof(Vertex, color_weight) );
		return layout;
	} ());

const auto kVertexMapping = ([] {
		return gl::Batch::AttributeMapping{ { geom::Attrib::CUSTOM_0, "DeformScaling" }, { geom::Attrib::CUSTOM_1, "FrameOffset" }, { geom::Attrib::CUSTOM_2, "ColorWeight" } };
	} ());

// Load a shader and handle exceptions. Return nullptr on failure.
gl::GlslProgRef loadShader( const fs::path &iVertex, const fs::path &iFragment )
{
	try {
		auto shader_format = gl::GlslProg::Format()
			.vertex( app::loadAsset( iVertex ) )
			.fragment( app::loadAsset( iFragment ) );

		return gl::GlslProg::create( shader_format );
	}
	catch( ci::Exception &exc ) {
		CI_LOG_E( "Error loading shader: " << exc.what() );
	}

	return nullptr;
}

///
/// Create a quadrilateral with clockwise vertices abcd.
/// Maps to frame at time and a slice of the video frame.
///
void addQuad( std::vector<Vertex> &vertices, const vec3 &a, const vec3 &b, const vec3 &c, const vec3 &d, float time, const Rectf &slice )
{
	auto normal = vec3( 0, 1, 0 );
	auto deform_scaling = 0.0f;

	vertices.insert( vertices.end(), {
		Vertex{ a, normal, slice.getUpperLeft(), slice.getUpperLeft(), deform_scaling, time, 0.0f },
		Vertex{ b, normal, slice.getUpperRight(), slice.getUpperRight(), deform_scaling, time, 0.0f },
		Vertex{ c, normal, slice.getLowerRight(), slice.getLowerRight(), deform_scaling, time, 0.0f },

		Vertex{ a, normal, slice.getUpperLeft(), slice.getUpperLeft(), deform_scaling, time, 0.0f },
		Vertex{ c, normal, slice.getLowerRight(), slice.getLowerRight(), deform_scaling, time, 0.0f },
		Vertex{ d, normal, slice.getLowerLeft(), slice.getLowerLeft(), deform_scaling, time, 0.0f }
	} );

}

/// Add a ring of geometry containing a given number of time bands (slitscanning effect) and repeats around the donut.
void addRing( std::vector<Vertex> &vertices, const vec3 &center, const vec3 &normal, float inner_radius, float outer_radius, float time_offset, int time_bands, int repeats, float color_weight, const vec2 &texture_insets = vec2( 0.05, 0.0875f ) )
{
	auto rings = time_bands;
	auto segments = 64;

	// Generate cartesian position.
	auto calc_pos = [=] (int r, int s) {
		auto distance = lmap<float>( r, 0, rings, 0.0f, 1.0f );
		auto radius = mix( inner_radius, outer_radius, distance );
		auto t = (float) s / segments;
		auto x = cos( t * Tau ) * radius;
		auto y = sin( t * Tau ) * radius;
		return vec3( x, 0, y ) + center;
	};

	// Generate texture coordinate mirrored at halfway point.
	auto calc_tc = [=] (int r, int s) {
		auto t = (float) s / segments;
		if( t < 1 ) {
			t = glm::fract( t * repeats );
		}
		// mirror copies
		t = std::abs( t - 0.5f ) * 2.0f;
		auto tc = vec2(0);
		// Repeat t with mirroring
		// insetting the texture coordinates minimizes edge color flashing.
		tc.y = mix( texture_insets.y, 1.0f - texture_insets.y, t );
		tc.x = lmap<float>( r, 0, rings, 1.0f - texture_insets.x, texture_insets.x );
		return tc;
	};

	// Add a vertex to texture (color_tc parameter allows us to do flat shading in ES2)
	auto add_vert = [=,&vertices] (int r, int s, const ivec2 &provoking) {
		auto deform_scaling = 0.0f;
		auto pos = calc_pos(r, s);
		auto tc = calc_tc(r, s);
		auto color_tc = calc_tc( provoking.x, provoking.y );
		auto time = time_offset; // + lmap<float>( r, 0, rings, 0.0f, 1.0f / 64.0f );
		if (time_bands > 1) {
			time += lmap<float>( provoking.x, 0.0f, rings, 0.0f, time_bands );
		}
		vertices.push_back( Vertex{ pos, normal, tc, color_tc, deform_scaling, time, color_weight } );
	};

	// Create triangles for flat shading
	for( auto r = 0; r < rings; r += 1 )
	{
		for( auto s = 0; s < segments; s += 1 )
		{
			auto provoking = ivec2(r, s);
			add_vert( r, s, provoking );
			add_vert( r, s + 1, provoking );
			add_vert( r + 1, s + 1, provoking );

			add_vert( r, s, provoking );
			add_vert( r + 1, s, provoking );
			add_vert( r + 1, s + 1, provoking );
		}
	}
}

} // namespace

void Landscape::setup()
{
	auto shader = loadShader( "landscape.vs", "landscape.fs" );

	std::vector<Vertex> vertices;

	auto normal = vec3( 0, 1, 0 );

	auto inner = 0.28f;
	auto outer = 2.4f;

	struct Params {
		float repeats;
		float frames;
		float color_weight;
		vec2	insets;
	};

	auto params = std::vector<Params> {
		{ 2, 1, 0.0f, vec2( 0.05, 0.0875f ) },
		{ 4, 1, 0.0f, vec2( 0.05, 0.0875f ) },
		{ 6, 1, 0.0f, vec2( 0.05, 0.0875f ) },
		{ 8, 1, 0.0f, vec2( 0.05, 0.0875f ) },
		{ 10, 1, 0.0f, vec2( 0.05, 0.0875f ) },
		{ 12, 2, 0.0f, vec2( 0.05, 0.0875f ) },
		{ 10, 3, 0.1f, vec2( 0.05, 0.0875f ) },
		{ 8, 6, 0.3f, vec2( 0.05, 0.0875f ) },
		{ 10, 12, 0.5f, vec2( 0.05, 0.0875f ) },
		{ 8, 24, 0.8f, vec2( 0.05, 0.0875f ) }
	};

	auto center = vec3( 0, -4.4f, 0 );

	for( auto i = 0; i < params.size(); i += 1 )
	{
		auto &p = params.at( i );
		auto copies = p.repeats;
		auto t = (i + 0.0f) / params.size();
		auto t2 = (i + 1.0f) / params.size();
		auto r1 = mix( inner, outer, t );
		auto r2 = mix( inner, outer, t2 );
		addRing( vertices, center, normal, r1, r2, i * 2 + 1.0f, p.frames, copies, p.color_weight, p.insets );
	}

	auto last_frame = params.size() * 2 + 4.0f; // actually some overlap
	auto remaining_frames = 64.0f - last_frame;
	addRing( vertices, center, normal, outer, outer + 1.6f, last_frame, remaining_frames, 2, 1.0f );

	// Deform stuff
//	/*
	auto min_distance = inner;
	auto max_distance = outer + 4.0f;
	for( auto &v : vertices ) {
		auto distance = lmap<float>( glm::clamp( length( v.position ), min_distance, max_distance ), min_distance, max_distance, 0.0f, 1.0f );
		// pos is on a radial axis, rotate it 90 degrees to bend along length
		auto axis = glm::rotate( glm::angleAxis( (float)Tau / 4.0f, vec3(0, 1, 0) ), normalize(v.position) );
		auto theta = mix( 0.0f, -(float)Tau / 4.0f, distance );
		auto xf = glm::rotate( theta, axis );
		v.normal = vec3(xf * vec4(v.normal, 0.0f));
//		v.deform_scaling = mix( 0.0f, 4.0f, distance );
		v.position = vec3(xf * vec4(v.position, 1.0f));
	}
//	*/

	// Plug center
	auto h = vec3( inner, 0, inner ) * 1.96f;
	auto c = center;
	addQuad( vertices, c + (h * vec3(-1, 0, -1)), c + (h * vec3(1, 0, -1)), c + (h * vec3(1, 0, 1)), c + (h * vec3(-1, 0, 1)), 0.0f, Rectf( 1, 1, 0, 0 ) );

	auto rotation = glm::rotate<float>( Tau * 0.25f, vec3( 0, 0, 1 ) );
	for( auto &v : vertices ) {
		v.position = vec3( rotation * vec4(v.position, 1.0f) );
	}

	auto copy = vertices;
	auto mirror = glm::angleAxis<float>( Tau * 0.5f, vec3( 0, 1, 0 ) ) * glm::angleAxis<float>( Tau * 0.25f, vec3( 1, 0, 0 ) );
	rotation = glm::mat4( mirror ); // glm::rotate<float>( Tau * 0.5f, vec3( 0, 1, 0 ) );
	for( auto &v : copy ) {
		v.position = vec3( rotation * vec4(v.position, 1.0f) );
	}

	vertices.insert( vertices.end(), copy.begin(), copy.end() );

	auto vbo = gl::Vbo::create( GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW );
	auto mesh = gl::VboMesh::create( vertices.size(), GL_TRIANGLES, {{ kVertexLayout, vbo }} );
	batch = gl::Batch::create( mesh, shader, kVertexMapping );
}

void Landscape::setTextureUnits( uint8_t iClearUnit, uint8_t iBlurredUnit )
{
	auto &shader = batch->getGlslProg();
	shader->uniform( "uClearTexture", iClearUnit );
	shader->uniform( "uBlurredTexture", iBlurredUnit );
}

void Landscape::draw( float iFrameOffset )
{
	auto &shader = batch->getGlslProg();
	shader->uniform( "uCurrentFrame", iFrameOffset );

	batch->draw();
}
<commit_msg>Center ring every 4th frame.<commit_after>//
//  Landscape.cpp
//
//  Created by Soso Limited on 5/26/15.
//
//

#include "Landscape.h"

#include "cinder/Log.h"
#include "Constants.h"

using namespace soso;
using namespace cinder;

namespace {

struct alignas(16) Vertex {
	vec3	position;
	vec3	normal;
	vec2	tex_coord;
	vec2	color_tex_coord;
	float deform_scaling;
	float frame_offset;
	float color_weight;
};

const auto kVertexLayout = ([] {
		auto layout = geom::BufferLayout();
		layout.append( geom::Attrib::POSITION, 3, sizeof(Vertex), offsetof(Vertex, position) );
		layout.append( geom::Attrib::NORMAL, 3, sizeof(Vertex), offsetof(Vertex, normal) );
		layout.append( geom::Attrib::TEX_COORD_0, 2, sizeof(Vertex), offsetof(Vertex, tex_coord) );
		layout.append( geom::Attrib::TEX_COORD_1, 2, sizeof(Vertex), offsetof(Vertex, color_tex_coord) );
		layout.append( geom::Attrib::CUSTOM_0, 1, sizeof(Vertex), offsetof(Vertex, deform_scaling) );
		layout.append( geom::Attrib::CUSTOM_1, 1, sizeof(Vertex), offsetof(Vertex, frame_offset) );
		layout.append( geom::Attrib::CUSTOM_2, 1, sizeof(Vertex), offsetof(Vertex, color_weight) );
		return layout;
	} ());

const auto kVertexMapping = ([] {
		return gl::Batch::AttributeMapping{ { geom::Attrib::CUSTOM_0, "DeformScaling" }, { geom::Attrib::CUSTOM_1, "FrameOffset" }, { geom::Attrib::CUSTOM_2, "ColorWeight" } };
	} ());

// Load a shader and handle exceptions. Return nullptr on failure.
gl::GlslProgRef loadShader( const fs::path &iVertex, const fs::path &iFragment )
{
	try {
		auto shader_format = gl::GlslProg::Format()
			.vertex( app::loadAsset( iVertex ) )
			.fragment( app::loadAsset( iFragment ) );

		return gl::GlslProg::create( shader_format );
	}
	catch( ci::Exception &exc ) {
		CI_LOG_E( "Error loading shader: " << exc.what() );
	}

	return nullptr;
}

///
/// Create a quadrilateral with clockwise vertices abcd.
/// Maps to frame at time and a slice of the video frame.
///
void addQuad( std::vector<Vertex> &vertices, const vec3 &a, const vec3 &b, const vec3 &c, const vec3 &d, float time, const Rectf &slice )
{
	auto normal = vec3( 0, 1, 0 );
	auto deform_scaling = 0.0f;

	vertices.insert( vertices.end(), {
		Vertex{ a, normal, slice.getUpperLeft(), slice.getUpperLeft(), deform_scaling, time, 0.0f },
		Vertex{ b, normal, slice.getUpperRight(), slice.getUpperRight(), deform_scaling, time, 0.0f },
		Vertex{ c, normal, slice.getLowerRight(), slice.getLowerRight(), deform_scaling, time, 0.0f },

		Vertex{ a, normal, slice.getUpperLeft(), slice.getUpperLeft(), deform_scaling, time, 0.0f },
		Vertex{ c, normal, slice.getLowerRight(), slice.getLowerRight(), deform_scaling, time, 0.0f },
		Vertex{ d, normal, slice.getLowerLeft(), slice.getLowerLeft(), deform_scaling, time, 0.0f }
	} );

}

/// Add a ring of geometry containing a given number of time bands (slitscanning effect) and repeats around the donut.
void addRing( std::vector<Vertex> &vertices, const vec3 &center, const vec3 &normal, float inner_radius, float outer_radius, float time_offset, int time_bands, int repeats, float color_weight, const vec2 &texture_insets = vec2( 0.05, 0.0875f ) )
{
	auto rings = time_bands;
	auto segments = 64;

	// Generate cartesian position.
	auto calc_pos = [=] (int r, int s) {
		auto distance = lmap<float>( r, 0, rings, 0.0f, 1.0f );
		auto radius = mix( inner_radius, outer_radius, distance );
		auto t = (float) s / segments;
		auto x = cos( t * Tau ) * radius;
		auto y = sin( t * Tau ) * radius;
		return vec3( x, 0, y ) + center;
	};

	// Generate texture coordinate mirrored at halfway point.
	auto calc_tc = [=] (int r, int s) {
		auto t = (float) s / segments;
		if( t < 1 ) {
			t = glm::fract( t * repeats );
		}
		// mirror copies
		t = std::abs( t - 0.5f ) * 2.0f;
		auto tc = vec2(0);
		// Repeat t with mirroring
		// insetting the texture coordinates minimizes edge color flashing.
		tc.y = mix( texture_insets.y, 1.0f - texture_insets.y, t );
		tc.x = lmap<float>( r, 0, rings, 1.0f - texture_insets.x, texture_insets.x );
		return tc;
	};

	// Add a vertex to texture (color_tc parameter allows us to do flat shading in ES2)
	auto add_vert = [=,&vertices] (int r, int s, const ivec2 &provoking) {
		auto deform_scaling = 0.0f;
		auto pos = calc_pos(r, s);
		auto tc = calc_tc(r, s);
		auto color_tc = calc_tc( provoking.x, provoking.y );
		auto time = time_offset; // + lmap<float>( r, 0, rings, 0.0f, 1.0f / 64.0f );
		if (time_bands > 1) {
			time += lmap<float>( provoking.x, 0.0f, rings, 0.0f, time_bands );
		}
		vertices.push_back( Vertex{ pos, normal, tc, color_tc, deform_scaling, time, color_weight } );
	};

	// Create triangles for flat shading
	for( auto r = 0; r < rings; r += 1 )
	{
		for( auto s = 0; s < segments; s += 1 )
		{
			auto provoking = ivec2(r, s);
			add_vert( r, s, provoking );
			add_vert( r, s + 1, provoking );
			add_vert( r + 1, s + 1, provoking );

			add_vert( r, s, provoking );
			add_vert( r + 1, s, provoking );
			add_vert( r + 1, s + 1, provoking );
		}
	}
}

} // namespace

void Landscape::setup()
{
	auto shader = loadShader( "landscape.vs", "landscape.fs" );

	std::vector<Vertex> vertices;

	auto normal = vec3( 0, 1, 0 );

	auto inner = 0.28f;
	auto outer = 2.4f;

	struct Params {
		float repeats;
		float frames;
		float color_weight;
		vec2	insets;
	};

	auto params = std::vector<Params> {
		{ 2, 1, 0.0f, vec2( 0.05, 0.0875f ) },
		{ 4, 1, 0.0f, vec2( 0.05, 0.0875f ) },
		{ 6, 1, 0.0f, vec2( 0.05, 0.0875f ) },
		{ 8, 1, 0.0f, vec2( 0.05, 0.0875f ) },
		{ 10, 1, 0.0f, vec2( 0.05, 0.0875f ) },
		{ 12, 2, 0.0f, vec2( 0.05, 0.0875f ) },
		{ 10, 3, 0.1f, vec2( 0.05, 0.0875f ) },
		{ 8, 6, 0.3f, vec2( 0.05, 0.0875f ) },
		{ 10, 12, 0.5f, vec2( 0.05, 0.0875f ) },
		{ 8, 24, 0.8f, vec2( 0.05, 0.0875f ) }
	};

	auto center = vec3( 0, -4.4f, 0 );

	for( auto i = 0; i < params.size(); i += 1 )
	{
		auto &p = params.at( i );
		auto copies = p.repeats;
		auto t = (i + 0.0f) / params.size();
		auto t2 = (i + 1.0f) / params.size();
		auto r1 = mix( inner, outer, t );
		auto r2 = mix( inner, outer, t2 );
		addRing( vertices, center, normal, r1, r2, i * 4 + 1.0f, p.frames, copies, p.color_weight, p.insets );
	}

	auto last_frame = params.size() * 2 + 4.0f; // actually some overlap
	auto remaining_frames = 64.0f - last_frame;
	addRing( vertices, center, normal, outer, outer + 1.6f, last_frame, remaining_frames, 2, 1.0f );

	// Deform stuff
//	/*
	auto min_distance = inner;
	auto max_distance = outer + 4.0f;
	for( auto &v : vertices ) {
		auto distance = lmap<float>( glm::clamp( length( v.position ), min_distance, max_distance ), min_distance, max_distance, 0.0f, 1.0f );
		// pos is on a radial axis, rotate it 90 degrees to bend along length
		auto axis = glm::rotate( glm::angleAxis( (float)Tau / 4.0f, vec3(0, 1, 0) ), normalize(v.position) );
		auto theta = mix( 0.0f, -(float)Tau / 4.0f, distance );
		auto xf = glm::rotate( theta, axis );
		v.normal = vec3(xf * vec4(v.normal, 0.0f));
//		v.deform_scaling = mix( 0.0f, 4.0f, distance );
		v.position = vec3(xf * vec4(v.position, 1.0f));
	}
//	*/

	// Plug center
	auto h = vec3( inner, 0, inner ) * 1.96f;
	auto c = center;
	addQuad( vertices, c + (h * vec3(-1, 0, -1)), c + (h * vec3(1, 0, -1)), c + (h * vec3(1, 0, 1)), c + (h * vec3(-1, 0, 1)), 0.0f, Rectf( 1, 1, 0, 0 ) );

	auto rotation = glm::rotate<float>( Tau * 0.25f, vec3( 0, 0, 1 ) );
	for( auto &v : vertices ) {
		v.position = vec3( rotation * vec4(v.position, 1.0f) );
	}

	auto copy = vertices;
	auto mirror = glm::angleAxis<float>( Tau * 0.5f, vec3( 0, 1, 0 ) ) * glm::angleAxis<float>( Tau * 0.25f, vec3( 1, 0, 0 ) );
	rotation = glm::mat4( mirror ); // glm::rotate<float>( Tau * 0.5f, vec3( 0, 1, 0 ) );
	for( auto &v : copy ) {
		v.position = vec3( rotation * vec4(v.position, 1.0f) );
	}

	vertices.insert( vertices.end(), copy.begin(), copy.end() );

	auto vbo = gl::Vbo::create( GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW );
	auto mesh = gl::VboMesh::create( vertices.size(), GL_TRIANGLES, {{ kVertexLayout, vbo }} );
	batch = gl::Batch::create( mesh, shader, kVertexMapping );
}

void Landscape::setTextureUnits( uint8_t iClearUnit, uint8_t iBlurredUnit )
{
	auto &shader = batch->getGlslProg();
	shader->uniform( "uClearTexture", iClearUnit );
	shader->uniform( "uBlurredTexture", iBlurredUnit );
}

void Landscape::draw( float iFrameOffset )
{
	auto &shader = batch->getGlslProg();
	shader->uniform( "uCurrentFrame", iFrameOffset );

	batch->draw();
}
<|endoftext|>


<commit_before>/**
 * @file rootfilepublisher-sample.C
 * @brief Macro for testing ROOT-file publishing and writing
 *
 * This macro is a testing/example macro of how to use the RootFilePublisher
 * (AliHLTRootFilePublisher) and RootFileWriter (AliHLTRootFileWriter).
 * It defines only two component in the chain, the publisher, which
 * publishes the content of the root files according to the selection.
 * Be aware there can be several root objects in one root file.
 *
 * The file myRootFile.root has to be changed with the actual file.
 * In this example, an ESD file is used, which contains a "esdTree" and
 * a "HLTesdTree" object. Only the "HLTesdTree" object is selected. The
 * data blocks, which will are published here, have the data type of
 * {ROOTTOBJ,"***"} and specification of 0x00000000. They also have to
 * been adopted to the actual content of the root file.
 *
 * @author thaeder@kip.uni-heidelberg.de
 * @ingroup alihlt_tutorial
 */

/** RootFilePublisher test macro
 *  @param nEvents Number of events which should be processed
 */
void rootfilepublisher(Int_t nEvents=1) {

  TString writerInput;
  TString arg;

  AliHLTSystem gHLT;
  gHLT.LoadComponentLibraries("libAliHLTUtil.so");

  // -- Root publisher configuration
  // !!! myRootFile.root has to be exchanged with an existing one.
  arg.Form("-objectname HLTesdTree -datatype 'ESD_TREE' 'TPC '-dataspec 0x00000000 -datafile myRootFile.root");

  // -- The AliHLTRootFilePublisher (Id 'ROOTFilePublisher') is a data source.
  //    It provides the given files to the subsequent components in the chain.
  //    see AliHLTRootFilePublisher for more options
  AliHLTConfiguration RootPublisher("RootPublisher", "ROOTFilePublisher", NULL, arg.Data() );
  if (!writerInput.IsNull()) writerInput+=" ";
  writerInput+="RootPublisher";

  // -
  // -- Processing Components can be put in here
  // -

  // -- The AliHLTRootFileWriter (Id 'ROOTFileWriter') is a data sink. It writes
  // all incoming data blocks to files. Several options available.
  AliHLTConfiguration RootWriter("RootWriter", "ROOTFileWriter", writerInput.Data(),"-datafile event");

  // -- Here you specify the top most configuration of the chain. The
  // configuration depends on all the parents. The task lisy is build
  // according to that.
  gHLT.BuildTaskList("RootWriter");
  gHLT.Run(nEvents);
}
<commit_msg>Fix of doxygen warning<commit_after>/**
 * @file rootfilepublisher.C
 * @brief Macro for testing ROOT-file publishing and writing
 *
 * This macro is a testing/example macro of how to use the RootFilePublisher
 * (AliHLTRootFilePublisher) and RootFileWriter (AliHLTRootFileWriter).
 * It defines only two component in the chain, the publisher, which
 * publishes the content of the root files according to the selection.
 * Be aware there can be several root objects in one root file.
 *
 * The file myRootFile.root has to be changed with the actual file.
 * In this example, an ESD file is used, which contains a "esdTree" and
 * a "HLTesdTree" object. Only the "HLTesdTree" object is selected. The
 * data blocks, which will are published here, have the data type of
 * {ROOTTOBJ,"***"} and specification of 0x00000000. They also have to
 * been adopted to the actual content of the root file.
 *
 * @author thaeder@kip.uni-heidelberg.de
 * @ingroup alihlt_tutorial
 */

/** RootFilePublisher test macro
 *  @param nEvents Number of events which should be processed
 */
void rootfilepublisher(Int_t nEvents=1) {

  TString writerInput;
  TString arg;

  AliHLTSystem gHLT;
  gHLT.LoadComponentLibraries("libAliHLTUtil.so");

  // -- Root publisher configuration
  // !!! myRootFile.root has to be exchanged with an existing one.
  arg.Form("-objectname HLTesdTree -datatype 'ESD_TREE' 'TPC '-dataspec 0x00000000 -datafile myRootFile.root");

  // -- The AliHLTRootFilePublisher (Id 'ROOTFilePublisher') is a data source.
  //    It provides the given files to the subsequent components in the chain.
  //    see AliHLTRootFilePublisher for more options
  AliHLTConfiguration RootPublisher("RootPublisher", "ROOTFilePublisher", NULL, arg.Data() );
  if (!writerInput.IsNull()) writerInput+=" ";
  writerInput+="RootPublisher";

  // -
  // -- Processing Components can be put in here
  // -

  // -- The AliHLTRootFileWriter (Id 'ROOTFileWriter') is a data sink. It writes
  // all incoming data blocks to files. Several options available.
  AliHLTConfiguration RootWriter("RootWriter", "ROOTFileWriter", writerInput.Data(),"-datafile event");

  // -- Here you specify the top most configuration of the chain. The
  // configuration depends on all the parents. The task lisy is build
  // according to that.
  gHLT.BuildTaskList("RootWriter");
  gHLT.Run(nEvents);
}
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

//...
//  Checks the quality assurance.
//  By comparing with reference data
//  Skeleton for HMPID
//...

// --- ROOT system ---
#include <TClass.h>
#include <TH1F.h>
#include <TH1I.h>
#include <TF1.h>
#include <TIterator.h>
#include <TKey.h>
#include <TFile.h>

// --- Standard library ---

// --- AliRoot header files ---
#include "AliLog.h"
#include "AliQAv1.h"
#include "AliQAChecker.h"
#include "AliHMPIDQAChecker.h"
#include "AliCDBEntry.h"
#include "AliQAManager.h"

ClassImp(AliHMPIDQAChecker)
 //_________________________________________________________________
AliHMPIDQAChecker::AliHMPIDQAChecker() :
AliQACheckerBase("HMPID","HMPID Quality Assurance Data Checker"),
fNoReference(kTRUE)
//fQARefRec(NULL)
{
    //ctor, fetches the reference data from OCDB
  char * detOCDBDir = Form("HMPID/%s/%s", AliQAv1::GetRefOCDBDirName(), AliQAv1::GetRefDataDirName()) ;
  AliCDBEntry * QARefRec = AliQAManager::QAManager()->Get(detOCDBDir);
  if(QARefRec) {
    fQARefRec = dynamic_cast<TObjArray*> (QARefRec->GetObject()) ;
    if (fQARefRec)
      if (fQARefRec->GetEntries())
        fNoReference = kFALSE ;
    if (fNoReference)
      AliInfo("QA reference data NOT retrieved for Reconstruction check. No HMPIDChecker!");
  }
}

//_________________________________________________________________
AliHMPIDQAChecker::AliHMPIDQAChecker(const AliHMPIDQAChecker& qac) :
AliQACheckerBase(qac.GetName(), qac.GetTitle()),
fNoReference(qac.fNoReference),
fQARefRec(NULL)
{
  fNoReference = qac.fNoReference ;
  if (qac.fQARefRec) {
    fQARefRec = new TObjArray(qac.fQARefRec->GetEntries()) ;
    for (Int_t index=0; index < qac.fQARefRec->GetEntries(); index++)
      fQARefRec->Add(qac.fQARefRec->At(index)) ;
  }
}

//_________________________________________________________________
AliHMPIDQAChecker::~AliHMPIDQAChecker()
{
  if(fQARefRec) { fQARefRec->Delete() ;   delete fQARefRec ; }
}
//_________________________________________________________________
void AliHMPIDQAChecker::Check(Double_t *  check, AliQAv1::ALITASK_t index, TObjArray ** list, const AliDetectorRecoParam * /*recoParam*/)
{
//
// Main check function: Depending on the TASK, different checks are applied
// At the moment:       check for empty histograms and checks for RecPoints

  if(fNoReference)

  for (Int_t specie = 0 ; specie < AliRecoParam::kNSpecies ; specie++) {
    check[specie] = 1.0;
    if ( !AliQAv1::Instance()->IsEventSpecieSet(specie) )
      continue ;
    // checking for empy histograms
    if(CheckEntries(list[specie]) == 0)  {
      AliWarning("histograms are empty");
      check[specie] = 0.4;//-> Corresponds to kWARNING see AliQACheckerBase::Run
    }

    //check sim
    if(index == AliQAv1::kSIM) check[specie] = CheckSim(list[specie], fQARefRec);

    // checking rec points
    if(index == AliQAv1::kREC) check[specie] = CheckRec(list[specie], fQARefRec);

    //default check response. It will be changed when reasonable checks will be considered
    else check[specie] = 0.7 ; // /-> Corresponds to kINFO see AliQACheckerBase::Run
  } // species loop
}
//_________________________________________________________________
Double_t AliHMPIDQAChecker::CheckEntries(TObjArray * list) const
{
  //
  //  check on the QA histograms on the input list:
  //

  Double_t test = 0.0  ;
  Int_t count = 0 ;

  if (list->GetEntries() == 0){
    test = 1. ; // nothing to check
  }
  else {
    TIter next(list) ;
    TH1 * hdata ;
    count = 0 ;
    while ( (hdata = dynamic_cast<TH1 *>(next())) ) {
      if (hdata) {
	Double_t rv = 0.;
        //Printf("hitogram %s     has entries: %f ",hdata->GetName(),hdata->GetEntries());
	if(hdata->GetEntries()>0)rv=1;
	count++ ;
	test += rv ;
      }
      else{
	AliError("Data type cannot be processed") ;
      }

    }
    if (count != 0) {
      if (test==0) {
	AliWarning("Histograms are booked for THIS specific Task, but they are all empty: setting flag to kWARNING");
	test = 0.;  //upper limit value to set kWARNING flag for a task
      }
      else test = 1 ;
    }
  }

  return test ;
}
//_________________________________________________________________
Double_t AliHMPIDQAChecker::CheckSim(TObjArray *listsim, TObjArray *listref) const
{
  //
  //  check on the HMPID RecPoints by using expo fit and Kolmogorov Test:
  //

   Float_t checkresponse = 0;

   Float_t counter = 0 ;
   TIter next(listsim) ;
   TH1* histo;
   while ( (histo = dynamic_cast<TH1 *>(next())) ) {
     //PH The histogram should have at least 10 bins with at least 5 entries
     Int_t nbinsabove = 0;
     for (Int_t ibin=histo->FindBin(1); ibin<=histo->FindBin(50); ibin++) {
       if (histo->GetBinContent(ibin)>5) nbinsabove++;
     }

   if( nbinsabove < 10 ) counter++;
   else {
    TString h = histo->GetTitle();
    if(h.Contains("Zoom")){
    histo->Fit("expo","LQ0","",5,50);
    if(histo->GetFunction("expo")->GetParameter(1) !=0 ) if(TMath::Abs((-1./(histo->GetFunction("expo"))->GetParameter(1)) - 35 ) > 5) counter++;
    }
    if(h.Contains("size  MIP"))   if(TMath::Abs(histo->GetMean()-5) > 2) counter++;
    if(h.Contains("size  Phots")) if(TMath::Abs(histo->GetMean()-2) > 2) counter++;
    if(h.Contains("distribution")) if(histo->KolmogorovTest((TH1F *)listref->At(0))<0.8) counter++;
    AliDebug(AliQAv1::GetQADebugLevel(),Form(" Kolm. test : %f ",histo->KolmogorovTest((TH1F *)listref->At(0))));
   }
  }
 Float_t response = counter/(7.+7.+42.+42.); // 7.+7.+42 +42 = N checked histograms (-> To be replaced by listsim->GetEntries())

 if(response < 0.1) checkresponse = 0.7;      // <10% of the check histograms show a failing check -> Corresponds to kINFO see AliQACheckerBase::Run
 else if(response < 0.5) checkresponse = 0.4; //  50%  of the check histograms show a failing check -> Corresponds to kWARNING see AliQACheckerBase::Run
 else checkresponse = 0.001;                  // > 50% of the check histograms show a failing check -> Corresponds to kERROR see AliQACheckerBase::Run
 return checkresponse;
}

//___________________________________________________________________________________________________
Double_t AliHMPIDQAChecker::CheckRec(TObjArray *listrec, TObjArray *listref) const
{
  //
  //  check on the HMPID RecPoints by using expo fit and Kolmogorov Test:
  //

   Float_t checkresponse = 0;

   Float_t counter = 0 ;
   TIter next(listrec) ;
   TH1* histo;
   while ( (histo = dynamic_cast<TH1 *>(next())) ) {
     //PH The histogram should have at least 10 bins with at least 5 entries
     Int_t nbinsabove = 0;
     for (Int_t ibin=histo->FindBin(1); ibin<=histo->FindBin(50); ibin++) {
       if (histo->GetBinContent(ibin)>5) nbinsabove++;
     }

   if( nbinsabove < 10 ) counter++;
   else {
    TString h = histo->GetTitle();
    if(h.Contains("Zoom")){
    histo->Fit("expo","LQ0","",5,50);
    if(histo->GetFunction("expo")->GetParameter(1) !=0 ) if(TMath::Abs((-1./(histo->GetFunction("expo"))->GetParameter(1)) - 35 ) > 5) counter++;
    }
    if(h.Contains("size  MIP"))   if(TMath::Abs(histo->GetMean()-5) > 2) counter++;
    if(h.Contains("size  Phots")) if(TMath::Abs(histo->GetMean()-2) > 2) counter++;
    if(h.Contains("distribution")) if(histo->KolmogorovTest((TH1F *)listref->At(0))<0.8) counter++;
    AliDebug(AliQAv1::GetQADebugLevel(),Form(" Kolm. test : %f ",histo->KolmogorovTest((TH1F *)listref->At(0))));
   }
  }
 Float_t response = counter/(7.+7.+42.+42.); // 7.+7.+42 +42 = N checked histograms (-> To be replaced by listrec->GetEntries())

 if(response < 0.1) checkresponse = 0.7;      // <10% of the check histograms show a failing check -> Corresponds to kINFO see AliQACheckerBase::Run
 else if(response < 0.5) checkresponse = 0.4; //  50%  of the check histograms show a failing check -> Corresponds to kWARNING see AliQACheckerBase::Run
 else checkresponse = 0.001;                  // > 50% of the check histograms show a failing check -> Corresponds to kERROR see AliQACheckerBase::Run
 return checkresponse;
}

<commit_msg>Warning fixed<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

//...
//  Checks the quality assurance.
//  By comparing with reference data
//  Skeleton for HMPID
//...

// --- ROOT system ---
#include <TClass.h>
#include <TH1F.h>
#include <TH1I.h>
#include <TF1.h>
#include <TIterator.h>
#include <TKey.h>
#include <TFile.h>

// --- Standard library ---

// --- AliRoot header files ---
#include "AliLog.h"
#include "AliQAv1.h"
#include "AliQAChecker.h"
#include "AliHMPIDQAChecker.h"
#include "AliCDBEntry.h"
#include "AliQAManager.h"

ClassImp(AliHMPIDQAChecker)
 //_________________________________________________________________
AliHMPIDQAChecker::AliHMPIDQAChecker() :
AliQACheckerBase("HMPID","HMPID Quality Assurance Data Checker"),
fNoReference(kTRUE),
fQARefRec(NULL)
{
    //ctor, fetches the reference data from OCDB
  char * detOCDBDir = Form("HMPID/%s/%s", AliQAv1::GetRefOCDBDirName(), AliQAv1::GetRefDataDirName()) ;
  AliCDBEntry * QARefRec = AliQAManager::QAManager()->Get(detOCDBDir);
  if(QARefRec) {
    fQARefRec = dynamic_cast<TObjArray*> (QARefRec->GetObject()) ;
    if (fQARefRec)
      if (fQARefRec->GetEntries())
        fNoReference = kFALSE ;
    if (fNoReference)
      AliInfo("QA reference data NOT retrieved for Reconstruction check. No HMPIDChecker!");
  }
}

//_________________________________________________________________
AliHMPIDQAChecker::AliHMPIDQAChecker(const AliHMPIDQAChecker& qac) :
AliQACheckerBase(qac.GetName(), qac.GetTitle()),
fNoReference(qac.fNoReference),
fQARefRec(NULL)
{
  fNoReference = qac.fNoReference ;
  if (qac.fQARefRec) {
    fQARefRec = new TObjArray(qac.fQARefRec->GetEntries()) ;
    for (Int_t index=0; index < qac.fQARefRec->GetEntries(); index++)
      fQARefRec->Add(qac.fQARefRec->At(index)) ;
  }
}

//_________________________________________________________________
AliHMPIDQAChecker::~AliHMPIDQAChecker()
{
  if(fQARefRec) { fQARefRec->Delete() ;   delete fQARefRec ; }
}
//_________________________________________________________________
void AliHMPIDQAChecker::Check(Double_t *  check, AliQAv1::ALITASK_t index, TObjArray ** list, const AliDetectorRecoParam * /*recoParam*/)
{
//
// Main check function: Depending on the TASK, different checks are applied
// At the moment:       check for empty histograms and checks for RecPoints

  if(fNoReference)

  for (Int_t specie = 0 ; specie < AliRecoParam::kNSpecies ; specie++) {
    check[specie] = 1.0;
    if ( !AliQAv1::Instance()->IsEventSpecieSet(specie) )
      continue ;
    // checking for empy histograms
    if(CheckEntries(list[specie]) == 0)  {
      AliWarning("histograms are empty");
      check[specie] = 0.4;//-> Corresponds to kWARNING see AliQACheckerBase::Run
    }

    //check sim
    if(index == AliQAv1::kSIM) check[specie] = CheckSim(list[specie], fQARefRec);

    // checking rec points
    if(index == AliQAv1::kREC) check[specie] = CheckRec(list[specie], fQARefRec);

    //default check response. It will be changed when reasonable checks will be considered
    else check[specie] = 0.7 ; // /-> Corresponds to kINFO see AliQACheckerBase::Run
  } // species loop
}
//_________________________________________________________________
Double_t AliHMPIDQAChecker::CheckEntries(TObjArray * list) const
{
  //
  //  check on the QA histograms on the input list:
  //

  Double_t test = 0.0  ;
  Int_t count = 0 ;

  if (list->GetEntries() == 0){
    test = 1. ; // nothing to check
  }
  else {
    TIter next(list) ;
    TH1 * hdata ;
    count = 0 ;
    while ( (hdata = dynamic_cast<TH1 *>(next())) ) {
      if (hdata) {
	Double_t rv = 0.;
        //Printf("hitogram %s     has entries: %f ",hdata->GetName(),hdata->GetEntries());
	if(hdata->GetEntries()>0)rv=1;
	count++ ;
	test += rv ;
      }
      else{
	AliError("Data type cannot be processed") ;
      }

    }
    if (count != 0) {
      if (test==0) {
	AliWarning("Histograms are booked for THIS specific Task, but they are all empty: setting flag to kWARNING");
	test = 0.;  //upper limit value to set kWARNING flag for a task
      }
      else test = 1 ;
    }
  }

  return test ;
}
//_________________________________________________________________
Double_t AliHMPIDQAChecker::CheckSim(TObjArray *listsim, TObjArray *listref) const
{
  //
  //  check on the HMPID RecPoints by using expo fit and Kolmogorov Test:
  //

   Float_t checkresponse = 0;

   Float_t counter = 0 ;
   TIter next(listsim) ;
   TH1* histo;
   while ( (histo = dynamic_cast<TH1 *>(next())) ) {
     //PH The histogram should have at least 10 bins with at least 5 entries
     Int_t nbinsabove = 0;
     for (Int_t ibin=histo->FindBin(1); ibin<=histo->FindBin(50); ibin++) {
       if (histo->GetBinContent(ibin)>5) nbinsabove++;
     }

   if( nbinsabove < 10 ) counter++;
   else {
    TString h = histo->GetTitle();
    if(h.Contains("Zoom")){
    histo->Fit("expo","LQ0","",5,50);
    if(histo->GetFunction("expo")->GetParameter(1) !=0 ) if(TMath::Abs((-1./(histo->GetFunction("expo"))->GetParameter(1)) - 35 ) > 5) counter++;
    }
    if(h.Contains("size  MIP"))   if(TMath::Abs(histo->GetMean()-5) > 2) counter++;
    if(h.Contains("size  Phots")) if(TMath::Abs(histo->GetMean()-2) > 2) counter++;
    if(h.Contains("distribution")) if(histo->KolmogorovTest((TH1F *)listref->At(0))<0.8) counter++;
    AliDebug(AliQAv1::GetQADebugLevel(),Form(" Kolm. test : %f ",histo->KolmogorovTest((TH1F *)listref->At(0))));
   }
  }
 Float_t response = counter/(7.+7.+42.+42.); // 7.+7.+42 +42 = N checked histograms (-> To be replaced by listsim->GetEntries())

 if(response < 0.1) checkresponse = 0.7;      // <10% of the check histograms show a failing check -> Corresponds to kINFO see AliQACheckerBase::Run
 else if(response < 0.5) checkresponse = 0.4; //  50%  of the check histograms show a failing check -> Corresponds to kWARNING see AliQACheckerBase::Run
 else checkresponse = 0.001;                  // > 50% of the check histograms show a failing check -> Corresponds to kERROR see AliQACheckerBase::Run
 return checkresponse;
}

//___________________________________________________________________________________________________
Double_t AliHMPIDQAChecker::CheckRec(TObjArray *listrec, TObjArray *listref) const
{
  //
  //  check on the HMPID RecPoints by using expo fit and Kolmogorov Test:
  //

   Float_t checkresponse = 0;

   Float_t counter = 0 ;
   TIter next(listrec) ;
   TH1* histo;
   while ( (histo = dynamic_cast<TH1 *>(next())) ) {
     //PH The histogram should have at least 10 bins with at least 5 entries
     Int_t nbinsabove = 0;
     for (Int_t ibin=histo->FindBin(1); ibin<=histo->FindBin(50); ibin++) {
       if (histo->GetBinContent(ibin)>5) nbinsabove++;
     }

   if( nbinsabove < 10 ) counter++;
   else {
    TString h = histo->GetTitle();
    if(h.Contains("Zoom")){
    histo->Fit("expo","LQ0","",5,50);
    if(histo->GetFunction("expo")->GetParameter(1) !=0 ) if(TMath::Abs((-1./(histo->GetFunction("expo"))->GetParameter(1)) - 35 ) > 5) counter++;
    }
    if(h.Contains("size  MIP"))   if(TMath::Abs(histo->GetMean()-5) > 2) counter++;
    if(h.Contains("size  Phots")) if(TMath::Abs(histo->GetMean()-2) > 2) counter++;
    if(h.Contains("distribution")) if(histo->KolmogorovTest((TH1F *)listref->At(0))<0.8) counter++;
    AliDebug(AliQAv1::GetQADebugLevel(),Form(" Kolm. test : %f ",histo->KolmogorovTest((TH1F *)listref->At(0))));
   }
  }
 Float_t response = counter/(7.+7.+42.+42.); // 7.+7.+42 +42 = N checked histograms (-> To be replaced by listrec->GetEntries())

 if(response < 0.1) checkresponse = 0.7;      // <10% of the check histograms show a failing check -> Corresponds to kINFO see AliQACheckerBase::Run
 else if(response < 0.5) checkresponse = 0.4; //  50%  of the check histograms show a failing check -> Corresponds to kWARNING see AliQACheckerBase::Run
 else checkresponse = 0.001;                  // > 50% of the check histograms show a failing check -> Corresponds to kERROR see AliQACheckerBase::Run
 return checkresponse;
}

<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2005 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "BzMaterial.h"
#include "ParseMaterial.h"

/* system headers */
#include <sstream>

/* common implementation headers */
#include "ParseColor.h"
#include "TextureMatrix.h"
#include "DynamicColor.h"

bool parseMaterials(const char* cmd, std::istream& input,
		    BzMaterial* materials, int materialCount, bool& error)
{
  int i;
  error = false;

  if (strcasecmp(cmd, "matref") == 0) {
    std::string name;
    if (!(input >> name)) {
      std::cout << "missing " << cmd << " parameters" << std::endl;
      error = true;
    }
    const BzMaterial* matref = MATERIALMGR.findMaterial(name);
    if (matref == NULL) {
      std::cout << "couldn't find reference material: " << name << std::endl;
      error = true;
    } else {
      for (i = 0; i < materialCount; i++) {
	materials[i] = *matref;
      }
    }
  }
  else if (strcasecmp(cmd, "resetmat") == 0) {
    for (i = 0; i < materialCount; i++) {
      materials[i].reset();
    }
  }
  else if (strcasecmp(cmd, "dyncol") == 0) {
    std::string dyncol;
    if (!(input >> dyncol)) {
      std::cout << "missing " << cmd << " parameters" << std::endl;
      error = true;
    }
    int dynamicColor = DYNCOLORMGR.findColor(dyncol);
    if ((dynamicColor == -1) && (dyncol != "-1")) {
      std::cout << "couldn't find dynamicColor: " << dyncol << std::endl;
      error = true;
    } else {
      for (i = 0; i < materialCount; i++) {
	materials[i].setDynamicColor(dynamicColor);
      }
    }
  }
  else if (strcasecmp(cmd, "ambient") == 0) {
    float ambient[4];
    error = !parseColorStream(input, ambient);
    if (!error) {
      for (i = 0; i < materialCount; i++) {
	materials[i].setAmbient(ambient);
      }
    } else {
      std::cout << "bad " << cmd << " specification" << std::endl;
    }
  }
  else if ((strcasecmp(cmd, "diffuse") == 0) || // currently used by bzflag
	   (strcasecmp(cmd, "color") == 0)) {
    float diffuse[4];
    error = !parseColorStream(input, diffuse);
    if (!error) {
      for (i = 0; i < materialCount; i++) {
	materials[i].setDiffuse(diffuse);
      }
    } else {
      std::cout << "bad " << cmd << " specification" << std::endl;
    }
  }
  else if (strcasecmp(cmd, "specular") == 0) {
    float specular[4];
    error = !parseColorStream(input, specular);
    if (!error) {
      for (i = 0; i < materialCount; i++) {
	materials[i].setSpecular(specular);
      }
    } else {
      std::cout << "bad " << cmd << " specification" << std::endl;
    }
  }
  else if (strcasecmp(cmd, "emission") == 0) {
    float emission[4];
    error = !parseColorStream(input, emission);
    if (!error) {
      for (i = 0; i < materialCount; i++) {
	materials[i].setEmission(emission);
      }
    } else {
      std::cout << "bad " << cmd << " specification" << std::endl;
    }
  }
  else if (strcasecmp(cmd, "shininess") == 0) {
    float shininess;
    if (!(input >> shininess)) {
      std::cout << "missing " << cmd << " parameters" << std::endl;
      error = true;
    }
    for (i = 0; i < materialCount; i++) {
      materials[i].setShininess(shininess);
    }
  }
  else if (strcasecmp(cmd, "alphathresh") == 0) {
    float alphaThresh;
    if (!(input >> alphaThresh)) {
      std::cout << "missing " << cmd << " parameters" << std::endl;
      error = true;
    }
    for (i = 0; i < materialCount; i++) {
      materials[i].setAlphaThreshold(alphaThresh);
    }
  }
  else if (strcasecmp(cmd, "noculling") == 0) {
    for (i = 0; i < materialCount; i++) {
      materials[i].setNoCulling(true);
    }
  }
  else if (strcasecmp(cmd, "nosorting") == 0) {
    for (i = 0; i < materialCount; i++) {
      materials[i].setNoSorting(true);
    }
  }
  else if (strcasecmp(cmd, "noradar") == 0) {
    for (i = 0; i < materialCount; i++) {
      materials[i].setNoRadar(true);
    }
  }
  else if (strcasecmp(cmd, "texture") == 0) {
    std::string name;
    if (!(input >> name)) {
      std::cout << "missing " << cmd << " parameters" << std::endl;
      error = true;
    } else {
      for (i = 0; i < materialCount; i++) {
	materials[i].setTexture(name);
      }
    }
  }
  else if (strcasecmp(cmd, "notextures") == 0) {
    for (i = 0; i < materialCount; i++) {
      materials[i].clearTextures();
    }
  }
  else if (strcasecmp(cmd, "addtexture") == 0) {
    std::string name;
    if (!(input >> name)) {
      std::cout << "missing " << cmd << " parameters" << std::endl;
      error = true;
    }
    for (i = 0; i < materialCount; i++) {
      materials[i].addTexture(name);
    }
  }
  else if (strcasecmp(cmd, "texmat") == 0) {
    std::string texmat;
    if (!(input >> texmat)) {
      std::cout << "missing " << cmd << " parameters" << std::endl;
      error = true;
    }
    int textureMatrix = TEXMATRIXMGR.findMatrix(texmat);
    if ((textureMatrix == -1) && (texmat != "-1")) {
      std::cout << "couldn't find textureMatrix: " << texmat << std::endl;
    }
    for (i = 0; i < materialCount; i++) {
      materials[i].setTextureMatrix(textureMatrix);
    }
  }
  else if (strcasecmp(cmd, "notexalpha") == 0) {
    for (i = 0; i < materialCount; i++) {
      materials[i].setUseTextureAlpha(false);
    }
  }
  else if (strcasecmp(cmd, "notexcolor") == 0) {
    for (i = 0; i < materialCount; i++) {
      materials[i].setUseColorOnTexture(false);
    }
  }
  else if (strcasecmp(cmd, "spheremap") == 0) {
    for (i = 0; i < materialCount; i++) {
      materials[i].setUseSphereMap(true);
    }
  }
  else if (strcasecmp(cmd, "shader") == 0) {
    std::string name;
    if (!(input >> name)) {
      std::cout << "missing " << cmd << " parameters" << std::endl;
      error = true;
    }
    for (i = 0; i < materialCount; i++) {
      materials[i].setShader(name);
    }
  }
  else if (strcasecmp(cmd, "addshader") == 0) {
    std::string name;
    if (!(input >> name)) {
      std::cout << "missing " << cmd << " parameters" << std::endl;
      error = true;
    }
    for (i = 0; i < materialCount; i++) {
      materials[i].addShader(name);
    }
  }
  else if (strcasecmp(cmd, "noshaders") == 0) {
    for (i = 0; i < materialCount; i++) {
      materials[i].clearShaders();
    }
  }
  else {
    return false;
  }

  return true;
}

bool parseMaterialsByName(const char* cmd, std::istream& input,
			  BzMaterial* materials, const char** names,
			  int materialCount, bool& error)
{
  error = false;

  for (int n = 0; n < materialCount; n++) {
    if (strcasecmp (cmd, names[n]) == 0) {
      std::string line, matcmd;
      std::getline(input, line);
      std::istringstream parms(line);
      if (!(parms >> matcmd)) {
	error = true;
      } else {
	// put the material command string back into the stream
        const int putbacklength = (int)(line.size() - matcmd.size());
        std::string::const_reverse_iterator it = line.rbegin();
        for (int i = 0; i < putbacklength; ++it, ++i)
          input.putback(*it);

	if (!parseMaterials(matcmd.c_str(), input, &materials[n], 1, error)) {
	  error = true;
	}
      }
      return true;
    }
  }

  return false;
}

// Local variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>another attempt<commit_after>/* bzflag
 * Copyright (c) 1993 - 2005 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "BzMaterial.h"
#include "ParseMaterial.h"

/* system headers */
#include <sstream>

/* common implementation headers */
#include "ParseColor.h"
#include "TextureMatrix.h"
#include "DynamicColor.h"

bool parseMaterials(const char* cmd, std::istream& input,
		    BzMaterial* materials, int materialCount, bool& error)
{
  int i;
  error = false;

  if (strcasecmp(cmd, "matref") == 0) {
    std::string name;
    if (!(input >> name)) {
      std::cout << "missing " << cmd << " parameters" << std::endl;
      error = true;
    }
    const BzMaterial* matref = MATERIALMGR.findMaterial(name);
    if (matref == NULL) {
      std::cout << "couldn't find reference material: " << name << std::endl;
      error = true;
    } else {
      for (i = 0; i < materialCount; i++) {
	materials[i] = *matref;
      }
    }
  }
  else if (strcasecmp(cmd, "resetmat") == 0) {
    for (i = 0; i < materialCount; i++) {
      materials[i].reset();
    }
  }
  else if (strcasecmp(cmd, "dyncol") == 0) {
    std::string dyncol;
    if (!(input >> dyncol)) {
      std::cout << "missing " << cmd << " parameters" << std::endl;
      error = true;
    }
    int dynamicColor = DYNCOLORMGR.findColor(dyncol);
    if ((dynamicColor == -1) && (dyncol != "-1")) {
      std::cout << "couldn't find dynamicColor: " << dyncol << std::endl;
      error = true;
    } else {
      for (i = 0; i < materialCount; i++) {
	materials[i].setDynamicColor(dynamicColor);
      }
    }
  }
  else if (strcasecmp(cmd, "ambient") == 0) {
    float ambient[4];
    error = !parseColorStream(input, ambient);
    if (!error) {
      for (i = 0; i < materialCount; i++) {
	materials[i].setAmbient(ambient);
      }
    } else {
      std::cout << "bad " << cmd << " specification" << std::endl;
    }
  }
  else if ((strcasecmp(cmd, "diffuse") == 0) || // currently used by bzflag
	   (strcasecmp(cmd, "color") == 0)) {
    float diffuse[4];
    error = !parseColorStream(input, diffuse);
    if (!error) {
      for (i = 0; i < materialCount; i++) {
	materials[i].setDiffuse(diffuse);
      }
    } else {
      std::cout << "bad " << cmd << " specification" << std::endl;
    }
  }
  else if (strcasecmp(cmd, "specular") == 0) {
    float specular[4];
    error = !parseColorStream(input, specular);
    if (!error) {
      for (i = 0; i < materialCount; i++) {
	materials[i].setSpecular(specular);
      }
    } else {
      std::cout << "bad " << cmd << " specification" << std::endl;
    }
  }
  else if (strcasecmp(cmd, "emission") == 0) {
    float emission[4];
    error = !parseColorStream(input, emission);
    if (!error) {
      for (i = 0; i < materialCount; i++) {
	materials[i].setEmission(emission);
      }
    } else {
      std::cout << "bad " << cmd << " specification" << std::endl;
    }
  }
  else if (strcasecmp(cmd, "shininess") == 0) {
    float shininess;
    if (!(input >> shininess)) {
      std::cout << "missing " << cmd << " parameters" << std::endl;
      error = true;
    }
    for (i = 0; i < materialCount; i++) {
      materials[i].setShininess(shininess);
    }
  }
  else if (strcasecmp(cmd, "alphathresh") == 0) {
    float alphaThresh;
    if (!(input >> alphaThresh)) {
      std::cout << "missing " << cmd << " parameters" << std::endl;
      error = true;
    }
    for (i = 0; i < materialCount; i++) {
      materials[i].setAlphaThreshold(alphaThresh);
    }
  }
  else if (strcasecmp(cmd, "noculling") == 0) {
    for (i = 0; i < materialCount; i++) {
      materials[i].setNoCulling(true);
    }
  }
  else if (strcasecmp(cmd, "nosorting") == 0) {
    for (i = 0; i < materialCount; i++) {
      materials[i].setNoSorting(true);
    }
  }
  else if (strcasecmp(cmd, "noradar") == 0) {
    for (i = 0; i < materialCount; i++) {
      materials[i].setNoRadar(true);
    }
  }
  else if (strcasecmp(cmd, "texture") == 0) {
    std::string name;
    if (!(input >> name)) {
      std::cout << "missing " << cmd << " parameters" << std::endl;
      error = true;
    } else {
      for (i = 0; i < materialCount; i++) {
	materials[i].setTexture(name);
      }
    }
  }
  else if (strcasecmp(cmd, "notextures") == 0) {
    for (i = 0; i < materialCount; i++) {
      materials[i].clearTextures();
    }
  }
  else if (strcasecmp(cmd, "addtexture") == 0) {
    std::string name;
    if (!(input >> name)) {
      std::cout << "missing " << cmd << " parameters" << std::endl;
      error = true;
    }
    for (i = 0; i < materialCount; i++) {
      materials[i].addTexture(name);
    }
  }
  else if (strcasecmp(cmd, "texmat") == 0) {
    std::string texmat;
    if (!(input >> texmat)) {
      std::cout << "missing " << cmd << " parameters" << std::endl;
      error = true;
    }
    int textureMatrix = TEXMATRIXMGR.findMatrix(texmat);
    if ((textureMatrix == -1) && (texmat != "-1")) {
      std::cout << "couldn't find textureMatrix: " << texmat << std::endl;
    }
    for (i = 0; i < materialCount; i++) {
      materials[i].setTextureMatrix(textureMatrix);
    }
  }
  else if (strcasecmp(cmd, "notexalpha") == 0) {
    for (i = 0; i < materialCount; i++) {
      materials[i].setUseTextureAlpha(false);
    }
  }
  else if (strcasecmp(cmd, "notexcolor") == 0) {
    for (i = 0; i < materialCount; i++) {
      materials[i].setUseColorOnTexture(false);
    }
  }
  else if (strcasecmp(cmd, "spheremap") == 0) {
    for (i = 0; i < materialCount; i++) {
      materials[i].setUseSphereMap(true);
    }
  }
  else if (strcasecmp(cmd, "shader") == 0) {
    std::string name;
    if (!(input >> name)) {
      std::cout << "missing " << cmd << " parameters" << std::endl;
      error = true;
    }
    for (i = 0; i < materialCount; i++) {
      materials[i].setShader(name);
    }
  }
  else if (strcasecmp(cmd, "addshader") == 0) {
    std::string name;
    if (!(input >> name)) {
      std::cout << "missing " << cmd << " parameters" << std::endl;
      error = true;
    }
    for (i = 0; i < materialCount; i++) {
      materials[i].addShader(name);
    }
  }
  else if (strcasecmp(cmd, "noshaders") == 0) {
    for (i = 0; i < materialCount; i++) {
      materials[i].clearShaders();
    }
  }
  else {
    return false;
  }

  return true;
}

bool parseMaterialsByName(const char* cmd, std::istream& input,
			  BzMaterial* materials, const char** names,
			  int materialCount, bool& error)
{
  error = false;

  for (int n = 0; n < materialCount; n++) {
    if (strcasecmp (cmd, names[n]) == 0) {
      std::string line, matcmd;
      std::getline(input, line);
      std::istringstream parms(line);
      if (!(parms >> matcmd)) {
	error = true;
      } else {
	// put the material command string back into the stream
        input.putback('\n');
	for (int i = 1; i < (int)(line.size() - matcmd.size()); i++) {
	  input.putback(line[line.size() - i]);
	}
	if (!parseMaterials(matcmd.c_str(), input, &materials[n], 1, error)) {
	  error = true;
	}
      }
      return true;
    }
  }

  return false;
}

// Local variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>#ifndef __RANK_FILTER__
#define __RANK_FILTER__

#include <list>
#include <set>
#include <cmath>
#include <cassert>
#include <iostream>
#include <iterator>
#include <type_traits>
#include <utility>

#include <vigra/multi_array.hxx>
#include <vigra/linear_algebra.hxx>

namespace vigra
{

template<unsigned int N,
        class T1, class S1,
        class T2, class S2,
        typename std::enable_if<(N == 1), int>::type = 0>
inline void lineRankOrderFilterND(const vigra::MultiArrayView <N, T1, S1> &src,
        vigra::MultiArrayView <N, T2, S2> dest,
        unsigned int half_length, float rank, unsigned int axis = N - 1)
{
    // Will ignore boundaries initially.
    // Then will try adding reflection.

    // Rank must be in the range 0 to 1
    assert((0 <= rank) && (rank <= 1));

    const int rank_pos = round(rank * (2 * half_length));

    // The position of the
    typename vigra::MultiArrayView<N, T1, S1>::difference_type_1 window_begin(0);
    std::multiset<T1> sorted_window;
    std::list< typename std::multiset<T1>::iterator > window_iters;

    // Get the initial sorted window.
    // Include the reflection.
    for (typename vigra::MultiArrayView<N, T1, S1>::difference_type_1 j(half_length); j > 0; j--)
    {
        window_iters.push_back(sorted_window.insert(src[window_begin + j]));
    }
    for (typename vigra::MultiArrayView<N, T1, S1>::difference_type_1 j(0); j <= half_length; j++)
    {
        window_iters.push_back(sorted_window.insert(src[window_begin + j]));
    }

    typename std::multiset<T1>::iterator rank_point = sorted_window.begin();

    for (int i = 0; i < rank_pos; i++)
    {
        rank_point++;
    }

    while ( window_begin < src.size() )
    {
        dest[window_begin] = *rank_point;

        typename std::multiset<T1>::iterator prev_iter(window_iters.front());
        T1 prev_value = *prev_iter;
        window_iters.pop_front();

        window_begin++;

        T1 next_value;
        if ( window_begin < (src.size() - half_length) )
        {
            next_value = src[window_begin + half_length];
        }
        else
        {
            next_value = src[2 * src.size() - (window_begin + half_length + 2)];
        }

        if ( ( *rank_point < *prev_iter ) && ( *rank_point <= next_value ) )
        {
            sorted_window.erase(prev_iter);
            window_iters.push_back(sorted_window.insert(next_value));
        }
        else if ( ( *rank_point >= *prev_iter ) && ( *rank_point > next_value ) )
        {
            if ( rank_point == prev_iter )
            {
                window_iters.push_back(sorted_window.insert(next_value));
                rank_point--;

                sorted_window.erase(prev_iter);
            }
            else
            {
                sorted_window.erase(prev_iter);
                window_iters.push_back(sorted_window.insert(next_value));
            }
        }
        else if ( ( *rank_point < *prev_iter ) && ( *rank_point > next_value ) )
        {
            sorted_window.erase(prev_iter);
            window_iters.push_back(sorted_window.insert(next_value));

            rank_point--;
        }
        else if ( ( *rank_point >= *prev_iter ) && ( *rank_point <= next_value ) )
        {
            if (rank_point == prev_iter)
            {
                window_iters.push_back(sorted_window.insert(next_value));
                rank_point++;

                sorted_window.erase(prev_iter);
            }
            else
            {
                sorted_window.erase(prev_iter);
                window_iters.push_back(sorted_window.insert(next_value));

                rank_point++;
            }
        }
    }
}

template<unsigned int N,
        class T1, class S1,
        class T2, class S2,
        typename std::enable_if<(N > 1), int>::type = 0>
inline void lineRankOrderFilterND(const vigra::MultiArrayView <N, T1, S1> &src,
        vigra::MultiArrayView <N, T2, S2> dest,
        unsigned int half_length, float rank, unsigned int axis = N - 1)
{
    typename vigra::MultiArrayView<N, T1, S1>::difference_type transposed_axes;

    for (unsigned int i = 0; i < N; i++)
    {
        transposed_axes[i] = i;
    }

    std::swap(transposed_axes[N - 1], transposed_axes[axis]);

    vigra::MultiArray<N, T1> src_transposed(src.transpose(transposed_axes));

    vigra::MultiArrayView<N, T1, S1> dest_transposed(dest.transpose(transposed_axes));

    typename vigra::MultiArrayView<N - 1, T1, S1>::difference_type pos;
    pos = 0;

    bool done = false;

    while (!done)
    {
        lineRankOrderFilter(src_transposed.bindInner(pos), dest_transposed.bindInner(pos), half_length, rank);

        bool carry = true;
        for (unsigned int i = 0; ( carry && (i < N) ); i++)
        {
            if ( (++pos[N - (i + 1)]) < src.shape(N - (i + 1)) )
            {
                carry = false;
            }
            else
            {
                pos[N - (i + 1)] = 0;
                carry = true;
            }
        }

        done = !carry;
    }
}

template<unsigned int N,
        class T1, class S1,
        class T2, class S2>
inline void lineRankOrderFilter(const vigra::MultiArrayView <N, T1, S1> &src,
        vigra::MultiArrayView <N, T2, S2> dest,
        unsigned int half_length, float rank, unsigned int axis = N - 1)
{
    lineRankOrderFilterND(src, dest, half_length, rank, axis);
}

}

#endif //__RANK_FILTER__
<commit_msg>rank_filter.hxx: Fixed indexing for pos.<commit_after>#ifndef __RANK_FILTER__
#define __RANK_FILTER__

#include <list>
#include <set>
#include <cmath>
#include <cassert>
#include <iostream>
#include <iterator>
#include <type_traits>
#include <utility>

#include <vigra/multi_array.hxx>
#include <vigra/linear_algebra.hxx>

namespace vigra
{

template<unsigned int N,
        class T1, class S1,
        class T2, class S2,
        typename std::enable_if<(N == 1), int>::type = 0>
inline void lineRankOrderFilterND(const vigra::MultiArrayView <N, T1, S1> &src,
        vigra::MultiArrayView <N, T2, S2> dest,
        unsigned int half_length, float rank, unsigned int axis = N - 1)
{
    // Will ignore boundaries initially.
    // Then will try adding reflection.

    // Rank must be in the range 0 to 1
    assert((0 <= rank) && (rank <= 1));

    const int rank_pos = round(rank * (2 * half_length));

    // The position of the
    typename vigra::MultiArrayView<N, T1, S1>::difference_type_1 window_begin(0);
    std::multiset<T1> sorted_window;
    std::list< typename std::multiset<T1>::iterator > window_iters;

    // Get the initial sorted window.
    // Include the reflection.
    for (typename vigra::MultiArrayView<N, T1, S1>::difference_type_1 j(half_length); j > 0; j--)
    {
        window_iters.push_back(sorted_window.insert(src[window_begin + j]));
    }
    for (typename vigra::MultiArrayView<N, T1, S1>::difference_type_1 j(0); j <= half_length; j++)
    {
        window_iters.push_back(sorted_window.insert(src[window_begin + j]));
    }

    typename std::multiset<T1>::iterator rank_point = sorted_window.begin();

    for (int i = 0; i < rank_pos; i++)
    {
        rank_point++;
    }

    while ( window_begin < src.size() )
    {
        dest[window_begin] = *rank_point;

        typename std::multiset<T1>::iterator prev_iter(window_iters.front());
        T1 prev_value = *prev_iter;
        window_iters.pop_front();

        window_begin++;

        T1 next_value;
        if ( window_begin < (src.size() - half_length) )
        {
            next_value = src[window_begin + half_length];
        }
        else
        {
            next_value = src[2 * src.size() - (window_begin + half_length + 2)];
        }

        if ( ( *rank_point < *prev_iter ) && ( *rank_point <= next_value ) )
        {
            sorted_window.erase(prev_iter);
            window_iters.push_back(sorted_window.insert(next_value));
        }
        else if ( ( *rank_point >= *prev_iter ) && ( *rank_point > next_value ) )
        {
            if ( rank_point == prev_iter )
            {
                window_iters.push_back(sorted_window.insert(next_value));
                rank_point--;

                sorted_window.erase(prev_iter);
            }
            else
            {
                sorted_window.erase(prev_iter);
                window_iters.push_back(sorted_window.insert(next_value));
            }
        }
        else if ( ( *rank_point < *prev_iter ) && ( *rank_point > next_value ) )
        {
            sorted_window.erase(prev_iter);
            window_iters.push_back(sorted_window.insert(next_value));

            rank_point--;
        }
        else if ( ( *rank_point >= *prev_iter ) && ( *rank_point <= next_value ) )
        {
            if (rank_point == prev_iter)
            {
                window_iters.push_back(sorted_window.insert(next_value));
                rank_point++;

                sorted_window.erase(prev_iter);
            }
            else
            {
                sorted_window.erase(prev_iter);
                window_iters.push_back(sorted_window.insert(next_value));

                rank_point++;
            }
        }
    }
}

template<unsigned int N,
        class T1, class S1,
        class T2, class S2,
        typename std::enable_if<(N > 1), int>::type = 0>
inline void lineRankOrderFilterND(const vigra::MultiArrayView <N, T1, S1> &src,
        vigra::MultiArrayView <N, T2, S2> dest,
        unsigned int half_length, float rank, unsigned int axis = N - 1)
{
    typename vigra::MultiArrayView<N, T1, S1>::difference_type transposed_axes;

    for (unsigned int i = 0; i < N; i++)
    {
        transposed_axes[i] = i;
    }

    std::swap(transposed_axes[N - 1], transposed_axes[axis]);

    vigra::MultiArray<N, T1> src_transposed(src.transpose(transposed_axes));

    vigra::MultiArrayView<N, T1, S1> dest_transposed(dest.transpose(transposed_axes));

    typename vigra::MultiArrayView<N - 1, T1, S1>::difference_type pos;
    pos = 0;

    bool done = false;

    while (!done)
    {
        lineRankOrderFilter(src_transposed.bindInner(pos), dest_transposed.bindInner(pos), half_length, rank);

        bool carry = true;
        for (unsigned int i = 0; ( carry && (i < (N - 1)) ); i++)
        {
            if ( (++pos[N - (i + 2)]) < src_transposed.shape(N - (i + 2)) )
            {
                carry = false;
            }
            else
            {
                pos[N - (i + 2)] = 0;
                carry = true;
            }
        }

        done = !carry;
    }
}

template<unsigned int N,
        class T1, class S1,
        class T2, class S2>
inline void lineRankOrderFilter(const vigra::MultiArrayView <N, T1, S1> &src,
        vigra::MultiArrayView <N, T2, S2> dest,
        unsigned int half_length, float rank, unsigned int axis = N - 1)
{
    lineRankOrderFilterND(src, dest, half_length, rank, axis);
}

}

#endif //__RANK_FILTER__
<|endoftext|>


<commit_before>#include "internal.hpp"
#include "macros.hpp"
#include "message.hpp"

namespace CaDiCaL {

/*------------------------------------------------------------------------*/

// Vivification is a special case of asymmetric tautology elimination and
// asymmetric literal elimination.  It strengthens and removes irredundant
// clauses proven redundant through unit propagation.  The original
// algorithm is due to a paper by Piette, Hamadi and Sais published at
// ECAI'08.  We have an inprocessing version, e.g., it does not necessarily
// run-to-completion.  Our version does not perform any conflict analysis
// and uses a new heuristic for selecting clauses to vivify. The idea is to
// focus on long clauses with many occurrences of its literals in other
// clauses first.  This both complements nicely our implementation of
// subsume, which is bounded, e.g., subsumption attempts are skipped for
// very long clauses with literals with many occurrences and also is
// stronger in the sence that it enables to remove more clauses.

/*------------------------------------------------------------------------*/

// Check whether literal occurs less often.

struct vivify_more_noccs {

  Internal * internal;

  vivify_more_noccs (Internal * i) : internal (i) { }

  bool operator () (int a, int b) {
    long n = internal->noccs (a);
    long m = internal->noccs (b);
    if (n > m) return true;
    if (n < m) return false;
    if (a == -b) return a > 0;
    return abs (a) < abs (b);
  }
};

// Sort candidate clauses by the number of occurrences of their literals,
// with clauses to be vivified first last.   We assume that clauses are
// sorted w.r.t. more occurring literals first (with 'vivify_more_noccs').

struct vivify_less_clause {

  Internal * internal;

  vivify_less_clause (Internal * i) : internal (i) { }

  bool operator () (Clause * a, Clause * b) const {
    assert (!a->redundant), assert (!b->redundant);
    const const_literal_iterator eoa = a->end (), eob = b->end ();
    const_literal_iterator i = a->begin (), j = b->begin ();
    for (i = a->begin (), j = b->begin (); i != eoa && j != eob; i++, j++)
      if (*i != *j) return vivify_more_noccs (internal) (*j, *i);
    if (i == eoa) {
      if (!b->garbage) {
	LOG (b, "vivification sorting finds subsumed");
	internal->mark_garbage (b);
      }
      return true;
    } else {
      assert (j == eob);
      if (!a->garbage) {
	LOG (a, "vivification sorting finds subsumed");
	internal->mark_garbage (a);
      }
      return false;
    }
  }
};

/*------------------------------------------------------------------------*/

void Internal::vivify () {

  if (unsat) return;

  opts.log = true;

  assert (opts.vivify);
  SWITCH_AND_START (search, simplify, vivify);

  assert (!vivifying);
  vivifying = true;

  stats.vivifications++;
  if (level) backtrack ();

  // Disconnect all watches since we sort literals in irredundant clauses.
  //
  disconnect_watches ();

  // Count the number of occurrences of literals in all irredundant clauses,
  // particularly the irredundant binary clauses, usually responsible for
  // most of the propagations.
  //
  init_noccs ();

  const const_clause_iterator end = clauses.end ();
  const_clause_iterator i;

  for (i = clauses.begin (); i != end; i++) {
    Clause * c = *i;
    if (c->garbage || c->redundant) continue;
    const const_literal_iterator eoc = c->end ();
    const_literal_iterator j;
    for (j = c->begin (); j != eoc; j++)
      noccs (*j)++;
  }

  // After an arithmetic increasing number of calls to 'vivify' reschedule
  // all clauses, instead of only those not tried before.  Then this limit
  // is increased by one. The argument is that we should focus on clauses
  // with many occurrences of their literals (also long clauses), but in the
  // limit eventually still should vivify all clauses.
  //
  bool reschedule_all;
  if (opts.vivifyreschedule) {
    reschedule_all = !lim.vivify_wait_reschedule;
    if (reschedule_all) {
      VRB ("vivify", stats.vivifications,
	"forced to reschedule all clauses");
      lim.vivify_wait_reschedule = ++inc.vivify_wait_reschedule;
    } else lim.vivify_wait_reschedule--;
  } else reschedule_all = false;

  // Refill the schedule every time.  Unchecked clauses are 'saved' by
  // setting their 'vivify' bit, such that they can be tried next time.
  //
  vector<Clause*> schedule;

  // In the first round check whether there are still clauses left, which
  // are scheduled but have not been vivified yet.  In the second round,
  // if no such clauses are found in the first round, all clauses are
  // selected.  This second round is also performed if rescheduling is
  // forced because 'reschedule_all' is  true.
  //
  for (int round = 0; schedule.empty () && round <= 1; round++) {
    for (i = clauses.begin (); i != end; i++) {
      Clause * c = *i;
      if (c->garbage) continue;
      if (c->redundant) continue;
      if (c->size == 2) continue;       // see also [NO-BINARY] below
      if (!reschedule_all && !round && !c->vivify) continue;
      sort (c->begin (), c->end (), vivify_more_noccs (this));
      schedule.push_back (c);
      c->vivify = true;
    }
  }
  shrink_vector (schedule);

  // Now sort candidates, with first candidate clause (many occurrences) last.
  //
  stable_sort (schedule.begin (), schedule.end (), vivify_less_clause (this));

#ifndef QUIET
  long scheduled = schedule.size ();
  VRB ("vivify", stats.vivifications,
    "scheduled %ld clauses to be vivified %.0f%%",
    scheduled, percent (scheduled, stats.irredundant));
#endif

  // Counters, for what happened.
  //
  long checked = 0, subsumed = 0, strengthened = 0, units = 0;

  // Limit the number of propagations during vivification as in 'probe'.
  //
  long delta = stats.propagations.search;
  delta -= lim.search_propagations.vivify;
  delta *= opts.vivifyreleff;
  if (delta < opts.vivifymineff) delta = opts.vivifymineff;
  if (delta > opts.vivifymaxeff) delta = opts.vivifymaxeff;
  long limit = stats.propagations.vivify + delta;

  connect_watches (true);		// watch only irredundant clauses

  while (!unsat &&
         !schedule.empty () &&
         stats.propagations.vivify < limit) {

    // Next candidate clause to vivify.
    //
    Clause * c = schedule.back ();
    schedule.pop_back ();
    assert (!c->redundant);
    assert (c->size > 2);               // see [NO-BINARY] above
    assert (c->vivify);
    c->vivify = false;
    if (c->garbage) continue;

    // First check whether the candidate clause is already satisfied.
    //
    const const_literal_iterator eoc = c->end ();
    const_literal_iterator j;
    int satisfied = 0;

    for (j = c->begin (); !satisfied && j != eoc; j++)
      if (fixed (*j) > 0) satisfied = *j;

    if (satisfied) {
      LOG (c, "satisfied by propagated unit %d", satisfied);
      mark_garbage (c);
      continue;
    }

    // The actual vivification checking is performed here, by assuming the
    // negation of each of the remaining literals of the clause in turn and
    // propagating it.  If a conflict occurs or another literal in the
    // clause becomes assigned during propagation, we can stop.
    //
    LOG (c, "vivification checking");
    checked++;

    // First check whether this clause is actually a reason for forcing one
    // of its literals to true and then backtrack appropriately.
    //
    if (level) {
      int forced = 0;
      for (j = c->begin (); !forced && j != eoc; j++) {
	const int lit = *j, tmp = val (lit);
	if (tmp < 0) continue;
	if (tmp > 0 && var (lit).reason == c) forced = lit;
	break;
      }
      if (forced) {
	LOG ("clause is reason forcing %d", forced);
	assert (var (forced).level);
	backtrack (var (forced).level - 1);
      }
    }

    // We are trying to reuse decisions, the trail and the propagations of
    // the previous vivification candidate.  As long the literals of the
    // clause match decisions on the trail we just reuse them.
    //
    int l = 1;
    for (j = c->begin (); j != eoc && l <= level; j++) {
      const int lit = *j;
      if (fixed (lit)) continue;
      const int decision = control[l].decision;
      if (-lit == decision) {
	LOG ("reusing decision %d at decision level %d", decision, l);
	stats.vivifyreused++;
	l++;
      } else {
	LOG ("literal %d does not match decision %d at decision level %d",
	  lit, decision, l);
	backtrack (l-1);
	break;
      }
    }

    if (level) LOG ("reused %d decision levels", level);
    else LOG ("no decision level reused");

    // Make sure to ignore this clause during propagation.  This is not that
    // easy for binary clauses [NO-BINARY], e.g., ignoring binary clauses,
    // without changing 'propagate' and actually we also do not want to
    // remove binary clauses which are subsumed.  Those are hyper binary
    // resolvents and should be kept as learned clauses instead unless they
    // are transitive in the binary implication graph, which in turn is
    // detected during transitive reduction in 'transred'.
    //
    c->ignore = true;           // see also [NO-BINARY] above

    bool redundant = false;     // determined to be redundant / subsumed
    int remove = 0;             // at least literal 'remove' can be removed

    for (j = c->begin (); !redundant && !remove && j != eoc; j++) {
      const int lit = *j, tmp = val (lit);
      if (tmp) {
	const Var & v = var (lit);
	if (!v.level) { LOG ("skipping fixed %d", lit); continue; }
	if (!v.reason) { LOG ("skipping decision %d", lit); continue; }
	if (tmp > 0) {
	  LOG ("redundant since literal %d already true", lit);
	  redundant = true;
	} else {
	  assert (tmp < 0);
	  LOG ("removing at least literal %d which is already false", lit);
	  remove = lit;
	}
      } else {
	stats.vivifydecs++;
        assume_decision (-lit);
        if (propagate ()) continue;
        LOG ("redundant since propagation produced conflict");
        redundant = true;
	assert (level > 0);
	backtrack (level - 1);
        conflict = 0;
      }
    }

    if (redundant) {
REDUNDANT:
      subsumed++;
      LOG (c, "redundant asymmetric tautology");
      mark_garbage (c);
    } else if (remove) {
      assert (level);
      assert (clause.empty ());
#ifndef NDEBUG
      bool found = false;
#endif
      // There might be other literals implied to false (or even root level
      // falsified).  Those should be removed in addition to 'remove'.  It
      // might further be possible that a latter to be assumed literal is
      // already forced to true in which case the clause is actually
      // redundant (we solved this by bad style 'goto' programming).
      //
      for (j = c->begin (); j != eoc; j++) {
        const int other = *j, tmp = val (other);
        Var & v = var (other);
        if (tmp > 0) {
	  assert (v.level), assert (v.reason);
          LOG ("redundant since literal %d already true", other);
          clause.clear ();
          goto REDUNDANT;
        }
        if (tmp < 0 && !v.level) continue;
        if (tmp < 0 && v.level && v.reason) {
          assert (v.level);
          assert (v.reason);
          LOG ("flushing literal %d", other);
          mark_removed (other);
#ifndef NDEBUG
          if (other == remove) found = true;
#endif
        } else clause.push_back (other);
      }
      assert (found);

      strengthened++; // only now because of 'goto REDUNDANT' above

      backtrack ();

      assert (!clause.empty ());

      if (clause.size () == 1) {
        const int unit = clause[0];
        LOG (c, "vivification shrunken to unit %d", unit);
        assert (!val (unit));
        assign_unit (unit);
        units++;
        bool ok = propagate ();
        if (!ok) learn_empty_clause ();
      } else {
#ifdef LOGGING
        Clause * d =
#endif
        new_clause_as (c);
        LOG (c, "before vivification");
        LOG (d, "after vivification");
      }
      clause.clear ();

      mark_garbage (c);
    } else LOG (c, "vivification failed on");
    assert (c->ignore);
    c->ignore = false;
  }

  if (level) backtrack ();

  if (!unsat) {

    reset_noccs ();
    erase_vector (schedule);
    disconnect_watches ();
    connect_watches ();

    // [RE-PROPAGATE] Since redundant clause were disconnected during
    // propagating vivified units above, and further irredundant clauses
    // are arbitrarily sorted, we have to propagate all literals again.
    //
    propagated = 0;
    if (!propagate ()) {
      LOG ("propagating vivified units leads to conflict");
      learn_empty_clause ();
    }
  }

  VRB ("vivify", stats.vivifications,
    "checked %ld clauses %.02f%% out of scheduled",
    checked, percent (checked, scheduled));
  if (units)
  VRB ("vivify", stats.vivifications,
    "found %ld units %.02f%% out of checked",
    units, percent (units, checked));
  VRB ("vivify", stats.vivifications,
    "subsumed %ld clauses %.02f%% out of checked",
    subsumed, percent (subsumed, checked));
  VRB ("vivify", stats.vivifications,
    "strengthened %ld clauses %.02f%% out of checked",
    strengthened, percent (strengthened, checked));

  stats.vivifychecks += checked;
  stats.vivifysubs += subsumed;
  stats.vivifystrs += strengthened;
  stats.vivifyunits += units;

  stats.subsumed += subsumed;
  stats.strengthened += strengthened;

  lim.search_propagations.vivify = stats.propagations.search;

  assert (vivifying);
  vivifying = false;

  report ('v');
  STOP_AND_SWITCH (vivify, simplify, search);

  opts.log = false;
}

};
<commit_msg>fixed<commit_after>#include "internal.hpp"
#include "macros.hpp"
#include "message.hpp"

namespace CaDiCaL {

/*------------------------------------------------------------------------*/

// Vivification is a special case of asymmetric tautology elimination and
// asymmetric literal elimination.  It strengthens and removes irredundant
// clauses proven redundant through unit propagation.  The original
// algorithm is due to a paper by Piette, Hamadi and Sais published at
// ECAI'08.  We have an inprocessing version, e.g., it does not necessarily
// run-to-completion.  Our version does not perform any conflict analysis
// and uses a new heuristic for selecting clauses to vivify. The idea is to
// focus on long clauses with many occurrences of its literals in other
// clauses first.  This both complements nicely our implementation of
// subsume, which is bounded, e.g., subsumption attempts are skipped for
// very long clauses with literals with many occurrences and also is
// stronger in the sence that it enables to remove more clauses.

/*------------------------------------------------------------------------*/

// Check whether literal occurs less often.

struct vivify_more_noccs {

  Internal * internal;

  vivify_more_noccs (Internal * i) : internal (i) { }

  bool operator () (int a, int b) {
    long n = internal->noccs (a);
    long m = internal->noccs (b);
    if (n > m) return true;
    if (n < m) return false;
    if (a == -b) return a > 0;
    return abs (a) < abs (b);
  }
};

// Sort candidate clauses by the number of occurrences of their literals,
// with clauses to be vivified first last.   We assume that clauses are
// sorted w.r.t. more occurring literals first (with 'vivify_more_noccs').

struct vivify_less_clause {

  Internal * internal;

  vivify_less_clause (Internal * i) : internal (i) { }

  bool operator () (Clause * a, Clause * b) const {
    assert (!a->redundant), assert (!b->redundant);
    const const_literal_iterator eoa = a->end (), eob = b->end ();
    const_literal_iterator i = a->begin (), j = b->begin ();
    for (i = a->begin (), j = b->begin (); i != eoa && j != eob; i++, j++)
      if (*i != *j) return vivify_more_noccs (internal) (*j, *i);
    if (i == eoa) {
      if (!b->garbage) {
	LOG (b, "vivification sorting finds subsumed");
	internal->mark_garbage (b);
      }
      return true;
    } else {
      assert (j == eob);
      if (!a->garbage) {
	LOG (a, "vivification sorting finds subsumed");
	internal->mark_garbage (a);
      }
      return false;
    }
  }
};

/*------------------------------------------------------------------------*/

void Internal::vivify () {

  if (unsat) return;

#ifdef LOGGING
  {
    int remove;
    opts.log = true;
  }
#endif

  assert (opts.vivify);
  SWITCH_AND_START (search, simplify, vivify);

  assert (!vivifying);
  vivifying = true;

  stats.vivifications++;
  if (level) backtrack ();

  // Disconnect all watches since we sort literals in irredundant clauses.
  //
  disconnect_watches ();

  // Count the number of occurrences of literals in all irredundant clauses,
  // particularly the irredundant binary clauses, usually responsible for
  // most of the propagations.
  //
  init_noccs ();

  const const_clause_iterator end = clauses.end ();
  const_clause_iterator i;

  for (i = clauses.begin (); i != end; i++) {
    Clause * c = *i;
    if (c->garbage || c->redundant) continue;
    const const_literal_iterator eoc = c->end ();
    const_literal_iterator j;
    for (j = c->begin (); j != eoc; j++)
      noccs (*j)++;
  }

  // After an arithmetic increasing number of calls to 'vivify' reschedule
  // all clauses, instead of only those not tried before.  Then this limit
  // is increased by one. The argument is that we should focus on clauses
  // with many occurrences of their literals (also long clauses), but in the
  // limit eventually still should vivify all clauses.
  //
  bool reschedule_all;
  if (opts.vivifyreschedule) {
    reschedule_all = !lim.vivify_wait_reschedule;
    if (reschedule_all) {
      VRB ("vivify", stats.vivifications,
	"forced to reschedule all clauses");
      lim.vivify_wait_reschedule = ++inc.vivify_wait_reschedule;
    } else lim.vivify_wait_reschedule--;
  } else reschedule_all = false;

  // Refill the schedule every time.  Unchecked clauses are 'saved' by
  // setting their 'vivify' bit, such that they can be tried next time.
  //
  vector<Clause*> schedule;

  // In the first round check whether there are still clauses left, which
  // are scheduled but have not been vivified yet.  In the second round,
  // if no such clauses are found in the first round, all clauses are
  // selected.  This second round is also performed if rescheduling is
  // forced because 'reschedule_all' is  true.
  //
  for (int round = 0; schedule.empty () && round <= 1; round++) {
    for (i = clauses.begin (); i != end; i++) {
      Clause * c = *i;
      if (c->garbage) continue;
      if (c->redundant) continue;
      if (c->size == 2) continue;       // see also [NO-BINARY] below
      if (!reschedule_all && !round && !c->vivify) continue;
      sort (c->begin (), c->end (), vivify_more_noccs (this));
      schedule.push_back (c);
      c->vivify = true;
    }
  }
  shrink_vector (schedule);

  // Now sort candidates, with first candidate clause (many occurrences) last.
  //
  stable_sort (schedule.begin (), schedule.end (), vivify_less_clause (this));

#ifndef QUIET
  long scheduled = schedule.size ();
  VRB ("vivify", stats.vivifications,
    "scheduled %ld clauses to be vivified %.0f%%",
    scheduled, percent (scheduled, stats.irredundant));
#endif

  // Counters, for what happened.
  //
  long checked = 0, subsumed = 0, strengthened = 0, units = 0;

  // Limit the number of propagations during vivification as in 'probe'.
  //
  long delta = stats.propagations.search;
  delta -= lim.search_propagations.vivify;
  delta *= opts.vivifyreleff;
  if (delta < opts.vivifymineff) delta = opts.vivifymineff;
  if (delta > opts.vivifymaxeff) delta = opts.vivifymaxeff;
  long limit = stats.propagations.vivify + delta;

  connect_watches (true);		// watch only irredundant clauses
  vector<int> sorted;			// sort literals of each candidate

  while (!unsat &&
         !schedule.empty () &&
         stats.propagations.vivify < limit) {

    // Next candidate clause to vivify.
    //
    Clause * c = schedule.back ();
    schedule.pop_back ();
    assert (!c->redundant);
    assert (c->size > 2);               // see [NO-BINARY] above
    assert (c->vivify);
    c->vivify = false;
    if (c->garbage) continue;

    // First check whether the candidate clause is already satisfied and at
    // the same time copy its non fixed literals to 'sorted'.  The literals
    // in the candidate clause might not be sorted anymore due to replacing
    // watches during propagation, even though we sorted them initially
    // while pushing this onto the schedule.
    //
    const const_literal_iterator eoc = c->end ();
    const_literal_iterator j;
    int satisfied = 0;
    sorted.clear ();
    for (j = c->begin (); !satisfied && j != eoc; j++) {
      const int lit = *j, tmp = fixed (lit);
      if (tmp > 0) satisfied = *j;
      else if (!tmp) sorted.push_back (lit);
    }
    if (satisfied) {
      LOG (c, "satisfied by propagated unit %d", satisfied);
      mark_garbage (c);
      continue;
    }
    sort (sorted.begin (), sorted.end (), vivify_more_noccs (this));

    // The actual vivification checking is performed here, by assuming the
    // negation of each of the remaining literals of the clause in turn and
    // propagating it.  If a conflict occurs or another literal in the
    // clause becomes assigned during propagation, we can stop.
    //
    LOG (c, "vivification checking");
    checked++;

    // First check whether this clause is actually a reason for forcing one
    // of its literals to true and then backtrack one level before that
    // happened.  Otherwise this clause might be considered to be redundant
    // and if not, redundancy by other clauses becomes impossible.
    //
    if (level) {
      int forced = 0;
      for (j = c->begin (); !forced && j != eoc; j++) {
	const int lit = *j, tmp = val (lit);
	if (tmp < 0) continue;
	if (tmp > 0 && var (lit).reason == c) forced = lit;
	break;
      }
      if (forced) {
	LOG ("clause is reason forcing %d", forced);
	assert (var (forced).level);
	backtrack (var (forced).level - 1);
      }
    }

    // We are trying to reuse decisions, the trail and the propagations of
    // the previous vivification candidate.  As long the literals of the
    // clause match decisions on the trail we just reuse them.
    //
    int l = 1;

    // TODO replace by iterating over 'sorted' again ...

    const const_int_iterator eos = sorted.end ();
    const_int_iterator k;

    for (k = sorted.begin (); k != eos && l <= level; k++) {
      const int lit = *k;
      if (fixed (lit)) continue;
      const int decision = control[l].decision;
      if (-lit == decision) {
	LOG ("reusing decision %d at decision level %d", decision, l);
	stats.vivifyreused++;
	l++;
      } else {
	LOG ("literal %d does not match decision %d at decision level %d",
	  lit, decision, l);
	backtrack (l-1);
	break;
      }
    }

    if (level) LOG ("reused %d decision levels", level);
    else LOG ("no decision level reused");

    // Make sure to ignore this clause during propagation.  This is not that
    // easy for binary clauses [NO-BINARY], e.g., ignoring binary clauses,
    // without changing 'propagate' and actually we also do not want to
    // remove binary clauses which are subsumed.  Those are hyper binary
    // resolvents and should be kept as learned clauses instead unless they
    // are transitive in the binary implication graph, which in turn is
    // detected during transitive reduction in 'transred'.
    //
    c->ignore = true;           // see also [NO-BINARY] above

    bool redundant = false;     // determined to be redundant / subsumed
    int remove = 0;             // at least literal 'remove' can be removed

    LOG (sorted, "sorted size %ld probing schedule", (long) sorted.size ());

    for (k = sorted.begin (); !redundant && !remove && k != eos; k++) {

      const int lit = *k, tmp = val (lit);
      if (tmp) {
	const Var & v = var (lit);
	if (!v.level) { LOG ("skipping fixed %d", lit); continue; }
	if (!v.reason) { LOG ("skipping decision %d", lit); continue; }
	if (tmp > 0) {
	  LOG ("redundant since literal %d already true", lit);
	  redundant = true;
	} else {
	  assert (tmp < 0);
	  LOG ("removing at least literal %d which is already false", lit);
	  remove = lit;
	}
      } else {
	stats.vivifydecs++;
        assume_decision (-lit);
        if (propagate ()) continue;
        LOG ("redundant since propagation produced conflict");
        redundant = true;
	assert (level > 0);
	backtrack (level - 1);
        conflict = 0;
      }
    }

    if (redundant) {
REDUNDANT:
      subsumed++;
      LOG (c, "redundant asymmetric tautology");
      mark_garbage (c);
    } else if (remove) {
      assert (level);
      assert (clause.empty ());
#ifndef NDEBUG
      bool found = false;
#endif
      // There might be other literals implied to false (or even root level
      // falsified).  Those should be removed in addition to 'remove'.  It
      // might further be possible that a latter to be assumed literal is
      // already forced to true in which case the clause is actually
      // redundant (we solved this by bad style 'goto' programming).
      //
      for (j = c->begin (); j != eoc; j++) {
        const int other = *j, tmp = val (other);
        Var & v = var (other);
        if (tmp > 0) {
	  assert (v.level), assert (v.reason);
          LOG ("redundant since literal %d already true", other);
          clause.clear ();
          goto REDUNDANT;
        }
        if (tmp < 0 && !v.level) continue;
        if (tmp < 0 && v.level && v.reason) {
          assert (v.level);
          assert (v.reason);
          LOG ("flushing literal %d", other);
          mark_removed (other);
#ifndef NDEBUG
          if (other == remove) found = true;
#endif
        } else clause.push_back (other);
      }
      assert (found);

      strengthened++; // only now because of 'goto REDUNDANT' above

      backtrack ();

      assert (!clause.empty ());

      if (clause.size () == 1) {
        const int unit = clause[0];
        LOG (c, "vivification shrunken to unit %d", unit);
        assert (!val (unit));
        assign_unit (unit);
        units++;
        bool ok = propagate ();
        if (!ok) learn_empty_clause ();
      } else {
        Clause * d = new_clause_as (c);
        LOG (c, "before vivification");
        LOG (d, "after vivification");
      }
      clause.clear ();

      mark_garbage (c);
    } else LOG (c, "vivification failed on");
    assert (c->ignore);
    c->ignore = false;
  }

  if (level) backtrack ();

  if (!unsat) {

    reset_noccs ();
    erase_vector (schedule);
    disconnect_watches ();
    connect_watches ();

    // [RE-PROPAGATE] Since redundant clause were disconnected during
    // propagating vivified units above, and further irredundant clauses
    // are arbitrarily sorted, we have to propagate all literals again.
    //
    propagated = 0;
    if (!propagate ()) {
      LOG ("propagating vivified units leads to conflict");
      learn_empty_clause ();
    }
  }

  VRB ("vivify", stats.vivifications,
    "checked %ld clauses %.02f%% out of scheduled",
    checked, percent (checked, scheduled));
  if (units)
  VRB ("vivify", stats.vivifications,
    "found %ld units %.02f%% out of checked",
    units, percent (units, checked));
  VRB ("vivify", stats.vivifications,
    "subsumed %ld clauses %.02f%% out of checked",
    subsumed, percent (subsumed, checked));
  VRB ("vivify", stats.vivifications,
    "strengthened %ld clauses %.02f%% out of checked",
    strengthened, percent (strengthened, checked));

  stats.vivifychecks += checked;
  stats.vivifysubs += subsumed;
  stats.vivifystrs += strengthened;
  stats.vivifyunits += units;

  stats.subsumed += subsumed;
  stats.strengthened += strengthened;

  lim.search_propagations.vivify = stats.propagations.search;

  assert (vivifying);
  vivifying = false;

  report ('v');
  STOP_AND_SWITCH (vivify, simplify, search);

#ifdef LOGGING
  {
    int remove;
    opts.log = false;
  }
#endif

}

};
<|endoftext|>