<commit_before>/// This file contains the implementation of VNS
#include "header/vns-priv.hpp"

using namespace std;

namespace pcp {
	Solution bestSolution;
	Solution origSolution;

	bool checkValid(Solution* s);

	/// Implementation of VNS, see vns.hpp
	Solution vnsRun(Solution& best, Solution& orig, char* units, int unsuccessfulShake,
						 int shakeStart, int shakeIncrement, int maxTime) {

		/// Backup the starting solutions
		bestSolution = new Solution(best);
		origSolution = new Solution(orig);

		if (DEBUG_LEVEL > 1) {
			cout<<"Best solution uses "<<bestSolution.colorsUsed<<" colors"<<endl;
			cout<<"Full solution uses "<<origSolution.colorsUsed<<" colors"<<endl;
		}
		if (DEBUG_LEVEL > 1) {
			cout<<"The supplied solution is valid: "<<(checkValid(&best) ? "true": "false")<<endl;
		}

		vector<VNS_Unit*> neighbors = vector<VNS_Unit*>();

		do {
			if (*units == changeNode::abbreviation())
				neighbors.push_back(new changeNode());
			else if (*units == changeColor::abbreviation())
				neighbors.push_back(new changeColor());
			else if (*units == tabuSearch::abbreviation())
				neighbors.push_back(new tabuSearch());
			else if (*units == dsatur::abbreviation())
				neighbors.push_back(new dsatur());
			else {
				cerr << "Invalid unit specified. " << *units << endl;
				return NULL;
			}
		} while (*(++units) != '\0') ;
		units = NULL;

		/// Initialize stat-tracking arrays
		int impStats[neighbors.size()];
		int clockStats[neighbors.size()];
		int runStats[neighbors.size()];

		for (int i = 0; i < neighbors.size(); i++) {
			impStats[i] = 0;
			clockStats[i] = 0;
			runStats[i] = 0;
		}

		time_t startTime = time(NULL);
		int no_imp_runs = 0;
		unsigned int curNeighbor = 0;
		int shakeSteps = shakeStart - shakeIncrement;
		Solution *toImprove = new Solution(&best);
		Solution *curBest = &best;

		/// Run as long as shaking still produces usefull solution
		while (true) {

			/// No time left, abort main loop
			if (startTime + maxTime < time(NULL)) {
				if (DEBUG_LEVEL > 0) {
					cout<<"Time's up"<<endl;
				}
				break;
			}

			/// Run all possible neighborhood
			while (curNeighbor < neighbors.size()) {

				/// Select the new neighborhood
				clock_t start = clock();
				VNS_Unit *neigh = neighbors[curNeighbor];

				if (DEBUG_LEVEL > 1) {
					cout<<"Running: "<< neigh->name() <<endl;
				}

				/// Compute the minimum for this neighborhood
				Solution *improved = neigh->findLocalMin(*toImprove, orig);

				/// Stats tracking
				impStats[curNeighbor] += (toImprove->colorsUsed - improved->colorsUsed);
				clockStats[curNeighbor] += (clock() - start);
				runStats[curNeighbor]++;

				if (DEBUG_LEVEL > 1) {
					cout<<neigh->name()<<" took about ";
					cout<<(clock() - start)/(float)CLOCKS_PER_SEC;
					cout<<" seconds to complete"<<endl;
					cout<<"Valid solution: "<<((checkValid(improved)) ? "true" : "false");
					cout<<endl;
				}
				/// Replace the existing solution with the new solution if it is an
				/// improvement
				if (improved->colorsUsed < toImprove->colorsUsed) {
					delete toImprove;
					toImprove = improved;

					if (DEBUG_LEVEL > 1) {
						cout<<"Improvement found with "<<neigh->name()<<endl;
						cout<<"Current solution uses "<<toImprove->colorsUsed<<" colors"<<endl;
					}

					/// Restart neighborhoods
					curNeighbor = curNeighbor == 0 ? 1 : 0;
				}

				/// Step to next neighborhood, no improvement found
				else {
					if (DEBUG_LEVEL > 1) {
						cout<<"No improvement found"<<endl;
						cout<<"Test next neighborhood"<<endl;
					}
					delete improved;
					curNeighbor++;
				}
				if (DEBUG_LEVEL > 1) {
					cout<<endl;
					cout<<"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
					cout<<endl<<endl;
				}
			} // end while neighborhood

			if (DEBUG_LEVEL > 1) {
				cout<<endl;
				cout<<"###################### End inner VNS loop ##################"<<endl;
				cout<<endl;
			}

			/// Local minimum of neighborhoods is better than current best
			/// solution
			if (toImprove->colorsUsed < best.colorsUsed) {
				if (DEBUG_LEVEL > 1) {
					cout<<"Improvement to global best solution found"<<endl;
				}

				best = toImprove;
				toImprove = new Solution(curBest);
				no_imp_runs = 0;
				shakeSteps = shakeStart - shakeIncrement;
			}
			/// Reset local best solution to global best Solution
			else {
				toImprove = curBest;
				no_imp_runs++;

				/// Stopping condition, quit VNS
				if (no_imp_runs > unsuccessfulShake) {
					if (DEBUG_LEVEL > 0) {
						cout<<"Too many unsuccessful shakes"<<endl;
					}
					break;
				}
			}

			int shakeNeighbor = rand() % neighbors.size();
			curNeighbor = 0;
			VNS_Unit *shaker = neighbors[shakeNeighbor];
			toImprove = shaker->shuffleSolution(*toImprove, orig, (shakeSteps += shakeIncrement));

			if (DEBUG_LEVEL > 1) {
				cout<<"Shaking Solution using "<<shaker->name()<<" with ";
				cout<<shakeSteps<<" steps"<<endl;
				cout<<"Shake was valid: "<<((checkValid(toImprove)) ? "true" : "false")<<endl;
				cout<<"Solution now uses "<<toImprove->colorsUsed<<" colors"<<endl;
			}
		}
		if (DEBUG_LEVEL > 0) {
			cout<<endl;
			cout<<"Final best solution uses "<<curBest->colorsUsed<<" colors";
			cout<<endl;
			cout<<"The solution appears to be ";
			cout<<((checkValid(curBest)) ? "valid" : "invalid")<<endl;
		}
		/// Print stats
		if (DEBUG_LEVEL > 1) {
			cout<<endl;
			cout<<"#################### STAT TRACKING ####################"<<endl;
			cout<<"#                                                     "<<endl;

			for (unsigned int i = 0; i < neighbors.size(); i++) {
				VNS_Unit *cur = neighbors[i];
				cout<<"# "<<cur->abbreviation()<<": Name: "<<cur->name()<<endl;
				cout<<"# Runs: "<<runStats[i]<<" runtime: ";
				cout<<((float)clockStats[i]/CLOCKS_PER_SEC)<<" improvements: ";
				cout<<impStats[i]<<endl;
				cout<<"#                                                     "<<endl;
			}
			cout<<"# Global improvement of ";
			cout<<(bestSolution.colorsUsed - curBest->colorsUsed);
			cout<<" colors, down to "<<curBest->colorsUsed<<" colors "<<endl;
			cout<<"#                                                     "<<endl;
			cout<<"##################### END TRACKING ####################"<<endl;
		}

		return new Solution(curBest);
	}

	/// validate solutions
	bool checkValid(Solution* s) {
		pair<VertexIter, VertexIter> vIter;
		int parts[s->numParts];
		int colors[s->numParts];
		typedef boost::graph_traits<Graph>::adjacency_iterator AdjIter;
		VertexPart_Map vParts = get(boost::vertex_index1_t(), *s->g);
		bool valid = true;

		/// Initialize parts and colors
		for (int i = 0; i < s->numParts; i++) {
			parts[i] = 0;
			colors[i] = 0;
		}

		/// Check all vertices
		for (vIter = vertices(*s->g); vIter.first != vIter.second; vIter.first++) {
			/// Mark partition and color as used
			parts[vParts[*vIter.first]] = 1;
			colors[s->partition[vParts[*vIter.first]]] = 1;

			/// Check color conflicts
			pair<AdjIter, AdjIter> aIter;
			for (aIter = adjacent_vertices(*vIter.first, *s->g);
				  aIter.first != aIter.second; aIter.first++) {

				if (s->partition[vParts[*aIter.first]] ==
					 s->partition[vParts[*vIter.first]]) {

					valid = false;
					cerr<<"Solution is invalid"<<endl;
					cerr<<"Adjacent vertices "<<*aIter.first<<" and "<<*vIter.first;
					cerr<<" have same color "<<s->partition[vParts[*vIter.first]];
					cerr<<endl;
				}
			}
		}

		/// Check colorsUsed
		int count = 0;
		for (int i = 0; i < s->numParts; i++) {
			if (colors[i] == 1) {
				count++;
			}
		}
		if (count != s->colorsUsed) {
			valid = false;
			cerr<<"Solution is invalid"<<endl;
			cerr<<"Wrong colorsUsed stored: stored: "<<s->colorsUsed;
			cerr<<", computed: "<<count<<endl;
		}

		/// Check partitions and representatives
		for (int i = 0; i < s->numParts; i++) {
			if (parts[i] == 0) {
				valid = false;
				cerr<<"Solution is invalid"<<endl;
				cerr<<"partition "<<i<<" seems to be missing"<<endl;
			}
			if (s->representatives[vParts[i]] != i) {
				valid = false;
				cerr<<"Solution is invalid"<<endl;
				cerr<<"Node "<<i<<" is not representative of partition "<<vParts[i];
				cerr<<endl;
			}
		}

		return valid;
	}
}

<commit_msg>Only tracking improved solutions in impStats<commit_after>/// This file contains the implementation of VNS
#include "header/vns-priv.hpp"

using namespace std;

namespace pcp {
	Solution bestSolution;
	Solution origSolution;

	bool checkValid(Solution* s);

