<commit_before>/*
 * file: packindex.cpp
 *
 * Purpose:
 *
 * Packed Format:
 *
 * The MRF packed format consist of a header of size 16 * ((49151 + isize) / 49152), followed
 * by the 512 byte blocks of the original MRF index that do hold value
 * The output index will be 1:3072 (0.03255%) of the original virtual size, rounded up to 16,
 * plus the actual content blocks.
 *
 * This is because the header is formed of 96 bit masks for every 96 blocks of 512 bytes of input,
 * plus a 32 bit running count of previously existing blocks. Thus, every 96 input blocks will
 * use 16 bytes.  Since the size of the header can be calculated based on the MRF size
 * it is used as a check that the header is correct.  Also the total number of set bits in the
 * header has to be equal to the number of blocks in the file, which results in another check
 *
 * The header line structure has 4 32bit unsigned integers, in big endian format
 * |start_count | bits 0 to 32 | bits 33 to 63 | bits 64 to 95 |
 * Where start_count is the total count of the bits set in the previous lines
 *
 */

#include <string>
#include <cstring>
#include <vector>
#include <fstream>
#include <iostream>
#include <cassert>
#include <cstdio>

 // #include <cinttypes>
// Undefine for big endian architectures
#define LITTLE_ENDIAN

#if defined(LITTLE_ENDIAN)
// Byte swap a 32bit int
static inline uint32_t big(uint32_t val) {
    return (val >> 24) | (val >> 8 & 0xff00) | (val << 8 & 0xff0000) | (val << 24);
}
#else
#define big(x) (x)
#endif

#if defined(_WIN32)
#define FSEEK _fseeki64
#define FTELL _ftelli64
#else
#define FSEEK fseek
#define FTELL ftell
#endif

using namespace std;

// Block size used, do not modify
const int BSZ = 512;

// Compare a substring of src with cmp, return true if same
// offset can be negative, in which case it is measured from the end of the src, python style
static bool substr_equal(const string &src, const string &cmp, int off = 0, size_t len = 0) {
    if (off < 0)
        off += static_cast<int>(src.size());
    if (off < 0 || off >= src.size())
        return false; // usage Error
    return cmp == (len ? src.substr(off, len) : src.substr(off));
}

// Returns true if the block is filled with zeros
inline bool check(const char *src, size_t len = BSZ) {
    assert(len % 8 == 0); // So we can use uint64_t
    len /= 8;
    const uint64_t *p = reinterpret_cast<const uint64_t *>(src);
    uint64_t accumulator = 0;
    while (len--)
        accumulator |= *p++;
    return 0 == accumulator;
}

// Program options
struct options {
    string in_idx_name;
    string out_idx_name;
    string error; // Empty if parsing went fine
    bool unpack; // Pack by default
    bool quiet;  // Verbose by default
};

static options parse(int argc, char **argv) {
    options opt;
    memset(&opt, 0, sizeof(opt));
    for (int i = 1; i < argc; i++) {
        string arg(argv[i]);
        if (0 == arg.find_first_of("-")) {
            if (arg == "-q") {
                opt.quiet = true;
                continue;
            }
            else
            if (arg == "-u") {
                opt.unpack = true;
                continue;
            }
            else {
                opt.error = string("Unknown option ") + arg;
                return opt;
            }
        }
        else { // file names
            if (opt.in_idx_name.empty()) {
                opt.in_idx_name = argv[i];
                if (!substr_equal(opt.in_idx_name, ".idx", -4)) {
                    opt.error = "Input file name should end in .idx";
                    return opt;
                }
            }
            else {
                if (!opt.out_idx_name.empty()) {
                    opt.error = "Too many files names";
                    return opt;
                }
                opt.out_idx_name = argv[i];
                if (!substr_equal(opt.out_idx_name, ".ix", -3)) {
                    opt.error = "Input file name should end in .ix";
                    return opt;
                }
            }
        }
    }

    // Final checks
    if (opt.in_idx_name.empty() || opt.out_idx_name.empty())
        opt.error = "Need input and output file names";

    return opt;
}

enum ERRORS { NO_ERR = 0, USAGE_ERR, IO_ERR, INTERNAL_ERR };

int Usage(const string &error) {
    cerr << error << endl;
    return USAGE_ERR;
}

int pack(const options &opt) {
    string in_idx_name(opt.in_idx_name);
    string out_idx_name(opt.out_idx_name);

    FILE *in_idx = fopen(in_idx_name.c_str(), "rb");
    FILE *out_idx = fopen(out_idx_name.c_str(), "wb");

    if (!in_idx || !out_idx) {
        cerr << "Can't open " << (in_idx ? out_idx_name : in_idx_name) << endl;
        return IO_ERR;
    }

    FSEEK(in_idx, 0, SEEK_END);
    auto in_size = FTELL(in_idx);
    FSEEK(in_idx, 0, SEEK_SET);

    // Input has to be an index, which is always a multiple of 16 bytes
    if (in_size % 16) {
        cerr << "Input file is not an index file, size is not a multiple of 16\n";
        return USAGE_ERR;
    }

    // Output has a 16 bit reserved line plus the line array
    uint64_t header_size = 16 * ((96 * BSZ - 1 + in_size) / (96 * BSZ));
    if (!opt.quiet)
        cout << "Header will be " << header_size << " bytes" << endl;

    // Get space for the header and reserve space on disk,
    // Header will be written at the end
    vector<uint32_t> header(header_size / sizeof(uint32_t));

    // Reserve space for the header
    FSEEK(out_idx, header_size, SEEK_SET);

    // Running count of output blocks
    size_t count = 0;
    size_t in_block_count = (BSZ - 1 + in_size) / BSZ;
    // Block buffer
    char buffer[BSZ];

    // Current line start within header as a 32bit int index
    // always a multiple of 4, since there are 4 ints per line
    int line = 0;
    // and current bit position within that line
    int bit_pos = 0;

#define BIT_FLIP(line, i) header[line + 1 + i / 32] |= 1 << (i % 32)

#if defined(LITTLE_ENDIAN)
#define FIX_LINE {\
    header[line + 1] = big(header[line + 1]);\
    header[line + 2] = big(header[line + 2]);\
    header[line + 3] = big(header[line + 3]);\
}
#else
#define FIX_LINE {}
#endif

    // Check all full blocks, transferring them as needed
    while (--in_block_count) {
        if (BSZ != fread(buffer, 1, BSZ, in_idx)) {
            cerr << "Error reading block from input file\n";
            return IO_ERR;
        }

        if (!check(buffer)) {
            if (BSZ != fwrite(buffer, 1, BSZ, out_idx)) {
                cerr << "Error writing to output file\n";
                return IO_ERR;
            }

            BIT_FLIP(line, bit_pos);
            count++;
        }

        bit_pos++;
        if (bit_pos % 96 == 0) {
            // Start a new line, store the running count
            bit_pos = 0;
            FIX_LINE;
            line += 4;
            // If there is another line, initialize running count
            if (line < header.size())
                header[line] = big(static_cast<uint32_t>(count));
        }
    }

    auto extra_bytes = in_size % BSZ;

    // The very last block may be partial
    if (extra_bytes) {
        if (extra_bytes != fread(buffer, 1, extra_bytes, in_idx)) {
            cerr << "Error reading block from input file\n";
            return IO_ERR;
        }

        // The buffer is in int64_t, so we divide by 8
        for (auto i = extra_bytes; i < BSZ; i++)
            buffer[i] = 0;

        if (!check(buffer)) {
            if (extra_bytes != fwrite(buffer, 1, extra_bytes, out_idx)) {
                cerr << "Error writing to output file\n";
                return IO_ERR;
            }

            BIT_FLIP(line, bit_pos);
        }

        FIX_LINE;
        line += 4; // Points right at the end of the header
    }

#undef BIT_FLIP
#undef FIX_LINE

    if (!opt.quiet)
        cout << "Index packed from " << in_size << " to " << FTELL(out_idx) << endl;

    // line should point to the last line or the one after the last
    if (!(header.size() == line))
        cerr << "Something is wrong, line is " << line << " header is " << header.size() << endl;

    // Done, write the header at the begining of the file
    fclose(in_idx);
    FSEEK(out_idx, 0, SEEK_SET);
    if (header.size() != fwrite(header.data(), sizeof(uint32_t), header.size(), out_idx)) {
        cerr << "Error writing output header\n";
        return IO_ERR;
    }
    fclose(out_idx);

    return NO_ERR;
}

int unpack(const options &opt) {
    cerr << "Unpack not yet implemented\n";
    return INTERNAL_ERR;
}

int main(int argc, char **argv)
{
    options opt(parse(argc, argv));
    if (!opt.error.empty())
        return Usage(opt.error);

    if (opt.unpack)
        return unpack(opt);
    return pack(opt);
}
<commit_msg>simpler swap<commit_after>/*
 * file: packindex.cpp
 *
 * Purpose:
 *
 * Packed Format:
 *
 * The MRF packed format consist of a header of size 16 * ((49151 + isize) / 49152), followed
 * by the 512 byte blocks of the original MRF index that do hold value
 * The output index will be 1:3072 (0.03255%) of the original virtual size, rounded up to 16,
 * plus the actual content blocks.
 *
 * This is because the header is formed of 96 bit masks for every 96 blocks of 512 bytes of input,
 * plus a 32 bit running count of previously existing blocks. Thus, every 96 input blocks will
 * use 16 bytes.  Since the size of the header can be calculated based on the MRF size
 * it is used as a check that the header is correct.  Also the total number of set bits in the
 * header has to be equal to the number of blocks in the file, which results in another check
 *
 * The header line structure has 4 32bit unsigned integers, in big endian format
 * |start_count | bits 0 to 32 | bits 33 to 63 | bits 64 to 95 |
 * Where start_count is the total count of the bits set in the previous lines
 *
 */

#include <string>
#include <vector>
#include <fstream>
#include <iostream>
#include <cassert>
#include <cstdio>

// For memset only
#include <cstring>

 // Undefine for big endian architectures
#define LITTLE_ENDIAN

#if defined(_WIN32)
#define FSEEK _fseeki64
#define FTELL _ftelli64
#else
#define FSEEK fseek
#define FTELL ftell
#endif

