13using Matrix = std::vector<std::vector<double>>;
16static constexpr double EPS_SYM = 1e-10;
17static constexpr double EPS_DIAG = 1e-8;
21 if (!(std::cin >> n) || n <= 0) {
22 throw std::runtime_error(
"Impossible to read n (matrix size).");
24 Matrix A(
static_cast<size_t>(n), std::vector<double>(
static_cast<size_t>(n)));
25 for (
int i = 0; i < n; ++i) {
26 for (
int j = 0; j < n; ++j) {
27 if (!(std::cin >> A[i][j])) {
28 throw std::runtime_error(
"Matrix lecture has failed.");
36 std::cout << std::fixed << std::setprecision(6);
37 for (
size_t i = 0; i < v.size(); ++i) {
38 if (i) std::cout <<
" ";
59 const size_t n = R.size();
60 if (n == 0)
throw std::invalid_argument(
"Invalid matrix.");
61 for (
const auto& row : R) {
62 if (row.size() != n)
throw std::invalid_argument(
"Non squared matrix.");
66 for (
size_t i = 0; i < n; ++i) {
67 for (
size_t j = i + 1; j < n; ++j) {
68 if (std::fabs(R[i][j] - R[j][i]) > EPS_SYM) {
69 throw std::invalid_argument(
"Non symmetric matrix.");
74 for (
size_t i = 0; i < n; ++i) {
75 if (std::fabs(R[i][i] - 1.0) > EPS_DIAG) {
76 throw std::invalid_argument(
"Diagonal elements of the matrix needs to be ones");
87 const size_t n = R.size();
88 Matrix L(n, std::vector<double>(n, 0.0));
90 for (
size_t i = 0; i < n; ++i) {
91 for (
size_t j = 0; j <= i; ++j) {
93 for (
size_t k = 0; k < j; ++k) {
94 sum -= L[i][k] * L[j][k];
98 throw std::invalid_argument(
99 "Matrix is not positive-definite for Cholesky decomposition.");
101 L[i][j] = std::sqrt(sum);
103 L[i][j] = sum / L[j][j];
114 : eng_(seed), dist_(0.0, 1.0) {}
118 for (std::size_t i = 0; i < n; ++i) z[i] = dist_(eng_);
124 std::normal_distribution<double> dist_;
129 static std::unique_ptr<IMarginalDistribution>
create(
const std::string& name,
130 unsigned int seed = std::random_device{}()) {
131 std::string lower = name;
132 std::transform(lower.begin(), lower.end(), lower.begin(), [](
unsigned char c) {
133 return static_cast<char>(std::tolower(c));
136 if (lower ==
"gaussian" || lower ==
"normal" || lower ==
"gauss") {
137 return std::make_unique<GaussianMarginal>(seed);
140 throw std::invalid_argument(
"Unkwown distribution: " + name +
141 " (try: gaussian|normal)");
148 std::unique_ptr<IDecomposition> decomp)
149 : dist_(
std::move(dist)), decomp_(
std::move(decomp)) {}
154 Matrix L = decomp_->factorize(correlation);
155 const std::size_t n = L.size();
157 Vector z = dist_->sample(n);
160 for (std::size_t i = 0; i < n; ++i) {
162 for (std::size_t k = 0; k <= i; ++k) {
163 acc += L[i][k] * z[k];
171 std::unique_ptr<IMarginalDistribution> dist_;
172 std::unique_ptr<IDecomposition> decomp_;
177 <<
"Usage: " << prog <<
" [distribution=gaussian] [seed (optionnel)] < matrice.txt\n"
178 <<
" - La matrice d'entree est lue sur stdin au format:\n"
180 <<
" r11 r12 ... r1n\\n\n"
182 <<
" rn1 rn2 ... rnn\\n\n"
183 <<
" - Distribution supportee: gaussian|normal\n"
185 <<
" " << prog <<
" gaussian 12345 < my_corr.txt\n";
188int main(
int argc,
char** argv) {
190 std::string distName =
"gaussian";
191 unsigned int seed = std::random_device{}();
194 std::string arg1 = argv[1];
195 if (arg1 ==
"-h" || arg1 ==
"--help") {
203 seed =
static_cast<unsigned int>(std::stoul(argv[2]));
205 std::cerr <<
"Avertissement: seed invalide, utilisation d'un seed aleatoire.\n";
206 seed = std::random_device{}();
213 auto decomp = std::make_unique<CholeskyDecomposition>();
220 }
catch (
const std::exception& ex) {
221 std::cerr <<
"Erreur: " << ex.what() <<
"\n";
Matrix factorize(const Matrix &R) override
void validate(const Matrix &R) const
static std::unique_ptr< IMarginalDistribution > create(const std::string &name, unsigned int seed=std::random_device{}())
One-dimensional Gaussian marginal distribution.
Vector sample(std::size_t n) override
GaussianMarginal(unsigned int seed=std::random_device{}())
Vector generate(const Matrix &correlation) const
JointDistribution(std::unique_ptr< IMarginalDistribution > dist, std::unique_ptr< IDecomposition > decomp)
Hash specialization for SymbolId<Tag>.
virtual ~IDecomposition()=default
virtual Matrix factorize(const Matrix &R)=0
Abstract interface for scalar marginal distributions.
virtual Vector sample(std::size_t n)=0
virtual ~IMarginalDistribution()=default