	/// Implementation of VNS, see vns.hpp
	Solution vnsRun(Solution& best, Solution& orig, char* units, int unsuccessfulShake,
						 int shakeStart, int shakeIncrement, int maxTime) {

		/// Backup the starting solutions
		bestSolution = new Solution(best);
		origSolution = new Solution(orig);

		if (DEBUG_LEVEL > 1) {
			cout<<"Best solution uses "<<bestSolution.colorsUsed<<" colors"<<endl;
			cout<<"Full solution uses "<<origSolution.colorsUsed<<" colors"<<endl;
		}
		if (DEBUG_LEVEL > 1) {
			cout<<"The supplied solution is valid: "<<(checkValid(&best) ? "true": "false")<<endl;
		}

		vector<VNS_Unit*> neighbors = vector<VNS_Unit*>();

		do {
			if (*units == changeNode::abbreviation())
				neighbors.push_back(new changeNode());
			else if (*units == changeColor::abbreviation())
				neighbors.push_back(new changeColor());
			else if (*units == tabuSearch::abbreviation())
				neighbors.push_back(new tabuSearch());
			else if (*units == dsatur::abbreviation())
				neighbors.push_back(new dsatur());
			else {
				cerr << "Invalid unit specified. " << *units << endl;
				return NULL;
			}
		} while (*(++units) != '\0') ;
		units = NULL;

		/// Initialize stat-tracking arrays
		int impStats[neighbors.size()];
		int clockStats[neighbors.size()];
		int runStats[neighbors.size()];

		for (int i = 0; i < neighbors.size(); i++) {
			impStats[i] = 0;
			clockStats[i] = 0;
			runStats[i] = 0;
		}

		time_t startTime = time(NULL);
		int no_imp_runs = 0;
		unsigned int curNeighbor = 0;
		int shakeSteps = shakeStart - shakeIncrement;
		Solution *toImprove = new Solution(&best);
		Solution *curBest = &best;

		/// Run as long as shaking still produces usefull solution
		while (true) {

			/// No time left, abort main loop
			if (startTime + maxTime < time(NULL)) {
				if (DEBUG_LEVEL > 0) {
					cout<<"Time's up"<<endl;
				}
				break;
			}

			/// Run all possible neighborhood
			while (curNeighbor < neighbors.size()) {

				/// Select the new neighborhood
				clock_t start = clock();
				VNS_Unit *neigh = neighbors[curNeighbor];

				if (DEBUG_LEVEL > 1) {
					cout<<"Running: "<< neigh->name() <<endl;
				}

				/// Compute the minimum for this neighborhood
				Solution *improved = neigh->findLocalMin(*toImprove, orig);

				/// Stats tracking
				clockStats[curNeighbor] += (clock() - start);
				runStats[curNeighbor]++;

				if (DEBUG_LEVEL > 1) {
					cout<<neigh->name()<<" took about ";
					cout<<(clock() - start)/(float)CLOCKS_PER_SEC;
					cout<<" seconds to complete"<<endl;
					cout<<"Valid solution: "<<((checkValid(improved)) ? "true" : "false");
					cout<<endl;
				}
				/// Replace the existing solution with the new solution if it is an
				/// improvement
				if (improved->colorsUsed < toImprove->colorsUsed) {
					/// Stats tracking
					impStats[curNeighbor] += (toImprove->colorsUsed - improved->colorsUsed);

					delete toImprove;
					toImprove = improved;

					if (DEBUG_LEVEL > 1) {
						cout<<"Improvement found with "<<neigh->name()<<endl;
						cout<<"Current solution uses "<<toImprove->colorsUsed<<" colors"<<endl;
					}

					/// Restart neighborhoods
					curNeighbor = curNeighbor == 0 ? 1 : 0;
				}

				/// Step to next neighborhood, no improvement found
				else {
					if (DEBUG_LEVEL > 1) {
						cout<<"No improvement found"<<endl;
						cout<<"Test next neighborhood"<<endl;
					}
					delete improved;
					curNeighbor++;
				}
				if (DEBUG_LEVEL > 1) {
					cout<<endl;
					cout<<"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
					cout<<endl<<endl;
				}
			} // end while neighborhood

			if (DEBUG_LEVEL > 1) {
				cout<<endl;
				cout<<"###################### End inner VNS loop ##################"<<endl;
				cout<<endl;
			}

			/// Local minimum of neighborhoods is better than current best
			/// solution
			if (toImprove->colorsUsed < best.colorsUsed) {
				if (DEBUG_LEVEL > 1) {
					cout<<"Improvement to global best solution found"<<endl;
				}

				best = toImprove;
				toImprove = new Solution(curBest);
				no_imp_runs = 0;
				shakeSteps = shakeStart - shakeIncrement;
			}
			/// Reset local best solution to global best Solution
			else {
				toImprove = curBest;
				no_imp_runs++;

				/// Stopping condition, quit VNS
				if (no_imp_runs > unsuccessfulShake) {
					if (DEBUG_LEVEL > 0) {
						cout<<"Too many unsuccessful shakes"<<endl;
					}
					break;
				}
			}

			int shakeNeighbor = rand() % neighbors.size();
			curNeighbor = 0;
			VNS_Unit *shaker = neighbors[shakeNeighbor];
			toImprove = shaker->shuffleSolution(*toImprove, orig, (shakeSteps += shakeIncrement));

			if (DEBUG_LEVEL > 1) {
				cout<<"Shaking Solution using "<<shaker->name()<<" with ";
				cout<<shakeSteps<<" steps"<<endl;
				cout<<"Shake was valid: "<<((checkValid(toImprove)) ? "true" : "false")<<endl;
				cout<<"Solution now uses "<<toImprove->colorsUsed<<" colors"<<endl;
			}
		}
		if (DEBUG_LEVEL > 0) {
			cout<<endl;
			cout<<"Final best solution uses "<<curBest->colorsUsed<<" colors";
			cout<<endl;
			cout<<"The solution appears to be ";
			cout<<((checkValid(curBest)) ? "valid" : "invalid")<<endl;
		}
		/// Print stats
		if (DEBUG_LEVEL > 1) {
			cout<<endl;
			cout<<"#################### STAT TRACKING ####################"<<endl;
			cout<<"#                                                     "<<endl;

			for (unsigned int i = 0; i < neighbors.size(); i++) {
				VNS_Unit *cur = neighbors[i];
				cout<<"# "<<cur->abbreviation()<<": Name: "<<cur->name()<<endl;
				cout<<"# Runs: "<<runStats[i]<<" runtime: ";
				cout<<((float)clockStats[i]/CLOCKS_PER_SEC)<<" improvements: ";
				cout<<impStats[i]<<endl;
				cout<<"#                                                     "<<endl;
			}
			cout<<"# Global improvement of ";
			cout<<(bestSolution.colorsUsed - curBest->colorsUsed);
			cout<<" colors, down to "<<curBest->colorsUsed<<" colors "<<endl;
			cout<<"#                                                     "<<endl;
			cout<<"##################### END TRACKING ####################"<<endl;
		}

		return new Solution(curBest);
	}

	/// validate solutions
	bool checkValid(Solution* s) {
		pair<VertexIter, VertexIter> vIter;
		int parts[s->numParts];
		int colors[s->numParts];
		typedef boost::graph_traits<Graph>::adjacency_iterator AdjIter;
		VertexPart_Map vParts = get(boost::vertex_index1_t(), *s->g);
		bool valid = true;

		/// Initialize parts and colors
		for (int i = 0; i < s->numParts; i++) {
			parts[i] = 0;
			colors[i] = 0;
		}

		/// Check all vertices
		for (vIter = vertices(*s->g); vIter.first != vIter.second; vIter.first++) {
			/// Mark partition and color as used
			parts[vParts[*vIter.first]] = 1;
			colors[s->partition[vParts[*vIter.first]]] = 1;

			/// Check color conflicts
			pair<AdjIter, AdjIter> aIter;
			for (aIter = adjacent_vertices(*vIter.first, *s->g);
				  aIter.first != aIter.second; aIter.first++) {

				if (s->partition[vParts[*aIter.first]] ==
					 s->partition[vParts[*vIter.first]]) {

					valid = false;
					cerr<<"Solution is invalid"<<endl;
					cerr<<"Adjacent vertices "<<*aIter.first<<" and "<<*vIter.first;
					cerr<<" have same color "<<s->partition[vParts[*vIter.first]];
					cerr<<endl;
				}
			}
		}

		/// Check colorsUsed
		int count = 0;
		for (int i = 0; i < s->numParts; i++) {
			if (colors[i] == 1) {
				count++;
			}
		}
		if (count != s->colorsUsed) {
			valid = false;
			cerr<<"Solution is invalid"<<endl;
			cerr<<"Wrong colorsUsed stored: stored: "<<s->colorsUsed;
			cerr<<", computed: "<<count<<endl;
		}

		/// Check partitions and representatives
		for (int i = 0; i < s->numParts; i++) {
			if (parts[i] == 0) {
				valid = false;
				cerr<<"Solution is invalid"<<endl;
				cerr<<"partition "<<i<<" seems to be missing"<<endl;
			}
			if (s->representatives[vParts[i]] != i) {
				valid = false;
				cerr<<"Solution is invalid"<<endl;
				cerr<<"Node "<<i<<" is not representative of partition "<<vParts[i];
				cerr<<endl;
			}
		}

		return valid;
	}
}

<|endoftext|>


<commit_before>/** \file    add_child_refs.cc
 *  \author  Oliver Obenland
 *
 *  A tool for marking superior records.
 */