#if defined(LITTLE_ENDIAN)
// Byte swap a 32bit int
inline uint32_t swab(uint32_t val) {
    return (val >> 24) | (val >> 8 & 0xff00) | (val << 8 & 0xff0000) | (val << 24);
}
#endif

using namespace std;

// Block size used, do not modify
const int BSZ = 512;

// Compare a substring of src with cmp, return true if same
// offset can be negative, in which case it is measured from the end of the src, python style
static bool substr_equal(const string &src, const string &cmp, int off = 0, size_t len = 0) {
    if (off < 0)
        off += static_cast<int>(src.size());
    if (off < 0 || off >= src.size())
        return false; // usage Error
    return cmp == (len ? src.substr(off, len) : src.substr(off));
}

// Returns true if the block is filled with zeros
inline bool check(const char *src, size_t len = BSZ) {
    assert(len % 8 == 0); // So we can use uint64_t
    len /= 8;
    const uint64_t *p = reinterpret_cast<const uint64_t *>(src);
    uint64_t accumulator = 0;
    while (len--)
        accumulator |= *p++;
    return 0 == accumulator;
}

// Program options
struct options {
    string in_idx_name;
    string out_idx_name;
    string error; // Empty if parsing went fine
    bool unpack; // Pack by default
    bool quiet;  // Verbose by default
};

static options parse(int argc, char **argv) {
    options opt;
    memset(&opt, 0, sizeof(opt));
    for (int i = 1; i < argc; i++) {
        string arg(argv[i]);
        if (0 == arg.find_first_of("-")) {
            if (arg == "-q") {
                opt.quiet = true;
                continue;
            }
            else
            if (arg == "-u") {
                opt.unpack = true;
                continue;
            }
            else {
                opt.error = string("Unknown option ") + arg;
                return opt;
            }
        }
        else { // file names
            if (opt.in_idx_name.empty()) {
                opt.in_idx_name = argv[i];
                if (!substr_equal(opt.in_idx_name, ".idx", -4)) {
                    opt.error = "Input file name should end in .idx";
                    return opt;
                }
            }
            else {
                if (!opt.out_idx_name.empty()) {
                    opt.error = "Too many files names";
                    return opt;
                }
                opt.out_idx_name = argv[i];
                if (!substr_equal(opt.out_idx_name, ".ix", -3)) {
                    opt.error = "Input file name should end in .ix";
                    return opt;
                }
            }
        }
    }

    // Final checks
    if (opt.in_idx_name.empty() || opt.out_idx_name.empty())
        opt.error = "Need input and output file names";

    return opt;
}

enum ERRORS { NO_ERR = 0, USAGE_ERR, IO_ERR, INTERNAL_ERR };

int Usage(const string &error) {
    cerr << error << endl;
    return USAGE_ERR;
}

int pack(const options &opt) {
    string in_idx_name(opt.in_idx_name);
    string out_idx_name(opt.out_idx_name);

    FILE *in_idx = fopen(in_idx_name.c_str(), "rb");
    FILE *out_idx = fopen(out_idx_name.c_str(), "wb");

    if (!in_idx || !out_idx) {
        cerr << "Can't open " << (in_idx ? out_idx_name : in_idx_name) << endl;
        return IO_ERR;
    }

    FSEEK(in_idx, 0, SEEK_END);
    auto in_size = FTELL(in_idx);
    FSEEK(in_idx, 0, SEEK_SET);

    // Input has to be an index, which is always a multiple of 16 bytes
    if (in_size % 16) {
        cerr << "Input file is not an index file, size is not a multiple of 16\n";
        return USAGE_ERR;
    }

    // Output has a 16 bit reserved line plus the line array
    uint64_t header_size = 16 * ((96 * BSZ - 1 + in_size) / (96 * BSZ));
    if (!opt.quiet)
        cout << "Header will be " << header_size << " bytes" << endl;

    // Get space for the header and reserve space on disk,
    // Header will be written at the end
    vector<uint32_t> header(header_size / sizeof(uint32_t));

    // Reserve space for the header
    FSEEK(out_idx, header_size, SEEK_SET);

    // Running count of output blocks
    size_t count = 0;
    size_t in_block_count = (BSZ - 1 + in_size) / BSZ;
    // Block buffer
    char buffer[BSZ];

    // Current line start within header as a 32bit int index
    // always a multiple of 4, since there are 4 ints per line
    int line = 0;
    // and current bit position within that line
    int bit_pos = 0;

#define BIT_SET(line, i) header[line + 1 + i / 32] |= 1 << (i % 32)

    // Check all full blocks, transferring them as needed
    while (--in_block_count) {
        if (BSZ != fread(buffer, 1, BSZ, in_idx)) {
            cerr << "Error reading block from input file\n";
            return IO_ERR;
        }

        if (!check(buffer)) {
            if (BSZ != fwrite(buffer, 1, BSZ, out_idx)) {
                cerr << "Error writing to output file\n";
                return IO_ERR;
            }

            BIT_SET(line, bit_pos);
            count++;
        }

        bit_pos++;
        if (bit_pos % 96 == 0) {
            // Start a new line, store the running count
            bit_pos = 0;
            line += 4;
            // If there is another line, initialize running count
            if (line < header.size())
                header[line] = static_cast<uint32_t>(count);
        }
    }

    auto extra_bytes = in_size % BSZ;

    // The very last block may be partial
    if (extra_bytes) {
        if (extra_bytes != fread(buffer, 1, extra_bytes, in_idx)) {
            cerr << "Error reading block from input file\n";
            return IO_ERR;
        }

        // The buffer is in int64_t, so we divide by 8
        for (auto i = extra_bytes; i < BSZ; i++)
            buffer[i] = 0;

        if (!check(buffer)) {
            if (extra_bytes != fwrite(buffer, 1, extra_bytes, out_idx)) {
                cerr << "Error writing to output file\n";
                return IO_ERR;
            }

            BIT_SET(line, bit_pos);
        }
        line += 4; // Points right at the end of the header
    }

#undef BIT_SET

    if (!opt.quiet)
        cout << "Index packed from " << in_size << " to " << FTELL(out_idx) << endl;

    // line should point to the last line or the one after the last
    if (!(header.size() == line))
        cerr << "Something is wrong, line is " << line << " header is " << header.size() << endl;

#if defined(LITTLE_ENDIAN)
    // swap all header values to big endian
    for (auto &v : header)
        v = swab(v);
#endif

    // Done, write the header at the begining of the file
    fclose(in_idx);
    FSEEK(out_idx, 0, SEEK_SET);
    if (header.size() != fwrite(header.data(), sizeof(uint32_t), header.size(), out_idx)) {
        cerr << "Error writing output header\n";
        return IO_ERR;
    }
    fclose(out_idx);

    return NO_ERR;
}

int unpack(const options &opt) {
    cerr << "Unpack not yet implemented\n";
    return INTERNAL_ERR;
}

int main(int argc, char **argv)
{
    options opt(parse(argc, argv));
    if (!opt.error.empty())
        return Usage(opt.error);

    if (opt.unpack)
        return unpack(opt);
    return pack(opt);
}
<|endoftext|>


<commit_before>//@author A0114171W
#include "stdafx.h"
#include "operation.h"
#include "operations/post_operation.h"
#include "operations/put_operation.h"
#include "operations/erase_operation.h"
#include "operations/branch_operation.h"
#include "internal_transaction.h"
#include "../exceptions/xml_parse_error_exception.h"
#include "internal_datastore.h"

namespace You {
namespace DataStore {
namespace Internal {

const std::string DataStore::FILE_PATH = std::string("data.xml");

DataStore& DataStore::get() {
	static DataStore store;
	return store;
}

You::DataStore::Transaction DataStore::begin() {
	You::DataStore::Transaction result;
	transactionStack.push(std::weak_ptr<Internal::Transaction>(result));

	return result;
}

void DataStore::onTransactionCommit(Transaction& transaction) {
	// Only transaction on top of the stack may be committed
	assert(*transactionStack.top().lock() == transaction);
	auto self = transactionStack.top();

	if (transactionStack.size() == 1) {
		// it is the only active transaction, execute the operations and save
		pugi::xml_document temp;
		temp.reset(document);
		executeTransaction(transaction, temp);
		document.reset(temp);
		saveData();
		transactionStack.pop();
	} else {
		// There is a transaction before it that is yet to be committed.
		// Merge with that transaction
		transactionStack.pop();
		auto below = transactionStack.top().lock();
		below->mergeOperationsQueue(transaction.operationsQueue);
		below->mergeOperationsQueue(transaction.mergedOperationsQueue);
	}
}

void DataStore::onTransactionRollback(Transaction& transaction) {
	// Can only rollback the latest transaction
	assert(*(transactionStack.top().lock()) == transaction);
	transactionStack.pop();
}

void DataStore::post(std::wstring branch, std::wstring id,
	const KeyValuePairs& kvp) {
	assert(!transactionStack.empty());

	std::unique_ptr<Internal::Operation> operation =
		std::make_unique<Internal::PostOperation>(branch, id, kvp);

	if (auto transaction = transactionStack.top().lock()) {
		transaction->push(std::move(operation));
	}
}

void DataStore::put(std::wstring branch, std::wstring id,
	const KeyValuePairs& kvp) {
	assert(!transactionStack.empty());

	std::unique_ptr<Internal::Operation> operation =
		std::make_unique<Internal::PutOperation>(branch, id, kvp);

	if (auto transaction = transactionStack.top().lock()) {
		transaction->push(std::move(operation));
	}
}

void DataStore::erase(std::wstring branch, std::wstring id) {
	assert(!transactionStack.empty());

	std::unique_ptr<Internal::Operation> operation =
		std::make_unique<Internal::EraseOperation>(branch, id);

	if (auto transaction = transactionStack.top().lock()) {
		transaction->push(std::move(operation));
	}
}

std::vector<KeyValuePairs> DataStore::getAll(std::wstring nodeName) {
	try {
		loadData();
	} catch (XmlParseErrorException& e) {
	}
	pugi::xml_node dataNode = BranchOperation::get(document, nodeName);
	std::vector<KeyValuePairs> allData;
	for (auto i = dataNode.begin(); i != dataNode.end(); ++i) {
		allData.push_back(SerializationOperation::deserialize(*i));
	}
	return allData;
}

void DataStore::wipeData() {
	document.reset();
	std::remove(FILE_PATH.c_str());
}

bool DataStore::saveData() {
	bool status = document.save_file(FILE_PATH.c_str());
	return status;
}

void DataStore::loadData() {
	bool isInitialized = !document.first_child().empty();
	if (!isInitialized) {
		pugi::xml_parse_result loadStatus = document.load_file(FILE_PATH.c_str());
		bool loadSuccessful = loadStatus;
		bool isFirstLoad =
			loadStatus.status == pugi::xml_parse_status::status_file_not_found;
		if (!loadSuccessful && !isFirstLoad) {
			// TODO(digawp): find a way to inform user where in the xml
			// the error is located.
			// Possible solution: log
			throw XmlParseErrorException(loadStatus.description());
		}
	}
}

void DataStore::executeTransaction(Transaction & transaction,
	pugi::xml_document& xml) {
	for (auto operation = transaction.operationsQueue.begin();
		operation != transaction.operationsQueue.end();
		++operation) {
		bool status = operation->run(xml);
		if (!status) {
			transaction.rollback();
			assert(false);
		}
	}
	for (auto mergedOperation = transaction.mergedOperationsQueue.begin();
		mergedOperation != transaction.mergedOperationsQueue.end();
		++mergedOperation) {
		bool status = mergedOperation->run(xml);
		if (!status) {
			transaction.rollback();
			assert(false);
		}
	}
}

}  // namespace Internal
}  // namespace DataStore
}  // namespace You
<commit_msg>Do not catch the exception<commit_after>//@author A0114171W
#include "stdafx.h"
#include "operation.h"
#include "operations/post_operation.h"
#include "operations/put_operation.h"
#include "operations/erase_operation.h"
#include "operations/branch_operation.h"
#include "internal_transaction.h"
#include "../exceptions/xml_parse_error_exception.h"
#include "internal_datastore.h"

