1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
export module linalgebra:vector;
import std;
import :error;
export namespace linalgebra {
class Vector {
public:
Vector() = default;
explicit Vector(std::size_t n);
Vector(std::size_t n, double value);
Vector(std::initializer_list<double> values);
[[nodiscard]] std::size_t size() const noexcept;
[[nodiscard]] bool empty() const noexcept;
double& operator[](std::size_t i);
const double& operator[](std::size_t i) const;
void fill(double value);
double* data() noexcept;
const double* data() const noexcept;
auto begin() noexcept { return data_.begin(); }
auto end() noexcept { return data_.end(); }
auto begin() const noexcept { return data_.begin(); }
auto end() const noexcept { return data_.end(); }
auto cbegin() const noexcept { return data_.cbegin(); }
auto cend() const noexcept { return data_.cend(); }
private:
void check_index(std::size_t i) const;
std::vector<double> data_;
};
Vector operator+(const Vector& lhs, const Vector& rhs);
Vector operator-(const Vector& lhs, const Vector& rhs);
Vector operator*(const Vector& v, double scalar);
Vector operator*(double scalar, const Vector& v);
Vector operator/(const Vector& v, double scalar);
double dot(const Vector& lhs, const Vector& rhs);
} // namespace linalgebra
namespace {
void check_same_size(const linalgebra::Vector& lhs, const linalgebra::Vector& rhs,
const char* operation) {
if (lhs.size() != rhs.size()) {
std::ostringstream oss;
oss << operation << " requires equal vector sizes, got " << lhs.size() << " and "
<< rhs.size();
throw linalgebra::DimensionMismatchError(oss.str());
}
}
} // namespace
namespace linalgebra {
Vector::Vector(std::size_t n) : data_(n) {}
Vector::Vector(std::size_t n, double value) : data_(n, value) {}
Vector::Vector(std::initializer_list<double> values) : data_(values) {}
std::size_t Vector::size() const noexcept { return data_.size(); }
bool Vector::empty() const noexcept { return data_.empty(); }
double& Vector::operator[](std::size_t i) {
check_index(i);
return data_[i];
}
const double& Vector::operator[](std::size_t i) const {
check_index(i);
return data_[i];
}
void Vector::fill(double value) { std::fill(data_.begin(), data_.end(), value); }
double* Vector::data() noexcept { return data_.data(); }
const double* Vector::data() const noexcept { return data_.data(); }
void Vector::check_index(std::size_t i) const {
if (i >= data_.size()) {
throw std::out_of_range("Vector index out of range");
}
}
Vector operator+(const Vector& lhs, const Vector& rhs) {
check_same_size(lhs, rhs, "Vector addition");
Vector result(lhs.size());
for (std::size_t i = 0; i < lhs.size(); ++i) {
result[i] = lhs[i] + rhs[i];
}
return result;
}
Vector operator-(const Vector& lhs, const Vector& rhs) {
check_same_size(lhs, rhs, "Vector subtraction");
Vector result(lhs.size());
for (std::size_t i = 0; i < lhs.size(); ++i) {
result[i] = lhs[i] - rhs[i];
}
return result;
}
Vector operator*(const Vector& v, double scalar) {
Vector result(v.size());
for (std::size_t i = 0; i < v.size(); ++i) {
result[i] = v[i] * scalar;
}
return result;
}
Vector operator*(double scalar, const Vector& v) { return v * scalar; }
Vector operator/(const Vector& v, double scalar) {
if (scalar == 0.0) {
throw std::invalid_argument("Vector scalar division requires a nonzero scalar");
}
Vector result(v.size());
for (std::size_t i = 0; i < v.size(); ++i) {
result[i] = v[i] / scalar;
}
return result;
}
double dot(const Vector& lhs, const Vector& rhs) {
check_same_size(lhs, rhs, "Dot product");
return std::inner_product(lhs.begin(), lhs.end(), rhs.begin(), 0.0);
}
} // namespace linalgebra
|