/*
    Copyright (C) 2015, Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <fstream>
#include <iostream>
#include <memory>
#include <unordered_map>
#include <cstdlib>
#include <cstring>
#include "DirectoryEntry.h"
#include "File.h"
#include "Leader.h"
#include "MarcUtil.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "util.h"
#include "XmlWriter.h"

static unsigned modified_count(0);
static std::set<std::string> superior_ppns;
static std::string superior_subfield_data;

void Usage() {
    std::cerr << "Usage: " << progname << " marc_input marc_output superior_ppns\n";
    std::exit(EXIT_FAILURE);
}

void ProcessRecord(XmlWriter * const xml_writer, MarcUtil::Record * const record) {
    record->setRecordWillBeWrittenAsXml(true);

    // Don't add the flag twice
    if (record->getFieldIndex("SPR") != -1) {
        record->write(xml_writer);
        return;
    }

    const std::vector<std::string> &field_data(record->getFields());
    const auto iter(superior_ppns.find(field_data.at(0)));
    if (iter != superior_ppns.end()) {
        if (not record->insertField("UBR", superior_subfield_data)) {
            Warning("Not enough room to add a SPR field! (Control number: " + field_data[0] + ")");
        }
	++modified_count;
    }

    record->write(xml_writer);
}

void AddSuperiorFlag(File * const input, File * const output) {
    XmlWriter xml_writer(output);
    xml_writer.openTag("marc:collection",
                       { std::make_pair("xmlns:marc", "http://www.loc.gov/MARC21/slim"),
                         std::make_pair("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"),
                         std::make_pair("xsi:schemaLocation", "http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd")});

    while (MarcUtil::Record record = MarcUtil::Record::XmlFactory(input))
	ProcessRecord(&xml_writer, &record);

    xml_writer.closeTag();

    std::cerr << "Modified " << modified_count << " record(s).\n";
}

void LoadSuperiorPPNs(const std::string &child_refs_filename) {
    std::ifstream child_refs(child_refs_filename.c_str());
    if (not child_refs.is_open())
        Error("Failed to open \"" + child_refs_filename + "\" for reading!");

    std::string line;
    unsigned line_no(0);
    while (std::getline(child_refs, line)) {
        ++line_no;
        superior_ppns.emplace(line);
    }

    if (unlikely(superior_ppns.empty()))
        Error("Found no data in \"" + child_refs_filename + "\"!");
    std::cerr << "Read " << line_no << " superior PPNs.\n";
}

int main(int argc, char **argv) {
    progname = argv[0];

    if (argc != 4)
        Usage();

    const std::string marc_input_filename(argv[1]);
    File marc_input(marc_input_filename, "rm");
    if (not marc_input)
        Error("can't open \"" + marc_input_filename + "\" for reading!");

    const std::string marc_output_filename(argv[2]);
    File marc_output(marc_output_filename, "w");
    if (not marc_output)
        Error("can't open \"" + marc_output_filename + "\" for writing!");

    try {
        LoadSuperiorPPNs(argv[3]);
    } catch (const std::exception &x) {
	Error("caught exception: " + std::string(x.what()));
    }

    Subfields superior_subfield(/* indicator1 = */' ', /* indicator2 = */' ');
    superior_subfield.addSubfield('a', "1");
    superior_subfield_data = superior_subfield.toString();

    AddSuperiorFlag(&marc_input, &marc_output);
}
<commit_msg>Reimplementing LoadSuperiorPPNs<commit_after>/** \file    add_child_refs.cc
 *  \author  Oliver Obenland
 *
 *  A tool for marking superior records.
 */

/*
    Copyright (C) 2015, Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <fstream>
#include <iostream>
#include <memory>
#include <unordered_map>
#include <cstdlib>
#include <cstring>
#include "DirectoryEntry.h"
#include "File.h"
#include "Leader.h"
#include "MarcUtil.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "util.h"
#include "XmlWriter.h"

static unsigned modified_count(0);
static std::set<std::string> superior_ppns;
static std::string superior_subfield_data;

void Usage() {
    std::cerr << "Usage: " << progname << " marc_input marc_output superior_ppns\n";
    std::exit(EXIT_FAILURE);
}

void ProcessRecord(XmlWriter * const xml_writer, MarcUtil::Record * const record) {
    record->setRecordWillBeWrittenAsXml(true);

    // Don't add the flag twice
    if (record->getFieldIndex("SPR") != -1) {
        record->write(xml_writer);
        return;
    }

    const std::vector<std::string> &field_data(record->getFields());
    const auto iter(superior_ppns.find(field_data.at(0)));
    if (iter != superior_ppns.end()) {
        if (not record->insertField("UBR", superior_subfield_data)) {
            Warning("Not enough room to add a SPR field! (Control number: " + field_data[0] + ")");
        }
	++modified_count;
    }

    record->write(xml_writer);
}

void AddSuperiorFlag(File * const input, File * const output) {
    XmlWriter xml_writer(output);
    xml_writer.openTag("marc:collection",
                       { std::make_pair("xmlns:marc", "http://www.loc.gov/MARC21/slim"),
                         std::make_pair("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"),
                         std::make_pair("xsi:schemaLocation", "http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd")});

    while (MarcUtil::Record record = MarcUtil::Record::XmlFactory(input))
	ProcessRecord(&xml_writer, &record);

    xml_writer.closeTag();

    std::cerr << "Modified " << modified_count << " record(s).\n";
}

void LoadSuperiorPPNs(File * const input) {
    unsigned line_no(0);
    std::string line;
    while (input->getline(&line)) {
        ++line_no;
        superior_ppns.emplace(line);
    }

    if (unlikely(superior_ppns.empty()))
        Error("Found no data in \"" + input->getPath() + "\"!");
    std::cerr << "Read " << line_no << " superior PPNs.\n";
}

int main(int argc, char **argv) {
    progname = argv[0];

    if (argc != 4)
        Usage();

    const std::string marc_input_filename(argv[1]);
    File marc_input(marc_input_filename, "r");
    if (not marc_input)
        Error("can't open \"" + marc_input_filename + "\" for reading!");

    const std::string marc_output_filename(argv[2]);
    File marc_output(marc_output_filename, "w");
    if (not marc_output)
        Error("can't open \"" + marc_output_filename + "\" for writing!");

    const std::string superior_ppns_filename(argv[3]);
    File superior_ppns_input(superior_ppns_filename, "r");
    if (not superior_ppns_input)
        Error("can't open \"" + superior_ppns_filename + "\" for reading!");

    try {
        LoadSuperiorPPNs(&superior_ppns_input);
    } catch (const std::exception &x) {
	Error("caught exception: " + std::string(x.what()));
    }

    Subfields superior_subfield(/* indicator1 = */' ', /* indicator2 = */' ');
    superior_subfield.addSubfield('a', "1");
    superior_subfield_data = superior_subfield.toString();

    AddSuperiorFlag(&marc_input, &marc_output);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2010 Digital Bazaar, Inc. All rights reserved.
 */
#define __STDC_CONSTANT_MACROS

#include <cstdlib>
#include <cstdio>

#include "monarch/app/App.h"
#include "monarch/app/AppPluginFactory.h"
#include "monarch/app/ConfigPlugin.h"
#include "monarch/app/LoggingPlugin.h"
#include "monarch/app/MonarchPlugin.h"
#include "monarch/app/KernelPlugin.h"
#include "monarch/data/json/JsonWriter.h"
#include "monarch/event/EventWaiter.h"
#include "monarch/logging/Logging.h"
#include "monarch/validation/Validation.h"

#include "monarch/app/KernelPlugin.h"

using namespace std;
using namespace monarch::app;
using namespace monarch::config;
using namespace monarch::data::json;
using namespace monarch::event;
using namespace monarch::fiber;
using namespace monarch::io;
using namespace monarch::kernel;
using namespace monarch::logging;
using namespace monarch::modest;
using namespace monarch::net;
using namespace monarch::rt;
namespace v = monarch::validation;

#define PLUGIN_NAME "monarch.app.Kernel"
#define PLUGIN_CL_CFG_ID PLUGIN_NAME ".commandLine"

KernelPlugin::KernelPlugin() :
   mState(Stopped),
   mKernel(NULL)
{
}

KernelPlugin::~KernelPlugin()
{
}

bool KernelPlugin::initMetaConfig(Config& meta)
{
   bool rval = monarch::app::AppPlugin::initMetaConfig(meta);

   // defaults
   if(rval)
   {
      Config& c =
         App::makeMetaConfig(meta, PLUGIN_NAME ".defaults", "defaults")
            [ConfigManager::MERGE][PLUGIN_NAME];
      // modulePath is a map of arrays
      // Keys are unique per module path source to allow for configured other
      // lists of paths. Values are arrays of files or dirs to load.
      c["modulePath"]->setType(Map);
      c["env"] = true;
      c["printModuleVersions"] = false;
      c["maxThreadCount"] = UINT32_C(100);
      c["maxConnectionCount"] = UINT32_C(100);
      // waitEvents is a map of arrays of event ids. The map keys should be
      // unique such as plugin ids. The kernel will wait for all these events
      // to occur before exiting. (Some special kernel events also can cause
      // a quicker exit.)
      c["waitEvents"]->setType(Map);
   }

   // command line options
   if(rval)
   {
      Config& c = App::makeMetaConfig(
         meta, PLUGIN_CL_CFG_ID, "command line", "options")
            [ConfigManager::MERGE][PLUGIN_NAME];
      c["modulePath"][PLUGIN_CL_CFG_ID]->setType(Array);
   }

   return rval;
}

DynamicObject KernelPlugin::getCommandLineSpecs()
{
   DynamicObject spec;
   spec["help"] =
"Module options:\n"
"  -m, --module-path PATH\n"
"                      A colon separated list of modules or directories where\n"
"                      modules are stored. May be specified multiple times.\n"
"                      Loaded after modules in MONARCH_MODULE_PATH.\n"
"      --no-module-path-env\n"
"                      Disable MONARCH_MODULE_PATH.\n"
"      --module-versions\n"
"                      Prints the module versions.\n"
"\n";

   DynamicObject opt;
   Config& options = getApp()->getMetaConfig()
      ["options"][PLUGIN_CL_CFG_ID][ConfigManager::MERGE];
   Config& configOptions = options[PLUGIN_NAME];

   opt = spec["options"]->append();
   opt["short"] = "-m";
   opt["long"] = "--module-path";
   opt["append"] = configOptions["modulePath"][PLUGIN_CL_CFG_ID];
   opt["argError"] = "No path specified.";

   opt = spec["options"]->append();
   opt["long"] = "--no-module-path-env";
   opt["setFalse"]["root"] = configOptions;
   opt["setFalse"]["path"] = "env";

   opt = spec["options"]->append();
   opt["long"] = "--module-versions";
   opt["setTrue"]["root"] = configOptions;
   opt["setTrue"]["path"] = "printModuleVersions";

   DynamicObject specs = AppPlugin::getCommandLineSpecs();
   specs->append(spec);
   return specs;
}

/**
 * Validates the wait events.
 *
 * @param waitEvents the wait events.
 *
 * @return true if successful, false if an exception occurred.
 */
static bool _validateWaitEvents(DynamicObject& waitEvents)
{
   bool rval = false;

   // create validator for node configuration
   v::ValidatorRef v = new v::All(
      new v::Type(Array),
      new v::Each(
         new v::Map(
            "id", new v::Type(String),
            "type", new v::Type(String),
            NULL)),
      NULL);

   rval = v->isValid(waitEvents);
   if(!rval)
   {
      ExceptionRef e = new Exception(
         "Invalid AppPlugin wait event configuration.",
         "monarch.app.Kernel.InvalidWaitEvents");
      e->getDetails()["waitEvents"] = waitEvents;
      Exception::push(e);
   }

   return rval;
}