namespace You {
namespace DataStore {
namespace Internal {

const std::string DataStore::FILE_PATH = std::string("data.xml");

DataStore& DataStore::get() {
	static DataStore store;
	return store;
}

You::DataStore::Transaction DataStore::begin() {
	You::DataStore::Transaction result;
	transactionStack.push(std::weak_ptr<Internal::Transaction>(result));

	return result;
}

void DataStore::onTransactionCommit(Transaction& transaction) {
	// Only transaction on top of the stack may be committed
	assert(*transactionStack.top().lock() == transaction);
	auto self = transactionStack.top();

	if (transactionStack.size() == 1) {
		// it is the only active transaction, execute the operations and save
		pugi::xml_document temp;
		temp.reset(document);
		executeTransaction(transaction, temp);
		document.reset(temp);
		saveData();
		transactionStack.pop();
	} else {
		// There is a transaction before it that is yet to be committed.
		// Merge with that transaction
		transactionStack.pop();
		auto below = transactionStack.top().lock();
		below->mergeOperationsQueue(transaction.operationsQueue);
		below->mergeOperationsQueue(transaction.mergedOperationsQueue);
	}
}

void DataStore::onTransactionRollback(Transaction& transaction) {
	// Can only rollback the latest transaction
	assert(*(transactionStack.top().lock()) == transaction);
	transactionStack.pop();
}

void DataStore::post(std::wstring branch, std::wstring id,
	const KeyValuePairs& kvp) {
	assert(!transactionStack.empty());

	std::unique_ptr<Internal::Operation> operation =
		std::make_unique<Internal::PostOperation>(branch, id, kvp);

	if (auto transaction = transactionStack.top().lock()) {
		transaction->push(std::move(operation));
	}
}

void DataStore::put(std::wstring branch, std::wstring id,
	const KeyValuePairs& kvp) {
	assert(!transactionStack.empty());

	std::unique_ptr<Internal::Operation> operation =
		std::make_unique<Internal::PutOperation>(branch, id, kvp);

	if (auto transaction = transactionStack.top().lock()) {
		transaction->push(std::move(operation));
	}
}

void DataStore::erase(std::wstring branch, std::wstring id) {
	assert(!transactionStack.empty());

	std::unique_ptr<Internal::Operation> operation =
		std::make_unique<Internal::EraseOperation>(branch, id);

	if (auto transaction = transactionStack.top().lock()) {
		transaction->push(std::move(operation));
	}
}

std::vector<KeyValuePairs> DataStore::getAll(std::wstring nodeName) {
	loadData();
	pugi::xml_node dataNode = BranchOperation::get(document, nodeName);
	std::vector<KeyValuePairs> allData;
	for (auto i = dataNode.begin(); i != dataNode.end(); ++i) {
		allData.push_back(SerializationOperation::deserialize(*i));
	}
	return allData;
}

void DataStore::wipeData() {
	document.reset();
	std::remove(FILE_PATH.c_str());
}

bool DataStore::saveData() {
	bool status = document.save_file(FILE_PATH.c_str());
	return status;
}

void DataStore::loadData() {
	bool isInitialized = !document.first_child().empty();
	if (!isInitialized) {
		pugi::xml_parse_result loadStatus = document.load_file(FILE_PATH.c_str());
		bool loadSuccessful = loadStatus;
		bool isFirstLoad =
			loadStatus.status == pugi::xml_parse_status::status_file_not_found;
		if (!loadSuccessful && !isFirstLoad) {
			// TODO(digawp): find a way to inform user where in the xml
			// the error is located.
			// Possible solution: log
			throw XmlParseErrorException(loadStatus.description());
		}
	}
}

void DataStore::executeTransaction(Transaction & transaction,
	pugi::xml_document& xml) {
	for (auto operation = transaction.operationsQueue.begin();
		operation != transaction.operationsQueue.end();
		++operation) {
		bool status = operation->run(xml);
		if (!status) {
			transaction.rollback();
			assert(false);
		}
	}
	for (auto mergedOperation = transaction.mergedOperationsQueue.begin();
		mergedOperation != transaction.mergedOperationsQueue.end();
		++mergedOperation) {
		bool status = mergedOperation->run(xml);
		if (!status) {
			transaction.rollback();
			assert(false);
		}
	}
}

}  // namespace Internal
}  // namespace DataStore
}  // namespace You
<|endoftext|>


<commit_before>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include <chrono>
#ifdef __ANDROID__
# include <cstdlib>
#endif

#include "VLCMetadataService.h"
#include "Media.h"
#include "utils/VLCInstance.h"

namespace medialibrary
{

VLCMetadataService::VLCMetadataService()
    : m_instance( VLCInstance::get() )
{
}

parser::Task::Status VLCMetadataService::run( parser::Task& task )
{
    auto media = task.media;
    auto file = task.file;
    // FIXME: This is now becomming an invalid predicate
    if ( media->duration() != -1 )
    {
        LOG_INFO( file->mrl(), " was already parsed" );
        return parser::Task::Status::Success;
    }

    LOG_INFO( "Parsing ", file->mrl() );
    auto chrono = std::chrono::steady_clock::now();

    auto fromType = file->mrl().find( "://" ) != std::string::npos ? VLC::Media::FromType::FromLocation :
                                                                      VLC::Media::FromType::FromPath;
    auto vlcMedia = VLC::Media( m_instance, file->mrl(), fromType );

    std::unique_lock<compat::Mutex> lock( m_mutex );
    VLC::Media::ParsedStatus status;
    bool done = false;

    auto event = vlcMedia.eventManager().onParsedChanged( [this, &status, &done](VLC::Media::ParsedStatus s ) {
        std::lock_guard<compat::Mutex> lock( m_mutex );
        status = s;
        done = true;
        m_cond.notify_all();
    });
    if ( vlcMedia.parseWithOptions( VLC::Media::ParseFlags::Local | VLC::Media::ParseFlags::Network, 5000 ) == false )
        return parser::Task::Status::Fatal;
    m_cond.wait( lock, [&status, &done]() {
        return done == true;
    });
    event->unregister();
    if ( status == VLC::Media::ParsedStatus::Failed || status == VLC::Media::ParsedStatus::Timeout )
        return parser::Task::Status::Fatal;
    auto tracks = vlcMedia.tracks();
    if ( tracks.size() == 0 )
    {
        LOG_ERROR( "Failed to fetch any tracks for ", file->mrl() );
        return parser::Task::Status::Fatal;
    }
    for ( const auto& track : tracks )
    {
        auto codec = track.codec();
        std::string fcc( reinterpret_cast<const char*>( &codec ), 4 );
        if ( track.type() == VLC::MediaTrack::Video )
        {
            auto fps = static_cast<float>( track.fpsNum() ) / static_cast<float>( track.fpsDen() );
            task.videoTracks.emplace_back( fcc, fps, track.width(), track.height(), track.language(),
                                           track.description() );
        }
        else if ( track.type() == VLC::MediaTrack::Audio )
        {
            task.audioTracks.emplace_back( fcc, track.bitrate(), track.rate(), track.channels(),
                                            track.language(), track.description() );
        }
    }
    storeMeta( task, vlcMedia );
    auto duration = std::chrono::steady_clock::now() - chrono;
    LOG_DEBUG("VLC parsing done in ", std::chrono::duration_cast<std::chrono::microseconds>( duration ).count(), "µs" );
    return parser::Task::Status::Success;
}

const char* VLCMetadataService::name() const
{
    return "VLC";
}

uint8_t VLCMetadataService::nbThreads() const
{
    return 1;
}

void VLCMetadataService::storeMeta( parser::Task& task, VLC::Media& vlcMedia )
{
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
    task.albumArtist = vlcMedia.meta( libvlc_meta_AlbumArtist );
    task.discNumber = toInt( vlcMedia, libvlc_meta_DiscNumber, "disc number" );
    task.discTotal = toInt( vlcMedia, libvlc_meta_DiscTotal, "disc total" );
#else
    task.discNumber = 0;
    task.discTotal = 0;
#endif
    task.artist = vlcMedia.meta( libvlc_meta_Artist );
    task.artworkMrl = vlcMedia.meta( libvlc_meta_ArtworkURL );
    task.title = vlcMedia.meta( libvlc_meta_Title );
    task.genre = vlcMedia.meta( libvlc_meta_Genre );
    task.releaseDate = vlcMedia.meta( libvlc_meta_Date );
    task.showName = vlcMedia.meta( libvlc_meta_ShowName );
    task.albumName = vlcMedia.meta( libvlc_meta_Album );
    task.duration = vlcMedia.duration();

    task.trackNumber = toInt( vlcMedia, libvlc_meta_TrackNumber, "track number" );
    task.episode = toInt( vlcMedia, libvlc_meta_Episode, "episode number" );
}

int VLCMetadataService::toInt( VLC::Media& vlcMedia, libvlc_meta_t meta, const char* name )
{
    auto str = vlcMedia.meta( meta );
    if ( str.empty() == false )
    {
#ifndef __ANDROID__
        try
        {
            return std::stoi( str );
        }
        catch( std::logic_error& ex)
        {
            LOG_WARN( "Invalid ", name, " provided (", str, "): ", ex.what() );
        }
#else
        return atoi( str.c_str() );
#endif
    }
    return 0;
}

}
<commit_msg>VLCMetadataService: Don't discard files without tracks<commit_after>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include <chrono>
#ifdef __ANDROID__
# include <cstdlib>
#endif

