Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
jschueller committed May 6, 2024
1 parent b40bd78 commit 43ca81d
Show file tree
Hide file tree
Showing 16 changed files with 462 additions and 73 deletions.
2 changes: 2 additions & 0 deletions lib/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
ot_add_current_dir_to_include_dirs ()

ot_add_source_file (SlicedInverseRegression.cxx)
ot_add_source_file (SlicedInverseRegressionResult.cxx)

ot_install_header_file (SlicedInverseRegression.hxx)
ot_install_header_file (SlicedInverseRegressionResult.hxx)


include_directories (${INTERNAL_INCLUDE_DIRS})
Expand Down
142 changes: 133 additions & 9 deletions lib/src/SlicedInverseRegression.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
*/
#include "otsliced/SlicedInverseRegression.hxx"
#include <openturns/PersistentObjectFactory.hxx>
#include <openturns/SquareComplexMatrix.hxx>
#include <openturns/SpecFunc.hxx>

using namespace OT;

Expand All @@ -38,22 +40,109 @@ SlicedInverseRegression::SlicedInverseRegression()
// Nothing to do
}

SlicedInverseRegression::SlicedInverseRegression(const Sample & inputSample,
const Sample & outputSample)
: PersistentObject()
, inputSample_(inputSample)
, outputSample_(outputSample)
, modesNumber_(inputSample.getDimension())
{
if (outputSample.getDimension() != 1)
throw InvalidArgumentException(HERE) << "Supervision variable must be of dimension 1";
}

/* Virtual constructor method */
SlicedInverseRegression * SlicedInverseRegression::clone() const
{
return new SlicedInverseRegression(*this);
}

/* example of a func that return a point squared. */
Point SlicedInverseRegression::square(Point& p) const
{
void SlicedInverseRegression::run()
{
const UnsignedInteger size = inputSample_.getSize();

Point p_out(p.getSize());
for(UnsignedInteger i = 0; i < p.getSize(); ++ i)
const Indices supervisionIndices = outputSample_.argsort();
Collection<Indices> list_chunk;
UnsignedInteger offset = 0;
Indices chunk_population;
for (UnsignedInteger i = 0; i < sliceNumber_; ++ i)
{
const UnsignedInteger localSize = std::min(size / sliceNumber_, size - offset);
Indices chunk(localSize);
std::copy(supervisionIndices.begin() + offset, supervisionIndices.begin() + offset + localSize, chunk.begin());
list_chunk.add(chunk);
chunk_population.add(localSize);
offset += localSize;
}
const Point center(inputSample_.computeMean());
Sample X_centered(inputSample_);
X_centered -= center;
CovarianceMatrix input_covariance(X_centered.computeCovariance());
input_covariance.getImplementation()->symmetrize();
Matrix u;
Matrix vT;
#if OPENTURNS_VERSION >= 102300
const Point singularValues = input_covariance.computeSVDInPlace(u, vT, false); // fullSVD
#else
const Point singularValues = input_covariance.computeSVD(u, vT, false, false); // fullSVD, keepIntact
#endif
Point s1(singularValues.getSize());
for(UnsignedInteger i = 0; i < s1.getSize(); ++ i)
s1[i] = 1.0 / singularValues[i];
Matrix us1(u);
for(UnsignedInteger j = 0; j < s1.getSize(); ++ j)
for(UnsignedInteger i = 0; i < s1.getSize(); ++ i)
us1(i, j) *= s1[j];
Matrix inverseCovariance(us1 * vT);
const UnsignedInteger inputDimension = inputSample_.getDimension();
Matrix weighted_covariance(inputDimension, inputDimension);
for(UnsignedInteger j = 0; j < sliceNumber_; ++ j)
{
p_out[i] = p[i] * p[i];
const Point meanSlice(inputSample_.select(list_chunk[j]).computeMean());
Matrix slice_moment(inputDimension, 1);
for(UnsignedInteger i = 0; i < inputDimension; ++ i)
slice_moment(i, 0) = meanSlice[i];
Matrix slice_covariance(slice_moment * slice_moment.transpose());
const Scalar w = chunk_population[j] * 1.0 / size;
weighted_covariance = weighted_covariance + slice_covariance * w;
}
return p_out;
SquareComplexMatrix eigen_vector;
SquareMatrix icwc((inverseCovariance * weighted_covariance).getImplementation());
#if OPENTURNS_VERSION >= 102300
const SquareMatrix::ComplexCollection eigen_value = icwc.computeEVInPlace(eigen_vector);
#else
const SquareMatrix::ComplexCollection eigen_value = icwc.computeEV(eigen_vector, false); // keepIntact
#endif
Sample evs(eigen_value.getSize(), 1);
Scalar max_imag = 0.0;
for(UnsignedInteger i = 0; i < eigen_value.getSize(); ++ i)
{
evs(i, 0) = eigen_value[i].real();
max_imag = std::max(max_imag, std::abs(eigen_value[i].imag()));
}

if (max_imag > std::sqrt(SpecFunc::Precision))
throw NotDefinedException(HERE) << "complex eigen-values during SIR";
else if (max_imag > 0.0)
LOGWARN("negligible complex eigen-values during SIR");

// Matrix eigen_vector2(eigen_vector.real());
const Indices order(evs.argsort(false));

Point singular_values(modesNumber_);
Matrix basis(inputDimension, modesNumber_);
for(UnsignedInteger j = 0; j < modesNumber_; ++ j)
{
singular_values[j] = eigen_value[order[j]].real();
for(UnsignedInteger i = 0; i < inputDimension; ++ i)
basis(i, j) = eigen_vector(i, order[j]).real();
}
result_ = SlicedInverseRegressionResult(basis, center);
}

SlicedInverseRegressionResult SlicedInverseRegression::getResult() const
{
return result_;
}

/* String converter */
Expand All @@ -64,16 +153,51 @@ String SlicedInverseRegression::__repr__() const
return oss;
}