bool KernelPlugin::didParseCommandLine()
{
   bool rval = AppPlugin::didParseCommandLine();

   // process flags
   // only done after bootstrap mode so that all modules info is available
   if(rval && getApp()->getMode() != App::BOOTSTRAP)
   {
      Config& cfg = getApp()->getMetaConfig()
         ["options"][PLUGIN_CL_CFG_ID][ConfigManager::MERGE][PLUGIN_NAME];

      if(cfg["printModuleVersions"]->getBoolean())
      {
         // FIXME: print out module info
         /*
         printf("%s v%s\n", ...);
         // Raise known exit exception.
         ExceptionRef e = new Exception(
            "Module versions printed.",
            "monarch.app.Exit", EXIT_SUCCESS);
         Exception::set(e);
         rval = false;
         */
         ExceptionRef e = new Exception(
            "Not implemented.",
            "monarch.app.NotImplemented", EXIT_FAILURE);
         Exception::set(e);
         rval = false;
      }
   }

   return rval;
}

bool KernelPlugin::runApp()
{
   bool rval = true;

   mState = Starting;
   while(mState == Starting || mState == Restarting)
   {
      // [re]start the node
      MO_CAT_INFO(MO_KERNEL_CAT,
         (mState == Restarting) ?
            "Restarting kernel..." : "Starting kernel...");

      // get kernel config
      Config cfg = getApp()->getConfig()[PLUGIN_NAME];
      App* app = new App;

      // create and start kernel
      mKernel = new MicroKernel();
      mKernel->setConfigManager(app->getConfigManager(), false);
      mKernel->setFiberScheduler(new FiberScheduler(), true);
      mKernel->setFiberMessageCenter(new FiberMessageCenter(), true);
      mKernel->setEventController(new EventController(), true);
      mKernel->setEventDaemon(new EventDaemon(), true);
      mKernel->setServer(new Server(), true);

      // set thread and connection limits
      mKernel->setMaxAuxiliaryThreads(cfg["maxThreadCount"]->getUInt32());
      mKernel->setMaxServerConnections(cfg["maxConnectionCount"]->getUInt32());

      rval = mKernel->start();
      if(rval)
      {
         rval =
            mKernel->loadModule(
               createMonarchPluginFactory, freeAppPluginFactory) &&
            mKernel->loadModule(
               createConfigPluginFactory, freeAppPluginFactory) &&
            mKernel->loadModule(
               createLoggingPluginFactory, freeAppPluginFactory) &&
            mKernel->loadModule(
               createKernelPluginFactory, freeAppPluginFactory);

         // FIXME: in did load configs should add env paths to config

         // Collect all module paths so they can be loaded in bulk.
         // This helps to avoid issues with needing to specify load order
         // explicitly.
         FileList modulePaths;
         ConfigIterator mpMods = cfg["modulePath"].getIterator();
         while(rval && mpMods->hasNext())
         {
            ConfigIterator mpPaths = mpMods->next().getIterator();
            while(rval && mpPaths->hasNext())
            {
               const char* path = mpPaths->next()->getString();
               FileList pathList = File::parsePath(path);
               modulePaths->concat(*pathList);
            }
         }
         // load all module paths at once
         rval = mKernel->loadModules(modulePaths);

         if(!rval)
         {
            MO_CAT_INFO(MO_KERNEL_CAT, "Stopping kernel due to exception.");
            mKernel->stop();
         }
      }
      mState = Running;

      if(rval)
      {
         MO_CAT_INFO(MO_KERNEL_CAT, "Kernel started.");

         // send ready event
         {
            Event e;
            e["type"] = "monarch.kernel.Kernel.ready";
            mKernel->getEventController()->schedule(e);
         }

         if(rval)
         {
            {
               // create AppPlugins from all loaded AppPluginFactories
               MicroKernel::ModuleApiList factories;
               mKernel->getModuleApisByType(
                  "monarch.app.AppPluginFactory", factories);
               for(MicroKernel::ModuleApiList::iterator i = factories.begin();
                  rval && i != factories.end(); i++)
               {
                  ModuleId id = dynamic_cast<Module*>(*i)->getId();
                  AppPluginFactory* f = dynamic_cast<AppPluginFactory*>(*i);
                  AppPluginRef p = f->createAppPlugin();
                  MO_CAT_OBJECT_INFO(
                     MO_KERNEL_CAT, app,
                     "Adding AppPlugin to App: %s v%s.", id.name, id.version);
                  rval = app->addPlugin(p);
               }
            }

            // waiter for kernel and plugin events
            // used to wait for plugins to complete or for kernel control events
            EventWaiter waiter(mKernel->getEventController());
            // wait for generic kernel events
            waiter.start("monarch.kernel.Kernel.shutdown");
            waiter.start("monarch.kernel.Kernel.restart");

            // make a map of event types to waiting ids
            DynamicObject waitEvents;
            waitEvents->setType(Map);
            {
               // array of events and counts
               DynamicObject appWaitEvents = app->getWaitEvents();
               rval = _validateWaitEvents(appWaitEvents);
               JsonWriter::writeToStdOut(appWaitEvents);
               DynamicObjectIterator i = appWaitEvents.getIterator();
               while(rval && i->hasNext())
               {
                  DynamicObject next = i->next();
                  const char* id = next["id"]->getString();
                  const char* type = next["type"]->getString();
                  if(!waitEvents->hasMember(type))
                  {
                     DynamicObject newInfo;
                     newInfo["ids"]->setType(Array);
                     waitEvents[type] = newInfo;
                  }
                  DynamicObject newId;
                  newId = id;
                  waitEvents[type]["ids"]->append(newId);
                  // start waiting for event
                  waiter.start(type);
               }
            }
            JsonWriter::writeToStdOut(waitEvents);

            int status;
            if(rval)
            {
               // run sub app
               status = app->start(getApp()->getCommandLine());
               rval = (status == EXIT_SUCCESS);
            }

            // wait for events if app started successfully
            // checking for exception in case of success with an exit exception
            if(rval && !Exception::isSet())
            {
               JsonWriter::writeToStdOut(waitEvents);
               while(mState == Running && waitEvents->length() != 0)
               {
                  JsonWriter::writeToStdOut(waitEvents);
                  waiter.waitForEvent();
                  Event e = waiter.popEvent();
                  const char* type = e["type"]->getString();
                  MO_CAT_INFO(MO_KERNEL_CAT,
                     "EventWaiter got event: %s", type);
                  if(strcmp("monarch.kernel.Kernel.shutdown", type) == 0)
                  {
                     mState = Stopping;
                  }
                  else if(strcmp("monarch.kernel.Kernel.restart", type) == 0)
                  {
                     mState = Restarting;
                  }
                  else
                  {
                     if(waitEvents->hasMember(type))
                     {
                        waitEvents->removeMember(type);
                     }
                  }
               }
               mState = Stopping;
            }

            if(!rval)
            {
               getApp()->setExitStatus(app->getExitStatus());
            }
         }

         delete app;
         app = NULL;

         // FIXME: actually stopping microkernel, not just node
         // stop node
         MO_CAT_INFO(MO_KERNEL_CAT,
            (mState == Restarting) ?
               "Stopping kernel for restart..." :
               "Stopping kernel...");
         mKernel->stop();
         MO_CAT_INFO(MO_KERNEL_CAT, "Kernel stopped.");
         // set to stopped unless restarting
         mState = (mState == Stopping) ? Stopped : mState;
      }
      else
      {
         MO_CAT_ERROR(MO_KERNEL_CAT, "Kernel start failed: %s",
            JsonWriter::writeToString(Exception::getAsDynamicObject()).c_str());
      }

      if(app != NULL)
      {
         delete app;
         app = NULL;
      }

      // clean up kernel
      delete mKernel;
      mKernel = NULL;
   }

   return rval;
}

bool KernelPlugin::run()
{
   bool rval = AppPlugin::run();
   if(rval && getApp()->getMode() == App::BOOTSTRAP)
   {
      rval = runApp();
   }
   return rval;
}

class KernelPluginFactory :
   public AppPluginFactory
{
public:
   KernelPluginFactory() :
      AppPluginFactory(PLUGIN_NAME, "1.0")
   {
      addDependency("monarch.app.Config", "1.0");
      addDependency("monarch.app.Logging", "1.0");
   }

   virtual ~KernelPluginFactory() {}

   virtual AppPluginRef createAppPlugin()
   {
      return new KernelPlugin();
   }
};

Module* monarch::app::createKernelPluginFactory()
{
   return new KernelPluginFactory();
}
<commit_msg>Remove debugging and use event defines.<commit_after>/*
 * Copyright (c) 2010 Digital Bazaar, Inc. All rights reserved.
 */
#define __STDC_CONSTANT_MACROS

#include <cstdlib>
#include <cstdio>

#include "monarch/app/App.h"
#include "monarch/app/AppPluginFactory.h"
#include "monarch/app/ConfigPlugin.h"
#include "monarch/app/LoggingPlugin.h"
#include "monarch/app/MonarchPlugin.h"
#include "monarch/app/KernelPlugin.h"
#include "monarch/data/json/JsonWriter.h"
#include "monarch/event/EventWaiter.h"
#include "monarch/logging/Logging.h"
#include "monarch/validation/Validation.h"

#include "monarch/app/KernelPlugin.h"

using namespace std;
using namespace monarch::app;
using namespace monarch::config;
using namespace monarch::data::json;
using namespace monarch::event;
using namespace monarch::fiber;
using namespace monarch::io;
using namespace monarch::kernel;
using namespace monarch::logging;
using namespace monarch::modest;
using namespace monarch::net;
using namespace monarch::rt;
namespace v = monarch::validation;

#define PLUGIN_NAME "monarch.app.Kernel"
#define PLUGIN_CL_CFG_ID PLUGIN_NAME ".commandLine"

#define SHUTDOWN_EVENT_TYPE "monarch.kernel.Kernel.shutdown"
#define RESTART_EVENT_TYPE "monarch.kernel.Kernel.restart"

KernelPlugin::KernelPlugin() :
   mState(Stopped),
   mKernel(NULL)
{
}

KernelPlugin::~KernelPlugin()
{
}

