<commit_before>/*
    open source routing machine
    Copyright (C) Dennis Luxen, others 2010

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
any later version.

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

You should have received a copy of the GNU Affero General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
or see http://www.gnu.org/licenses/agpl.txt.
 */

#include "DataStructures/QueryEdge.h"
#include "DataStructures/SharedMemoryFactory.h"
#include "DataStructures/SharedMemoryVectorWrapper.h"
#include "DataStructures/StaticGraph.h"
#include "DataStructures/StaticRTree.h"
#include "Server/DataStructures/BaseDataFacade.h"
#include "Server/DataStructures/SharedDataType.h"
#include "Util/BoostFileSystemFix.h"
#include "Util/IniFile.h"
#include "Util/SimpleLogger.h"
#include "Util/UUID.h"
#include "typedefs.h"

#include <boost/integer.hpp>
#include <boost/filesystem/fstream.hpp>

#include <string>
#include <vector>

int main(int argc, char * argv[]) {
    try {
        LogPolicy::GetInstance().Unmute();
        SimpleLogger().Write() << "Checking input parameters";

        boost::filesystem::path base_path = boost::filesystem::absolute(
            (argc > 1 ? argv[1] : "server.ini")
        ).parent_path();
        IniFile server_config((argc > 1 ? argv[1] : "server.ini"));
        //check contents of config file
        if ( !server_config.Holds("hsgrData")) {
            throw OSRMException("no ram index file name in server ini");
        }
        if ( !server_config.Holds("ramIndex") ) {
            throw OSRMException("no mem index file name in server ini");
        }
        if ( !server_config.Holds("nodesData") ) {
            throw OSRMException("no nodes file name in server ini");
        }
        if ( !server_config.Holds("edgesData") ) {
            throw OSRMException("no edges file name in server ini");
        }

        //generate paths of data files
        boost::filesystem::path hsgr_path = boost::filesystem::absolute(
                server_config.GetParameter("hsgrData"),
                base_path
        );
        boost::filesystem::path ram_index_path = boost::filesystem::absolute(
                server_config.GetParameter("ramIndex"),
                base_path
        );
        boost::filesystem::path node_data_path = boost::filesystem::absolute(
                server_config.GetParameter("nodesData"),
                base_path
        );
        boost::filesystem::path edge_data_path = boost::filesystem::absolute(
                server_config.GetParameter("edgesData"),
                base_path
        );
        boost::filesystem::path name_data_path = boost::filesystem::absolute(
                server_config.GetParameter("namesData"),
                base_path
        );
        boost::filesystem::path timestamp_path = boost::filesystem::absolute(
                server_config.GetParameter("timestamp"),
                base_path
        );

        //check if data files actually exist
        if ( !boost::filesystem::exists(hsgr_path) ) {
            throw(".hsgr not found");
        }
        if ( !boost::filesystem::exists(ram_index_path) ) {
            throw(".ramIndex not found");
        }
        if ( !boost::filesystem::exists(node_data_path) ) {
            throw(".nodes not found");
        }
        if ( !boost::filesystem::exists(edge_data_path) ) {
            throw(".edges not found");
        }
        if ( !boost::filesystem::exists(name_data_path) ) {
            throw(".names not found");
        }

        // check if data files empty
        if ( 0 == boost::filesystem::file_size( node_data_path ) ) {
            throw OSRMException("nodes file is empty");
        }
        if ( 0 == boost::filesystem::file_size( edge_data_path ) ) {
            throw OSRMException("edges file is empty");
        }

        // Allocate a memory layout in shared memory //
          SharedMemory * layout_memory = SharedMemoryFactory::Get(
            LAYOUT_1,
            sizeof(SharedDataLayout)
        );
        SharedDataLayout * shared_layout_ptr = static_cast<SharedDataLayout *>(
            layout_memory->Ptr()
        );
        shared_layout_ptr = new(layout_memory->Ptr()) SharedDataLayout();

        //                                                             //
        // collect number of elements to store in shared memory object //
        //                                                             //
        SimpleLogger().Write() << "Collecting files sizes";
        // number of entries in name index
        boost::filesystem::ifstream name_stream(
            name_data_path, std::ios::binary
        );
        unsigned name_index_size = 0;
        name_stream.read((char *)&name_index_size, sizeof(unsigned));
        shared_layout_ptr->name_index_list_size = name_index_size;
        // SimpleLogger().Write() << "name index size: " << shared_layout_ptr->name_index_list_size;
        BOOST_ASSERT_MSG(0 != shared_layout_ptr->name_index_list_size, "name file broken");

        unsigned number_of_chars = 0;
        name_stream.read((char *)&number_of_chars, sizeof(unsigned));
        shared_layout_ptr->name_char_list_size = number_of_chars;
        // SimpleLogger().Write() << "name char size: " << shared_layout_ptr->name_char_list_size;

        //Loading information for original edges
        boost::filesystem::ifstream edges_input_stream(
            edge_data_path,
            std::ios::binary
        );
        unsigned number_of_original_edges = 0;
        edges_input_stream.read((char*)&number_of_original_edges, sizeof(unsigned));
        SimpleLogger().Write(logDEBUG) <<
            "number of edges: " << number_of_original_edges;

        shared_layout_ptr->via_node_list_size = number_of_original_edges;
        shared_layout_ptr->name_id_list_size = number_of_original_edges;
        shared_layout_ptr->turn_instruction_list_size = number_of_original_edges;

        SimpleLogger().Write(logDEBUG) << "noted number of edges";

        SimpleLogger().Write(logDEBUG) << "loading hsgr from " << hsgr_path.string();
        boost::filesystem::ifstream hsgr_input_stream(
            hsgr_path,
            std::ios::binary
        );

        UUID uuid_loaded, uuid_orig;
        hsgr_input_stream.read((char *)&uuid_loaded, sizeof(UUID));
        if( !uuid_loaded.TestGraphUtil(uuid_orig) ) {
            SimpleLogger().Write(logWARNING) <<
                ".hsgr was prepared with different build. "
                "Reprocess to get rid of this warning.";
        } else {
            SimpleLogger().Write() << "UUID checked out ok";
        }

        // load checksum
        unsigned checksum = 0;
        hsgr_input_stream.read((char*)&checksum, sizeof(unsigned) );
        SimpleLogger().Write() << "checksum: " << checksum;
        shared_layout_ptr->checksum = checksum;
        SimpleLogger().Write(logDEBUG) << "noted checksum";
        // load graph node size
        unsigned number_of_graph_nodes = 0;
        hsgr_input_stream.read(
            (char*) &number_of_graph_nodes,
            sizeof(unsigned)
        );
        SimpleLogger().Write(logDEBUG) << "number of nodes: " << number_of_graph_nodes;
        BOOST_ASSERT_MSG(
            (0 != number_of_graph_nodes),
            "number of nodes is zero"
        );
        shared_layout_ptr->graph_node_list_size = number_of_graph_nodes;

        // load graph edge size
        unsigned number_of_graph_edges = 0;
        hsgr_input_stream.read( (char*) &number_of_graph_edges, sizeof(unsigned) );
        SimpleLogger().Write() << "number of graph edges: " << number_of_graph_edges;
        BOOST_ASSERT_MSG( 0 != number_of_graph_edges, "number of graph edges is zero");
        shared_layout_ptr->graph_edge_list_size = number_of_graph_edges;

        // load rsearch tree size
        SimpleLogger().Write(logDEBUG) << "loading r-tree search list size";
        boost::filesystem::ifstream tree_node_file(
            ram_index_path,
            std::ios::binary
        );

        uint32_t tree_size = 0;
        tree_node_file.read((char*)&tree_size, sizeof(uint32_t));
        shared_layout_ptr->r_search_tree_size = tree_size;

        //load timestamp size
        SimpleLogger().Write(logDEBUG) << "Loading timestamp";
        std::string m_timestamp;
        if( boost::filesystem::exists(timestamp_path) ) {
            boost::filesystem::ifstream timestampInStream( timestamp_path );
            if(!timestampInStream) {
                SimpleLogger().Write(logWARNING) << timestamp_path << " not found";
            }
            getline(timestampInStream, m_timestamp);
            timestampInStream.close();
        }
        if(m_timestamp.empty()) {
            m_timestamp = "n/a";
        }
        if(25 < m_timestamp.length()) {
            m_timestamp.resize(25);
        }
        shared_layout_ptr->timestamp_length = m_timestamp.length();

        //load coordinate size
        SimpleLogger().Write() <<
            "Loading coordinates list from " << node_data_path.string();
        boost::filesystem::ifstream nodes_input_stream(
            node_data_path,
            std::ios::binary
        );
        unsigned coordinate_list_size = 0;
        nodes_input_stream.read((char *)&coordinate_list_size, sizeof(unsigned));
        shared_layout_ptr->coordinate_list_size = coordinate_list_size;

        // allocate shared memory block
        SimpleLogger().Write() << "allocating shared memory of " << shared_layout_ptr->GetSizeOfLayout() << " bytes";
        SharedMemory * shared_memory = SharedMemoryFactory::Get(
            DATA_1,
            shared_layout_ptr->GetSizeOfLayout()
        );
        char * shared_memory_ptr = static_cast<char *>(shared_memory->Ptr());

        // read actual data into shared memory object //
        // Loading street names
        SimpleLogger().Write() << "Loading names index and chars from: " << name_data_path.string();
        unsigned * name_index_ptr = (unsigned*)(
            shared_memory_ptr + shared_layout_ptr->GetNameIndexOffset()
        );
        SimpleLogger().Write(logDEBUG) << "Bytes: " << shared_layout_ptr->name_index_list_size*sizeof(unsigned);

        name_stream.read(
            (char*)name_index_ptr,
            shared_layout_ptr->name_index_list_size*sizeof(unsigned)
        );

        SimpleLogger().Write(logDEBUG) << "Loading names char list";
        SimpleLogger().Write(logDEBUG) << "Bytes: " << shared_layout_ptr->name_char_list_size*sizeof(char);
        char * name_char_ptr = shared_memory_ptr + shared_layout_ptr->GetNameListOffset();
        name_stream.read(
            name_char_ptr,
            shared_layout_ptr->name_char_list_size*sizeof(char)
        );
        name_stream.close();

        //load original edge information
        SimpleLogger().Write() <<
            "Loading via node, coordinates and turn instruction lists from: " <<
            edge_data_path.string();

        NodeID * via_node_ptr = (NodeID *)(
            shared_memory_ptr + shared_layout_ptr->GetViaNodeListOffset()
        );

        unsigned * name_id_ptr = (unsigned *)(
            shared_memory_ptr + shared_layout_ptr->GetNameIDListOffset()
        );

        TurnInstruction * turn_instructions_ptr = (TurnInstruction *)(
            shared_memory_ptr + shared_layout_ptr->GetTurnInstructionListOffset()
        );

        OriginalEdgeData current_edge_data;
        for(unsigned i = 0; i < number_of_original_edges; ++i) {
            // SimpleLogger().Write() << i << "/" << number_of_edges;
            edges_input_stream.read(
                (char*)&(current_edge_data),
                sizeof(OriginalEdgeData)
            );
            via_node_ptr[i] = current_edge_data.viaNode;
            name_id_ptr[i]  = current_edge_data.nameID;
            turn_instructions_ptr[i] = current_edge_data.turnInstruction;
        }
        edges_input_stream.close();

        // Loading list of coordinates
        FixedPointCoordinate * coordinates_ptr = (FixedPointCoordinate *)(
            shared_memory_ptr + shared_layout_ptr->GetCoordinateListOffset()
        );

        NodeInfo current_node;
        for(unsigned i = 0; i < coordinate_list_size; ++i) {
            nodes_input_stream.read((char *)&current_node, sizeof(NodeInfo));
            coordinates_ptr[i] = FixedPointCoordinate(current_node.lat, current_node.lon);
        }
        nodes_input_stream.close();

        //store timestamp
        char * timestamp_ptr = static_cast<char *>(
            shared_memory_ptr + shared_layout_ptr->GetTimeStampOffset()
        );
        std::copy(
            m_timestamp.c_str(),
            m_timestamp.c_str()+m_timestamp.length(),
            timestamp_ptr
        );

        // store search tree portion of rtree
        char * rtree_ptr = static_cast<char *>(
            shared_memory_ptr + shared_layout_ptr->GetRSearchTreeOffset()
        );

        tree_node_file.read(rtree_ptr, sizeof(RTreeNode)*tree_size);
        tree_node_file.close();

        // load the nodes of the search graph
        QueryGraph::_StrNode * graph_node_list_ptr = (QueryGraph::_StrNode*)(
            shared_memory_ptr + shared_layout_ptr->GetGraphNodeListOffset()
        );
        hsgr_input_stream.read(
            (char*) graph_node_list_ptr,
            shared_layout_ptr->graph_node_list_size*sizeof(QueryGraph::_StrNode)
        );

        // load the edges of the search graph
        QueryGraph::_StrEdge * graph_edge_list_ptr = (QueryGraph::_StrEdge *)(
            shared_memory_ptr + shared_layout_ptr->GetGraphEdgeListOffsett()
        );
        hsgr_input_stream.read(
            (char*) graph_edge_list_ptr,
            shared_layout_ptr->graph_edge_list_size*sizeof(QueryGraph::_StrEdge)
        );
        hsgr_input_stream.close();

        SimpleLogger().Write() << "all data loaded. pressing a key deallocates memory";
        std::cin.get();

    } catch(const std::exception & e) {
        SimpleLogger().Write(logWARNING) << "caught exception: " << e.what();
    }

    return 0;
}
<commit_msg>use program options in data store tool<commit_after>/*
    open source routing machine
    Copyright (C) Dennis Luxen, others 2010

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
any later version.

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

You should have received a copy of the GNU Affero General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
or see http://www.gnu.org/licenses/agpl.txt.
 */