#include "VLCMetadataService.h"
#include "Media.h"
#include "utils/VLCInstance.h"

namespace medialibrary
{

VLCMetadataService::VLCMetadataService()
    : m_instance( VLCInstance::get() )
{
}

parser::Task::Status VLCMetadataService::run( parser::Task& task )
{
    auto media = task.media;
    auto file = task.file;
    // FIXME: This is now becomming an invalid predicate
    if ( media->duration() != -1 )
    {
        LOG_INFO( file->mrl(), " was already parsed" );
        return parser::Task::Status::Success;
    }

    LOG_INFO( "Parsing ", file->mrl() );
    auto chrono = std::chrono::steady_clock::now();

    auto fromType = file->mrl().find( "://" ) != std::string::npos ? VLC::Media::FromType::FromLocation :
                                                                      VLC::Media::FromType::FromPath;
    auto vlcMedia = VLC::Media( m_instance, file->mrl(), fromType );

    std::unique_lock<compat::Mutex> lock( m_mutex );
    VLC::Media::ParsedStatus status;
    bool done = false;

    auto event = vlcMedia.eventManager().onParsedChanged( [this, &status, &done](VLC::Media::ParsedStatus s ) {
        std::lock_guard<compat::Mutex> lock( m_mutex );
        status = s;
        done = true;
        m_cond.notify_all();
    });
    if ( vlcMedia.parseWithOptions( VLC::Media::ParseFlags::Local | VLC::Media::ParseFlags::Network, 5000 ) == false )
        return parser::Task::Status::Fatal;
    m_cond.wait( lock, [&status, &done]() {
        return done == true;
    });
    event->unregister();
    if ( status == VLC::Media::ParsedStatus::Failed || status == VLC::Media::ParsedStatus::Timeout )
        return parser::Task::Status::Fatal;
    auto tracks = vlcMedia.tracks();
    if ( tracks.size() == 0 )
        LOG_WARN( "Failed to fetch any tracks for ", file->mrl() );
    for ( const auto& track : tracks )
    {
        auto codec = track.codec();
        std::string fcc( reinterpret_cast<const char*>( &codec ), 4 );
        if ( track.type() == VLC::MediaTrack::Video )
        {
            auto fps = static_cast<float>( track.fpsNum() ) / static_cast<float>( track.fpsDen() );
            task.videoTracks.emplace_back( fcc, fps, track.width(), track.height(), track.language(),
                                           track.description() );
        }
        else if ( track.type() == VLC::MediaTrack::Audio )
        {
            task.audioTracks.emplace_back( fcc, track.bitrate(), track.rate(), track.channels(),
                                            track.language(), track.description() );
        }
    }
    storeMeta( task, vlcMedia );
    auto duration = std::chrono::steady_clock::now() - chrono;
    LOG_DEBUG("VLC parsing done in ", std::chrono::duration_cast<std::chrono::microseconds>( duration ).count(), "µs" );
    return parser::Task::Status::Success;
}

const char* VLCMetadataService::name() const
{
    return "VLC";
}

uint8_t VLCMetadataService::nbThreads() const
{
    return 1;
}

void VLCMetadataService::storeMeta( parser::Task& task, VLC::Media& vlcMedia )
{
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
    task.albumArtist = vlcMedia.meta( libvlc_meta_AlbumArtist );
    task.discNumber = toInt( vlcMedia, libvlc_meta_DiscNumber, "disc number" );
    task.discTotal = toInt( vlcMedia, libvlc_meta_DiscTotal, "disc total" );
#else
    task.discNumber = 0;
    task.discTotal = 0;
#endif
    task.artist = vlcMedia.meta( libvlc_meta_Artist );
    task.artworkMrl = vlcMedia.meta( libvlc_meta_ArtworkURL );
    task.title = vlcMedia.meta( libvlc_meta_Title );
    task.genre = vlcMedia.meta( libvlc_meta_Genre );
    task.releaseDate = vlcMedia.meta( libvlc_meta_Date );
    task.showName = vlcMedia.meta( libvlc_meta_ShowName );
    task.albumName = vlcMedia.meta( libvlc_meta_Album );
    task.duration = vlcMedia.duration();

    task.trackNumber = toInt( vlcMedia, libvlc_meta_TrackNumber, "track number" );
    task.episode = toInt( vlcMedia, libvlc_meta_Episode, "episode number" );
}

int VLCMetadataService::toInt( VLC::Media& vlcMedia, libvlc_meta_t meta, const char* name )
{
    auto str = vlcMedia.meta( meta );
    if ( str.empty() == false )
    {
#ifndef __ANDROID__
        try
        {
            return std::stoi( str );
        }
        catch( std::logic_error& ex)
        {
            LOG_WARN( "Invalid ", name, " provided (", str, "): ", ex.what() );
        }
#else
        return atoi( str.c_str() );
#endif
    }
    return 0;
}

}
<|endoftext|>


<commit_before>#ifndef MYPARSER_PASS_REPR_HPP
#define MYPARSER_PASS_REPR_HPP

#include "myparser_pass.hpp"

namespace myparser {

template <>
class Pass<PASS_REPR>: public PassProto<PASS_REPR> {
private:
    const bool optionV;
    const bool optionC;

protected:
    std::ostream &out;
    size_t indent;

    virtual void putName(const std::string &name) {
        (void) name;
    }

    virtual void putIndex(const size_t index) {
        (void) index;
    }

    virtual void putText(const std::string &text) {
        (void) text;
    }

    virtual void putError(const std::string &error) {
        (void) error;
    }

    virtual void putMainBegin() {}

    virtual void putMainEnd() {}

    virtual void putPlaceHolder() {}

    virtual void putBegin() {}

    virtual void putEnd() {}

    virtual void putLnBegin() {}

    virtual void putLnEnd() {}

    virtual void putLn(const bool first) {
        (void) first;
    }

public:
    inline Pass(std::ostream &target, const bool verbose, const bool compact):
        PassProto<PASS_REPR>(), optionV(verbose), optionC(compact),
        out(target), indent(0) {}

    // virtual ~Pass() {}

    void run(const NodeList<> *node) {
        putMainBegin();

        putName(node->getRuleName());
        putIndex(node->getIndex());

        std::vector<const Node *> children1;

        if (!optionV) {
            for (const Node *child: node->getChildren()) {
                if (!child->empty()) {
                    children1.push_back(child);
                }
            }
        }

        const std::vector<const Node *> &children =
            optionV ? node->getChildren() : children1;

        if (optionC && children.size() == 1) {
            putBegin();
            children[0]->runPass(this);
            putEnd();
        } else {
            putPlaceHolder();

            putLnBegin();
            ++indent;

            bool first = true;
            for (const Node *child: children) {
                putLn(first);
                first = false;
                child->runPass(this);
            }

            --indent;
            putLnEnd();
        }

        putMainEnd();
    }

    void run(const NodeText<> *node) {
        putMainBegin();

        putName(node->getRuleName());

        putBegin();
        putText(node->getText());
        putEnd();

        putMainEnd();
    }

    template <class E>
    void run(const NodeErrorNative<E> *node) {
        putMainBegin();

        putName(node->getRuleName());

        putBegin();
        putError(E::getStr());
        putEnd();

        putMainEnd();
    }

    template <class E>
    void run(const NodeErrorWrap<E> *node) {
        putMainBegin();

        putName(node->getRuleName());

        putBegin();
        putError(E::getStr());
        putEnd();

        putLnBegin();
        ++indent;
        putLn(true);
        node->getChild()->runPass(this);
        --indent;
        putLnEnd();

        putMainEnd();
    }
};

template <class TX = void> // actually not a template
class PassReprText: public Pass<PASS_REPR> {
protected:
    virtual void putText(const std::string &text) {
        out << text;
    }

public:
    inline PassReprText(std::ostream &target):
        Pass<PASS_REPR>(target, true, false) {}

    // virtual ~PassReprText() {}
};

template <class TX = void> // actually not a template
class PassReprSimple: public Pass<PASS_REPR> {
protected:
    virtual void putText(const std::string &text) {
        out << style_keyword << text << style_normal;
    }

    virtual void putError(const std::string &error) {
        out << style_error << "ERROR: " << style_normal << error;
    }

    virtual void putPlaceHolder() {
        out << "=>";
    }

    virtual void putLn(const bool first) {
        (void) first;

        out << '\n';
        for (size_t i = 0; i < indent; ++i) {
            out << "    ";
        }
    }

public:
    inline PassReprSimple(
        std::ostream &target,
        const bool verbose = false, const bool compact = true
    ):
        Pass<PASS_REPR>(target, verbose, compact) {}

    // virtual ~PassReprSimple() {}
};

template <class TX = void> // actually not a template
class PassReprFull: public Pass<PASS_REPR> {
protected:
    virtual void putName(const std::string &name) {
        out << name;
    }

    virtual void putIndex(const size_t index) {
        out << '[';
        out << style_index << index << style_normal;
        out << ']';
    }

    virtual void putText(const std::string &text) {
        out << style_keyword << text << style_normal;
    }

    virtual void putError(const std::string &error) {
        out << style_error << "ERROR: " << style_normal << error;
    }

    virtual void putBegin() {
        out << style_faint << " - " << style_normal;
    }

    virtual void putLn(const bool first) {
        (void) first;

        out << '\n';
        for (size_t i = 0; i < indent; ++i) {
            out << "    ";
        }
    }

public:
    inline PassReprFull(
        std::ostream &target,
        const bool verbose = false, const bool compact = true
    ):
        Pass<PASS_REPR>(target, verbose, compact) {}