bool KernelPlugin::initMetaConfig(Config& meta)
{
   bool rval = monarch::app::AppPlugin::initMetaConfig(meta);

   // defaults
   if(rval)
   {
      Config& c =
         App::makeMetaConfig(meta, PLUGIN_NAME ".defaults", "defaults")
            [ConfigManager::MERGE][PLUGIN_NAME];
      // modulePath is a map of arrays
      // Keys are unique per module path source to allow for configured other
      // lists of paths. Values are arrays of files or dirs to load.
      c["modulePath"]->setType(Map);
      c["env"] = true;
      c["printModuleVersions"] = false;
      c["maxThreadCount"] = UINT32_C(100);
      c["maxConnectionCount"] = UINT32_C(100);
      // waitEvents is a map of arrays of event ids. The map keys should be
      // unique such as plugin ids. The kernel will wait for all these events
      // to occur before exiting. (Some special kernel events also can cause
      // a quicker exit.)
      c["waitEvents"]->setType(Map);
   }

   // command line options
   if(rval)
   {
      Config& c = App::makeMetaConfig(
         meta, PLUGIN_CL_CFG_ID, "command line", "options")
            [ConfigManager::MERGE][PLUGIN_NAME];
      c["modulePath"][PLUGIN_CL_CFG_ID]->setType(Array);
   }

   return rval;
}

DynamicObject KernelPlugin::getCommandLineSpecs()
{
   DynamicObject spec;
   spec["help"] =
"Module options:\n"
"  -m, --module-path PATH\n"
"                      A colon separated list of modules or directories where\n"
"                      modules are stored. May be specified multiple times.\n"
"                      Loaded after modules in MONARCH_MODULE_PATH.\n"
"      --no-module-path-env\n"
"                      Disable MONARCH_MODULE_PATH.\n"
"      --module-versions\n"
"                      Prints the module versions.\n"
"\n";

   DynamicObject opt;
   Config& options = getApp()->getMetaConfig()
      ["options"][PLUGIN_CL_CFG_ID][ConfigManager::MERGE];
   Config& configOptions = options[PLUGIN_NAME];

   opt = spec["options"]->append();
   opt["short"] = "-m";
   opt["long"] = "--module-path";
   opt["append"] = configOptions["modulePath"][PLUGIN_CL_CFG_ID];
   opt["argError"] = "No path specified.";

   opt = spec["options"]->append();
   opt["long"] = "--no-module-path-env";
   opt["setFalse"]["root"] = configOptions;
   opt["setFalse"]["path"] = "env";

   opt = spec["options"]->append();
   opt["long"] = "--module-versions";
   opt["setTrue"]["root"] = configOptions;
   opt["setTrue"]["path"] = "printModuleVersions";

   DynamicObject specs = AppPlugin::getCommandLineSpecs();
   specs->append(spec);
   return specs;
}

/**
 * Validates the wait events.
 *
 * @param waitEvents the wait events.
 *
 * @return true if successful, false if an exception occurred.
 */
static bool _validateWaitEvents(DynamicObject& waitEvents)
{
   bool rval = false;

   // create validator for node configuration
   v::ValidatorRef v = new v::All(
      new v::Type(Array),
      new v::Each(
         new v::Map(
            "id", new v::Type(String),
            "type", new v::Type(String),
            NULL)),
      NULL);

   rval = v->isValid(waitEvents);
   if(!rval)
   {
      ExceptionRef e = new Exception(
         "Invalid AppPlugin wait event configuration.",
         "monarch.app.Kernel.InvalidWaitEvents");
      e->getDetails()["waitEvents"] = waitEvents;
      Exception::push(e);
   }

   return rval;
}

bool KernelPlugin::didParseCommandLine()
{
   bool rval = AppPlugin::didParseCommandLine();

   // process flags
   // only done after bootstrap mode so that all modules info is available
   if(rval && getApp()->getMode() != App::BOOTSTRAP)
   {
      Config& cfg = getApp()->getMetaConfig()
         ["options"][PLUGIN_CL_CFG_ID][ConfigManager::MERGE][PLUGIN_NAME];

      if(cfg["printModuleVersions"]->getBoolean())
      {
         // FIXME: print out module info
         /*
         printf("%s v%s\n", ...);
         // Raise known exit exception.
         ExceptionRef e = new Exception(
            "Module versions printed.",
            "monarch.app.Exit", EXIT_SUCCESS);
         Exception::set(e);
         rval = false;
         */
         ExceptionRef e = new Exception(
            "Not implemented.",
            "monarch.app.NotImplemented", EXIT_FAILURE);
         Exception::set(e);
         rval = false;
      }
   }

   return rval;
}

bool KernelPlugin::runApp()
{
   bool rval = true;

   mState = Starting;
   while(mState == Starting || mState == Restarting)
   {
      // [re]start the node
      MO_CAT_INFO(MO_KERNEL_CAT,
         (mState == Restarting) ?
            "Restarting kernel..." : "Starting kernel...");

      // get kernel config
      Config cfg = getApp()->getConfig()[PLUGIN_NAME];
      App* app = new App;

      // create and start kernel
      mKernel = new MicroKernel();
      mKernel->setConfigManager(app->getConfigManager(), false);
      mKernel->setFiberScheduler(new FiberScheduler(), true);
      mKernel->setFiberMessageCenter(new FiberMessageCenter(), true);
      mKernel->setEventController(new EventController(), true);
      mKernel->setEventDaemon(new EventDaemon(), true);
      mKernel->setServer(new Server(), true);

      // set thread and connection limits
      mKernel->setMaxAuxiliaryThreads(cfg["maxThreadCount"]->getUInt32());
      mKernel->setMaxServerConnections(cfg["maxConnectionCount"]->getUInt32());

      rval = mKernel->start();
      if(rval)
      {
         rval =
            mKernel->loadModule(
               createMonarchPluginFactory, freeAppPluginFactory) &&
            mKernel->loadModule(
               createConfigPluginFactory, freeAppPluginFactory) &&
            mKernel->loadModule(
               createLoggingPluginFactory, freeAppPluginFactory) &&
            mKernel->loadModule(
               createKernelPluginFactory, freeAppPluginFactory);

         // FIXME: in did load configs should add env paths to config

         // Collect all module paths so they can be loaded in bulk.
         // This helps to avoid issues with needing to specify load order
         // explicitly.
         FileList modulePaths;
         ConfigIterator mpMods = cfg["modulePath"].getIterator();
         while(rval && mpMods->hasNext())
         {
            ConfigIterator mpPaths = mpMods->next().getIterator();
            while(rval && mpPaths->hasNext())
            {
               const char* path = mpPaths->next()->getString();
               FileList pathList = File::parsePath(path);
               modulePaths->concat(*pathList);
            }
         }
         // load all module paths at once
         rval = mKernel->loadModules(modulePaths);

         if(!rval)
         {
            MO_CAT_INFO(MO_KERNEL_CAT, "Stopping kernel due to exception.");
            mKernel->stop();
         }
      }
      mState = Running;

      if(rval)
      {
         MO_CAT_INFO(MO_KERNEL_CAT, "Kernel started.");

         // send ready event
         {
            Event e;
            e["type"] = "monarch.kernel.Kernel.ready";
            mKernel->getEventController()->schedule(e);
         }

         if(rval)
         {
            {
               // create AppPlugins from all loaded AppPluginFactories
               MicroKernel::ModuleApiList factories;
               mKernel->getModuleApisByType(
                  "monarch.app.AppPluginFactory", factories);
               for(MicroKernel::ModuleApiList::iterator i = factories.begin();
                  rval && i != factories.end(); i++)
               {
                  ModuleId id = dynamic_cast<Module*>(*i)->getId();
                  AppPluginFactory* f = dynamic_cast<AppPluginFactory*>(*i);
                  AppPluginRef p = f->createAppPlugin();
                  MO_CAT_INFO(MO_KERNEL_CAT,
                     "Adding AppPlugin to App: %s v%s.", id.name, id.version);
                  rval = app->addPlugin(p);
               }
            }

            // waiter for kernel and plugin events
            // used to wait for plugins to complete or for kernel control events
            EventWaiter waiter(mKernel->getEventController());
            // wait for generic kernel events
            MO_CAT_INFO(MO_KERNEL_CAT,
               "EventWaiter waiting: kernel on \"%s\"", SHUTDOWN_EVENT_TYPE);
            waiter.start(SHUTDOWN_EVENT_TYPE);
            MO_CAT_INFO(MO_KERNEL_CAT,
               "EventWaiter waiting: kernel on \"%s\"", RESTART_EVENT_TYPE);
            waiter.start(RESTART_EVENT_TYPE);

            // make a map of event types to waiting ids
            DynamicObject waitEvents;
            waitEvents->setType(Map);
            {
               // array of events and counts
               DynamicObject appWaitEvents = app->getWaitEvents();
               rval = _validateWaitEvents(appWaitEvents);
               DynamicObjectIterator i = appWaitEvents.getIterator();
               while(rval && i->hasNext())
               {
                  DynamicObject next = i->next();
                  const char* id = next["id"]->getString();
                  const char* type = next["type"]->getString();
                  if(!waitEvents->hasMember(type))
                  {
                     DynamicObject newInfo;
                     newInfo["ids"]->setType(Array);
                     waitEvents[type] = newInfo;
                  }
                  DynamicObject newId;
                  newId = id;
                  waitEvents[type]["ids"]->append(newId);
                  // start waiting for event
                  MO_CAT_INFO(MO_KERNEL_CAT,
                     "EventWaiter waiting: \"%s\" on \"%s\"", id, type);
                  waiter.start(type);
               }
            }

            int status;
            if(rval)
            {
               // run sub app
               status = app->start(getApp()->getCommandLine());
               rval = (status == EXIT_SUCCESS);
            }

            // wait for events if app started successfully
            // checking for exception in case of success with an exit exception
            if(rval && !Exception::isSet())
            {
               while(mState == Running && waitEvents->length() != 0)
               {
                  waiter.waitForEvent();
                  Event e = waiter.popEvent();
                  const char* type = e["type"]->getString();
                  MO_CAT_INFO(MO_KERNEL_CAT,
                     "EventWaiter got event: %s", type);
                  if(strcmp(SHUTDOWN_EVENT_TYPE, type) == 0)
                  {
                     mState = Stopping;
                  }
                  else if(strcmp(RESTART_EVENT_TYPE, type) == 0)
                  {
                     mState = Restarting;
                  }
                  else
                  {
                     if(waitEvents->hasMember(type))
                     {
                        waitEvents->removeMember(type);
                     }
                  }
               }
               mState = Stopping;
            }

            if(!rval)
            {
               getApp()->setExitStatus(app->getExitStatus());
            }
         }

         delete app;
         app = NULL;

         // FIXME: actually stopping microkernel, not just node
         // stop node
         MO_CAT_INFO(MO_KERNEL_CAT,
            (mState == Restarting) ?
               "Stopping kernel for restart..." :
               "Stopping kernel...");
         mKernel->stop();
         MO_CAT_INFO(MO_KERNEL_CAT, "Kernel stopped.");
         // set to stopped unless restarting
         mState = (mState == Stopping) ? Stopped : mState;
      }
      else
      {
         MO_CAT_ERROR(MO_KERNEL_CAT, "Kernel start failed: %s",
            JsonWriter::writeToString(Exception::getAsDynamicObject()).c_str());
      }

      if(app != NULL)
      {
         delete app;
         app = NULL;
      }

      // clean up kernel
      delete mKernel;
      mKernel = NULL;
   }

   return rval;
}