#include "DataStructures/QueryEdge.h"
#include "DataStructures/SharedMemoryFactory.h"
#include "DataStructures/SharedMemoryVectorWrapper.h"
#include "DataStructures/StaticGraph.h"
#include "DataStructures/StaticRTree.h"
#include "Server/DataStructures/BaseDataFacade.h"
#include "Server/DataStructures/SharedDataType.h"
#include "Util/BoostFileSystemFix.h"
#include "Util/ProgramOptions.h"
#include "Util/SimpleLogger.h"
#include "Util/UUID.h"
#include "typedefs.h"

#include <boost/integer.hpp>
#include <boost/filesystem/fstream.hpp>

#include <string>
#include <vector>

int main( const int argc, const char * argv[] ) {
    try {
        LogPolicy::GetInstance().Unmute();
        SimpleLogger().Write() << "Checking input parameters";

        bool use_shared_memory = false;
        std::string ip_address;
        int ip_port, requested_num_threads;

        ServerPaths server_paths;
        if( !GenerateServerProgramOptions(
                argc,
                argv,
                server_paths,
                ip_address,
                ip_port,
                requested_num_threads,
                use_shared_memory
             )
        ) {
            return 0;
        }
        if( server_paths.find("hsgrdata") == server_paths.end() ) {
            throw OSRMException("no hsgr file given in ini file");
        }
        if( server_paths.find("ramindex") == server_paths.end() ) {
            throw OSRMException("no ram index file given in ini file");
        }
        if( server_paths.find("fileindex") == server_paths.end() ) {
            throw OSRMException("no leaf index file given in ini file");
        }
        if( server_paths.find("nodesdata") == server_paths.end() ) {
            throw OSRMException("no nodes file given in ini file");
        }
        if( server_paths.find("edgesdata") == server_paths.end() ) {
            throw OSRMException("no edges file given in ini file");
        }
        if( server_paths.find("namesdata") == server_paths.end() ) {
            throw OSRMException("no names file given in ini file");
        }

        ServerPaths::const_iterator paths_iterator = server_paths.find("hsgrdata");
        BOOST_ASSERT(server_paths.end() != paths_iterator);
        const boost::filesystem::path & hsgr_path = paths_iterator->second;
        paths_iterator = server_paths.find("timestamp");
        BOOST_ASSERT(server_paths.end() != paths_iterator);
        const boost::filesystem::path & timestamp_path = paths_iterator->second;
        paths_iterator = server_paths.find("ramindex");
        BOOST_ASSERT(server_paths.end() != paths_iterator);
        const boost::filesystem::path & ram_index_path = paths_iterator->second;
        // paths_iterator = server_paths.find("fileindex");
        // BOOST_ASSERT(server_paths.end() != paths_iterator);
        // const boost::filesystem::path & file_index_path = paths_iterator->second;
        paths_iterator = server_paths.find("nodesdata");
        BOOST_ASSERT(server_paths.end() != paths_iterator);
        const boost::filesystem::path & nodes_data_path = paths_iterator->second;
        paths_iterator = server_paths.find("edgesdata");
        BOOST_ASSERT(server_paths.end() != paths_iterator);
        const boost::filesystem::path & edges_data_path = paths_iterator->second;
        paths_iterator = server_paths.find("namesdata");
        BOOST_ASSERT(server_paths.end() != paths_iterator);
        const boost::filesystem::path & names_data_path = paths_iterator->second;

        // Allocate a memory layout in shared memory //
          SharedMemory * layout_memory = SharedMemoryFactory::Get(
            LAYOUT_1,
            sizeof(SharedDataLayout)
        );
        SharedDataLayout * shared_layout_ptr = static_cast<SharedDataLayout *>(
            layout_memory->Ptr()
        );
        shared_layout_ptr = new(layout_memory->Ptr()) SharedDataLayout();

        //                                                             //
        // collect number of elements to store in shared memory object //
        //                                                             //
        SimpleLogger().Write() << "Collecting files sizes";
        // number of entries in name index
        boost::filesystem::ifstream name_stream(
            names_data_path, std::ios::binary
        );
        unsigned name_index_size = 0;
        name_stream.read((char *)&name_index_size, sizeof(unsigned));
        shared_layout_ptr->name_index_list_size = name_index_size;
        // SimpleLogger().Write() << "name index size: " << shared_layout_ptr->name_index_list_size;
        BOOST_ASSERT_MSG(0 != shared_layout_ptr->name_index_list_size, "name file broken");

        unsigned number_of_chars = 0;
        name_stream.read((char *)&number_of_chars, sizeof(unsigned));
        shared_layout_ptr->name_char_list_size = number_of_chars;
        // SimpleLogger().Write() << "name char size: " << shared_layout_ptr->name_char_list_size;

        //Loading information for original edges
        boost::filesystem::ifstream edges_input_stream(
            edges_data_path,
            std::ios::binary
        );
        unsigned number_of_original_edges = 0;
        edges_input_stream.read((char*)&number_of_original_edges, sizeof(unsigned));
        SimpleLogger().Write(logDEBUG) <<
            "number of edges: " << number_of_original_edges;

        shared_layout_ptr->via_node_list_size = number_of_original_edges;
        shared_layout_ptr->name_id_list_size = number_of_original_edges;
        shared_layout_ptr->turn_instruction_list_size = number_of_original_edges;

        SimpleLogger().Write(logDEBUG) << "noted number of edges";

        SimpleLogger().Write(logDEBUG) << "loading hsgr from " << hsgr_path.string();
        boost::filesystem::ifstream hsgr_input_stream(
            hsgr_path,
            std::ios::binary
        );

        UUID uuid_loaded, uuid_orig;
        hsgr_input_stream.read((char *)&uuid_loaded, sizeof(UUID));
        if( !uuid_loaded.TestGraphUtil(uuid_orig) ) {
            SimpleLogger().Write(logWARNING) <<
                ".hsgr was prepared with different build. "
                "Reprocess to get rid of this warning.";
        } else {
            SimpleLogger().Write() << "UUID checked out ok";
        }

        // load checksum
        unsigned checksum = 0;
        hsgr_input_stream.read((char*)&checksum, sizeof(unsigned) );
        SimpleLogger().Write() << "checksum: " << checksum;
        shared_layout_ptr->checksum = checksum;
        SimpleLogger().Write(logDEBUG) << "noted checksum";
        // load graph node size
        unsigned number_of_graph_nodes = 0;
        hsgr_input_stream.read(
            (char*) &number_of_graph_nodes,
            sizeof(unsigned)
        );
        SimpleLogger().Write(logDEBUG) << "number of nodes: " << number_of_graph_nodes;
        BOOST_ASSERT_MSG(
            (0 != number_of_graph_nodes),
            "number of nodes is zero"
        );
        shared_layout_ptr->graph_node_list_size = number_of_graph_nodes;

        // load graph edge size
        unsigned number_of_graph_edges = 0;
        hsgr_input_stream.read( (char*) &number_of_graph_edges, sizeof(unsigned) );
        SimpleLogger().Write() << "number of graph edges: " << number_of_graph_edges;
        BOOST_ASSERT_MSG( 0 != number_of_graph_edges, "number of graph edges is zero");
        shared_layout_ptr->graph_edge_list_size = number_of_graph_edges;

        // load rsearch tree size
        SimpleLogger().Write(logDEBUG) << "loading r-tree search list size";
        boost::filesystem::ifstream tree_node_file(
            ram_index_path,
            std::ios::binary
        );

        uint32_t tree_size = 0;
        tree_node_file.read((char*)&tree_size, sizeof(uint32_t));
        shared_layout_ptr->r_search_tree_size = tree_size;

        //load timestamp size
        SimpleLogger().Write(logDEBUG) << "Loading timestamp";
        std::string m_timestamp;
        if( boost::filesystem::exists(timestamp_path) ) {
            boost::filesystem::ifstream timestampInStream( timestamp_path );
            if(!timestampInStream) {
                SimpleLogger().Write(logWARNING) << timestamp_path << " not found";
            }
            getline(timestampInStream, m_timestamp);
            timestampInStream.close();
        }
        if(m_timestamp.empty()) {
            m_timestamp = "n/a";
        }
        if(25 < m_timestamp.length()) {
            m_timestamp.resize(25);
        }
        shared_layout_ptr->timestamp_length = m_timestamp.length();

        //load coordinate size
        SimpleLogger().Write() <<
            "Loading coordinates list from " << nodes_data_path.string();
        boost::filesystem::ifstream nodes_input_stream(
            nodes_data_path,
            std::ios::binary
        );
        unsigned coordinate_list_size = 0;
        nodes_input_stream.read((char *)&coordinate_list_size, sizeof(unsigned));
        shared_layout_ptr->coordinate_list_size = coordinate_list_size;

        // allocate shared memory block
        SimpleLogger().Write() << "allocating shared memory of " << shared_layout_ptr->GetSizeOfLayout() << " bytes";
        SharedMemory * shared_memory = SharedMemoryFactory::Get(
            DATA_1,
            shared_layout_ptr->GetSizeOfLayout()
        );
        char * shared_memory_ptr = static_cast<char *>(shared_memory->Ptr());

        // read actual data into shared memory object //
        // Loading street names
        SimpleLogger().Write() << "Loading names index and chars from: " << names_data_path.string();
        unsigned * name_index_ptr = (unsigned*)(
            shared_memory_ptr + shared_layout_ptr->GetNameIndexOffset()
        );
        SimpleLogger().Write(logDEBUG) << "Bytes: " << shared_layout_ptr->name_index_list_size*sizeof(unsigned);

        name_stream.read(
            (char*)name_index_ptr,
            shared_layout_ptr->name_index_list_size*sizeof(unsigned)
        );

        SimpleLogger().Write(logDEBUG) << "Loading names char list";
        SimpleLogger().Write(logDEBUG) << "Bytes: " << shared_layout_ptr->name_char_list_size*sizeof(char);
        char * name_char_ptr = shared_memory_ptr + shared_layout_ptr->GetNameListOffset();
        name_stream.read(
            name_char_ptr,
            shared_layout_ptr->name_char_list_size*sizeof(char)
        );
        name_stream.close();

        //load original edge information
        SimpleLogger().Write() <<
            "Loading via node, coordinates and turn instruction lists from: " <<
            edges_data_path.string();

        NodeID * via_node_ptr = (NodeID *)(
            shared_memory_ptr + shared_layout_ptr->GetViaNodeListOffset()
        );

        unsigned * name_id_ptr = (unsigned *)(
            shared_memory_ptr + shared_layout_ptr->GetNameIDListOffset()
        );

        TurnInstruction * turn_instructions_ptr = (TurnInstruction *)(
            shared_memory_ptr + shared_layout_ptr->GetTurnInstructionListOffset()
        );

        OriginalEdgeData current_edge_data;
        for(unsigned i = 0; i < number_of_original_edges; ++i) {
            // SimpleLogger().Write() << i << "/" << number_of_edges;
            edges_input_stream.read(
                (char*)&(current_edge_data),
                sizeof(OriginalEdgeData)
            );
            via_node_ptr[i] = current_edge_data.viaNode;
            name_id_ptr[i]  = current_edge_data.nameID;
            turn_instructions_ptr[i] = current_edge_data.turnInstruction;
        }
        edges_input_stream.close();

        // Loading list of coordinates
        FixedPointCoordinate * coordinates_ptr = (FixedPointCoordinate *)(
            shared_memory_ptr + shared_layout_ptr->GetCoordinateListOffset()
        );

        NodeInfo current_node;
        for(unsigned i = 0; i < coordinate_list_size; ++i) {
            nodes_input_stream.read((char *)&current_node, sizeof(NodeInfo));
            coordinates_ptr[i] = FixedPointCoordinate(current_node.lat, current_node.lon);
        }
        nodes_input_stream.close();

        //store timestamp
        char * timestamp_ptr = static_cast<char *>(
            shared_memory_ptr + shared_layout_ptr->GetTimeStampOffset()
        );
        std::copy(
            m_timestamp.c_str(),
            m_timestamp.c_str()+m_timestamp.length(),
            timestamp_ptr
        );

        // store search tree portion of rtree
        char * rtree_ptr = static_cast<char *>(
            shared_memory_ptr + shared_layout_ptr->GetRSearchTreeOffset()
        );

        tree_node_file.read(rtree_ptr, sizeof(RTreeNode)*tree_size);
        tree_node_file.close();

        // load the nodes of the search graph
        QueryGraph::_StrNode * graph_node_list_ptr = (QueryGraph::_StrNode*)(
            shared_memory_ptr + shared_layout_ptr->GetGraphNodeListOffset()
        );
        hsgr_input_stream.read(
            (char*) graph_node_list_ptr,
            shared_layout_ptr->graph_node_list_size*sizeof(QueryGraph::_StrNode)
        );

        // load the edges of the search graph
        QueryGraph::_StrEdge * graph_edge_list_ptr = (QueryGraph::_StrEdge *)(
            shared_memory_ptr + shared_layout_ptr->GetGraphEdgeListOffsett()
        );
        hsgr_input_stream.read(
            (char*) graph_edge_list_ptr,
            shared_layout_ptr->graph_edge_list_size*sizeof(QueryGraph::_StrEdge)
        );
        hsgr_input_stream.close();

        SimpleLogger().Write() << "all data loaded. pressing a key deallocates memory";
        std::cin.get();

    } catch(const std::exception & e) {
        SimpleLogger().Write(logWARNING) << "caught exception: " << e.what();
    }

    return 0;
}
<|endoftext|>


