Vector sum implementations
The vector sum operation
\[
d = a \cdot x + y,
\]
is implemented via a polymorphic interface in C++. This allows seamless switching between a simple element-wise loop and a GSL-optimized version.
Common interface
All implementations derive from an abstract base class VectorSumInterface
, declared in VectorSumInterface.hpp
:
VectorSumInterface.hpp |
---|
| class VectorSumInterface {
public:
virtual ~VectorSumInterface() {}
/// Compute d = a*x + y.
virtual void compute_sum(
const std::vector<double>& x,
const std::vector<double>& y,
double a,
std::vector<double>& d
) = 0;
};
|
This enforces a uniform method signature across all concrete classes.
Default (element-by-element) implementation
The class VectorSumDefault
provides the straightforward loop-based approach. Its code is in VectorSumDefault.hpp
:
VectorSumDefault.hpp |
---|
| class VectorSumDefault : public VectorSumInterface {
public:
void compute_sum(
const std::vector<double>& x,
const std::vector<double>& y,
double a,
std::vector<double>& d
) override {
size_t N = x.size();
d.resize(N);
for (size_t i = 0; i < N; ++i) {
d[i] = a * x[i] + y[i];
}
}
};
|
This version requires only the C++ standard library and works reliably for all vector sizes.
GSL-based implementation
For larger vectors or performance-sensitive scenarios, VectorSumGSL
uses the GNU Scientific Library. Its implementation resides in VectorSumGSL.hpp
:
VectorSumGSL.hpp |
---|
| #include <gsl/gsl_vector.h>
#include <gsl/gsl_blas.h>
class VectorSumGSL : public VectorSumInterface {
public:
void compute_sum(
const std::vector<double>& x,
const std::vector<double>& y,
double a,
std::vector<double>& d
) override {
size_t N = x.size();
d.resize(N);
// Allocate GSL vectors
gsl_vector* vx = gsl_vector_alloc(N);
gsl_vector* vy = gsl_vector_alloc(N);
gsl_vector* vd = gsl_vector_alloc(N);
// Copy data into GSL vectors
for (size_t i = 0; i < N; ++i) {
gsl_vector_set(vx, i, x[i]);
gsl_vector_set(vy, i, y[i]);
}
// Initialize vd = y
gsl_vector_memcpy(vd, vy);
// Compute vd = a * vx + 1.0 * vd ⇒ d = a*x + y
gsl_vector_axpby(a, vx, 1.0, vd);
// Copy result back to std::vector
for (size_t i = 0; i < N; ++i) {
d[i] = gsl_vector_get(vd, i);
}
// Free GSL resources
gsl_vector_free(vx);
gsl_vector_free(vy);
gsl_vector_free(vd);
}
};
|
This leverages gsl_vector_axpby, which internally can use optimized BLAS routines.
Runtime selection of implementation
At execution, the implementation is chosen based on the implementation field in the YAML
config. In vectorSum.cpp
, a std::unique_ptr<VectorSumInterface>
is created as either VectorSumDefault
or VectorSumGSL
:
vectorSum.cpp |
---|
| std::unique_ptr<VectorSumInterface> vs;
if (implementation == "default") {
vs.reset(new VectorSumDefault());
}
else if (implementation == "gsl") {
vs.reset(new VectorSumGSL());
}
else {
std::cerr << "Unsupported implementation: " << implementation << std::endl;
return 1;
}
// Compute the sum
std::vector<double> d;
vs->compute_sum(x, y, a, d);
|
This pattern ensures that the rest of the codebase treats both cases uniformly.