bool KernelPlugin::run()
{
   bool rval = AppPlugin::run();
   if(rval && getApp()->getMode() == App::BOOTSTRAP)
   {
      rval = runApp();
   }
   return rval;
}

class KernelPluginFactory :
   public AppPluginFactory
{
public:
   KernelPluginFactory() :
      AppPluginFactory(PLUGIN_NAME, "1.0")
   {
      addDependency("monarch.app.Config", "1.0");
      addDependency("monarch.app.Logging", "1.0");
   }

   virtual ~KernelPluginFactory() {}

   virtual AppPluginRef createAppPlugin()
   {
      return new KernelPlugin();
   }
};

Module* monarch::app::createKernelPluginFactory()
{
   return new KernelPluginFactory();
}
<|endoftext|>


<commit_before>#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdexcept>
#include <fstream>
#include <xorg/gtest/xorg-gtest.h>

#include "video-driver-test.h"

void VideoDriverTest::StartServer() {
    server.Start();
    xorg::testing::Test::SetDisplayString(server.GetDisplayString());

    ASSERT_NO_FATAL_FAILURE(xorg::testing::Test::SetUp());
}

void VideoDriverTest::SetUpConfigAndLog(const std::string& param) {
    std::stringstream s;
    s << "/tmp/Xorg-" << param << ".log";
    server.SetOption("-logfile", s.str());

    s.str(std::string());
    s << "/tmp/" << param << ".conf";
    config.SetPath(s.str());

    config.AddDefaultScreenWithDriver(param, param);
    config.WriteConfig();
    server.SetOption("-config", config.GetPath());
}

void VideoDriverTest::SetUpEventListener() {
    failed = false;

    testing::TestEventListeners &listeners = ::testing::UnitTest::GetInstance()->listeners();
    listeners.Append(this);
}

void VideoDriverTest::SetUp() {
    SetUp("");
}

void VideoDriverTest::SetUp(const std::string &param) {
    SetUpEventListener();
    SetUpConfigAndLog(param);
    StartServer();
}

void VideoDriverTest::TearDown() {
    if (server.Pid() != -1)
        if (!server.Terminate(3000))
            server.Kill(3000);

    if (!Failed()) {
        config.RemoveConfig();
        server.RemoveLogFile();
    }

    testing::TestEventListeners &listeners = ::testing::UnitTest::GetInstance()->listeners();
    listeners.Release(this);
}

void VideoDriverTest::OnTestPartResult(const ::testing::TestPartResult &test_part_result) {
    failed = test_part_result.failed();
}

bool VideoDriverTest::Failed() {
    return failed;
}
<commit_msg>common: video driver test should use default log paths too<commit_after>#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdexcept>
#include <fstream>
#include <xorg/gtest/xorg-gtest.h>

#include "video-driver-test.h"
#include "helpers.h"

void VideoDriverTest::StartServer() {
    server.Start();
    xorg::testing::Test::SetDisplayString(server.GetDisplayString());

    ASSERT_NO_FATAL_FAILURE(xorg::testing::Test::SetUp());
}

void VideoDriverTest::SetUpConfigAndLog(const std::string& param) {
    InitDefaultLogFiles(server, &config);

    config.AddDefaultScreenWithDriver(param, param);
    config.WriteConfig();
}

void VideoDriverTest::SetUpEventListener() {
    failed = false;

    testing::TestEventListeners &listeners = ::testing::UnitTest::GetInstance()->listeners();
    listeners.Append(this);
}

void VideoDriverTest::SetUp() {
    SetUp("");
}

void VideoDriverTest::SetUp(const std::string &param) {
    SetUpEventListener();
    SetUpConfigAndLog(param);
    StartServer();
}

void VideoDriverTest::TearDown() {
    if (server.Pid() != -1)
        if (!server.Terminate(3000))
            server.Kill(3000);

    if (!Failed()) {
        config.RemoveConfig();
        server.RemoveLogFile();
    }

    testing::TestEventListeners &listeners = ::testing::UnitTest::GetInstance()->listeners();
    listeners.Release(this);
}

void VideoDriverTest::OnTestPartResult(const ::testing::TestPartResult &test_part_result) {
    failed = test_part_result.failed();
}

bool VideoDriverTest::Failed() {
    return failed;
}
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2013.  All rights reserved
 */
#include    "../StroikaPreComp.h"

#include    "OpenSSLCryptoStream.h"

#include    "AES.h"

using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Containers;
using   namespace   Stroika::Foundation::Cryptography;

#if     qHas_OpenSSL
namespace {
    OpenSSLCryptoParams cvt_ (const Memory::BLOB& key, AESOptions options, OpenSSLCryptoParams::Direction direction)
    {
        switch (options) {
            case AESOptions::e128_CBC:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_128_CBC, key, direction);
            case AESOptions::e128_ECB:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_128_ECB, key, direction);
            case AESOptions::e128_OFB:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_128_OFB, key, direction);
            case AESOptions::e128_CFB1:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_128_CFB1, key, direction);
            case AESOptions::e128_CFB8:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_128_CFB8, key, direction);
            case AESOptions::e128_CFB128:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_128_CFB128, key, direction);
            case AESOptions::e192_CBC:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_192_CBC, key, direction);
            case AESOptions::e192_ECB:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_192_ECB, key, direction);
            case AESOptions::e192_OFB:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_192_OFB, key, direction);
            case AESOptions::e192_CFB1:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_192_CFB1, key, direction);
            case AESOptions::e192_CFB8:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_128_CBC, key, direction);
            case AESOptions::e192_CFB128:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_192_CFB128, key, direction);
            case AESOptions::e256_CBC:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_256_CBC, key, direction);
            case AESOptions::e256_ECB:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_256_ECB, key, direction);
            case AESOptions::e256_OFB:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_256_OFB, key, direction);
            case AESOptions::e256_CFB1:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_256_CFB1, key, direction);
            case AESOptions::e256_CFB8:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_256_CFB8, key, direction);
            case AESOptions::e256_CFB128:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_256_CFB128, key, direction);
            default:
                RequireNotReached ();
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_256_CFB128, key, direction);
        }
    }
}
#endif

#if     qHas_OpenSSL
/*
 ********************************************************************************
 ************************** Cryptography::DecodeAES *****************************
 ********************************************************************************
 */
Streams::BinaryInputStream  Cryptography::DecodeAES (const Memory::BLOB& key, Streams::BinaryInputStream in, AESOptions options)
{
    return OpenSSLInputStream (OpenSSLCryptoParams (key, options, OpenSSLCryptoParams::Direction::eDecrypt), in);
}
#endif

#if     qHas_OpenSSL
/*
 ********************************************************************************
 *************************** Cryptography::EncodeAES ****************************
 ********************************************************************************
 */
Streams::BinaryInputStream  Cryptography::EncodeAES (const Memory::BLOB& key, Streams::BinaryInputStream in, AESOptions options)
{
    return OpenSSLInputStream (OpenSSLCryptoParams (key, options, OpenSSLCryptoParams::Direction::eEncrypt), in);
}
#endif

<commit_msg>AES.cpp cleanup<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2013.  All rights reserved
 */
#include    "../StroikaPreComp.h"

#include    "OpenSSLCryptoStream.h"

#include    "AES.h"

using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Containers;
using   namespace   Stroika::Foundation::Cryptography;

#if     qHas_OpenSSL
namespace {
    OpenSSLCryptoParams cvt_ (const Memory::BLOB& key, AESOptions options, OpenSSLCryptoParams::Direction direction)
    {
        switch (options) {
            case AESOptions::e128_CBC:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_128_CBC, key, direction);
            case AESOptions::e128_ECB:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_128_ECB, key, direction);
            case AESOptions::e128_OFB:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_128_OFB, key, direction);
            case AESOptions::e128_CFB1:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_128_CFB1, key, direction);
            case AESOptions::e128_CFB8:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_128_CFB8, key, direction);
            case AESOptions::e128_CFB128:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_128_CFB128, key, direction);
            case AESOptions::e192_CBC:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_192_CBC, key, direction);
            case AESOptions::e192_ECB:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_192_ECB, key, direction);
            case AESOptions::e192_OFB:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_192_OFB, key, direction);
            case AESOptions::e192_CFB1:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_192_CFB1, key, direction);
            case AESOptions::e192_CFB8:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_192_CFB8, key, direction);
            case AESOptions::e192_CFB128:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_192_CFB128, key, direction);
            case AESOptions::e256_CBC:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_256_CBC, key, direction);
            case AESOptions::e256_ECB:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_256_ECB, key, direction);
            case AESOptions::e256_OFB:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_256_OFB, key, direction);
            case AESOptions::e256_CFB1:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_256_CFB1, key, direction);
            case AESOptions::e256_CFB8:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_256_CFB8, key, direction);
            case AESOptions::e256_CFB128:
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_256_CFB128, key, direction);
            default:
                RequireNotReached ();
                return OpenSSLCryptoParams (OpenSSLCryptoParams::Algorithm::eAES_256_CFB128, key, direction);
        }
    }
}
#endif

#if     qHas_OpenSSL
/*
 ********************************************************************************
 ************************** Cryptography::DecodeAES *****************************
 ********************************************************************************
 */
Streams::BinaryInputStream  Cryptography::DecodeAES (const Memory::BLOB& key, Streams::BinaryInputStream in, AESOptions options)
{
    return OpenSSLInputStream (OpenSSLCryptoParams (key, options, OpenSSLCryptoParams::Direction::eDecrypt), in);
}
#endif