<commit_before>/* Copyright (c) 2011 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any purpose
 * with or without fee is hereby granted, provided that the above copyright
 * notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR ANY
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "BenchUtil.h"
#include "ServiceManager.h"

namespace RAMCloud {
/**
 * Default object used to make system calls.
 */
static Syscall defaultSyscall;

/**
 * Used by this class to make all system calls.  In normal production
 * use it points to defaultSyscall; for testing it points to a mock
 * object.
 */
Syscall* ServiceManager::sys = &defaultSyscall;

ServiceManager* ServiceManager::serviceManager = NULL;

// Pick a polling period that's much longer than typical RPC round-trip
// times (so the worker thread doesn't go to sleep in an ongoing conversation
// with a single client).
int ServiceManager::pollMicros = 100;

// The following constant is used to signal a worker thread that
// it should exit.
#define WORKER_EXIT reinterpret_cast<Transport::ServerRpc*>(1)

/**
 * Construct a ServiceManager.
 *
 * \param service
 *      Service that will execute all incoming RPCs.  Eventually this class
 *      needs to support multiple services of different types.  In test mode
 *      this is NULL; see documentation for #service member for details.
 */
ServiceManager::ServiceManager(Service* service)
    : service(service), worker(service), waitingRpcs()
{
    serviceManager = this;
    worker.thread.construct(workerMain, &worker);
}

/**
 * Destroy a ServiceManager.  This method is most commonly invoked during
 * testing (ServiceManagers rarely, if ever, get deleted in normal operation).
 */
ServiceManager::~ServiceManager()
{
    if (serviceManager == this) {
        serviceManager = NULL;
    }
    worker.exit();
}

/**
 * Transports invoke this method when an incoming RPC is complete and
 * ready for processing.  This method will arrange for the RPC (eventually)
 * to be serviced, and will invoke its #sendReply method once the RPC
 * has been serviced.
 *
 * \param rpc
 *      RPC object containing a fully-formed request that is ready for
 *      service.
 */
void
ServiceManager::handleRpc(Transport::ServerRpc* rpc)
{
    if (!serviceManager->worker.idle
            || (serviceManager->service == NULL)) {
        // Worker thread is busy: save this RPC for execution later.
        serviceManager->waitingRpcs.push(rpc);
    } else {
        // The worker thread is available: hand off the RPC.
        serviceManager->worker.handoff(rpc);
    }
}

/**
 * Returns true if there are currently no RPCs being serviced, false
 * if at least one RPC is currently being executed by a worker.
 */
bool
ServiceManager::idle()
{
    return serviceManager->worker.idle;
}

/**
 * This method is invoked by Dispatch during its polling loop.  It checks
 * for completion of outstanding RPCs.
 */
void
ServiceManager::poll()
{
    if (worker.idle) {
        // Quick shortcut for the common case.
        return;
    }
    int state = worker.state.load();
    if (state == Worker::WORKING) {
        return;
    }

    // The worker is either post-processing or idle; in either case, if
    // there is an RPC that we haven't yet responded to, respond now.
    if (worker.rpc != NULL) {
        worker.rpc->sendReply();
        worker.rpc = NULL;
    }

    // If the worker is idle and there are waiting RPCs, start the next one.
    if (state != Worker::POSTPROCESSING) {
        worker.idle = true;
        if (!waitingRpcs.empty()) {
            worker.handoff(waitingRpcs.front());
            waitingRpcs.pop();
        }
    }
}

/**
 * Wait for an RPC request to arrive, but give up if it takes too long.
 * This method is intended only for testing (it assumes that a NULL
 * service was specified in the constructor).
 *
 * \param timeoutSeconds
 *      If a request doesn't arrive within this many seconds, return NULL.
 *
 * \result
 *      The incoming RPC request, or NULL if nothing arrived within the time
 *      limit.
 */
Transport::ServerRpc*
ServiceManager::waitForRpc(double timeoutSeconds) {
    uint64_t start = rdtsc();
    while (true) {
        if (!waitingRpcs.empty()) {
            Transport::ServerRpc* result = waitingRpcs.front();
            waitingRpcs.pop();
            return result;
        }
        if (cyclesToSeconds(rdtsc() - start) > timeoutSeconds) {
            return NULL;
        }
        dispatch->poll();
    }
}

/**
 * This is the top-level method for worker threads.  It repeatedly waits for
 * an RPC to be assigned to it, then executes that RPC and communicates its
 * completion back to the dispatch thread.
 *
 * \param worker
 *      Pointer to information used to communicate between the worker thread
 *      and the dispatch thread.
 */
void
ServiceManager::workerMain(Worker* worker)
{
    uint64_t pollCycles = nanosecondsToCycles(1000*pollMicros);
    while (true) {
        uint64_t stopPollingTime = dispatch->currentTime + pollCycles;

        // Wait for ServiceManager to supply us with some work to do.
        while (worker->state.load() != Worker::WORKING) {
            if (dispatch->currentTime >= stopPollingTime) {
                // It's been a long time since we've had any work to do; go
                // to sleep so we don't waste any more CPU cycles.  Tricky
                // race condition: the dispatch thread could change the state
                // to WORKING just before we change it to SLEEPING, so use an
                // atomic op and only change to SLEEPING if the current value
                // is POLLING.
                int expected = Worker::POLLING;
                if (worker->state.compare_exchange_weak(expected,
                        Worker::SLEEPING)) {
                    if (sys->futexWait(reinterpret_cast<int*>(&worker->state),
                            Worker::SLEEPING) == -1) {
                        // EWOULDBLOCK means that someone already changed
                        // worker->state, so we didn't block; this is benign.
                        if (errno != EWOULDBLOCK) {
                            LOG(ERROR, "futexWait failed in ServiceManager::"
                                    "workerMain: %s", strerror(errno));
                        }
                    }
                }
            }
            // Empty loop body.
        }
        if (worker->rpc == WORKER_EXIT)
            break;

        Service::Rpc rpc(worker, worker->rpc->requestPayload,
                worker->rpc->replyPayload);
        worker->service->handleRpc(rpc);

        // Pass the RPC back to ServiceManager for completion.
        worker->state.store(Worker::POLLING);
    }
    TEST_LOG("exiting");
}

/**
 * Force this worker's thread to exit (and don't return until it has exited).
 * This method is only used during testing and ServiceManager destruction.
 * This method should be invoked only in the dispatch thread.
 */
void
Worker::exit()
{
    assert(dispatch->isDispatchThread());
    if (exited) {
        // Worker already exited; nothing to do.  This should only happen
        // during tests.
        return;
    }

    // Wait for the worker thread to finish handling any RPCs already
    // queued for it.
    while (!idle) {
        dispatch->poll();
    }

    // Tell the worker thread to exit, and wait for it to actually exit
    // (don't want it referencing the Worker structure anymore, since
    // it could go away).
    handoff(WORKER_EXIT);
    thread->join();
    rpc = NULL;
    idle = true;
    exited = true;
}

/**
 * This method is invoked by the dispatch thread to pass an RPC to an idle
 * worker.  It should only be invoked when the worker is idle (i.e. #rpc is
 * NULL).
 *
 * \param newRpc
 *      RPC object containing a fully-formed request that is ready for
 *      service.
 */
void
Worker::handoff(Transport::ServerRpc* newRpc)
{
    assert(rpc == NULL);
    assert(idle);
    rpc = newRpc;
    int prevState = state.exchange(WORKING);
    if (prevState == SLEEPING) {
        // The worker got tired of polling and went to sleep, so we
        // have to do extra work to wake it up.
        if (ServiceManager::sys->futexWake(reinterpret_cast<int*>(&state), 1)
                == -1) {
            LOG(ERROR,
                    "futexWake failed in Worker::handoff: %s",
                    strerror(errno));
        }
    }
    idle = false;
}

/**
 * Tell the dispatch thread that this worker has finished processing its RPC,
 * so it is safe to start sending the reply.  This method should only be
 * invoked in the worker thread.
 */
void
Worker::sendReply()
{
    state.store(POSTPROCESSING);
}

} // namespace RAMCloud
<commit_msg>Change worker threads to log fatal exceptions<commit_after>/* Copyright (c) 2011 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any purpose
 * with or without fee is hereby granted, provided that the above copyright
 * notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR ANY
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "BenchUtil.h"
#include "ServiceManager.h"

namespace RAMCloud {
/**
 * Default object used to make system calls.
 */
static Syscall defaultSyscall;

/**
 * Used by this class to make all system calls.  In normal production
 * use it points to defaultSyscall; for testing it points to a mock
 * object.
 */