    // virtual ~PassReprFull() {}
};

template <class TX = void> // actually not a template
class PassReprJSON: public Pass<PASS_REPR> {
protected:
    virtual void putName(const std::string &name) {
        putLn1();
        out << "\"name\": \"" << name << "\","; // TODO: escape?
    }

    virtual void putIndex(const size_t index) {
        putLn1();
        out << "\"index\": \"" << index << "\",";
    }

    virtual void putText(const std::string &text) {
        putLn1();
        out << "\"text\": \"" << text << "\",";
    }

    virtual void putError(const std::string &error) {
        putLn1();
        out << "\"error\": \"" << error << "\",";
    }

    virtual void putMainBegin() {
        out << "{";
        ++indent; // extra
    }

    virtual void putMainEnd() {
        --indent; // extra
        putLn1();
        out << "}";
    }

    virtual void putLnBegin() {
        putLn1();
        out << "\"children\": [";
        --indent; // extra
    }

    virtual void putLnEnd() {
        ++indent; // extra
        out << "]";
    }

    virtual void putLn(const bool first) {
        if (!first) {
            out << ',';
            putLn1();
        }
    }

    void putLn1() {
        out << '\n';
        for (size_t i = 0; i < indent; ++i) {
            out << "    ";
        }
    }

public:
    inline PassReprJSON(
        std::ostream &target, const bool verbose = false
    ):
        Pass<PASS_REPR>(target, verbose, false) {}

    // virtual ~PassReprJSON() {}
};

}

#endif
<commit_msg>add JSON escape<commit_after>#ifndef MYPARSER_PASS_REPR_HPP
#define MYPARSER_PASS_REPR_HPP

#include "myparser_pass.hpp"

namespace myparser {

template <>
class Pass<PASS_REPR>: public PassProto<PASS_REPR> {
private:
    const bool optionV;
    const bool optionC;

protected:
    std::ostream &out;
    size_t indent;

    virtual void putName(const std::string &name) {
        (void) name;
    }

    virtual void putIndex(const size_t index) {
        (void) index;
    }

    virtual void putText(const std::string &text) {
        (void) text;
    }

    virtual void putError(const std::string &error) {
        (void) error;
    }

    virtual void putMainBegin() {}

    virtual void putMainEnd() {}

    virtual void putPlaceHolder() {}

    virtual void putBegin() {}

    virtual void putEnd() {}

    virtual void putLnBegin() {}

    virtual void putLnEnd() {}

    virtual void putLn(const bool first) {
        (void) first;
    }

public:
    inline Pass(std::ostream &target, const bool verbose, const bool compact):
        PassProto<PASS_REPR>(), optionV(verbose), optionC(compact),
        out(target), indent(0) {}

    // virtual ~Pass() {}

    void run(const NodeList<> *node) {
        putMainBegin();

        putName(node->getRuleName());
        putIndex(node->getIndex());

        std::vector<const Node *> children1;

        if (!optionV) {
            for (const Node *child: node->getChildren()) {
                if (!child->empty()) {
                    children1.push_back(child);
                }
            }
        }

        const std::vector<const Node *> &children =
            optionV ? node->getChildren() : children1;

        if (optionC && children.size() == 1) {
            putBegin();
            children[0]->runPass(this);
            putEnd();
        } else {
            putPlaceHolder();

            putLnBegin();
            ++indent;

            bool first = true;
            for (const Node *child: children) {
                putLn(first);
                first = false;
                child->runPass(this);
            }

            --indent;
            putLnEnd();
        }

        putMainEnd();
    }

    void run(const NodeText<> *node) {
        putMainBegin();

        putName(node->getRuleName());

        putBegin();
        putText(node->getText());
        putEnd();

        putMainEnd();
    }

    template <class E>
    void run(const NodeErrorNative<E> *node) {
        putMainBegin();

        putName(node->getRuleName());

        putBegin();
        putError(E::getStr());
        putEnd();

        putMainEnd();
    }

    template <class E>
    void run(const NodeErrorWrap<E> *node) {
        putMainBegin();

        putName(node->getRuleName());

        putBegin();
        putError(E::getStr());
        putEnd();

        putLnBegin();
        ++indent;
        putLn(true);
        node->getChild()->runPass(this);
        --indent;
        putLnEnd();

        putMainEnd();
    }
};

template <class TX = void> // actually not a template
class PassReprText: public Pass<PASS_REPR> {
protected:
    virtual void putText(const std::string &text) {
        out << text;
    }

public:
    inline PassReprText(std::ostream &target):
        Pass<PASS_REPR>(target, true, false) {}

    // virtual ~PassReprText() {}
};

template <class TX = void> // actually not a template
class PassReprSimple: public Pass<PASS_REPR> {
protected:
    virtual void putText(const std::string &text) {
        out << style_keyword << text << style_normal;
    }

    virtual void putError(const std::string &error) {
        out << style_error << "ERROR: " << style_normal << error;
    }

    virtual void putPlaceHolder() {
        out << "=>";
    }

    virtual void putLn(const bool first) {
        (void) first;

        out << '\n';
        for (size_t i = 0; i < indent; ++i) {
            out << "    ";
        }
    }

public:
    inline PassReprSimple(
        std::ostream &target,
        const bool verbose = false, const bool compact = true
    ):
        Pass<PASS_REPR>(target, verbose, compact) {}

    // virtual ~PassReprSimple() {}
};

template <class TX = void> // actually not a template
class PassReprFull: public Pass<PASS_REPR> {
protected:
    virtual void putName(const std::string &name) {
        out << name;
    }

    virtual void putIndex(const size_t index) {
        out << '[';
        out << style_index << index << style_normal;
        out << ']';
    }

    virtual void putText(const std::string &text) {
        out << style_keyword << text << style_normal;
    }

    virtual void putError(const std::string &error) {
        out << style_error << "ERROR: " << style_normal << error;
    }

    virtual void putBegin() {
        out << style_faint << " - " << style_normal;
    }

    virtual void putLn(const bool first) {
        (void) first;

        out << '\n';
        for (size_t i = 0; i < indent; ++i) {
            out << "    ";
        }
    }

public:
    inline PassReprFull(
        std::ostream &target,
        const bool verbose = false, const bool compact = true
    ):
        Pass<PASS_REPR>(target, verbose, compact) {}

    // virtual ~PassReprFull() {}
};

template <class TX = void> // actually not a template
class PassReprJSON: public Pass<PASS_REPR> {
protected:
    void putStrEscaped(const std::string &str) {
        for (const char c: str) {
            switch (c) {
            // case '\0':
                // never reach
            case '\b':
                out << "\\b";
                break;
            case '\t':
                out << "\\t";
                break;
            case '\n':
                out << "\\n";
                break;
            case '\v':
                out << "\\v";
                break;
            case '\f':
                out << "\\f";
                break;
            case '\r':
                out << "\\r";
                break;
            case '\"':
                out << "\\\"";
                break;
            case '\'':
                out << "\\\'";
                break;
            case '\\':
                out << "\\\\";
                break;
            case '\x7F':
                out << "\\x7F";
                break;
            default:
                if (c < '\x10') {
                    out << "\\x0" << ("0123456789ABCDEF"[c & 0xF]);
                } else if (c < '\x20') {
                    out << "\\x1" << ("0123456789ABCDEF"[c & 0xF]);
                } else {
                    out << c;
                }
                break;
            }
        }
    }

    virtual void putName(const std::string &name) {
        putLn1();
        out << "\"rulename\": \"" << name << "\",";
    }

    virtual void putIndex(const size_t index) {
        putLn1();
        out << "\"ruleindex\": \"" << index << "\",";
    }

    virtual void putText(const std::string &text) {
        putLn1();
        out << "\"text\": \"";
        putStrEscaped(text);
        out << "\",";
    }

    virtual void putError(const std::string &error) {
        putLn1();
        out << "\"error\": \"";
        putStrEscaped(error);
        out << "\",";
    }

    virtual void putMainBegin() {
        out << "{";
        ++indent; // extra
    }

    virtual void putMainEnd() {
        --indent; // extra
        putLn1();
        out << "}";
    }

    virtual void putLnBegin() {
        putLn1();
        out << "\"children\": [";
        --indent; // extra
    }

    virtual void putLnEnd() {
        ++indent; // extra
        out << "]";
    }

    virtual void putLn(const bool first) {
        if (!first) {
            out << ',';
            putLn1();
        }
    }

    void putLn1() {
        out << '\n';
        for (size_t i = 0; i < indent; ++i) {
            out << "    ";
        }
    }

public:
    inline PassReprJSON(
        std::ostream &target, const bool verbose = false
    ):
        Pass<PASS_REPR>(target, verbose, false) {}

    // virtual ~PassReprJSON() {}
};

}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright © 2015, United States Government, as represented by the
 * Administrator of the National Aeronautics and Space Administration.
 * All rights reserved.
 *
 * The NASA Tensegrity Robotics Toolkit (NTRT) v1 platform is licensed
 * under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
*/

/**
 * @file ScarrArmModel.cpp
 * @brief Contains the implementation of class ScarrArmModel.
 * Measurements are scaled to average adult male
 * $Id$
 */

// This module
#include "ScarrArmModel.h"
// This library
#include "core/tgBasicActuator.h"
#include "core/tgRod.h"
#include "core/abstractMarker.h"
#include "tgcreator/tgBuildSpec.h"
#include "tgcreator/tgBasicActuatorInfo.h"
#include "tgcreator/tgRodInfo.h"
#include "tgcreator/tgStructure.h"
#include "tgcreator/tgStructureInfo.h"
// The Bullet Physics library
#include "LinearMath/btVector3.h"
// The C++ Standard Library
#include <stdexcept>

namespace
{
    // see tgBaseString.h for a descripton of some of these rod parameters
    // (specifically, those related to the motor moving the strings.)
    // NOTE that any parameter that depends on units of length will scale
    // with the current gravity scaling. E.g., with gravity as 98.1,
    // the length units below are in decimeters.

    // Note: This current model of the SUPERball rod is 1.5m long by 3 cm radius,
    // which is 0.00424 m^3.
    // For SUPERball v1.5, mass = 3.5kg per strut, which comes out to
    // 0.825 kg / (decimeter^3).