#if     qHas_OpenSSL
/*
 ********************************************************************************
 *************************** Cryptography::EncodeAES ****************************
 ********************************************************************************
 */
Streams::BinaryInputStream  Cryptography::EncodeAES (const Memory::BLOB& key, Streams::BinaryInputStream in, AESOptions options)
{
    return OpenSSLInputStream (OpenSSLCryptoParams (key, options, OpenSSLCryptoParams::Direction::eEncrypt), in);
}
#endif

<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <iomanip>
#include <stdexcept>
#include <opencv2/core/ocl.hpp>
#include <opencv2/core/utility.hpp>
#include "opencv2/imgcodecs.hpp"
#include <opencv2/video.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/objdetect.hpp>
#include <opencv2/imgproc.hpp>

using namespace std;
using namespace cv;

class App
{
public:
    App(CommandLineParser& cmd);
    void run();
    void handleKey(char key);
    void hogWorkBegin();
    void hogWorkEnd();
    string hogWorkFps() const;
    void workBegin();
    void workEnd();
    string workFps() const;
    string message() const;

// This function test if gpu_rst matches cpu_rst.
// If the two vectors are not equal, it will return the difference in vector size
// Else if will return
// (total diff of each cpu and gpu rects covered pixels)/(total cpu rects covered pixels)
    double checkRectSimilarity(Size sz,
                               std::vector<Rect>& cpu_rst,
                               std::vector<Rect>& gpu_rst);
private:
    App operator=(App&);

    //Args args;
    bool running;
    bool make_gray;
    bool use_ocl;
    bool ocl_switch;
    double scale;
    double resize_scale;
    int win_width;
    int win_stride_width, win_stride_height;
    int gr_threshold;
    int nlevels;
    double hit_threshold;
    bool gamma_corr;

    int64 hog_work_begin;
    double hog_work_fps;
    int64 work_begin;
    double work_fps;

    string img_source;
    string vdo_source;
    string output;
    int camera_id;
    bool write_once;
};

int main(int argc, char** argv)
{
    const char* keys =
        "{ h help      | false          | print help message }"
        "{ i input     |                | specify input image}"
        "{ c camera    | -1             | enable camera capturing }"
        "{ v video     | 768x576.avi    | use video as input }"
        "{ g gray      | false          | convert image to gray one or not}"
        "{ s scale     | 1.0            | resize the image before detect}"
        "{ o output    |                | specify output path when input is images}";
    CommandLineParser cmd(argc, argv, keys);
    if (cmd.has("help"))
    {
        cout << "Usage : hog [options]" << endl;
        cout << "Available options:" << endl;
        cmd.printMessage();
        return EXIT_SUCCESS;
    }

    App app(cmd);
    try
    {
        app.run();
    }
    catch (const Exception& e)
    {
        return cout << "error: "  << e.what() << endl, 1;
    }
    catch (const exception& e)
    {
        return cout << "error: "  << e.what() << endl, 1;
    }
    catch(...)
    {
        return cout << "unknown exception" << endl, 1;
    }
    return EXIT_SUCCESS;
}

App::App(CommandLineParser& cmd)
{
    cout << "\nControls:\n"
         << "\tESC - exit\n"
         << "\tm - change mode GPU <-> CPU\n"
         << "\tg - convert image to gray or not\n"
         << "\to - save output image once, or switch on/off video save\n"
         << "\t1/q - increase/decrease HOG scale\n"
         << "\t2/w - increase/decrease levels count\n"
         << "\t3/e - increase/decrease HOG group threshold\n"
         << "\t4/r - increase/decrease hit threshold\n"
         << endl;

    make_gray = cmd.has("gray");
    resize_scale = cmd.get<double>("s");
    vdo_source = cmd.get<string>("v");
    img_source = cmd.get<string>("i");
    output = cmd.get<string>("o");
    camera_id = cmd.get<int>("c");

    win_width = 48;
    win_stride_width = 8;
    win_stride_height = 8;
    gr_threshold = 8;
    nlevels = 13;
    hit_threshold = 1.4;
    scale = 1.05;
    gamma_corr = true;
    write_once = false;

    use_ocl = ocl::useOpenCL();
    ocl_switch = true;

    cout << "Group threshold: " << gr_threshold << endl;
    cout << "Levels number: " << nlevels << endl;
    cout << "Win width: " << win_width << endl;
    cout << "Win stride: (" << win_stride_width << ", " << win_stride_height << ")\n";
    cout << "Hit threshold: " << hit_threshold << endl;
    cout << "Gamma correction: " << gamma_corr << endl;
    cout << endl;
}

void App::run()
{
    running = true;
    VideoWriter video_writer;

    Size win_size(win_width, win_width * 2);
    Size win_stride(win_stride_width, win_stride_height);

    // Create HOG descriptors and detectors here

    HOGDescriptor hog(win_size, Size(16, 16), Size(8, 8), Size(8, 8), 9, 1, -1,
                          HOGDescriptor::L2Hys, 0.2, gamma_corr, cv::HOGDescriptor::DEFAULT_NLEVELS);

    while (running)
    {
        VideoCapture vc;
        UMat frame;

        if (vdo_source!="")
        {
            vc.open(vdo_source.c_str());
            if (!vc.isOpened())
                throw runtime_error(string("can't open video file: " + vdo_source));
            vc >> frame;
        }
        else if (camera_id != -1)
        {
            vc.open(camera_id);
            if (!vc.isOpened())
            {
                stringstream msg;
                msg << "can't open camera: " << camera_id;
                throw runtime_error(msg.str());
            }
            vc >> frame;
        }
        else
        {
            imread(img_source).copyTo(frame);
            if (frame.empty())
                throw runtime_error(string("can't open image file: " + img_source));
        }

        Mat img_to_show;

        // Iterate over all frames
        while (running && !frame.empty())
        {
            workBegin();
            if(ocl_switch){
                hog.setSVMDetector( HOGDescriptor::getDaimlerPeopleDetector() );
                ocl_switch = false;
            }
            UMat img_aux, img;

            // Change format of the image
            if (make_gray) cvtColor(frame, img_aux, COLOR_BGR2GRAY );
            else frame.copyTo(img_aux);

            // Resize image
            if (abs(scale-1.0)>0.001)
            {
                Size sz((int)((double)img_aux.cols/resize_scale), (int)((double)img_aux.rows/resize_scale));
                resize(img_aux, img, sz);
            }
            else img = img_aux;
            img.copyTo(img_to_show);
            hog.nlevels = nlevels;
            vector<Rect> found;

            // Perform HOG classification
            hogWorkBegin();

            if(use_ocl)
                hog.detectMultiScale(img, found, hit_threshold, win_stride,
                        Size(0, 0), scale, gr_threshold);
            else
                hog.detectMultiScale(img.getMat(ACCESS_READ), found, hit_threshold, win_stride,
                        Size(0, 0), scale, gr_threshold);
            hogWorkEnd();

            // Draw positive classified windows
            for (size_t i = 0; i < found.size(); i++)
            {
                Rect r = found[i];
                rectangle(img_to_show, r.tl(), r.br(), Scalar(0, 255, 0), 3);
            }

            putText(img_to_show, use_ocl ? "Mode: OpenCL"  : "Mode: CPU", Point(5, 25), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2);
            putText(img_to_show, "FPS (HOG only): " + hogWorkFps(), Point(5, 65), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2);
            putText(img_to_show, "FPS (total): " + workFps(), Point(5, 105), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2);
            imshow("opencv_hog", img_to_show);
            if (vdo_source!="" || camera_id!=-1) vc >> frame;

            workEnd();

            if (output!="" && write_once)
            {
                if (img_source!="")     // wirte image
                {
                    write_once = false;
                    imwrite(output, img_to_show);
                }
                else                    //write video
                {
                    if (!video_writer.isOpened())
                    {
                        video_writer.open(output, VideoWriter::fourcc('x','v','i','d'), 24,
                                          img_to_show.size(), true);
                        if (!video_writer.isOpened())
                            throw std::runtime_error("can't create video writer");
                    }

                    if (make_gray) cvtColor(img_to_show, img, COLOR_GRAY2BGR);
                    else cvtColor(img_to_show, img, COLOR_BGRA2BGR);

                    video_writer << img.getMat(ACCESS_READ);
                }
            }

            handleKey((char)waitKey(3));
        }
    }
}

void App::handleKey(char key)
{
    switch (key)
    {
    case 27:
        running = false;
        break;
    case 'm':
    case 'M':
        ocl::setUseOpenCL(!cv::ocl::useOpenCL());
        ocl_switch = true;
        use_ocl =  ocl::useOpenCL();
        cout << "Switched to " << (use_ocl ? "OpenCL enabled" : "CPU") << " mode\n";
        break;
    case 'g':
    case 'G':
        make_gray = !make_gray;
        cout << "Convert image to gray: " << (make_gray ? "YES" : "NO") << endl;
        break;
    case '1':
        scale *= 1.05;
        cout << "Scale: " << scale << endl;
        break;
    case 'q':
    case 'Q':
        scale /= 1.05;
        cout << "Scale: " << scale << endl;
        break;
    case '2':
        nlevels++;
        cout << "Levels number: " << nlevels << endl;
        break;
    case 'w':
    case 'W':
        nlevels = max(nlevels - 1, 1);
        cout << "Levels number: " << nlevels << endl;
        break;
    case '3':
        gr_threshold++;
        cout << "Group threshold: " << gr_threshold << endl;
        break;
    case 'e':
    case 'E':
        gr_threshold = max(0, gr_threshold - 1);
        cout << "Group threshold: " << gr_threshold << endl;
        break;
    case '4':
        hit_threshold+=0.25;
        cout << "Hit threshold: " << hit_threshold << endl;
        break;
    case 'r':
    case 'R':
        hit_threshold = max(0.0, hit_threshold - 0.25);
        cout << "Hit threshold: " << hit_threshold << endl;
        break;
    case 'c':
    case 'C':
        gamma_corr = !gamma_corr;
        cout << "Gamma correction: " << gamma_corr << endl;
        break;
    case 'o':
    case 'O':
        write_once = !write_once;
        break;
    }
}

inline void App::hogWorkBegin()
{
    hog_work_begin = getTickCount();
}

inline void App::hogWorkEnd()
{
    int64 delta = getTickCount() - hog_work_begin;
    double freq = getTickFrequency();
    hog_work_fps = freq / delta;
}

inline string App::hogWorkFps() const
{
    stringstream ss;
    ss << hog_work_fps;
    return ss.str();
}