Syscall* ServiceManager::sys = &defaultSyscall;

ServiceManager* ServiceManager::serviceManager = NULL;

// Pick a polling period that's much longer than typical RPC round-trip
// times (so the worker thread doesn't go to sleep in an ongoing conversation
// with a single client).
int ServiceManager::pollMicros = 100;

// The following constant is used to signal a worker thread that
// it should exit.
#define WORKER_EXIT reinterpret_cast<Transport::ServerRpc*>(1)

/**
 * Construct a ServiceManager.
 *
 * \param service
 *      Service that will execute all incoming RPCs.  Eventually this class
 *      needs to support multiple services of different types.  In test mode
 *      this is NULL; see documentation for #service member for details.
 */
ServiceManager::ServiceManager(Service* service)
    : service(service), worker(service), waitingRpcs()
{
    serviceManager = this;
    worker.thread.construct(workerMain, &worker);
}

/**
 * Destroy a ServiceManager.  This method is most commonly invoked during
 * testing (ServiceManagers rarely, if ever, get deleted in normal operation).
 */
ServiceManager::~ServiceManager()
{
    if (serviceManager == this) {
        serviceManager = NULL;
    }
    worker.exit();
}

/**
 * Transports invoke this method when an incoming RPC is complete and
 * ready for processing.  This method will arrange for the RPC (eventually)
 * to be serviced, and will invoke its #sendReply method once the RPC
 * has been serviced.
 *
 * \param rpc
 *      RPC object containing a fully-formed request that is ready for
 *      service.
 */
void
ServiceManager::handleRpc(Transport::ServerRpc* rpc)
{
    if (!serviceManager->worker.idle
            || (serviceManager->service == NULL)) {
        // Worker thread is busy: save this RPC for execution later.
        serviceManager->waitingRpcs.push(rpc);
    } else {
        // The worker thread is available: hand off the RPC.
        serviceManager->worker.handoff(rpc);
    }
}

/**
 * Returns true if there are currently no RPCs being serviced, false
 * if at least one RPC is currently being executed by a worker.
 */
bool
ServiceManager::idle()
{
    return serviceManager->worker.idle;
}

/**
 * This method is invoked by Dispatch during its polling loop.  It checks
 * for completion of outstanding RPCs.
 */
void
ServiceManager::poll()
{
    if (worker.idle) {
        // Quick shortcut for the common case.
        return;
    }
    int state = worker.state.load();
    if (state == Worker::WORKING) {
        return;
    }

    // The worker is either post-processing or idle; in either case, if
    // there is an RPC that we haven't yet responded to, respond now.
    if (worker.rpc != NULL) {
        worker.rpc->sendReply();
        worker.rpc = NULL;
    }

    // If the worker is idle and there are waiting RPCs, start the next one.
    if (state != Worker::POSTPROCESSING) {
        worker.idle = true;
        if (!waitingRpcs.empty()) {
            worker.handoff(waitingRpcs.front());
            waitingRpcs.pop();
        }
    }
}

/**
 * Wait for an RPC request to arrive, but give up if it takes too long.
 * This method is intended only for testing (it assumes that a NULL
 * service was specified in the constructor).
 *
 * \param timeoutSeconds
 *      If a request doesn't arrive within this many seconds, return NULL.
 *
 * \result
 *      The incoming RPC request, or NULL if nothing arrived within the time
 *      limit.
 */
Transport::ServerRpc*
ServiceManager::waitForRpc(double timeoutSeconds) {
    uint64_t start = rdtsc();
    while (true) {
        if (!waitingRpcs.empty()) {
            Transport::ServerRpc* result = waitingRpcs.front();
            waitingRpcs.pop();
            return result;
        }
        if (cyclesToSeconds(rdtsc() - start) > timeoutSeconds) {
            return NULL;
        }
        dispatch->poll();
    }
}

/**
 * This is the top-level method for worker threads.  It repeatedly waits for
 * an RPC to be assigned to it, then executes that RPC and communicates its
 * completion back to the dispatch thread.
 *
 * \param worker
 *      Pointer to information used to communicate between the worker thread
 *      and the dispatch thread.
 */
void
ServiceManager::workerMain(Worker* worker)
try {
    uint64_t pollCycles = nanosecondsToCycles(1000*pollMicros);
    while (true) {
        uint64_t stopPollingTime = dispatch->currentTime + pollCycles;

        // Wait for ServiceManager to supply us with some work to do.
        while (worker->state.load() != Worker::WORKING) {
            if (dispatch->currentTime >= stopPollingTime) {
                // It's been a long time since we've had any work to do; go
                // to sleep so we don't waste any more CPU cycles.  Tricky
                // race condition: the dispatch thread could change the state
                // to WORKING just before we change it to SLEEPING, so use an
                // atomic op and only change to SLEEPING if the current value
                // is POLLING.
                int expected = Worker::POLLING;
                if (worker->state.compare_exchange_weak(expected,
                        Worker::SLEEPING)) {
                    if (sys->futexWait(reinterpret_cast<int*>(&worker->state),
                            Worker::SLEEPING) == -1) {
                        // EWOULDBLOCK means that someone already changed
                        // worker->state, so we didn't block; this is benign.
                        if (errno != EWOULDBLOCK) {
                            LOG(ERROR, "futexWait failed in ServiceManager::"
                                    "workerMain: %s", strerror(errno));
                        }
                    }
                }
            }
            // Empty loop body.
        }
        if (worker->rpc == WORKER_EXIT)
            break;

        Service::Rpc rpc(worker, worker->rpc->requestPayload,
                worker->rpc->replyPayload);
        worker->service->handleRpc(rpc);

        // Pass the RPC back to ServiceManager for completion.
        worker->state.store(Worker::POLLING);
    }
    TEST_LOG("exiting");
} catch (std::exception& e) {
    using namespace RAMCloud;
    LOG(ERROR, "worker: %s", e.what());
    throw; // will likely call std::terminate()
}

/**
 * Force this worker's thread to exit (and don't return until it has exited).
 * This method is only used during testing and ServiceManager destruction.
 * This method should be invoked only in the dispatch thread.
 */
void
Worker::exit()
{
    assert(dispatch->isDispatchThread());
    if (exited) {
        // Worker already exited; nothing to do.  This should only happen
        // during tests.
        return;
    }

    // Wait for the worker thread to finish handling any RPCs already
    // queued for it.
    while (!idle) {
        dispatch->poll();
    }

    // Tell the worker thread to exit, and wait for it to actually exit
    // (don't want it referencing the Worker structure anymore, since
    // it could go away).
    handoff(WORKER_EXIT);
    thread->join();
    rpc = NULL;
    idle = true;
    exited = true;
}

/**
 * This method is invoked by the dispatch thread to pass an RPC to an idle
 * worker.  It should only be invoked when the worker is idle (i.e. #rpc is
 * NULL).
 *
 * \param newRpc
 *      RPC object containing a fully-formed request that is ready for
 *      service.
 */
void
Worker::handoff(Transport::ServerRpc* newRpc)
{
    assert(rpc == NULL);
    assert(idle);
    rpc = newRpc;
    int prevState = state.exchange(WORKING);
    if (prevState == SLEEPING) {
        // The worker got tired of polling and went to sleep, so we
        // have to do extra work to wake it up.
        if (ServiceManager::sys->futexWake(reinterpret_cast<int*>(&state), 1)
                == -1) {
            LOG(ERROR,
                    "futexWake failed in Worker::handoff: %s",
                    strerror(errno));
        }
    }
    idle = false;
}

/**
 * Tell the dispatch thread that this worker has finished processing its RPC,
 * so it is safe to start sending the reply.  This method should only be
 * invoked in the worker thread.
 */
void
Worker::sendReply()
{
    state.store(POSTPROCESSING);
}

} // namespace RAMCloud
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */

/*
 * $Id$
 */

#include <xercesc/framework/psvi/XSWildcard.hpp>
#include <xercesc/framework/psvi/XSModel.hpp>
#include <xercesc/util/ValueVectorOf.hpp>
#include <xercesc/util/StringPool.hpp>
#include <xercesc/validators/common/ContentSpecNode.hpp>
#include <xercesc/validators/schema/SchemaAttDef.hpp>

XERCES_CPP_NAMESPACE_BEGIN

// ---------------------------------------------------------------------------
//  XSWildcard: Constructors and Destructor
// ---------------------------------------------------------------------------
XSWildcard::XSWildcard(SchemaAttDef* const  attWildCard,
                       XSAnnotation* const  annot,
                       XSModel* const       xsModel,
                       MemoryManager* const manager)
    : XSObject(XSConstants::WILDCARD, xsModel, manager)
    , fConstraintType(NSCONSTRAINT_ANY)
    , fProcessContents(PC_STRICT)
    , fNsConstraintList(0)
    , fAnnotation(annot)
{
    XMLAttDef::AttTypes attType = attWildCard->getType();
    if (attType == XMLAttDef::Any_Other)
    {
        fConstraintType = NSCONSTRAINT_NOT;
        fNsConstraintList = new (manager) RefArrayVectorOf<XMLCh>(1, true, manager);
        fNsConstraintList->addElement
        (
            XMLString::replicate(fXSModel->getURIStringPool()->getValueForId(
                    attWildCard->getAttName()->getURI()), manager)
        );
    }
    else if (attType == XMLAttDef::Any_List)
    {
        fConstraintType = NSCONSTRAINT_DERIVATION_LIST;
        ValueVectorOf<unsigned int>* nsList = attWildCard->getNamespaceList();
        if (nsList)
        {
            unsigned int nsListSize = nsList->size();
            if (nsListSize)
            {
                fNsConstraintList = new (manager) RefArrayVectorOf<XMLCh>(nsListSize, true, manager);
                for (unsigned int i=0; i < nsListSize; i++)
                {
                    fNsConstraintList->addElement
                    (
                        XMLString::replicate
                        (
                            fXSModel->getURIStringPool()->getValueForId
                            (
                                nsList->elementAt(i)
                            )
                            , manager
                        )
                    );
                }
            }
        }
    }

    XMLAttDef::DefAttTypes attDefType = attWildCard->getDefaultType();
    if (attDefType == XMLAttDef::ProcessContents_Skip)
        fProcessContents = PC_SKIP;
    else if (attDefType == XMLAttDef::ProcessContents_Lax)
        fProcessContents = PC_LAX;
}

XSWildcard::XSWildcard(const ContentSpecNode* const elmWildCard,
                       XSAnnotation* const annot,
                       XSModel* const xsModel,
                       MemoryManager* const manager)
    : XSObject(XSConstants::WILDCARD, xsModel, manager)
    , fConstraintType(NSCONSTRAINT_ANY)
    , fProcessContents(PC_STRICT)
    , fNsConstraintList(0)
    , fAnnotation(annot)
{
    ContentSpecNode::NodeTypes nodeType = elmWildCard->getType();
    if ((nodeType & 0x0f) == ContentSpecNode::Any_Other)
    {
        fConstraintType = NSCONSTRAINT_NOT;
        if (nodeType == ContentSpecNode::Any_Other_Lax)
            fProcessContents = PC_LAX;
        else if (nodeType == ContentSpecNode::Any_Other_Skip)
            fProcessContents = PC_SKIP;
    }
    else if ((nodeType & 0x0f) == ContentSpecNode::Any_NS)
    {
        fConstraintType = NSCONSTRAINT_DERIVATION_LIST;
        if (nodeType == ContentSpecNode::Any_NS_Lax)
            fProcessContents = PC_LAX;
        else if (nodeType == ContentSpecNode::Any_NS_Skip)
            fProcessContents = PC_SKIP;
    }
    else if (nodeType == ContentSpecNode::Any_NS_Choice)
    {
        fConstraintType = NSCONSTRAINT_DERIVATION_LIST;
        ContentSpecNode::NodeTypes anyType = elmWildCard->getFirst()->getType();

        if (anyType == ContentSpecNode::Any_NS_Lax)
            fProcessContents = PC_LAX;
        else if (anyType == ContentSpecNode::Any_NS_Skip)
            fProcessContents = PC_SKIP;

        fNsConstraintList = new (manager) RefArrayVectorOf<XMLCh>(4, true, manager);
        buildNamespaceList(elmWildCard);
    }
    // must be any
    else
    {
        if (nodeType == ContentSpecNode::Any_Lax)
            fProcessContents = PC_LAX;
        else if (nodeType == ContentSpecNode::Any_Skip)
            fProcessContents = PC_SKIP;
    }

    if (fConstraintType == NSCONSTRAINT_NOT
        || (fConstraintType == NSCONSTRAINT_DERIVATION_LIST
            && !fNsConstraintList))
    {
        fNsConstraintList = new (manager) RefArrayVectorOf<XMLCh>(1, true, manager);
        fNsConstraintList->addElement
        (
             XMLString::replicate(fXSModel->getURIStringPool()->getValueForId(
                     elmWildCard->getElement()->getURI()), manager)
        );
    }
}