    // similarly, frictional parameters are for the tgRod objects.
    const struct Config
    {
        double density;
        double radius;
        double stiffness;
        double damping;
        double rod_length;
        double rod_space;
        double friction;
        double rollFriction;
        double restitution;
        double pretension_olecranon;
        double pretension_anconeus;
        double pretension_brachioradialis;
        double pretension_ulnaradius;
        double pretension_support;
        bool   history;
        double maxTens;
        double targetVelocity;
    } c =
   {
     0.825,    // density (kg / length^3)
     0.31,     // radius (length)
     3000.0,   // stiffness (kg / sec^2)
     200.0,    // damping (kg / sec)
     15.0,     // rod_length (length)
     7.5,      // rod_space (length)
     1.0,      // friction (unitless)
     0.01,     // rollFriction (unitless)
     0.2,      // restitution (?)
     3000.0/15.55,   // pretension_olecranon (force), stiffness/initial length
     3000.0/15.55,   // pretension_anconeus (force), stiffness/initial length
     3000.0/262,     // pretension_brachioradialis (force), stiffness/initial length
     3000.0/1,        // pretension_ulnaradius (force), stiffness/initial length
     3000.0/1,        // pretension_support (force), stiffness/initial length
     false,    // history (boolean)
     100000,   // maxTens
     10000    // targetVelocity
#if (0)
     20000     // maxAcc
#endif
     // Use the below values for earlier versions of simulation.
     // 1.006,
     // 0.31,
     // 300000.0,
     // 3000.0,
     // 15.0,
     // 7.5,
  };
} // namespace

/*
 * helper arrays for node and rod numbering schema
 */
/*returns the number of the rod for a given node */
//const int rodNumbersPerNode[11]={0,1,2,3,3,4,0,1,2,5,5,4,6};

/*returns the node that is at the other end of the given node */
//const int otherEndOfTheRod[11]={6,7,8,4,3,11,0,1,2,10,9,5,12};

/*returns the node that is at the parallel rod
 * and at the same end of the given node
 */
//const int parallelNode[11]={1,0,5,9,10,2,7,6,11,3,4,8,12};

ScarrArmModel::ScarrArmModel() : tgModel()
{
}

ScarrArmModel::~ScarrArmModel()
{
}

void ScarrArmModel::addNodes(tgStructure& s)
{
    const double scale = 0.1;
    const size_t nNodes = 11 + 2; //2 for massless rod

    // Average Adult Male Measurements with scale
    // Lengths are in mm
    const double a = 22 * scale; //ulnta distal width
    const double b = 265 * scale * 0.5; //ulna length
    const double c = 334 * scale * 0.5; //humerus length
    const double d = 66 * scale; // humerus epicondylar width
    const double e = 246 * scale * 0.5; //radius length
    const double f = 25 * scale; // humerus head radius
    const double g = 17 * scale; //ulna proximal width
    const double sigma = 10 * scale; // gap from end of radius to olecranon TODO: tinker
    const double ulna_diameter = g; //TODO: tinker
    const double x = a/2;
    const double z = c/2;

    nodePositions.push_back(btVector3(a/2, 0, 0));
    nodePositions.push_back(btVector3(0, -g, 0));
    nodePositions.push_back(btVector3(-a/2, 0, 0));
    nodePositions.push_back(btVector3(0, 0, f));
    nodePositions.push_back(btVector3(0, 0, -f));
    nodePositions.push_back(btVector3(0, d, 0));
    nodePositions.push_back(btVector3(0, c, 0));
    nodePositions.push_back(btVector3(x, z, 0));
    nodePositions.push_back(btVector3(b+a/2, 0, 0));
    nodePositions.push_back(btVector3(a/2 + sigma, -ulna_diameter, 0));
    nodePositions.push_back(btVector3(a/2 + sigma + e, -ulna_diameter, 0));
    nodePositions.push_back(btVector3(0, c+5, f));
    nodePositions.push_back(btVector3(0, c+5, -f));

    for(size_t i=0;i<nNodes;i++) {
		s.addNode(nodePositions[i][0],nodePositions[i][1],nodePositions[i][2]);
    }
}

void ScarrArmModel::addRods(tgStructure& s)
{
    // ulna
    s.addPair(0,  1,  "rod");
    s.addPair(0,  8,  "rod");
    s.addPair(1,  2,  "rod");

    // humerus
    s.addPair(3,  5,  "rod");
    s.addPair(4,  5,  "rod");
    s.addPair(5,  6,  "rod");

    //radius
    s.addPair(9, 10,  "rod");

    // massless support beam
    s.addPair(11, 12, "massless");
}

/*
void ScarrArmModel::addMarkers(tgStructure &s)
{
    std::vector<tgRod *> rods=find<tgRod>("rod");

	for(int i=0;i<10;i++)
	{
		const btRigidBody* bt = rods[rodNumbersPerNode[i]]->getPRigidBody();
		btTransform inverseTransform = bt->getWorldTransform().inverse();
		btVector3 pos = inverseTransform * (nodePositions[i]);
		abstractMarker tmp=abstractMarker(bt,pos,btVector3(0.08*i,1.0 - 0.08*i,.0),i);
		this->addMarker(tmp);
	}
}
*/

void ScarrArmModel::addMuscles(tgStructure& s)
{
    const std::vector<tgStructure*> children = s.getChildren();

    s.addPair(0, 3, "olecranon muscle"); //NB actually fascial tissue
    s.addPair(0, 4, "olecranon muscle"); //NB actually fascial tissue
    s.addPair(1, 3, "olecranon muscle"); //NB actually fascial tissue
    s.addPair(1, 4, "olecranon muscle"); //NB actually fascial tissue
    s.addPair(2, 3, "olecranon muscle"); //NB actually fascial tissue
    s.addPair(2, 4, "olecranon muscle"); //NB actually fascial tissue
    s.addPair(3, 9, "anconeus muscle");
    //s.addPair(4, 9, "muscle");
    //s.addPair(5, 7, "muscle");
    //s.addPair(6, 7, "muscle");
    //s.addPair(7, 8, "muscle");
    s.addPair(5, 8, "brachioradialis muscle");
    s.addPair(8, 10, "ulnaradius muscle");  //NB not a true muscle

    //Muscles to massless rod
    s.addPair(6, 11, "support muscle");
    s.addPair(6, 12, "support muscle");
}

void ScarrArmModel::setup(tgWorld& world)
{
    const tgRod::Config rodConfig(c.radius, c.density, c.friction, c.rollFriction, c.restitution);
    const tgRod::Config rodConfigMassless(c.radius, 0.00/*c.density*/, c.friction, c.rollFriction, c.restitution);
    /// @todo acceleration constraint was removed on 12/10/14 Replace with tgKinematicActuator as appropreate

    tgBasicActuator::Config olecranonMuscleConfig(c.stiffness, c.damping, c.pretension_olecranon, c.history, c.maxTens, c.targetVelocity);
    tgBasicActuator::Config anconeusMuscleConfig(c.stiffness, c.damping, c.pretension_anconeus, c.history, c.maxTens, c.targetVelocity);
    tgBasicActuator::Config brachioradialisMuscleConfig(c.stiffness, c.damping, c.pretension_brachioradialis, c.history, c.maxTens, c.targetVelocity);
    tgBasicActuator::Config ulnaradiusMuscleConfig(c.stiffness, c.damping, c.pretension_ulnaradius, c.history, c.maxTens, c.targetVelocity);
    tgBasicActuator::Config supportstringMuscleConfig(c.stiffness, c.damping, c.pretension_support, c.history, c.maxTens, c.targetVelocity);

    // Start creating the structure
    tgStructure s;
    addNodes(s);
    addRods(s);
    addMuscles(s);

    // Move the arm out of the ground
    btVector3 offset(0.0, 20.0, 0.0);
    s.move(offset);

    // Create the build spec that uses tags to turn the structure into a real model
    tgBuildSpec spec;
    spec.addBuilder("massless", new tgRodInfo(rodConfigMassless));
    spec.addBuilder("rod", new tgRodInfo(rodConfig));
    spec.addBuilder("olecranon muscle", new tgBasicActuatorInfo(olecranonMuscleConfig));
    spec.addBuilder("anconeus muscle", new tgBasicActuatorInfo(anconeusMuscleConfig));
    spec.addBuilder("brachioradialis muscle", new tgBasicActuatorInfo(brachioradialisMuscleConfig));
    spec.addBuilder("ulnaradius muscle", new tgBasicActuatorInfo(ulnaradiusMuscleConfig));
    spec.addBuilder("support muscle", new tgBasicActuatorInfo(supportstringMuscleConfig));

    // Create your structureInfo
    tgStructureInfo structureInfo(s, spec);

    // Use the structureInfo to build ourselves
    structureInfo.buildInto(*this, world);

    // We could now use tgCast::filter or similar to pull out the
    // models (e.g. muscles) that we want to control.
    allMuscles = tgCast::filter<tgModel, tgBasicActuator> (getDescendants());

    // call the onSetup methods of all observed things e.g. controllers
    notifySetup();

    // Actually setup the children
    tgModel::setup(world);

    //map the rods and add the markers to them
    //addMarkers(s);

}

void ScarrArmModel::step(double dt)
{
    // Precondition
    if (dt <= 0.0) {
        throw std::invalid_argument("dt is not positive");
    } else {
        // Notify observers (controllers) of the step so that they can take action
        notifyStep(dt);
        tgModel::step(dt);  // Step any children
    }
}

void ScarrArmModel::onVisit(tgModelVisitor& r)
{
    tgModel::onVisit(r);
}

const std::vector<tgBasicActuator*>& ScarrArmModel::getAllMuscles() const
{
    return allMuscles;
}

void ScarrArmModel::teardown()
{
    tgModel::teardown();
}

<commit_msg>Updated lengths<commit_after>/*
 * Copyright © 2015, United States Government, as represented by the
 * Administrator of the National Aeronautics and Space Administration.
 * All rights reserved.
 *
 * The NASA Tensegrity Robotics Toolkit (NTRT) v1 platform is licensed
 * under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
*/

/**
 * @file ScarrArmModel.cpp
 * @brief Contains the implementation of class ScarrArmModel.
 * Measurements are scaled to average adult male
 * $Id$
 */