/* Slice number accessor */
UnsignedInteger SlicedInverseRegression::getSliceNumber() const
{
return sliceNumber_;
}

void SlicedInverseRegression::setSliceNumber(const UnsignedInteger sliceNumber)
{
sliceNumber_ = sliceNumber;
}

/* Modes number accessor */
void SlicedInverseRegression::setModesNumber(const UnsignedInteger modesNumber)
{
if (modesNumber_ > inputSample_.getDimension())
throw InvalidArgumentException(HERE) << "Cannot use more than " <<inputSample_.getDimension() << " modes";
modesNumber_ = modesNumber;
}

UnsignedInteger SlicedInverseRegression::getModesNumber() const
{
return modesNumber_;
}

/* Method save() stores the object through the StorageManager */
void SlicedInverseRegression::save(Advocate & adv) const
{
PersistentObject::save( adv );
PersistentObject::save(adv);
adv.saveAttribute( "inputSample_", inputSample_ );
adv.saveAttribute( "outputSample_", outputSample_ );
adv.saveAttribute( "sliceNumber_", sliceNumber_ );
adv.saveAttribute( "modesNumber", modesNumber_ );
adv.saveAttribute( "result_", result_ );
}

/* Method load() reloads the object from the StorageManager */
void SlicedInverseRegression::load(Advocate & adv)
{
PersistentObject::load( adv );
PersistentObject::load(adv);
adv.loadAttribute( "inputSample_", inputSample_ );
adv.loadAttribute( "outputSample_", outputSample_ );
adv.loadAttribute( "sliceNumber_", sliceNumber_ );
adv.loadAttribute( "modesNumber", modesNumber_ );
adv.loadAttribute( "result_", result_ );
}


Expand Down
94 changes: 94 additions & 0 deletions lib/src/SlicedInverseRegressionResult.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// -*- C++ -*-
/**
* @brief SlicedInverseRegressionResult
*
* Copyright 2005-2024 Airbus-EDF-IMACS-ONERA-Phimeca
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*
*/

#include "otsliced/SlicedInverseRegressionResult.hxx"