XSWildcard::~XSWildcard()
{
    if (fNsConstraintList)
        delete fNsConstraintList;
}

// ---------------------------------------------------------------------------
//  XSWildcard: helper methods
// ---------------------------------------------------------------------------
void XSWildcard::buildNamespaceList(const ContentSpecNode* const rootNode)
{
    ContentSpecNode::NodeTypes nodeType = rootNode->getType();
    if (nodeType == ContentSpecNode::Any_NS_Choice)
    {
        buildNamespaceList(rootNode->getFirst());
        buildNamespaceList(rootNode->getSecond());
    }
    else
    {
        fNsConstraintList->addElement
        (
            XMLString::replicate(fXSModel->getURIStringPool()->getValueForId(
                    rootNode->getElement()->getURI()), fMemoryManager)
        );
    }
}

XERCES_CPP_NAMESPACE_END
<commit_msg>XSWildcard was always getting a 'strict' processContent when the namespace list contained more than 2 elements<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */

/*
 * $Id$
 */

#include <xercesc/framework/psvi/XSWildcard.hpp>
#include <xercesc/framework/psvi/XSModel.hpp>
#include <xercesc/util/ValueVectorOf.hpp>
#include <xercesc/util/StringPool.hpp>
#include <xercesc/validators/common/ContentSpecNode.hpp>
#include <xercesc/validators/schema/SchemaAttDef.hpp>

XERCES_CPP_NAMESPACE_BEGIN

// ---------------------------------------------------------------------------
//  XSWildcard: Constructors and Destructor
// ---------------------------------------------------------------------------
XSWildcard::XSWildcard(SchemaAttDef* const  attWildCard,
                       XSAnnotation* const  annot,
                       XSModel* const       xsModel,
                       MemoryManager* const manager)
    : XSObject(XSConstants::WILDCARD, xsModel, manager)
    , fConstraintType(NSCONSTRAINT_ANY)
    , fProcessContents(PC_STRICT)
    , fNsConstraintList(0)
    , fAnnotation(annot)
{
    XMLAttDef::AttTypes attType = attWildCard->getType();
    if (attType == XMLAttDef::Any_Other)
    {
        fConstraintType = NSCONSTRAINT_NOT;
        fNsConstraintList = new (manager) RefArrayVectorOf<XMLCh>(1, true, manager);
        fNsConstraintList->addElement
        (
            XMLString::replicate(fXSModel->getURIStringPool()->getValueForId(
                    attWildCard->getAttName()->getURI()), manager)
        );
    }
    else if (attType == XMLAttDef::Any_List)
    {
        fConstraintType = NSCONSTRAINT_DERIVATION_LIST;
        ValueVectorOf<unsigned int>* nsList = attWildCard->getNamespaceList();
        if (nsList)
        {
            unsigned int nsListSize = nsList->size();
            if (nsListSize)
            {
                fNsConstraintList = new (manager) RefArrayVectorOf<XMLCh>(nsListSize, true, manager);
                for (unsigned int i=0; i < nsListSize; i++)
                {
                    fNsConstraintList->addElement
                    (
                        XMLString::replicate
                        (
                            fXSModel->getURIStringPool()->getValueForId
                            (
                                nsList->elementAt(i)
                            )
                            , manager
                        )
                    );
                }
            }
        }
    }

    XMLAttDef::DefAttTypes attDefType = attWildCard->getDefaultType();
    if (attDefType == XMLAttDef::ProcessContents_Skip)
        fProcessContents = PC_SKIP;
    else if (attDefType == XMLAttDef::ProcessContents_Lax)
        fProcessContents = PC_LAX;
}

XSWildcard::XSWildcard(const ContentSpecNode* const elmWildCard,
                       XSAnnotation* const annot,
                       XSModel* const xsModel,
                       MemoryManager* const manager)
    : XSObject(XSConstants::WILDCARD, xsModel, manager)
    , fConstraintType(NSCONSTRAINT_ANY)
    , fProcessContents(PC_STRICT)
    , fNsConstraintList(0)
    , fAnnotation(annot)
{
    ContentSpecNode::NodeTypes nodeType = elmWildCard->getType();
    if ((nodeType & 0x0f) == ContentSpecNode::Any_Other)
    {
        fConstraintType = NSCONSTRAINT_NOT;
        if (nodeType == ContentSpecNode::Any_Other_Lax)
            fProcessContents = PC_LAX;
        else if (nodeType == ContentSpecNode::Any_Other_Skip)
            fProcessContents = PC_SKIP;
    }
    else if ((nodeType & 0x0f) == ContentSpecNode::Any_NS)
    {
        fConstraintType = NSCONSTRAINT_DERIVATION_LIST;
        if (nodeType == ContentSpecNode::Any_NS_Lax)
            fProcessContents = PC_LAX;
        else if (nodeType == ContentSpecNode::Any_NS_Skip)
            fProcessContents = PC_SKIP;
    }
    else if (nodeType == ContentSpecNode::Any_NS_Choice)
    {
        fConstraintType = NSCONSTRAINT_DERIVATION_LIST;
        // inspect the second child, not the first one, as the first could hold another Any_NS_Choice wrapper
        // if the choices are more than 2, while the second child is always a leaf node
        ContentSpecNode::NodeTypes anyType = elmWildCard->getSecond()->getType();

        if (anyType == ContentSpecNode::Any_NS_Lax)
            fProcessContents = PC_LAX;
        else if (anyType == ContentSpecNode::Any_NS_Skip)
            fProcessContents = PC_SKIP;

        fNsConstraintList = new (manager) RefArrayVectorOf<XMLCh>(4, true, manager);
        buildNamespaceList(elmWildCard);
    }
    // must be any
    else
    {
        if (nodeType == ContentSpecNode::Any_Lax)
            fProcessContents = PC_LAX;
        else if (nodeType == ContentSpecNode::Any_Skip)
            fProcessContents = PC_SKIP;
    }

    if (fConstraintType == NSCONSTRAINT_NOT
        || (fConstraintType == NSCONSTRAINT_DERIVATION_LIST
            && !fNsConstraintList))
    {
        fNsConstraintList = new (manager) RefArrayVectorOf<XMLCh>(1, true, manager);
        fNsConstraintList->addElement
        (
             XMLString::replicate(fXSModel->getURIStringPool()->getValueForId(
                     elmWildCard->getElement()->getURI()), manager)
        );
    }
}

XSWildcard::~XSWildcard()
{
    if (fNsConstraintList)
        delete fNsConstraintList;
}

// ---------------------------------------------------------------------------
//  XSWildcard: helper methods
// ---------------------------------------------------------------------------
void XSWildcard::buildNamespaceList(const ContentSpecNode* const rootNode)
{
    ContentSpecNode::NodeTypes nodeType = rootNode->getType();
    if (nodeType == ContentSpecNode::Any_NS_Choice)
    {
        buildNamespaceList(rootNode->getFirst());
        buildNamespaceList(rootNode->getSecond());
    }
    else
    {
        fNsConstraintList->addElement
        (
            XMLString::replicate(fXSModel->getURIStringPool()->getValueForId(
                    rootNode->getElement()->getURI()), fMemoryManager)
        );
    }
}

XERCES_CPP_NAMESPACE_END
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: ucbcmds.hxx,v $
 *
 *  $Revision: 1.1 $
 *
 *  last change: $Author: kso $ $Date: 2001-02-02 08:18:49 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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 library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): Kai Sommerfeld ( kso@sun.com )
 *
 *
 ************************************************************************/

#ifndef _UCBCMDS_HXX
#define _UCBCMDS_HXX

//////////////////////////////////////////////////////////////////////////
//
// Definitions for the commands supported by the UCB.
//
//////////////////////////////////////////////////////////////////////////

#define GETCOMMANDINFO_NAME     "getCommandInfo"
#define GETCOMMANDINFO_HANDLE   1024

#define GLOBALTRANSFER_NAME     "globalTransfer"
#define GLOBALTRANSFER_HANDLE   1025

#endif /* !_UCBCMDS_HXX */
<commit_msg>INTEGRATION: CWS ooo19126 (1.1.286); FILE MERGED 2005/09/05 18:44:54 rt 1.1.286.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ucbcmds.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 15:16:40 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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 library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _UCBCMDS_HXX
#define _UCBCMDS_HXX

//////////////////////////////////////////////////////////////////////////
//
// Definitions for the commands supported by the UCB.
//
//////////////////////////////////////////////////////////////////////////

#define GETCOMMANDINFO_NAME     "getCommandInfo"
#define GETCOMMANDINFO_HANDLE   1024

#define GLOBALTRANSFER_NAME     "globalTransfer"
#define GLOBALTRANSFER_HANDLE   1025

#endif /* !_UCBCMDS_HXX */
<|endoftext|>


<commit_before>#ifndef __RETRO_CPHYSICSACTOR_HPP__
#define __RETRO_CPHYSICSACTOR_HPP__

#include "CActor.hpp"

namespace Retro
{

class CCollisionPrimitive
{
public:
    Zeus::CVector3f x1d8_offset;
};

class CCollisionInfoList
{
};

class CPhysicsActor : public CActor
{
protected:
    float xd8_mass;
    float xdc_massRecip;
    float xe0_inertialTensor;
    float xe4_inertialTensorRecip;
    Zeus::CAABox x194_baseBoundingBox;
    CCollisionPrimitive x1b0_collisionPrimitive;
    float x228_stepUpHeight;
    float x22c_stepDownHeight;
    float x230_restitutionCoefModifier;
    float x234_collisionAccuracyModifier;
public:

    float GetCollisionAccuracyModifier()
    { return x234_collisionAccuracyModifier; }

    void SetCollisionAccuracyModifier(float modifier)
    { x234_collisionAccuracyModifier = modifier; }

    float GetCoefficientOfRestitutionModifier()
    { return x230_restitutionCoefModifier; }

    void SetCoefficientOfRestitutionModifier(float modifier)
    { x230_restitutionCoefModifier = modifier;}

    void DrawCollisionPrimitive()
    { }

    void Render(const CStateManager&)
    {}

    Zeus::CVector3f GetAimPosition(const CStateManager&, float val)
    {
        if (val <= 0.0)
            return GetBoundingBox().center();
        //Zeus::CVector3f delta = PredictMotion(val);
        return Zeus::CVector3f();
    }

    Zeus::CVector3f GetOrbitPosition(const CStateManager&)
    { return GetBoundingBox().center(); }

    float GetStepUpHeight()
    { return x228_stepUpHeight; }

    float GetStepDownHeight()
    { return x22c_stepDownHeight; }

    void SetPrimitiveOffset(const Zeus::CVector2f& offset)
    { x1b0_collisionPrimitive.x1d8_offset = offset; }

    Zeus::CVector3f GetPrimitiveOffset()
    { return x1b0_collisionPrimitive.x1d8_offset; }

    float GetWeight()
    { return 24.525002f * xd8_mass; }

    void SetBoundingBox(const Zeus::CAABox& box)
    { x194_baseBoundingBox = box; }