// This module
#include "ScarrArmModel.h"
// This library
#include "core/tgBasicActuator.h"
#include "core/tgRod.h"
#include "core/abstractMarker.h"
#include "tgcreator/tgBuildSpec.h"
#include "tgcreator/tgBasicActuatorInfo.h"
#include "tgcreator/tgRodInfo.h"
#include "tgcreator/tgStructure.h"
#include "tgcreator/tgStructureInfo.h"
// The Bullet Physics library
#include "LinearMath/btVector3.h"
// The C++ Standard Library
#include <stdexcept>

namespace
{
    // see tgBaseString.h for a descripton of some of these rod parameters
    // (specifically, those related to the motor moving the strings.)
    // NOTE that any parameter that depends on units of length will scale
    // with the current gravity scaling. E.g., with gravity as 98.1,
    // the length units below are in decimeters.

    // Note: This current model of the SUPERball rod is 1.5m long by 3 cm radius,
    // which is 0.00424 m^3.
    // For SUPERball v1.5, mass = 3.5kg per strut, which comes out to
    // 0.825 kg / (decimeter^3).

    // similarly, frictional parameters are for the tgRod objects.
    const struct Config
    {
        double density;
        double radius;
        double stiffness;
        double damping;
        double rod_length;
        double rod_space;
        double friction;
        double rollFriction;
        double restitution;
        double pretension_olecranon;
        double pretension_anconeus;
        double pretension_brachioradialis;
        double pretension_ulnaradius;
        double pretension_support;
        bool   history;
        double maxTens;
        double targetVelocity;
    } c =
   {
     0.825,    // density (kg / length^3)
     0.31,     // radius (length)
     3000.0,   // stiffness (kg / sec^2)
     200.0,    // damping (kg / sec)
     15.0,     // rod_length (length)
     7.5,      // rod_space (length)
     1.0,      // friction (unitless)
     0.01,     // rollFriction (unitless)
     0.2,      // restitution (?)
     3000.0/15.55,   // pretension_olecranon (force), stiffness/initial length
     3000.0/15.55,   // pretension_anconeus (force), stiffness/initial length
     3000.0/262,     // pretension_brachioradialis (force), stiffness/initial length
     3000.0/1,        // pretension_ulnaradius (force), stiffness/initial length
     3000.0/1,        // pretension_support (force), stiffness/initial length
     false,    // history (boolean)
     100000,   // maxTens
     10000    // targetVelocity
#if (0)
     20000     // maxAcc
#endif
     // Use the below values for earlier versions of simulation.
     // 1.006,
     // 0.31,
     // 300000.0,
     // 3000.0,
     // 15.0,
     // 7.5,
  };
} // namespace

/*
 * helper arrays for node and rod numbering schema
 */
/*returns the number of the rod for a given node */
//const int rodNumbersPerNode[11]={0,1,2,3,3,4,0,1,2,5,5,4,6};

/*returns the node that is at the other end of the given node */
//const int otherEndOfTheRod[11]={6,7,8,4,3,11,0,1,2,10,9,5,12};

/*returns the node that is at the parallel rod
 * and at the same end of the given node
 */
//const int parallelNode[11]={1,0,5,9,10,2,7,6,11,3,4,8,12};

ScarrArmModel::ScarrArmModel() : tgModel()
{
}

ScarrArmModel::~ScarrArmModel()
{
}

void ScarrArmModel::addNodes(tgStructure& s)
{
    const double scale = 0.5;
    const double bone_scale = 0.5;
    const size_t nNodes = 11 + 2; //2 for massless rod

    // Average Adult Male Measurements with scale
    // Lengths are in mm
    const double a = 22 * scale; //ulnta distal width
    const double b = 265 * scale * bone_scale; //ulna length
    const double c = 334 * scale * bone_scale; //humerus length
    const double d = 66 * scale; // humerus epicondylar width
    const double e = 246 * scale * bone_scale; //radius length
    const double f = 25 * scale; // humerus head radius
    const double g = 17 * scale; //ulna proximal width
    const double sigma = 10 * scale; // gap from end of radius to olecranon TODO: tinker
    const double ulna_diameter = g; //TODO: tinker
    const double x = a/2;
    const double z = c/2;

    nodePositions.push_back(btVector3(a/2, 0, 0));
    nodePositions.push_back(btVector3(0, -g, 0));
    nodePositions.push_back(btVector3(-a/2, 0, 0));
    nodePositions.push_back(btVector3(0, 0, f));
    nodePositions.push_back(btVector3(0, 0, -f));
    nodePositions.push_back(btVector3(0, d, 0));
    nodePositions.push_back(btVector3(0, c, 0));
    nodePositions.push_back(btVector3(x, z, 0));
    nodePositions.push_back(btVector3(b+a/2, 0, 0));
    nodePositions.push_back(btVector3(a/2 + sigma, -ulna_diameter, 0));
    nodePositions.push_back(btVector3(a/2 + sigma + e, -ulna_diameter, 0));
    nodePositions.push_back(btVector3(0, c+5, f));
    nodePositions.push_back(btVector3(0, c+5, -f));

    for(size_t i=0;i<nNodes;i++) {
		s.addNode(nodePositions[i][0],nodePositions[i][1],nodePositions[i][2]);
    }
}

void ScarrArmModel::addRods(tgStructure& s)
{
    // ulna
    s.addPair(0,  1,  "rod");
    s.addPair(0,  8,  "rod");
    s.addPair(1,  2,  "rod");

    // humerus
    s.addPair(3,  5,  "rod");
    s.addPair(4,  5,  "rod");
    s.addPair(5,  6,  "rod");

    //radius
    s.addPair(9, 10,  "rod");

    // massless support beam
    s.addPair(11, 12, "massless");
}

/*
void ScarrArmModel::addMarkers(tgStructure &s)
{
    std::vector<tgRod *> rods=find<tgRod>("rod");

	for(int i=0;i<10;i++)
	{
		const btRigidBody* bt = rods[rodNumbersPerNode[i]]->getPRigidBody();
		btTransform inverseTransform = bt->getWorldTransform().inverse();
		btVector3 pos = inverseTransform * (nodePositions[i]);
		abstractMarker tmp=abstractMarker(bt,pos,btVector3(0.08*i,1.0 - 0.08*i,.0),i);
		this->addMarker(tmp);
	}
}
*/

void ScarrArmModel::addMuscles(tgStructure& s)
{
    const std::vector<tgStructure*> children = s.getChildren();

    s.addPair(0, 3, "olecranon muscle"); //NB actually fascial tissue
    s.addPair(0, 4, "olecranon muscle"); //NB actually fascial tissue
    s.addPair(1, 3, "olecranon muscle"); //NB actually fascial tissue
    s.addPair(1, 4, "olecranon muscle"); //NB actually fascial tissue
    s.addPair(2, 3, "olecranon muscle"); //NB actually fascial tissue
    s.addPair(2, 4, "olecranon muscle"); //NB actually fascial tissue
    s.addPair(3, 9, "anconeus muscle");
    //s.addPair(4, 9, "muscle");
    //s.addPair(5, 7, "muscle");
    //s.addPair(6, 7, "muscle");
    //s.addPair(7, 8, "muscle");
    s.addPair(5, 8, "brachioradialis muscle");
    s.addPair(8, 10, "ulnaradius muscle");  //NB not a true muscle

    //Muscles to massless rod
    s.addPair(6, 11, "support muscle");
    s.addPair(6, 12, "support muscle");
}

void ScarrArmModel::setup(tgWorld& world)
{
    const tgRod::Config rodConfig(c.radius, c.density, c.friction, c.rollFriction, c.restitution);
    const tgRod::Config rodConfigMassless(c.radius, 0.00/*c.density*/, c.friction, c.rollFriction, c.restitution);
    /// @todo acceleration constraint was removed on 12/10/14 Replace with tgKinematicActuator as appropreate

    tgBasicActuator::Config olecranonMuscleConfig(c.stiffness, c.damping, c.pretension_olecranon, c.history, c.maxTens, c.targetVelocity);
    tgBasicActuator::Config anconeusMuscleConfig(c.stiffness, c.damping, c.pretension_anconeus, c.history, c.maxTens, c.targetVelocity);
    tgBasicActuator::Config brachioradialisMuscleConfig(c.stiffness, c.damping, c.pretension_brachioradialis, c.history, c.maxTens, c.targetVelocity);
    tgBasicActuator::Config ulnaradiusMuscleConfig(c.stiffness, c.damping, c.pretension_ulnaradius, c.history, c.maxTens, c.targetVelocity);
    tgBasicActuator::Config supportstringMuscleConfig(c.stiffness, c.damping, c.pretension_support, c.history, c.maxTens, c.targetVelocity);

    // Start creating the structure
    tgStructure s;
    addNodes(s);
    addRods(s);
    addMuscles(s);

    // Move the arm out of the ground
    btVector3 offset(0.0, 10.0, 0.0);
    s.move(offset);

    // Create the build spec that uses tags to turn the structure into a real model
    tgBuildSpec spec;
    spec.addBuilder("massless", new tgRodInfo(rodConfigMassless));
    spec.addBuilder("rod", new tgRodInfo(rodConfig));
    spec.addBuilder("olecranon muscle", new tgBasicActuatorInfo(olecranonMuscleConfig));
    spec.addBuilder("anconeus muscle", new tgBasicActuatorInfo(anconeusMuscleConfig));
    spec.addBuilder("brachioradialis muscle", new tgBasicActuatorInfo(brachioradialisMuscleConfig));
    spec.addBuilder("ulnaradius muscle", new tgBasicActuatorInfo(ulnaradiusMuscleConfig));
    spec.addBuilder("support muscle", new tgBasicActuatorInfo(supportstringMuscleConfig));

    // Create your structureInfo
    tgStructureInfo structureInfo(s, spec);

    // Use the structureInfo to build ourselves
    structureInfo.buildInto(*this, world);

    // We could now use tgCast::filter or similar to pull out the
    // models (e.g. muscles) that we want to control.
    allMuscles = tgCast::filter<tgModel, tgBasicActuator> (getDescendants());

    // call the onSetup methods of all observed things e.g. controllers
    notifySetup();

    // Actually setup the children
    tgModel::setup(world);

    //map the rods and add the markers to them
    //addMarkers(s);

}

