/* This file is part of the Pangolin Project. * http://github.com/stevenlovegrove/Pangolin * * Copyright (c) 2011 Steven Lovegrove * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #include #include // std::min, std::max #include #include #include #include #include #include #if defined(HAVE_EIGEN) && !defined(__CUDACC__) //prevent including Eigen in cuda files #define USE_EIGEN #endif #ifdef USE_EIGEN #include #endif namespace pangolin { /// Simple statistics recorded for a logged input dimension. struct DimensionStats { DimensionStats() { Reset(); } void Reset() { isMonotonic = true; sum = 0.0f; sum_sq = 0.0f; min = std::numeric_limits::max(); max = std::numeric_limits::lowest(); } void Add(const float v) { isMonotonic = isMonotonic && (v >= max); sum += v; sum_sq += v*v; min = std::min(min, v); max = std::max(max, v); } bool isMonotonic; float sum; float sum_sq; float min; float max; }; class DataLogBlock { public: /// @param dim: dimension of sample /// @param max_samples: maximum number of samples this block can hold /// @param start_id: index of first sample (from entire dataset) in this buffer DataLogBlock(size_t dim, size_t max_samples, size_t start_id) : dim(dim), max_samples(max_samples), samples(0), start_id(start_id) { sample_buffer = std::unique_ptr(new float[dim*max_samples]); // stats = std::unique_ptr(new DimensionStats[dim]); } ~DataLogBlock() { } size_t Samples() const { return samples; } size_t MaxSamples() const { return max_samples; } /// Return how many more samples can fit in this block size_t SampleSpaceLeft() const { return MaxSamples()- Samples(); } bool IsFull() const { return Samples() >= MaxSamples(); } /// Add data to block void AddSamples(size_t num_samples, size_t dimensions, const float* data_dim_major ); /// Delete all samples void ClearLinked() { samples = 0; nextBlock.reset(); } DataLogBlock* NextBlock() const { return nextBlock.get(); } size_t StartId() const { return start_id; } float* DimData(size_t d) const { return sample_buffer.get() + d; } size_t Dimensions() const { return dim; } const float* Sample(size_t n) const { const int id = (int)n - (int)start_id; if( 0 <= id && id < (int)samples ) { return sample_buffer.get() + dim*id; }else{ if(nextBlock) { return nextBlock->Sample(n); }else{ throw std::out_of_range("Index out of range."); } } } protected: size_t dim; size_t max_samples; size_t samples; size_t start_id; std::unique_ptr sample_buffer; // std::unique_ptr stats; std::unique_ptr nextBlock; }; /// A DataLog can efficiently record floating point sample data of any size. /// Memory is allocated in blocks is transparent to the user. class PANGOLIN_EXPORT DataLog { public: /// @param block_samples_alloc number of samples each memory block can hold. DataLog(unsigned int block_samples_alloc = 10000 ); ~DataLog(); /// Provide textual labels corresponding to each dimension logged. /// This information may be used by graphical interfaces to DataLog. void SetLabels(const std::vector & labels); const std::vector& Labels() const; void Log(size_t dimension, const float * vals, unsigned int samples = 1); void Log(float v); void Log(float v1, float v2); void Log(float v1, float v2, float v3); void Log(float v1, float v2, float v3, float v4); void Log(float v1, float v2, float v3, float v4, float v5); void Log(float v1, float v2, float v3, float v4, float v5, float v6); void Log(float v1, float v2, float v3, float v4, float v5, float v6, float v7); void Log(float v1, float v2, float v3, float v4, float v5, float v6, float v7, float v8); void Log(float v1, float v2, float v3, float v4, float v5, float v6, float v7, float v8, float v9); void Log(float v1, float v2, float v3, float v4, float v5, float v6, float v7, float v8, float v9, float v10); void Log(const std::vector & vals); #ifdef USE_EIGEN template void Log(const Eigen::MatrixBase& M) { Log( M.rows() * M.cols(), M.template cast().eval().data() ); } #endif void Clear(); void Save(std::string filename); // Return first block of stored data const DataLogBlock* FirstBlock() const; // Return last block of stored data const DataLogBlock* LastBlock() const; // Return number of samples stored in this DataLog size_t Samples() const; // Return pointer to stored sample n const float* Sample(int n) const; // Return stats computed for each dimension if enabled. const DimensionStats& Stats(size_t dim) const; std::mutex access_mutex; protected: unsigned int block_samples_alloc; std::vector labels; std::unique_ptr block0; DataLogBlock* blockn; std::vector stats; bool record_stats; }; }