    Zeus::CAABox GetMotionVolume()
    { return Zeus::CAABox::skInvertedBox; }

    Zeus::CAABox GetBoundingBox()
    { return Zeus::CAABox::skInvertedBox; }

    const Zeus::CAABox& GetBaseBoundingBox() const
    { return x194_baseBoundingBox; }

    void CollidedWith(const TUniqueId&, const CCollisionInfoList&, CStateManager&)
    {}

    Zeus::CTransform GetPrimitiveTransform()
    {
        return Zeus::CTransform;
    }

    const CCollisionPrimitive& GetCollisionPrimitive() const
    { return x1b0_collisionPrimitive; }

    void SetInertiaTensorScalar(float tensor)
    {
        if (tensor <= 0.0f)
            tensor = 1.0f;
        xe0_inertialTensor = tensor;
        xe4_inertialTensorRecip = 1.0f / tensor;
    }

    void SetMass(float mass)
    {
        xd8_mass = mass;
        float tensor = 1.0f;
        if (mass > 0.0f)
            tensor = 1.0f / mass;

        xdc_massRecip = tensor;
        SetInertiaTensorScalar(mass * tensor);
    }
};

}

#endif // __RETRO_CPHYSICSACTOR_HPP__
<commit_msg>I'm an idiot.<commit_after>#ifndef __RETRO_CPHYSICSACTOR_HPP__
#define __RETRO_CPHYSICSACTOR_HPP__

#include "CActor.hpp"

namespace Retro
{

class CCollisionPrimitive
{
public:
    Zeus::CVector3f x1d8_offset;
};

class CCollisionInfoList
{
};

class CPhysicsActor : public CActor
{
protected:
    float xd8_mass;
    float xdc_massRecip;
    float xe0_inertialTensor;
    float xe4_inertialTensorRecip;
    Zeus::CAABox x194_baseBoundingBox;
    CCollisionPrimitive x1b0_collisionPrimitive;
    float x228_stepUpHeight;
    float x22c_stepDownHeight;
    float x230_restitutionCoefModifier;
    float x234_collisionAccuracyModifier;
public:

    float GetCollisionAccuracyModifier()
    { return x234_collisionAccuracyModifier; }

    void SetCollisionAccuracyModifier(float modifier)
    { x234_collisionAccuracyModifier = modifier; }

    float GetCoefficientOfRestitutionModifier()
    { return x230_restitutionCoefModifier; }

    void SetCoefficientOfRestitutionModifier(float modifier)
    { x230_restitutionCoefModifier = modifier;}

    void DrawCollisionPrimitive()
    { }

    void Render(const CStateManager&)
    {}

    Zeus::CVector3f GetAimPosition(const CStateManager&, float val)
    {
        if (val <= 0.0)
            return GetBoundingBox().center();
        //Zeus::CVector3f delta = PredictMotion(val);
        return Zeus::CVector3f();
    }

    Zeus::CVector3f GetOrbitPosition(const CStateManager&)
    { return GetBoundingBox().center(); }

    float GetStepUpHeight()
    { return x228_stepUpHeight; }

    float GetStepDownHeight()
    { return x22c_stepDownHeight; }

    void SetPrimitiveOffset(const Zeus::CVector2f& offset)
    { x1b0_collisionPrimitive.x1d8_offset = offset; }

    Zeus::CVector3f GetPrimitiveOffset()
    { return x1b0_collisionPrimitive.x1d8_offset; }

    float GetWeight()
    { return 24.525002f * xd8_mass; }

    void SetBoundingBox(const Zeus::CAABox& box)
    { x194_baseBoundingBox = box; }

    Zeus::CAABox GetMotionVolume()
    { return Zeus::CAABox::skInvertedBox; }

    Zeus::CAABox GetBoundingBox()
    { return Zeus::CAABox::skInvertedBox; }

    const Zeus::CAABox& GetBaseBoundingBox() const
    { return x194_baseBoundingBox; }

    void CollidedWith(const TUniqueId&, const CCollisionInfoList&, CStateManager&)
    {}

    Zeus::CTransform GetPrimitiveTransform()
    {
        return Zeus::CTransform();
    }

    const CCollisionPrimitive& GetCollisionPrimitive() const
    { return x1b0_collisionPrimitive; }

    void SetInertiaTensorScalar(float tensor)
    {
        if (tensor <= 0.0f)
            tensor = 1.0f;
        xe0_inertialTensor = tensor;
        xe4_inertialTensorRecip = 1.0f / tensor;
    }

    void SetMass(float mass)
    {
        xd8_mass = mass;
        float tensor = 1.0f;
        if (mass > 0.0f)
            tensor = 1.0f / mass;

        xdc_massRecip = tensor;
        SetInertiaTensorScalar(mass * tensor);
    }
};

}

#endif // __RETRO_CPHYSICSACTOR_HPP__
<|endoftext|>


<commit_before>#include <memory>
#include <random>
#include <string>
#include <glm/glm.hpp>
#include <pup_stl.h>
#include "pt/pt.h"
#include "pup_operators.h"
#include "main.decl.h"
#include "main.h"
#include "image_parallel_tile.decl.h"
#include "image_parallel_tile.h"

// readonly global Charm++ variables
extern CProxy_Main main_proxy;
extern SceneMessage *scene;
extern uint64_t IMAGE_W;
extern uint64_t IMAGE_H;
extern uint64_t TILE_W;
extern uint64_t TILE_H;

glm::vec3 linear_to_srgb(const glm::vec3 &v) {
	const float a = 0.055;
	const float b = 1.f / 2.4f;
	glm::vec3 srgb(0);
	for (size_t i = 0; i < 3; ++i) {
		if (v[i] <= 0.0031308) {
			srgb[i] = 12.92 * v[i];
		} else {
			srgb[i] = (1.0 + a) * std::pow(v[i], b) - a;
		}
	}
	return srgb;
}

ImageParallelTile::ImageParallelTile() {}
ImageParallelTile::ImageParallelTile(CkMigrateMessage *msg) {}
void ImageParallelTile::render() {
	const uint64_t tiles_x = IMAGE_W / TILE_W;
	const uint64_t start_x = thisIndex.x * TILE_W;
	const uint64_t start_y = thisIndex.y * TILE_H;
	const pt::Camera camera(scene->cam_pos, scene->cam_target, scene->cam_up, 65.0, IMAGE_W, IMAGE_H);

	std::shared_ptr<pt::BxDF> lambertian = std::make_shared<pt::Lambertian>(glm::vec3(0.1, 0.1, 0.8));
	std::shared_ptr<pt::BxDF> lambertian_white = std::make_shared<pt::Lambertian>(glm::vec3(0.8));
	std::shared_ptr<pt::BxDF> lambertian_red = std::make_shared<pt::Lambertian>(glm::vec3(0.8, 0.1, 0.1));
	std::shared_ptr<pt::BxDF> reflective = std::make_shared<pt::SpecularReflection>(glm::vec3(0.8));
	// Each tile is RGB8 color data
	// TODO: Each tile should be RGBA8 + ZF32 for compositing primary rays.
	// Maybe for transparency we'd want floating point alpha and color?
	uint8_t *tile = new uint8_t[TILE_W * TILE_H * 3];
	const pt::PathIntegrator integrator(glm::vec3(0.05), pt::Scene({
			std::make_shared<pt::Sphere>(glm::vec3(0), 1.0, reflective),
			std::make_shared<pt::Sphere>(glm::vec3(0.25, 0.7, 1.0), 0.25, lambertian),
			std::make_shared<pt::Sphere>(glm::vec3(0), 8, lambertian),
			std::make_shared<pt::Sphere>(glm::vec3(-1, -0.75, 1.2), 0.5, lambertian_red),
			std::make_shared<pt::Plane>(glm::vec3(0, -1, 0), glm::vec3(0, 1, 0), lambertian_white)
		},
		{
			std::make_shared<pt::PointLight>(glm::vec3(1, 1.5, 1.5), glm::vec3(1.0)),
			std::make_shared<pt::PointLight>(glm::vec3(-0.5, 1.5, 1.5), glm::vec3(0.7))
		}
	));
	std::mt19937 rng{std::random_device()()};
	std::uniform_real_distribution<float> real_distrib;

	for (uint64_t i = 0; i < TILE_H; ++i) {
		for (uint64_t j = 0; j < TILE_W; ++j) {
		glm::vec3 color(0);
		// TODO: Samples should be in multiple passes like in the aobench render
		for (uint64_t sp = 0; sp < 32; ++sp) {
			const float px = j + start_x;
			const float py = i + start_y;
			pt::Ray ray = camera.generate_ray(px, py, {real_distrib(rng), real_distrib(rng)});
			color += integrator.integrate(ray);
		}
		color = linear_to_srgb(color / 32.f);
			for (size_t c = 0; c < 3; ++c) {
				tile[(i * TILE_W + j) * 3 + c] = glm::clamp(color[c] * 255.f, 0.f, 255.f);
			}
		}
	}
	main_proxy.tile_done(start_x, start_y, tile);
	delete[] tile;
}

#include "image_parallel_tile.def.h"

<commit_msg>Change scene to box with one light, seems like there's a material bug<commit_after>#include <memory>
#include <random>
#include <string>
#include <glm/glm.hpp>
#include <pup_stl.h>
#include "pt/pt.h"
#include "pup_operators.h"
#include "main.decl.h"
#include "main.h"
#include "image_parallel_tile.decl.h"
#include "image_parallel_tile.h"

// readonly global Charm++ variables
extern CProxy_Main main_proxy;
extern SceneMessage *scene;
extern uint64_t IMAGE_W;
extern uint64_t IMAGE_H;
extern uint64_t TILE_W;
extern uint64_t TILE_H;

glm::vec3 linear_to_srgb(const glm::vec3 &v) {
	const float a = 0.055;
	const float b = 1.f / 2.4f;
	glm::vec3 srgb(0);
	for (size_t i = 0; i < 3; ++i) {
		if (v[i] <= 0.0031308) {
			srgb[i] = 12.92 * v[i];
		} else {
			srgb[i] = (1.0 + a) * std::pow(v[i], b) - a;
		}
	}
	return srgb;
}

ImageParallelTile::ImageParallelTile() {}
ImageParallelTile::ImageParallelTile(CkMigrateMessage *msg) {}
void ImageParallelTile::render() {
	const uint64_t tiles_x = IMAGE_W / TILE_W;
	const uint64_t start_x = thisIndex.x * TILE_W;
	const uint64_t start_y = thisIndex.y * TILE_H;
	const pt::Camera camera(scene->cam_pos, scene->cam_target, scene->cam_up, 65.0, IMAGE_W, IMAGE_H);

	std::shared_ptr<pt::BxDF> lambertian_blue = std::make_shared<pt::Lambertian>(glm::vec3(0.1, 0.1, 0.8));
	std::shared_ptr<pt::BxDF> lambertian_white = std::make_shared<pt::Lambertian>(glm::vec3(0.8));
	std::shared_ptr<pt::BxDF> lambertian_red = std::make_shared<pt::Lambertian>(glm::vec3(0.8, 0.1, 0.1));
	std::shared_ptr<pt::BxDF> reflective = std::make_shared<pt::SpecularReflection>(glm::vec3(0.8));
	// Each tile is RGB8 color data
	// TODO: Each tile should be RGBA8 + ZF32 for compositing primary rays.
	// Maybe for transparency we'd want floating point alpha and color?
	uint8_t *tile = new uint8_t[TILE_W * TILE_H * 3];
	const pt::PathIntegrator integrator(glm::vec3(0.05), pt::Scene({
			std::make_shared<pt::Sphere>(glm::vec3(0), 1.0, reflective),
			std::make_shared<pt::Sphere>(glm::vec3(1.0, 0.7, 1.0), 0.25, lambertian_blue),
			std::make_shared<pt::Sphere>(glm::vec3(-1, -0.75, 1.2), 0.5, lambertian_red),
			// Walls
			std::make_shared<pt::Plane>(glm::vec3(0, -1, 0), glm::vec3(0, 1, 0), lambertian_white),
			std::make_shared<pt::Plane>(glm::vec3(0, 2, 0), glm::vec3(0, -1, 0), lambertian_white),
			std::make_shared<pt::Plane>(glm::vec3(-1.5, 0, 0), glm::vec3(1, 0, 0), lambertian_white),
			std::make_shared<pt::Plane>(glm::vec3(1.5, 0, 0), glm::vec3(-1, 0, 0), lambertian_white),
			std::make_shared<pt::Plane>(glm::vec3(0, 0, -2), glm::vec3(0, 0, 1), lambertian_white)
		},
		{
			std::make_shared<pt::PointLight>(glm::vec3(0, 1.5, 0), glm::vec3(0.9)),
		}
	));
	std::mt19937 rng{std::random_device()()};
	std::uniform_real_distribution<float> real_distrib;

	for (uint64_t i = 0; i < TILE_H; ++i) {
		for (uint64_t j = 0; j < TILE_W; ++j) {
		glm::vec3 color(0);
		const uint64_t spp = 32;
		// TODO: Samples should be in multiple passes like in the aobench render
		for (uint64_t sp = 0; sp < spp; ++sp) {
			const float px = j + start_x;
			const float py = i + start_y;
			pt::Ray ray = camera.generate_ray(px, py, {real_distrib(rng), real_distrib(rng)});
			color += integrator.integrate(ray);
		}
		color = linear_to_srgb(color / static_cast<float>(spp));
			for (size_t c = 0; c < 3; ++c) {
				tile[(i * TILE_W + j) * 3 + c] = glm::clamp(color[c] * 255.f, 0.f, 255.f);
			}
		}
	}
	main_proxy.tile_done(start_x, start_y, tile);
	delete[] tile;
}

