Commit f43b1fce authored by Hahn, Steven's avatar Hahn, Steven
Browse files

Merge remote-tracking branch 'origin/master' into history_view

parents d4383552 ef0fb3f9
......@@ -114,8 +114,9 @@ private:
/// Calculates the distance of the current solution
double distance(const Kernel::DblMatrix &s2, const std::vector<double> &beta);
/// Populates the output workspaces
void populateOutputWS(const API::MatrixWorkspace_sptr &inWS, size_t spec,
size_t nspec, const std::vector<double> &data,
void populateOutputWS(const API::MatrixWorkspace_sptr &inWS, bool complex,
size_t spec, size_t nspec,
const std::vector<double> &data,
const std::vector<double> &image,
API::MatrixWorkspace_sptr &outData,
API::MatrixWorkspace_sptr &outImage);
......
......@@ -57,6 +57,12 @@ void MaxEnt::init() {
new WorkspaceProperty<>("InputWorkspace", "", Direction::Input),
"An input workspace.");
declareProperty("ComplexData", false,
"Whether or not the input data are complex. If true, the "
"input workspace is expected to have an even number of "
"histograms, with real and imaginary parts arranged in "
"consecutive workspaces");
auto mustBeNonNegative = boost::make_shared<BoundedValidator<double>>();
mustBeNonNegative->setLower(1E-12);
declareProperty(new PropertyWithValue<double>("A", 0.4, mustBeNonNegative,
......@@ -122,6 +128,12 @@ std::map<std::string, std::string> MaxEnt::validateInputs() {
}
}
size_t nhistograms = inWS->getNumberHistograms();
bool complex = getProperty("ComplexData");
if (complex && (nhistograms % 2))
result["InputWorkspace"] = "The number of histograms in the input "
"workspace must be even for complex data";
return result;
}
......@@ -132,6 +144,8 @@ void MaxEnt::exec() {
// Read input workspace
MatrixWorkspace_sptr inWS = getProperty("InputWorkspace");
// Complex data?
bool complex = getProperty("ComplexData");
// Background (default level, sky background, etc)
double background = getProperty("A");
......@@ -154,25 +168,39 @@ void MaxEnt::exec() {
size_t npoints = inWS->blocksize();
// Number of X bins
size_t npointsX = inWS->isHistogramData() ? npoints + 1 : npoints;
// We need to handle complex data
npoints *= 2;
// Create output workspaces
MatrixWorkspace_sptr outImageWS =
WorkspaceFactory::Instance().create(inWS, 2 * nspec, npointsX, npoints);
MatrixWorkspace_sptr outDataWS =
WorkspaceFactory::Instance().create(inWS, nspec, npointsX, npoints);
// Create evol workspaces
MatrixWorkspace_sptr outEvolChi =
WorkspaceFactory::Instance().create(inWS, nspec, niter, niter);
MatrixWorkspace_sptr outEvolTest =
WorkspaceFactory::Instance().create(inWS, nspec, niter, niter);
// Start distribution (flat background)
std::vector<double> image(npoints, background);
// Output workspaces
MatrixWorkspace_sptr outImageWS;
MatrixWorkspace_sptr outDataWS;
MatrixWorkspace_sptr outEvolChi;
MatrixWorkspace_sptr outEvolTest;
if (complex) {
outImageWS =
WorkspaceFactory::Instance().create(inWS, nspec, npointsX, npoints);
outDataWS =
WorkspaceFactory::Instance().create(inWS, nspec, npointsX, npoints);
outEvolChi =
WorkspaceFactory::Instance().create(inWS, nspec / 2, niter, niter);
outEvolTest =
WorkspaceFactory::Instance().create(inWS, nspec / 2, niter, niter);
nspec = nspec / 2;
} else {
outImageWS =
WorkspaceFactory::Instance().create(inWS, 2 * nspec, npointsX, npoints);
outDataWS =
WorkspaceFactory::Instance().create(inWS, nspec, npointsX, npoints);
outEvolChi = WorkspaceFactory::Instance().create(inWS, nspec, niter, niter);
outEvolTest =
WorkspaceFactory::Instance().create(inWS, nspec, niter, niter);
}
// We need to handle complex data
npoints *= 2;
for (size_t s = 0; s < nspec; s++) {
// Start distribution (flat background)
std::vector<double> image(npoints, background);
// Read data from the input workspace
// Only real part, complex part is zero
std::vector<double> data(npoints, 0.);
......@@ -181,6 +209,12 @@ void MaxEnt::exec() {
data[2 * i] = inWS->readY(s)[i];
error[2 * i] = inWS->readE(s)[i];
}
if (complex) {
for (size_t i = 0; i < npoints / 2; i++) {
data[2 * i + 1] = inWS->readY(2 * s + 1)[i];
error[2 * i + 1] = inWS->readE(2 * s + 1)[i];
}
}
// To record the algorithm's progress
std::vector<double> evolChi(niter, 0.);
......@@ -248,7 +282,7 @@ void MaxEnt::exec() {
std::vector<double> solutionData = transformImageToData(newImage);
// Populate the output workspaces
populateOutputWS(inWS, s, nspec, solutionData, newImage, outDataWS,
populateOutputWS(inWS, complex, s, nspec, solutionData, newImage, outDataWS,
outImageWS);
// Populate workspaces recording the evolution of Chi and Test
......@@ -756,8 +790,21 @@ double MaxEnt::distance(const DblMatrix &s2, const std::vector<double> &beta) {
return dist;
}
void MaxEnt::populateOutputWS(const MatrixWorkspace_sptr &inWS, size_t spec,
size_t nspec, const std::vector<double> &data,
/** Populates the output workspaces
* @param inWS :: [input] The input workspace
* @param complex :: [input] Whether or not the input is complex
* @param spec :: [input] The current spectrum being analyzed
* @param nspec :: [input] The total number of histograms in the input workspace
* @param data :: [input] The reconstructed data
* @param image :: [input] The reconstructed image
* @param outData :: [output] The output workspace containing the reconstructed
* data
* @param outImage :: [output] The output workspace containing the reconstructed
* image
*/
void MaxEnt::populateOutputWS(const MatrixWorkspace_sptr &inWS, bool complex,
size_t spec, size_t nspec,
const std::vector<double> &data,
const std::vector<double> &image,
MatrixWorkspace_sptr &outData,
MatrixWorkspace_sptr &outImage) {
......@@ -774,10 +821,18 @@ void MaxEnt::populateOutputWS(const MatrixWorkspace_sptr &inWS, size_t spec,
// Reconstructed data
for (int i = 0; i < npoints; i++)
for (int i = 0; i < npoints; i++) {
YR[i] = data[2 * i];
YI[i] = data[2 * i + 1];
}
outData->dataX(spec) = inWS->readX(spec);
outData->dataY(spec).assign(YR.begin(), YR.end());
outData->dataE(spec).assign(E.begin(), E.end());
if (complex) {
outData->dataX(nspec + spec) = inWS->readX(spec);
outData->dataY(nspec + spec).assign(YI.begin(), YI.end());
outData->dataE(nspec + spec).assign(E.begin(), E.end());
}
// Reconstructed image
......@@ -794,15 +849,14 @@ void MaxEnt::populateOutputWS(const MatrixWorkspace_sptr &inWS, size_t spec,
if (npointsX == npoints + 1)
X[npoints] = X[npoints - 1] + delta;
// Real part
outImage->dataX(spec).assign(X.begin(), X.end());
outImage->dataY(spec).assign(YR.begin(), YR.end());
outImage->dataE(spec).assign(E.begin(), E.end());
// Imaginary part
outImage->dataX(nspec + spec).assign(X.begin(), X.end());
outImage->dataY(nspec + spec).assign(YI.begin(), YI.end());
// No errors
outData->dataE(spec).assign(E.begin(), E.end());
outImage->dataE(spec).assign(E.begin(), E.end());
outImage->dataE(spec + nspec).assign(E.begin(), E.end());
outImage->dataE(nspec + spec).assign(E.begin(), E.end());
}
} // namespace Algorithms
......
......@@ -13,6 +13,7 @@
#include "MantidAlgorithms/Power.h"
#include "MantidAPI/AlgorithmManager.h"
#include "MantidAPI/FrameworkManager.h"
#include "MantidKernel/make_unique.h"
#include <Poco/File.h>
using namespace Mantid;
......@@ -149,7 +150,7 @@ public:
// set up history for the algorithn which is presumably removed from Mantid
auto ws = API::FrameworkManager::Instance().getWorkspace(wsName);
API::WorkspaceHistory &history = ws->history();
auto pAlg = std::auto_ptr<API::Algorithm>(new NonExistingAlgorithm());
auto pAlg = Mantid::Kernel::make_unique<NonExistingAlgorithm>();
pAlg->initialize();
history.addHistory(boost::make_shared<AlgorithmHistory>(
API::AlgorithmHistory(pAlg.get())));
......
......@@ -2,6 +2,7 @@
#define MANTID_ALGORITHMS_GENERATEPYTHONSCRIPTTEST_H_
#include <cxxtest/TestSuite.h>
#include "MantidKernel/make_unique.h"
#include "MantidKernel/Timer.h"
#include "MantidKernel/System.h"
#include <fstream>
......@@ -147,7 +148,7 @@ public:
// set up history for the algorithn which is presumably removed from Mantid
auto ws = API::FrameworkManager::Instance().getWorkspace(wsName);
API::WorkspaceHistory &history = ws->history();
auto pAlg = std::auto_ptr<API::Algorithm>(new NonExistingAlgorithm());
auto pAlg = Mantid::Kernel::make_unique<NonExistingAlgorithm>();
pAlg->initialize();
history.addHistory(boost::make_shared<AlgorithmHistory>(
API::AlgorithmHistory(pAlg.get())));
......
......@@ -5,6 +5,7 @@
#include "MantidAPI/FrameworkManager.h"
#include "MantidAPI/AlgorithmManager.h"
#include "MantidTestHelpers/WorkspaceCreationHelper.h"
using namespace Mantid::API;
using Mantid::MantidVec;
......@@ -22,9 +23,96 @@ public:
TS_ASSERT(alg->isInitialized())
}
void test_real_data() {
// Run one iteration, we just want to test the output workspaces' dimensions
int nHist = 5;
int nBins = 10;
auto ws = WorkspaceCreationHelper::Create2DWorkspace(nHist, nBins);
IAlgorithm_sptr alg = AlgorithmManager::Instance().create("MaxEnt");
alg->initialize();
alg->setChild(true);
alg->setProperty("InputWorkspace", ws);
alg->setPropertyValue("MaxIterations", "1");
alg->setPropertyValue("ReconstructedImage", "image");
alg->setPropertyValue("ReconstructedData", "data");
alg->setPropertyValue("EvolChi", "evolChi");
alg->setPropertyValue("EvolAngle", "evolAngle");
TS_ASSERT_THROWS_NOTHING(alg->execute());
MatrixWorkspace_sptr data = alg->getProperty("ReconstructedData");
MatrixWorkspace_sptr image = alg->getProperty("ReconstructedImage");
MatrixWorkspace_sptr chi = alg->getProperty("EvolChi");
MatrixWorkspace_sptr angle = alg->getProperty("EvolAngle");
TS_ASSERT_EQUALS(data->getNumberHistograms(), nHist);
TS_ASSERT_EQUALS(image->getNumberHistograms(), nHist * 2);
TS_ASSERT_EQUALS(chi->getNumberHistograms(), nHist);
TS_ASSERT_EQUALS(angle->getNumberHistograms(), nHist);
TS_ASSERT_EQUALS(data->blocksize(), nBins);
TS_ASSERT_EQUALS(image->blocksize(), nBins);
TS_ASSERT_EQUALS(chi->blocksize(), 1);
TS_ASSERT_EQUALS(angle->blocksize(), 1);
}
void test_complex_data() {
// Run one iteration, we just want to test the output workspaces' dimensions
int nHist = 6;
int nBins = 10;
auto ws = WorkspaceCreationHelper::Create2DWorkspace(nHist, nBins);
IAlgorithm_sptr alg = AlgorithmManager::Instance().create("MaxEnt");
alg->initialize();
alg->setChild(true);
alg->setProperty("InputWorkspace", ws);
alg->setProperty("ComplexData", true);
alg->setPropertyValue("MaxIterations", "1");
alg->setPropertyValue("ReconstructedImage", "image");
alg->setPropertyValue("ReconstructedData", "data");
alg->setPropertyValue("EvolChi", "evolChi");
alg->setPropertyValue("EvolAngle", "evolAngle");
TS_ASSERT_THROWS_NOTHING(alg->execute());
MatrixWorkspace_sptr data = alg->getProperty("ReconstructedData");
MatrixWorkspace_sptr image = alg->getProperty("ReconstructedImage");
MatrixWorkspace_sptr chi = alg->getProperty("EvolChi");
MatrixWorkspace_sptr angle = alg->getProperty("EvolAngle");
TS_ASSERT_EQUALS(data->getNumberHistograms(), nHist);
TS_ASSERT_EQUALS(image->getNumberHistograms(), nHist);
TS_ASSERT_EQUALS(chi->getNumberHistograms(), nHist / 2);
TS_ASSERT_EQUALS(angle->getNumberHistograms(), nHist / 2);
TS_ASSERT_EQUALS(data->blocksize(), nBins);
TS_ASSERT_EQUALS(image->blocksize(), nBins);
TS_ASSERT_EQUALS(chi->blocksize(), 1);
TS_ASSERT_EQUALS(angle->blocksize(), 1);
}
void test_bad_complex_data() {
auto ws = WorkspaceCreationHelper::Create2DWorkspace(5, 10);
IAlgorithm_sptr alg = AlgorithmManager::Instance().create("MaxEnt");
alg->initialize();
alg->setChild(true);
alg->setProperty("InputWorkspace", ws);
alg->setProperty("ComplexData", true);
alg->setPropertyValue("MaxIterations", "1");
alg->setPropertyValue("ReconstructedImage", "image");
alg->setPropertyValue("ReconstructedData", "data");
alg->setPropertyValue("EvolChi", "evolChi");
alg->setPropertyValue("EvolAngle", "evolAngle");
TS_ASSERT_THROWS_ANYTHING(alg->execute());
}
void test_cosine() {
auto ws = createWorkspace(0.0);
auto ws = createWorkspace(50, 0.0);
IAlgorithm_sptr alg = AlgorithmManager::Instance().create("MaxEnt");
alg->initialize();
......@@ -57,7 +145,7 @@ public:
void test_sine() {
auto ws = createWorkspace(M_PI / 2.);
auto ws = createWorkspace(50, M_PI / 2.);
IAlgorithm_sptr alg = AlgorithmManager::Instance().create("MaxEnt");
alg->initialize();
......@@ -88,14 +176,12 @@ public:
TS_ASSERT_DELTA(data->readY(0)[27], 0.7218, 0.0001);
}
MatrixWorkspace_sptr createWorkspace(double phase) {
MatrixWorkspace_sptr createWorkspace(size_t maxt, double phase) {
// Create cosine with phase 'phase'
// Frequency of the oscillations
double w = 1.6;
// Maximum time
size_t maxt = 50;
MantidVec X;
MantidVec Y;
......@@ -106,7 +192,6 @@ public:
Y.push_back(cos(w * x + phase));
E.push_back(0.1);
}
auto createWS = AlgorithmManager::Instance().create("CreateWorkspace");
createWS->initialize();
createWS->setChild(true);
......
......@@ -281,9 +281,8 @@ public:
TS_ASSERT_THROWS_NOTHING(
norm5.setPropertyValue("OutputWorkspace", "normMon5"));
std::auto_ptr<MonIDPropChanger> pID =
std::auto_ptr<MonIDPropChanger>(new MonIDPropChanger(
"InputWorkspace", "MonitorSpectrum", "MonitorWorkspace"));
auto pID = Mantid::Kernel::make_unique<MonIDPropChanger>(
"InputWorkspace", "MonitorSpectrum", "MonitorWorkspace");
// property is enabled but the conditions have not changed;
TS_ASSERT(pID->isEnabled(&norm5));
......@@ -322,9 +321,8 @@ public:
norm6.setPropertyValue("InputWorkspace", "normMon"));
TS_ASSERT_THROWS_NOTHING(
norm6.setPropertyValue("OutputWorkspace", "normMon6"));
std::auto_ptr<MonIDPropChanger> pID =
std::auto_ptr<MonIDPropChanger>(new MonIDPropChanger(
"InputWorkspace", "MonitorSpectrum", "MonitorWorkspace"));
auto pID = Mantid::Kernel::make_unique<MonIDPropChanger>(
"InputWorkspace", "MonitorSpectrum", "MonitorWorkspace");
// first time in a row the condition has changed as it shluld read the
// monitors from the workspace
TS_ASSERT(pID->isConditionChanged(&norm6));
......
......@@ -10,6 +10,7 @@
#include "MantidDataObjects/TableWorkspace.h"
#include "MantidAPI/TableRow.h"
#include "MantidAPI/FrameworkManager.h"
#include <array>
using namespace Mantid;
using namespace Mantid::API;
......@@ -386,13 +387,7 @@ public:
#else
// TS_ASSERT_EQUALS(char(0x0A),descr.line_end);
#endif
std::vector<double> pattern(6, 0);
pattern[0] = 10;
pattern[1] = 0;
pattern[2] = 5;
pattern[3] = 6;
pattern[4] = 7;
pattern[5] = 8;
std::vector<double> pattern{10, 0, 5, 6, 7, 8};
for (size_t j = 0; j < descr.nData_records; j++) {
for (size_t i = 0; i < 6; i++) {
TS_ASSERT_DELTA(pattern[i], result[i + j * 6], FLT_EPSILON)
......@@ -541,18 +536,17 @@ private:
std::string polw_pattern("0.804071,0.804258,0.804442,");
std::string azw_pattern("5.72472,5.72472,5.72472,");
std::auto_ptr<std::stringstream> bufs[5];
std::array<std::stringstream, 5> bufs;
for (int j = 0; j < 5; j++) {
bufs[j] = std::auto_ptr<std::stringstream>(new std::stringstream);
for (int i = 0; i < 3; i++) {
*(bufs[j]) << spResult->cell<double>(i, j) << ",";
bufs[j] << spResult->cell<double>(i, j) << ",";
}
}
TSM_ASSERT_EQUALS("azimut wrong", pol_pattern, bufs[0]->str());
TSM_ASSERT_EQUALS("polar wrong ", azim_pattern, bufs[1]->str());
TSM_ASSERT_EQUALS("flight path wrong ", sfp_pattern, bufs[2]->str());
TSM_ASSERT_EQUALS("polar width wrong ", polw_pattern, bufs[3]->str());
TSM_ASSERT_EQUALS("azimuthal width wrong ", azw_pattern, bufs[4]->str());
TSM_ASSERT_EQUALS("azimut wrong", pol_pattern, bufs[0].str());
TSM_ASSERT_EQUALS("polar wrong ", azim_pattern, bufs[1].str());
TSM_ASSERT_EQUALS("flight path wrong ", sfp_pattern, bufs[2].str());
TSM_ASSERT_EQUALS("polar width wrong ", polw_pattern, bufs[3].str());
TSM_ASSERT_EQUALS("azimuthal width wrong ", azw_pattern, bufs[4].str());
}
};
#endif
......@@ -5,13 +5,7 @@
#include "MantidDataObjects/MDEventFactory.h"
#include <Poco/File.h>
// clang-format off
#if defined(__GLIBCXX__) && __GLIBCXX__ >= 20100121 // libstdc++-4.4.3
typedef std::unique_ptr< ::NeXus::File> file_holder_type;
#else
typedef std::auto_ptr< ::NeXus::File> file_holder_type;
#endif
// clang-format on
typedef std::unique_ptr<::NeXus::File> file_holder_type;
namespace Mantid {
namespace DataObjects {
......
......@@ -14,23 +14,45 @@
namespace Mantid {
namespace Geometry {
/// Functor for fuzzy comparison of V3D-objects using Kernel::Tolerance
struct MANTID_GEOMETRY_DLL FuzzyV3DLessThan {
bool operator()(const Kernel::V3D &lhs, const Kernel::V3D &rhs) {
if (fabs(lhs.X() - rhs.X()) > Kernel::Tolerance) {
/// Equality-functor for comparison of atom positions with specifiable precision
class MANTID_GEOMETRY_DLL AtomPositionsEqual {
public:
AtomPositionsEqual(double precision = 1.e-4) : m_precision(precision) {}
bool operator()(const Kernel::V3D &lhs, const Kernel::V3D &rhs) const {
return !(fabs(lhs.X() - rhs.X()) > m_precision ||
fabs(lhs.Y() - rhs.Y()) > m_precision ||
fabs(lhs.Z() - rhs.Z()) > m_precision);
}
private:
double m_precision;
};
/// Less-than-functor for comparison of atom positions with specifiable
/// precision
class MANTID_GEOMETRY_DLL AtomPositionsLessThan {
public:
AtomPositionsLessThan(double precision = 1.e-4) : m_precision(precision) {}
bool operator()(const Kernel::V3D &lhs, const Kernel::V3D &rhs) const {
if (fabs(lhs.X() - rhs.X()) > m_precision) {
return lhs.X() < rhs.X();
}
if (fabs(lhs.Y() - rhs.Y()) > Kernel::Tolerance) {
if (fabs(lhs.Y() - rhs.Y()) > m_precision) {
return lhs.Y() < rhs.Y();
}
if (fabs(lhs.Z() - rhs.Z()) > Kernel::Tolerance) {
if (fabs(lhs.Z() - rhs.Z()) > m_precision) {
return lhs.Z() < rhs.Z();
}
return false;
}
private:
double m_precision;
};
/**
......
......@@ -81,8 +81,9 @@ public:
}
// Use fuzzy compare with the same condition as V3D::operator==().
std::sort(equivalents.begin(), equivalents.end(), FuzzyV3DLessThan());
equivalents.erase(std::unique(equivalents.begin(), equivalents.end()),
std::sort(equivalents.begin(), equivalents.end(), AtomPositionsLessThan());
equivalents.erase(std::unique(equivalents.begin(), equivalents.end(),
AtomPositionsEqual()),
equivalents.end());
return equivalents;
......
......@@ -91,7 +91,7 @@ std::vector<Kernel::V3D> Group::operator*(const Kernel::V3D &vector) const {
result.push_back(Geometry::getWrappedVector((*op) * vector));
}
std::sort(result.begin(), result.end(), FuzzyV3DLessThan());
std::sort(result.begin(), result.end(), AtomPositionsLessThan());
result.erase(std::unique(result.begin(), result.end()), result.end());
return result;
......
......@@ -105,9 +105,11 @@ Group_const_sptr SpaceGroup::getSiteSymmetryGroup(const V3D &position) const {
std::vector<SymmetryOperation> siteSymmetryOps;
AtomPositionsEqual comparator;
for (auto op = m_allOperations.begin(); op != m_allOperations.end(); ++op) {
if (Geometry::getWrappedVector((*op) * wrappedPosition) ==
wrappedPosition) {
if (comparator(Geometry::getWrappedVector((*op) * wrappedPosition),
wrappedPosition)) {
siteSymmetryOps.push_back(*op);
}
}
......
......@@ -185,8 +185,8 @@ public:
TS_ASSERT_EQUALS(two.getCoordinateSystem(), Group::Hexagonal);
}
void testFuzzyV3DLessThan() {
FuzzyV3DLessThan lessThan;
void testAtomPositionLessThan() {
AtomPositionsLessThan lessThan(1.e-6);
V3D v1(0.654321, 0.0, 0.0);
V3D v2(0.654320, 0.0, 0.0);
......@@ -220,6 +220,33 @@ public:
TS_ASSERT(!lessThan(v7, v1));
}
void testAtomPositionEqual() {
AtomPositionsEqual equal(1.e-6);
V3D v1(0.654321, 0.0, 0.0);
V3D v2(0.654320, 0.0, 0.0);
TS_ASSERT(!equal(v2, v1));
// 7th digit is not compared.
V3D v3(0.6543211, 0.0, 0.0);
TS_ASSERT(equal(v1, v3));
TS_ASSERT(equal(v3, v1));
// Same for y
V3D v4(0.654321, 0.0000010001, 0.0);
TS_ASSERT(!equal(v1, v4));
V3D v5(0.654321, 0.0000001, 0.0);
TS_ASSERT(equal(v5, v1));
// Same for z
V3D v6(0.654321, 0.0, 0.0000010001);
TS_ASSERT(!equal(v1, v6));
V3D v7(0.654321, 0.0, 0.0000001);
TS_ASSERT(equal(v1, v7));
}
void testContainsOperation() {
Group group("x,y,z; -x,-y,-z");
......
......@@ -28,11 +28,7 @@
#include <boost/algorithm/string.hpp>
#include <vector>
#if defined(__GLIBCXX__) && __GLIBCXX__ >= 20100121 // libstdc++-4.4.3
typedef std::unique_ptr<Mantid::API::IBoxControllerIO> file_holder_type;
#else
typedef std::auto_ptr