void ScarrArmModel::step(double dt)
{
    // Precondition
    if (dt <= 0.0) {
        throw std::invalid_argument("dt is not positive");
    } else {
        // Notify observers (controllers) of the step so that they can take action
        notifyStep(dt);
        tgModel::step(dt);  // Step any children
    }
}

void ScarrArmModel::onVisit(tgModelVisitor& r)
{
    tgModel::onVisit(r);
}

const std::vector<tgBasicActuator*>& ScarrArmModel::getAllMuscles() const
{
    return allMuscles;
}

void ScarrArmModel::teardown()
{
    tgModel::teardown();
}

<|endoftext|>


<commit_before>/**
 * @file mult_div_update_rules.hpp
 * @author Mohan Rajendran
 *
 * Update rules for the Non-negative Matrix Factorization. This follows a method
 * described in the paper 'Algorithms for Non-negative Matrix Factorization'
 * by D. D. Lee and H. S. Seung. This is a multiplicative rule that ensures
 * that the Kullback–Leibler divergence
 * \f$ \sum_i \sum_j (V_{ij} log\frac{V_{ij}}{(WH)_{ij}}-V_{ij}+(WH)_{ij}) \f$is
 * non-increasing between subsequent iterations. Both of the update rules
 * for W and H are defined in this file.
 */
#ifndef __MLPACK_METHODS_NMF_MULT_DIV_UPDATE_RULES_HPP
#define __MLPACK_METHODS_NMF_MULT_DIV_UPDATE_RULES_HPP

#include <mlpack/core.hpp>

namespace mlpack {
namespace nmf {

/**
 * The update rule for the basis matrix W. The formula used is
 * \f[
 * W_{ia} \leftarrow W_{ia} \frac{\sum_{\mu} H_{a\mu} V_{i\mu}/(WH)_{i\mu}}
 * {\sum_{\nu} H_{a\nu}}
 * \f]
 */
class WMultiplicativeDivergenceRule
{
 public:
  // Empty constructor required for the WUpdateRule template.
  WMultiplicativeDivergenceRule() { }

  /**
   * The update function that actually updates the W matrix. The function takes
   * in all the matrices and only changes the value of the W matrix.
   *
   * @param V Input matrix to be factorized.
   * @param W Basis matrix to be updated.
   * @param H Encoding matrix.
   */
  template<typename MatType>
  inline static void Update(const MatType& V,
                            arma::mat& W,
                            const arma::mat& H)
  {
    // Simple implementation left in the header file.
    arma::mat t1;
    arma::rowvec t2;

    t1 = W * H;
    for (size_t i = 0; i < W.n_rows; ++i)
    {
      for (size_t j = 0; j < W.n_cols; ++j)
      {
        // Writing this as a single expression does not work as of Armadillo
        // 3.920.  This should be fixed in a future release, and then the code
        // below can be fixed.
        //t2 = H.row(j) % V.row(i) / t1.row(i);
        t2.set_size(H.n_cols);
        for (size_t k = 0; k < t2.n_elem; ++k)
        {
          // This may produce NaNs if V(i, k) = 0.
          // Technically the math in the paper does not define what to do in
          // this case, but considering the basic intent of the update rules,
          // we'll make this modification and take t2(k) = 0.0.
          t2(k) = H(j, k) * V(i, k) / t1(i, k);
          if (t2(k) != t2(k))
            t2(k) = 0.0;
        }

        // Only update if the sum is not going to be 0, so as to prevent a
        // divide by zero.  If sum(H.row(j)) is 0, then t2 should be 0 too.
        W(i, j) *= sum(t2) / sum(H.row(j));
      }
    }
  }
};

/**
 * The update rule for the encoding matrix H. The formula used is
 * \f[
 * H_{a\mu} \leftarrow H_{a\mu} \frac{\sum_{i} W_{ia} V_{i\mu}/(WH)_{i\mu}}
 * {\sum_{k} H_{ka}}
 * \f]
 */
class HMultiplicativeDivergenceRule
{
 public:
  // Empty constructor required for the HUpdateRule template.
  HMultiplicativeDivergenceRule() { }

  /**
   * The update function that actually updates the H matrix. The function takes
   * in all the matrices and only changes the value of the H matrix.
   *
   * @param V Input matrix to be factorized.
   * @param W Basis matrix.
   * @param H Encoding matrix to updated.
   */
  template<typename MatType>
  inline static void Update(const MatType& V,
                            const arma::mat& W,
                            arma::mat& H)
  {
    // Simple implementation left in the header file.
    arma::mat t1;
    arma::colvec t2;

    t1 = W * H;
    for (size_t i = 0; i < H.n_rows; i++)
    {
      for (size_t j = 0; j < H.n_cols; j++)
      {
        // Writing this as a single expression does not work as of Armadillo
        // 3.920.  This should be fixed in a future release, and then the code
        // below can be fixed.
        //t2 = W.col(i) % V.col(j) / t1.col(j);
        t2.set_size(W.n_rows);
        for (size_t k = 0; k < t2.n_elem; ++k)
        {
          // This may produce NaNs if V(i, k) = 0.
          // Technically the math in the paper does not define what to do in
          // this case, but considering the basic intent of the update rules,
          // we'll make this modification and take t2(k) = 0.0.
          t2(k) = W(k, i) * V(k, j) / t1(k, j);
          if (t2(k) != t2(k))
            t2(k) = 0.0;
        }

        // Only update if the sum is not going to be 0, so as to prevent a
        // divide by zero.  If sum(W.col(j)) is 0, then t2 should be 0 too.
        H(i, j) *= sum(t2) / sum(W.col(i));
      }
    }
  }
};

}; // namespace nmf
}; // namespace mlpack

#endif
<commit_msg>Remove incorrect comments.<commit_after>/**
 * @file mult_div_update_rules.hpp
 * @author Mohan Rajendran
 *
 * Update rules for the Non-negative Matrix Factorization. This follows a method
 * described in the paper 'Algorithms for Non-negative Matrix Factorization'
 * by D. D. Lee and H. S. Seung. This is a multiplicative rule that ensures
 * that the Kullback–Leibler divergence
 * \f$ \sum_i \sum_j (V_{ij} log\frac{V_{ij}}{(WH)_{ij}}-V_{ij}+(WH)_{ij}) \f$is
 * non-increasing between subsequent iterations. Both of the update rules
 * for W and H are defined in this file.
 */
#ifndef __MLPACK_METHODS_NMF_MULT_DIV_UPDATE_RULES_HPP
#define __MLPACK_METHODS_NMF_MULT_DIV_UPDATE_RULES_HPP

#include <mlpack/core.hpp>

namespace mlpack {
namespace nmf {

/**
 * The update rule for the basis matrix W. The formula used is
 * \f[
 * W_{ia} \leftarrow W_{ia} \frac{\sum_{\mu} H_{a\mu} V_{i\mu}/(WH)_{i\mu}}
 * {\sum_{\nu} H_{a\nu}}
 * \f]
 */
class WMultiplicativeDivergenceRule
{
 public:
  // Empty constructor required for the WUpdateRule template.
  WMultiplicativeDivergenceRule() { }

  /**
   * The update function that actually updates the W matrix. The function takes
   * in all the matrices and only changes the value of the W matrix.
   *
   * @param V Input matrix to be factorized.
   * @param W Basis matrix to be updated.
   * @param H Encoding matrix.
   */
  template<typename MatType>
  inline static void Update(const MatType& V,
                            arma::mat& W,
                            const arma::mat& H)
  {
    // Simple implementation left in the header file.
    arma::mat t1;
    arma::rowvec t2;

    t1 = W * H;
    for (size_t i = 0; i < W.n_rows; ++i)
    {
      for (size_t j = 0; j < W.n_cols; ++j)
      {
        // Writing this as a single expression does not work as of Armadillo
        // 3.920.  This should be fixed in a future release, and then the code
        // below can be fixed.
        //t2 = H.row(j) % V.row(i) / t1.row(i);
        t2.set_size(H.n_cols);
        for (size_t k = 0; k < t2.n_elem; ++k)
        {
          // This may produce NaNs if V(i, k) = 0.
          // Technically the math in the paper does not define what to do in
          // this case, but considering the basic intent of the update rules,
          // we'll make this modification and take t2(k) = 0.0.
          t2(k) = H(j, k) * V(i, k) / t1(i, k);
          if (t2(k) != t2(k))
            t2(k) = 0.0;
        }

        W(i, j) *= sum(t2) / sum(H.row(j));
      }
    }
  }
};

/**
 * The update rule for the encoding matrix H. The formula used is
 * \f[
 * H_{a\mu} \leftarrow H_{a\mu} \frac{\sum_{i} W_{ia} V_{i\mu}/(WH)_{i\mu}}
 * {\sum_{k} H_{ka}}
 * \f]
 */
class HMultiplicativeDivergenceRule
{
 public:
  // Empty constructor required for the HUpdateRule template.
  HMultiplicativeDivergenceRule() { }

  /**
   * The update function that actually updates the H matrix. The function takes
   * in all the matrices and only changes the value of the H matrix.
   *
   * @param V Input matrix to be factorized.
   * @param W Basis matrix.
   * @param H Encoding matrix to updated.
   */
  template<typename MatType>
  inline static void Update(const MatType& V,
                            const arma::mat& W,
                            arma::mat& H)
  {
    // Simple implementation left in the header file.
    arma::mat t1;
    arma::colvec t2;

    t1 = W * H;
    for (size_t i = 0; i < H.n_rows; i++)
    {
      for (size_t j = 0; j < H.n_cols; j++)
      {
        // Writing this as a single expression does not work as of Armadillo
        // 3.920.  This should be fixed in a future release, and then the code
        // below can be fixed.
        //t2 = W.col(i) % V.col(j) / t1.col(j);
        t2.set_size(W.n_rows);
        for (size_t k = 0; k < t2.n_elem; ++k)
        {
          // This may produce NaNs if V(i, k) = 0.
          // Technically the math in the paper does not define what to do in
          // this case, but considering the basic intent of the update rules,
          // we'll make this modification and take t2(k) = 0.0.
          t2(k) = W(k, i) * V(k, j) / t1(k, j);
          if (t2(k) != t2(k))
            t2(k) = 0.0;
        }

        H(i, j) *= sum(t2) / sum(W.col(i));
      }
    }
  }
};

}; // namespace nmf
}; // namespace mlpack

#endif
<|endoftext|>