#include "image_parallel_tile.def.h"

<|endoftext|>


<commit_before>#ifndef STAN_MATH_REV_FUN_GENERALIZED_INVERSE_HPP
#define STAN_MATH_REV_FUN_GENERALIZED_INVERSE_HPP

#include <stan/math/rev/core.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/rev/fun/cholesky_decompose.hpp>
#include <stan/math/rev/fun/transpose.hpp>
#include <stan/math/rev/fun/tcrossprod.hpp>
#include <stan/math/rev/fun/crossprod.hpp>
#include <stan/math/rev/fun/inverse_spd.hpp>
#include <stan/math/rev/fun/mdivide_left_spd.hpp>
#include <stan/math/rev/fun/mdivide_right_spd.hpp>
#include <stan/math/rev/fun/inverse.hpp>

namespace stan {
namespace math {

/**
 * Reverse mode differentiation algorithm reference:
 *
 * The Differentiation of Pseudo-Inverses and Nonlinear Least Squares Problems
 * Whose Variables Separate. Author(s): G. H. Golub and V. Pereyra. Source: SIAM
 * Journal on Numerical Analysis, Vol. 10, No. 2 (Apr., 1973), pp. 413-432
 *
 * Equation 4.12 in the paper
 */
template <typename EigMat, require_eigen_vt<is_var, EigMat>* = nullptr>
inline auto generalized_inverse(const EigMat& A) {
  using value_t = value_type_t<EigMat>;
  if (A.size() == 0) {
    return {};
  }

  const auto n = A.rows();
  const auto m = A.cols();

  if (A.rows() == A.cols()) {
    return inverse(A);
  }
  if (n < m) {
    arena_t<plain_type_t<EigMat>> A_arena(A);
    arena_t<EigMat> A_spd = tcrossprod(A_arena.val());
    arena_t<EigMat> inv_A(transpose(mdivide_left_spd(A_spd, A_arena.val())));
    arena_t<EigMat> aP = (1 - A * inv_A.transpose());
    arena_t<EigMat> Pa = (1 - inv_A * A);
    reverse_pass_callback([A_arena, inv_A]() mutable {
      A_arena.adj() += -inv_A * A.adj() * inv_A;
      A_arena.adj() += tcrossprod(inv_A) * A.adj().transpose() * aP;
      A_arena.adj() += Pa * A.adj().transpose() * crossprod(inv_A());
    });
    return ret;
  } else {
    arena_t<plain_type_t<EigMat>> A_arena(A);
    arena_t<EigMat> A_spd = crossprod(A_arena.val());
    arena_t<EigMat> inv_A(transpose(mdivide_right_spd(A_arena.val(), A_spd)));
    arena_t<EigMat> aP = (1 - A * inv_A.transpose());
    arena_t<EigMat> Pa = (1 - inv_A * A);
    reverse_pass_callback([A_arena, inv_A]() mutable {
      A_arena.adj() += -inv_A * A.adj() * inv_A;
      A_arena.adj() += tcrossprod(inv_A) * A.adj().transpose() * aP;
      A_arena.adj() += Pa * A.adj().transpose() * crossprod(inv_A());
    });
    return ret;
  }
}

/**
 * Reverse mode differentiation algorithm reference:
 *
 * The Differentiation of Pseudo-Inverses and Nonlinear Least Squares Problems
 * Whose Variables Separate. Author(s): G. H. Golub and V. Pereyra. Source: SIAM
 * Journal on Numerical Analysis, Vol. 10, No. 2 (Apr., 1973), pp. 413-432
 *
 * Equation 4.12 in the paper
 */
template <typename EigMat, typename Scal, require_eigen_t<EigMat>* = nullptr,
          require_stan_scalar_t<Scal>* = nullptr>
inline Eigen::Matrix<value_type_t<EigMat>, EigMat::RowsAtCompileTime,
                     EigMat::ColsAtCompileTime>
generalized_inverse(const EigMat& A, const Scal& a) {
  using value_t = value_type_t<EigMat>;
  if (A.size() == 0) {
    return {};
  }

  const auto n = A.rows();
  const auto m = A.cols();

  if (A.rows() == A.cols()) {
    return inverse(A);
  }

  if (n < m) {
    arena_t<plain_type_t<EigMat>> A_arena(A);
    arena_t<EigMat> A_spd = tcrossprod(A_arena.val());
    A_spd.diagonal().array() += a;

    arena_t<EigMat> inv_A(transpose(mdivide_left_spd(A_spd, A_arena.val())));
    arena_t<EigMat> aP = (1 - A * inv_A.transpose());
    arena_t<EigMat> Pa = (1 - inv_A * A);
    reverse_pass_callback([A_arena, inv_A]() mutable {
      A_arena.adj() += -inv_A * A.adj() * inv_A;
      A_arena.adj() += tcrossprod(inv_A) * A.adj().transpose() * aP;
      A_arena.adj() += Pa * A.adj().transpose() * crossprod(inv_A());
    });
    return ret;
  } else {
    arena_t<plain_type_t<EigMat>> A_arena(A);
    arena_t<EigMat> A_spd = crossprod(A_arena.val());
    A_spd.diagonal().array() += a;

    arena_t<plain_type_t<EigMat>> A_arena(A);
    arena_t<EigMat> inv_A(transpose(mdivide_right_spd(A_arena.val(), A_spd));
    arena_t<EigMat> aP = (1 - A * inv_A.transpose());
    arena_t<EigMat> Pa = (1 - inv_A * A);
    reverse_pass_callback([A_arena, inv_A]() mutable {
      A_arena.adj() += -inv_A * A.adj() * inv_A;
      A_arena.adj() += tcrossprod(inv_A) * A.adj().transpose() * aP;
      A_arena.adj() += Pa * A.adj().transpose() * crossprod(inv_A());
    });
    return ret;
  }
}

}  // namespace math
}  // namespace stan

#endif
<commit_msg>[Jenkins] auto-formatting by clang-format version 6.0.0-1ubuntu2~16.04.1 (tags/RELEASE_600/final)<commit_after>#ifndef STAN_MATH_REV_FUN_GENERALIZED_INVERSE_HPP
#define STAN_MATH_REV_FUN_GENERALIZED_INVERSE_HPP

#include <stan/math/rev/core.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/rev/fun/cholesky_decompose.hpp>
#include <stan/math/rev/fun/transpose.hpp>
#include <stan/math/rev/fun/tcrossprod.hpp>
#include <stan/math/rev/fun/crossprod.hpp>
#include <stan/math/rev/fun/inverse_spd.hpp>
#include <stan/math/rev/fun/mdivide_left_spd.hpp>
#include <stan/math/rev/fun/mdivide_right_spd.hpp>
#include <stan/math/rev/fun/inverse.hpp>

namespace stan {
namespace math {

/**
 * Reverse mode differentiation algorithm reference:
 *
 * The Differentiation of Pseudo-Inverses and Nonlinear Least Squares Problems
 * Whose Variables Separate. Author(s): G. H. Golub and V. Pereyra. Source: SIAM
 * Journal on Numerical Analysis, Vol. 10, No. 2 (Apr., 1973), pp. 413-432
 *
 * Equation 4.12 in the paper
 */
template <typename EigMat, require_eigen_vt<is_var, EigMat>* = nullptr>
inline auto generalized_inverse(const EigMat& A) {
  using value_t = value_type_t<EigMat>;
  if (A.size() == 0) {
    return {};
  }

  const auto n = A.rows();
  const auto m = A.cols();

  if (A.rows() == A.cols()) {
    return inverse(A);
  }
  if (n < m) {
    arena_t<plain_type_t<EigMat>> A_arena(A);
    arena_t<EigMat> A_spd = tcrossprod(A_arena.val());
    arena_t<EigMat> inv_A(transpose(mdivide_left_spd(A_spd, A_arena.val())));
    arena_t<EigMat> aP = (1 - A * inv_A.transpose());
    arena_t<EigMat> Pa = (1 - inv_A * A);
    reverse_pass_callback([A_arena, inv_A]() mutable {
      A_arena.adj() += -inv_A * A.adj() * inv_A;
      A_arena.adj() += tcrossprod(inv_A) * A.adj().transpose() * aP;
      A_arena.adj() += Pa * A.adj().transpose() * crossprod(inv_A());
    });
    return ret;
  } else {
    arena_t<plain_type_t<EigMat>> A_arena(A);
    arena_t<EigMat> A_spd = crossprod(A_arena.val());
    arena_t<EigMat> inv_A(transpose(mdivide_right_spd(A_arena.val(), A_spd)));
    arena_t<EigMat> aP = (1 - A * inv_A.transpose());
    arena_t<EigMat> Pa = (1 - inv_A * A);
    reverse_pass_callback([A_arena, inv_A]() mutable {
      A_arena.adj() += -inv_A * A.adj() * inv_A;
      A_arena.adj() += tcrossprod(inv_A) * A.adj().transpose() * aP;
      A_arena.adj() += Pa * A.adj().transpose() * crossprod(inv_A());
    });
    return ret;
  }
}

/**
 * Reverse mode differentiation algorithm reference:
 *
 * The Differentiation of Pseudo-Inverses and Nonlinear Least Squares Problems
 * Whose Variables Separate. Author(s): G. H. Golub and V. Pereyra. Source: SIAM
 * Journal on Numerical Analysis, Vol. 10, No. 2 (Apr., 1973), pp. 413-432
 *
 * Equation 4.12 in the paper
 */
template <typename EigMat, typename Scal, require_eigen_t<EigMat>* = nullptr,
          require_stan_scalar_t<Scal>* = nullptr>
inline Eigen::Matrix<value_type_t<EigMat>, EigMat::RowsAtCompileTime,
                     EigMat::ColsAtCompileTime>
generalized_inverse(const EigMat& A, const Scal& a) {
  using value_t = value_type_t<EigMat>;
  if (A.size() == 0) {
    return {};
  }

  const auto n = A.rows();
  const auto m = A.cols();

  if (A.rows() == A.cols()) {
    return inverse(A);
  }

  if (n < m) {
    arena_t<plain_type_t<EigMat>> A_arena(A);
    arena_t<EigMat> A_spd = tcrossprod(A_arena.val());
    A_spd.diagonal().array() += a;

    arena_t<EigMat> inv_A(transpose(mdivide_left_spd(A_spd, A_arena.val())));
    arena_t<EigMat> aP = (1 - A * inv_A.transpose());
    arena_t<EigMat> Pa = (1 - inv_A * A);
    reverse_pass_callback([A_arena, inv_A]() mutable {
      A_arena.adj() += -inv_A * A.adj() * inv_A;
      A_arena.adj() += tcrossprod(inv_A) * A.adj().transpose() * aP;
      A_arena.adj() += Pa * A.adj().transpose() * crossprod(inv_A());
    });
    return ret;
  } else {
    arena_t<plain_type_t<EigMat>> A_arena(A);
    arena_t<EigMat> A_spd = crossprod(A_arena.val());
    A_spd.diagonal().array() += a;

    arena_t<plain_type_t<EigMat>> A_arena(A);
    arena_t<EigMat> inv_A(transpose(mdivide_right_spd(A_arena.val(), A_spd));
    arena_t<EigMat> aP = (1 - A * inv_A.transpose());
    arena_t<EigMat> Pa = (1 - inv_A * A);
    reverse_pass_callback([A_arena, inv_A]() mutable {
      A_arena.adj() += -inv_A * A.adj() * inv_A;
      A_arena.adj() += tcrossprod(inv_A) * A.adj().transpose() * aP;
      A_arena.adj() += Pa * A.adj().transpose() * crossprod(inv_A());
    });
    return ret;
  }
}

}  // namespace math
}  // namespace stan

#endif
<|endoftext|>


<commit_before>#ifndef STAN_MATH_REV_FUN_GENERALIZED_INVERSE_HPP
#define STAN_MATH_REV_FUN_GENERALIZED_INVERSE_HPP

#include <stan/math/rev/core.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/rev/fun/cholesky_decompose.hpp>
#include <stan/math/rev/fun/transpose.hpp>
#include <stan/math/rev/fun/tcrossprod.hpp>
#include <stan/math/rev/fun/crossprod.hpp>
#include <stan/math/rev/fun/inverse_spd.hpp>
#include <stan/math/rev/fun/mdivide_left_spd.hpp>
#include <stan/math/rev/fun/mdivide_right_spd.hpp>
#include <stan/math/rev/fun/inverse.hpp>

namespace stan {
namespace math {

/**
 * Reverse mode differentiation algorithm reference:
 *
 * The Differentiation of Pseudo-Inverses and Nonlinear Least Squares Problems
 * Whose Variables Separate. Author(s): G. H. Golub and V. Pereyra. Source: SIAM
 * Journal on Numerical Analysis, Vol. 10, No. 2 (Apr., 1973), pp. 413-432
 *
 * Equation 4.12 in the paper
 */
template <typename EigMat, require_eigen_vt<is_var, EigMat>* = nullptr>
inline auto generalized_inverse(const EigMat& A) {
  using value_t = value_type_t<EigMat>;
  if (A.size() == 0) {
    return {};
  }

  const auto n = A.rows();
  const auto m = A.cols();

  if (A.rows() == A.cols()) {
    return inverse(A);
  }
  if (n < m) {
    arena_t<plain_type_t<EigMat>> A_arena(A);
    arena_t<EigMat> inv_A(
        transpose(mdivide_left_spd(tcrossprod(A_arena.val()), A_arena.val())));
    reverse_pass_callback([A_arena, inv_A]() mutable {
      A_arena.adj()
          += -inv_A * A.adj() * inv_A
             + tcrossprod(inv_A) * A.adj().transpose()
                   * (1 - A * inv_A.transpose())
             + (1 - inv_A * A) * A.adj().transpose() * crossprod(inv_A());
    });
    return ret;
  } else {
    arena_t<plain_type_t<EigMat>> A_arena(A);
    arena_t<EigMat> inv_A(transpose(mdivide_right_spd(A_arena.val(), crossprod(A_arena.val())));
    reverse_pass_callback([A_arena, inv_A]() mutable {
      A_arena.adj()
          += -inv_A * A.adj() * inv_A
             + tcrossprod(inv_A) * A.adj().transpose()
                   * (1 - A * inv_A.tranpose())
             + (1 - inv_A * A) * A.adj().transpose() * crossprod(inv_A());
    });
    return ret;
  }
}

/**
 * Reverse mode differentiation algorithm reference:
 *
 * The Differentiation of Pseudo-Inverses and Nonlinear Least Squares Problems
 * Whose Variables Separate. Author(s): G. H. Golub and V. Pereyra. Source: SIAM
 * Journal on Numerical Analysis, Vol. 10, No. 2 (Apr., 1973), pp. 413-432
 *
 * Equation 4.12 in the paper
 */
template <typename EigMat, typename Scal, require_eigen_t<EigMat>* = nullptr,
          require_stan_scalar_t<Scal>* = nullptr>
inline Eigen::Matrix<value_type_t<EigMat>, EigMat::RowsAtCompileTime,
                     EigMat::ColsAtCompileTime>
generalized_inverse(const EigMat& A, const Scal& a) {
  using value_t = value_type_t<EigMat>;
  if (A.size() == 0) {
    return {};
  }

  const auto n = A.rows();
  const auto m = A.cols();

  if (A.rows() == A.cols()) {
    return inverse(A);
  }

  if (n < m) {
    arena_t<plain_type_t<EigMat>> A_arena(A);
    arena_t<EigMat> A_spd = tcrossprod(A_arena.val());
    A_spd.diagonal().array() += a;

    arena_t<EigMat> inv_A(transpose(mdivide_left_spd(A_spd, A_arena.val())));
    reverse_pass_callback([A_arena, inv_A]() mutable {
      A_arena.adj()
          += -inv_A * A.adj() * inv_A
             + tcrossprod(inv_A) * A.adj().transpose()
                   * (1 - A * inv_A.transpose())
             + (1 - inv_A * A) * A.adj().transpose() * crossprod(inv_A());
    });
    return ret;
  } else {
    arena_t<plain_type_t<EigMat>> A_arena(A);
    arena_t<EigMat> A_spd = crossprod(A_arena.val());
    A_spd.diagonal().array() += a;

    arena_t<plain_type_t<EigMat>> A_arena(A);
    arena_t<EigMat> inv_A(transpose(mdivide_right_spd(A_arena.val(), A_spd));
    reverse_pass_callback([A_arena, inv_A]() mutable {
      A_arena.adj()
          += -inv_A * A.adj() * inv_A
             + tcrossprod(inv_A) * A.adj().transpose()
                   * (1 - A * inv_A.tranpose())
             + (1 - inv_A * A) * A.adj().transpose() * crossprod(inv_A());
    });
    return ret;
  }
}

}  // namespace math
}  // namespace stan

#endif
<commit_msg>make lines <= 80 char<commit_after>#ifndef STAN_MATH_REV_FUN_GENERALIZED_INVERSE_HPP
#define STAN_MATH_REV_FUN_GENERALIZED_INVERSE_HPP

#include <stan/math/rev/core.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/rev/fun/cholesky_decompose.hpp>
#include <stan/math/rev/fun/transpose.hpp>
#include <stan/math/rev/fun/tcrossprod.hpp>
#include <stan/math/rev/fun/crossprod.hpp>
#include <stan/math/rev/fun/inverse_spd.hpp>
#include <stan/math/rev/fun/mdivide_left_spd.hpp>
#include <stan/math/rev/fun/mdivide_right_spd.hpp>
#include <stan/math/rev/fun/inverse.hpp>

namespace stan {
namespace math {

/**
 * Reverse mode differentiation algorithm reference:
 *
 * The Differentiation of Pseudo-Inverses and Nonlinear Least Squares Problems
 * Whose Variables Separate. Author(s): G. H. Golub and V. Pereyra. Source: SIAM
 * Journal on Numerical Analysis, Vol. 10, No. 2 (Apr., 1973), pp. 413-432
 *
 * Equation 4.12 in the paper
 */
template <typename EigMat, require_eigen_vt<is_var, EigMat>* = nullptr>
inline auto generalized_inverse(const EigMat& A) {
  using value_t = value_type_t<EigMat>;
  if (A.size() == 0) {
    return {};
  }

  const auto n = A.rows();
  const auto m = A.cols();

  if (A.rows() == A.cols()) {
    return inverse(A);
  }
  if (n < m) {
    arena_t<plain_type_t<EigMat>> A_arena(A);
    arena_t<EigMat> inv_A(
        transpose(mdivide_left_spd(tcrossprod(A_arena.val()), A_arena.val())));
    reverse_pass_callback([A_arena, inv_A]() mutable {
      A_arena.adj() += -inv_A * A.adj() * inv_A;
      A_arena.adj() += tcrossprod(inv_A) * A.adj().transpose()
                   * (1 - A * inv_A.transpose());
      A_arena.adj() += (1 - inv_A * A) * A.adj().transpose() * crossprod(inv_A());
    });
    return ret;
  } else {
    arena_t<plain_type_t<EigMat>> A_arena(A);
    arena_t<EigMat> inv_A(transpose(mdivide_right_spd(A_arena.val(), crossprod(A_arena.val())));
    reverse_pass_callback([A_arena, inv_A]() mutable {
      A_arena.adj() += -inv_A * A.adj() * inv_A;
      A_arena.adj() += tcrossprod(inv_A) * A.adj().transpose()
                   * (1 - A * inv_A.transpose());
      A_arena.adj() += (1 - inv_A * A) * A.adj().transpose() * crossprod(inv_A());
    });
    return ret;
  }
}

/**
 * Reverse mode differentiation algorithm reference:
 *
 * The Differentiation of Pseudo-Inverses and Nonlinear Least Squares Problems
 * Whose Variables Separate. Author(s): G. H. Golub and V. Pereyra. Source: SIAM
 * Journal on Numerical Analysis, Vol. 10, No. 2 (Apr., 1973), pp. 413-432
 *
 * Equation 4.12 in the paper
 */
template <typename EigMat, typename Scal, require_eigen_t<EigMat>* = nullptr,
          require_stan_scalar_t<Scal>* = nullptr>
inline Eigen::Matrix<value_type_t<EigMat>, EigMat::RowsAtCompileTime,
                     EigMat::ColsAtCompileTime>
generalized_inverse(const EigMat& A, const Scal& a) {
  using value_t = value_type_t<EigMat>;
  if (A.size() == 0) {
    return {};
  }

  const auto n = A.rows();
  const auto m = A.cols();

  if (A.rows() == A.cols()) {
    return inverse(A);
  }

  if (n < m) {
    arena_t<plain_type_t<EigMat>> A_arena(A);
    arena_t<EigMat> A_spd = tcrossprod(A_arena.val());
    A_spd.diagonal().array() += a;

    arena_t<EigMat> inv_A(transpose(mdivide_left_spd(A_spd, A_arena.val())));
    reverse_pass_callback([A_arena, inv_A]() mutable {
      A_arena.adj() += -inv_A * A.adj() * inv_A;
      A_arena.adj() += tcrossprod(inv_A) * A.adj().transpose()
                   * (1 - A * inv_A.transpose());
      A_arena.adj() += (1 - inv_A * A) * A.adj().transpose() * crossprod(inv_A());
    });
    return ret;
  } else {
    arena_t<plain_type_t<EigMat>> A_arena(A);
    arena_t<EigMat> A_spd = crossprod(A_arena.val());
    A_spd.diagonal().array() += a;

    arena_t<plain_type_t<EigMat>> A_arena(A);
    arena_t<EigMat> inv_A(transpose(mdivide_right_spd(A_arena.val(), A_spd));
    reverse_pass_callback([A_arena, inv_A]() mutable {
      A_arena.adj() += -inv_A * A.adj() * inv_A;
      A_arena.adj() += tcrossprod(inv_A) * A.adj().transpose()
                   * (1 - A * inv_A.transpose());
      A_arena.adj() += (1 - inv_A * A) * A.adj().transpose() * crossprod(inv_A());
    });
    return ret;
  }
}

}  // namespace math
}  // namespace stan

#endif
<|endoftext|>