#include <openturns/PersistentObjectFactory.hxx>
#include <openturns/LinearFunction.hxx>

using namespace OT;

namespace OTSLICED
{

CLASSNAMEINIT(SlicedInverseRegressionResult);

static Factory<SlicedInverseRegressionResult> Factory_SlicedInverseRegressionResult;


/* Default constructor */
SlicedInverseRegressionResult::SlicedInverseRegressionResult()
: PersistentObject()
{
// Nothing to do
}

SlicedInverseRegressionResult::SlicedInverseRegressionResult(const OT::Matrix & basis,
const OT::Point & center)
: PersistentObject()
, basis_(basis)
, center_(center)
{
}

/* Virtual constructor method */
SlicedInverseRegressionResult * SlicedInverseRegressionResult::clone() const
{
return new SlicedInverseRegressionResult(*this);
}

/* String converter */
String SlicedInverseRegressionResult::__repr__() const
{
OSS oss;
oss << "class=" << SlicedInverseRegressionResult::GetClassName();
return oss;
}

Function SlicedInverseRegressionResult::getTransformation() const
{
return LinearFunction(center_, Point(center_.getDimension()), basis_);
}

Function SlicedInverseRegressionResult::getInverseTransformation() const
{
Matrix inv(basis_.solveLinearSystem(IdentityMatrix(center_.getDimension())));
return LinearFunction(-center_, Point(center_.getDimension()), inv);
}

/* Method save() stores the object through the StorageManager */
void SlicedInverseRegressionResult::save(Advocate & adv) const
{
PersistentObject::save(adv);
adv.saveAttribute( "basis_", basis_ );
adv.saveAttribute( "center_", center_ );
}

/* Method load() reloads the object from the StorageManager */
void SlicedInverseRegressionResult::load(Advocate & adv)
{
PersistentObject::load(adv);
adv.loadAttribute( "basis_", basis_ );
adv.loadAttribute( "center_", center_ );
}


} /* namespace OTSLICED */
32 changes: 25 additions & 7 deletions lib/src/otsliced/SlicedInverseRegression.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,17 @@
#ifndef OTSLICED_SLICEDINVERSEREGRESSION_HXX
#define OTSLICED_SLICEDINVERSEREGRESSION_HXX

#include <openturns/PersistentObject.hxx>
#include <openturns/StorageManager.hxx>
#include <openturns/Point.hxx>
#include "otsliced/otslicedprivate.hxx"
#include "otsliced/SlicedInverseRegressionResult.hxx"

#include <openturns/Sample.hxx>

namespace OTSLICED
{

/**
* @class SlicedInverseRegression
*
* SlicedInverseRegression is some slicedinverseregression type to illustrate how to add some classes in OpenTURNS
* SIR dimension reduction
*/
class OTSLICED_API SlicedInverseRegression
: public OT::PersistentObject
Expand All @@ -43,11 +42,23 @@ public:
/** Default constructor */
SlicedInverseRegression();

SlicedInverseRegression(const OT::Sample & inputSample,
const OT::Sample & outputSample);

/** Virtual constructor method */
SlicedInverseRegression * clone() const override;

/** example of a func that return a point squared. **/
OT::Point square(OT::Point& p) const;
/** Slice number accessor */
void setSliceNumber(const OT::UnsignedInteger sliceNumber);
OT::UnsignedInteger getSliceNumber() const;

/** Modes number accessor */
void setModesNumber(const OT::UnsignedInteger modesNumber);
OT::UnsignedInteger getModesNumber() const;

void run();

SlicedInverseRegressionResult getResult() const;

/** String converter */
OT::String __repr__() const override;
Expand All @@ -59,6 +70,13 @@ public:
void load(OT::Advocate & adv) override;

private:
OT::Sample inputSample_;
OT::Sample outputSample_;

OT::UnsignedInteger modesNumber_ = 0;
OT::UnsignedInteger sliceNumber_ = 10;

SlicedInverseRegressionResult result_;

}; /* class SlicedInverseRegression */

Expand Down
Loading

0 comments on commit 43ca81d

Please sign in to comment.