inline void App::workBegin()
{
    work_begin = getTickCount();
}

inline void App::workEnd()
{
    int64 delta = getTickCount() - work_begin;
    double freq = getTickFrequency();
    work_fps = freq / delta;
}

inline string App::workFps() const
{
    stringstream ss;
    ss << work_fps;
    return ss.str();
}
<commit_msg>Update hog.cpp<commit_after>#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <iomanip>
#include <stdexcept>
#include <opencv2/core/ocl.hpp>
#include <opencv2/core/utility.hpp>
#include "opencv2/imgcodecs.hpp"
#include <opencv2/video.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/objdetect.hpp>
#include <opencv2/imgproc.hpp>

using namespace std;
using namespace cv;

class App
{
public:
    App(CommandLineParser& cmd);
    void run();
    void handleKey(char key);
    void hogWorkBegin();
    void hogWorkEnd();
    string hogWorkFps() const;
    void workBegin();
    void workEnd();
    string workFps() const;
    string message() const;

// This function test if gpu_rst matches cpu_rst.
// If the two vectors are not equal, it will return the difference in vector size
// Else if will return
// (total diff of each cpu and gpu rects covered pixels)/(total cpu rects covered pixels)
    double checkRectSimilarity(Size sz,
                               std::vector<Rect>& cpu_rst,
                               std::vector<Rect>& gpu_rst);
private:
    App operator=(App&);

    //Args args;
    bool running;
    bool make_gray;
    double scale;
    double resize_scale;
    int win_width;
    int win_stride_width, win_stride_height;
    int gr_threshold;
    int nlevels;
    double hit_threshold;
    bool gamma_corr;

    int64 hog_work_begin;
    double hog_work_fps;
    int64 work_begin;
    double work_fps;

    string img_source;
    string vdo_source;
    string output;
    int camera_id;
    bool write_once;
};

int main(int argc, char** argv)
{
    const char* keys =
        "{ h help      | false          | print help message }"
        "{ i input     |                | specify input image}"
        "{ c camera    | -1             | enable camera capturing }"
        "{ v video     | 768x576.avi    | use video as input }"
        "{ g gray      | false          | convert image to gray one or not}"
        "{ s scale     | 1.0            | resize the image before detect}"
        "{ o output    |                | specify output path when input is images}";
    CommandLineParser cmd(argc, argv, keys);
    if (cmd.has("help"))
    {
        cout << "Usage : hog [options]" << endl;
        cout << "Available options:" << endl;
        cmd.printMessage();
        return EXIT_SUCCESS;
    }

    App app(cmd);
    try
    {
        app.run();
    }
    catch (const Exception& e)
    {
        return cout << "error: "  << e.what() << endl, 1;
    }
    catch (const exception& e)
    {
        return cout << "error: "  << e.what() << endl, 1;
    }
    catch(...)
    {
        return cout << "unknown exception" << endl, 1;
    }
    return EXIT_SUCCESS;
}

App::App(CommandLineParser& cmd)
{
    cout << "\nControls:\n"
         << "\tESC - exit\n"
         << "\tm - change mode GPU <-> CPU\n"
         << "\tg - convert image to gray or not\n"
         << "\to - save output image once, or switch on/off video save\n"
         << "\t1/q - increase/decrease HOG scale\n"
         << "\t2/w - increase/decrease levels count\n"
         << "\t3/e - increase/decrease HOG group threshold\n"
         << "\t4/r - increase/decrease hit threshold\n"
         << endl;

    make_gray = cmd.has("gray");
    resize_scale = cmd.get<double>("s");
    vdo_source = cmd.get<string>("v");
    img_source = cmd.get<string>("i");
    output = cmd.get<string>("o");
    camera_id = cmd.get<int>("c");

    win_width = 48;
    win_stride_width = 8;
    win_stride_height = 8;
    gr_threshold = 8;
    nlevels = 13;
    hit_threshold = 1.4;
    scale = 1.05;
    gamma_corr = true;
    write_once = false;

    cout << "Group threshold: " << gr_threshold << endl;
    cout << "Levels number: " << nlevels << endl;
    cout << "Win width: " << win_width << endl;
    cout << "Win stride: (" << win_stride_width << ", " << win_stride_height << ")\n";
    cout << "Hit threshold: " << hit_threshold << endl;
    cout << "Gamma correction: " << gamma_corr << endl;
    cout << endl;
}

void App::run()
{
    running = true;
    VideoWriter video_writer;

    Size win_size(win_width, win_width * 2);
    Size win_stride(win_stride_width, win_stride_height);

    // Create HOG descriptors and detectors here

    HOGDescriptor hog(win_size, Size(16, 16), Size(8, 8), Size(8, 8), 9, 1, -1,
                          HOGDescriptor::L2Hys, 0.2, gamma_corr, cv::HOGDescriptor::DEFAULT_NLEVELS);
    hog.setSVMDetector( HOGDescriptor::getDaimlerPeopleDetector() );

    while (running)
    {
        VideoCapture vc;
        UMat frame;

        if (vdo_source!="")
        {
            vc.open(vdo_source.c_str());
            if (!vc.isOpened())
                throw runtime_error(string("can't open video file: " + vdo_source));
            vc >> frame;
        }
        else if (camera_id != -1)
        {
            vc.open(camera_id);
            if (!vc.isOpened())
            {
                stringstream msg;
                msg << "can't open camera: " << camera_id;
                throw runtime_error(msg.str());
            }
            vc >> frame;
        }
        else
        {
            imread(img_source).copyTo(frame);
            if (frame.empty())
                throw runtime_error(string("can't open image file: " + img_source));
        }

        UMat img_aux, img;
        Mat img_to_show;

        // Iterate over all frames
        while (running && !frame.empty())
        {
            workBegin();

            // Change format of the image
            if (make_gray) cvtColor(frame, img_aux, COLOR_BGR2GRAY );
            else frame.copyTo(img_aux);

            // Resize image
            if (abs(scale-1.0)>0.001)
            {
                Size sz((int)((double)img_aux.cols/resize_scale), (int)((double)img_aux.rows/resize_scale));
                resize(img_aux, img, sz);
            }
            else img = img_aux;
            img.copyTo(img_to_show);
            hog.nlevels = nlevels;
            vector<Rect> found;

            // Perform HOG classification
            hogWorkBegin();

            hog.detectMultiScale(img, found, hit_threshold, win_stride,
                    Size(0, 0), scale, gr_threshold);
            hogWorkEnd();

            // Draw positive classified windows
            for (size_t i = 0; i < found.size(); i++)
            {
                Rect r = found[i];
                rectangle(img_to_show, r.tl(), r.br(), Scalar(0, 255, 0), 3);
            }

            putText(img_to_show, ocl::useOpenCL() ? "Mode: OpenCL"  : "Mode: CPU", Point(5, 25), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2);
            putText(img_to_show, "FPS (HOG only): " + hogWorkFps(), Point(5, 65), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2);
            putText(img_to_show, "FPS (total): " + workFps(), Point(5, 105), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2);
            imshow("opencv_hog", img_to_show);
            if (vdo_source!="" || camera_id!=-1) vc >> frame;

            workEnd();

            if (output!="" && write_once)
            {
                if (img_source!="")     // wirte image
                {
                    write_once = false;
                    imwrite(output, img_to_show);
                }
                else                    //write video
                {
                    if (!video_writer.isOpened())
                    {
                        video_writer.open(output, VideoWriter::fourcc('x','v','i','d'), 24,
                                          img_to_show.size(), true);
                        if (!video_writer.isOpened())
                            throw std::runtime_error("can't create video writer");
                    }

                    if (make_gray) cvtColor(img_to_show, img, COLOR_GRAY2BGR);
                    else cvtColor(img_to_show, img, COLOR_BGRA2BGR);

                    video_writer << img.getMat(ACCESS_READ);
                }
            }

            handleKey((char)waitKey(3));
        }
    }
}

void App::handleKey(char key)
{
    switch (key)
    {
    case 27:
        running = false;
        break;
    case 'm':
    case 'M':
        ocl::setUseOpenCL(!cv::ocl::useOpenCL());
        cout << "Switched to " << (ocl::useOpenCL() ? "OpenCL enabled" : "CPU") << " mode\n";
        break;
    case 'g':
    case 'G':
        make_gray = !make_gray;
        cout << "Convert image to gray: " << (make_gray ? "YES" : "NO") << endl;
        break;
    case '1':
        scale *= 1.05;
        cout << "Scale: " << scale << endl;
        break;
    case 'q':
    case 'Q':
        scale /= 1.05;
        cout << "Scale: " << scale << endl;
        break;
    case '2':
        nlevels++;
        cout << "Levels number: " << nlevels << endl;
        break;
    case 'w':
    case 'W':
        nlevels = max(nlevels - 1, 1);
        cout << "Levels number: " << nlevels << endl;
        break;
    case '3':
        gr_threshold++;
        cout << "Group threshold: " << gr_threshold << endl;
        break;
    case 'e':
    case 'E':
        gr_threshold = max(0, gr_threshold - 1);
        cout << "Group threshold: " << gr_threshold << endl;
        break;
    case '4':
        hit_threshold+=0.25;
        cout << "Hit threshold: " << hit_threshold << endl;
        break;
    case 'r':
    case 'R':
        hit_threshold = max(0.0, hit_threshold - 0.25);
        cout << "Hit threshold: " << hit_threshold << endl;
        break;
    case 'c':
    case 'C':
        gamma_corr = !gamma_corr;
        cout << "Gamma correction: " << gamma_corr << endl;
        break;
    case 'o':
    case 'O':
        write_once = !write_once;
        break;
    }
}

inline void App::hogWorkBegin()
{
    hog_work_begin = getTickCount();
}

inline void App::hogWorkEnd()
{
    int64 delta = getTickCount() - hog_work_begin;
    double freq = getTickFrequency();
    hog_work_fps = freq / delta;
}

inline string App::hogWorkFps() const
{
    stringstream ss;
    ss << hog_work_fps;
    return ss.str();
}

inline void App::workBegin()
{
    work_begin = getTickCount();
}

inline void App::workEnd()
{
    int64 delta = getTickCount() - work_begin;
    double freq = getTickFrequency();
    work_fps = freq / delta;
}

inline string App::workFps() const
{
    stringstream ss;
    ss << work_fps;
    return ss.str();
}
<|endoftext|>