#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
#include <numeric>
using namespace std;
long gcd(long a, long b) {
if (a < 0 || b < 0) return gcd(abs(a), abs(b));
else if (min(a, b) == 0)
return max(1l, max(a, b));
else if (a == b)
return a;
else
return gcd(min(a, b), max(a, b) - min(a, b));
}
struct vec {
vec(vector<long> v) : v_(v) {}
vector<long>& v() { return v_; }
const vector<long>& v() const { return v_; }
vec operator+(const vec&) const;
vec operator*(long) const;
long operator*(const vec&) const;
void reduceByGCD();
bool isZero() const { return v() == vector<long>(v().size()); }
private:
vector<long> v_;
long gcd() const;
};
long
vec::gcd() const
{
if (v_.empty()) return 1;
long res = v_[0];
for (int i = 1; i < v_.size(); ++i)
res = ::gcd(res, v_[i]);
return res;
}
void
vec::reduceByGCD()
{
long div = gcd();
for (auto &a: v_) a /= div;
}
vec
vec::operator+(const vec& r) const
{
vector<long> res(v().size());
transform(this->v_.begin(), this->v_.end(), r.v_.begin(), res.begin(), plus<long>());
return vec(res);
}
vec
vec::operator*(long k) const
{
vector<long> res(v().size());
transform(this->v_.begin(), this->v_.end(), res.begin(), bind(multiplies<long>(), placeholders::_1, k));
return vec(res);
}
long
vec::operator*(const vec& r) const
{
return inner_product(v_.begin(), v_.end(), r.v().begin(), 0l);
}
vec gschmidt_and_reduce(const vec& what, const vec& other)
{
long sqNorm = other*other;
vec res = what*sqNorm + other*(what*other)*-1;
res.reduceByGCD();
return res;
}
vector<vec>
gschmidt_and_reduce(const vector<vec>& vs)
{
vector<vec> res;
for (size_t i = 0; i < vs.size(); ++i) {
vec cur = vs[i];
for (int k = 0; k < i; ++k)
cur = gschmidt_and_reduce(cur, res[k]);
res.push_back(cur);
}
return res;
}
int main() {
vector<vec> A = {
vec({ 3, 5, 4, -4 }),
vec({ -2, -3, -2, 1 }),
vec({ -5, -9, -6, 8 }),
vec({ 1, 0, 0, 0 }),
vec({ 0, 1, 0, 0 }),
vec({ 0, 0, 1, 0 }),
vec({ 0, 0, 0, 1 }),
};
vector<vec> orthogonilizedA = gschmidt_and_reduce(A);
cout << "Orthogonalized a:"<< endl;
for (int i = 0; i < orthogonilizedA.size(); ++i) {
if (!orthogonilizedA[i].isZero()) {
for (auto coordinate: orthogonilizedA[i].v())
cout << coordinate << ", ";
cout << endl;
}
if (i == 2)
cout << "Orthogonal complement of a:" << endl;
}
vector<vec> B = {
vec({ -4, -5, -3, 3 }),
vec({ 2, 7, 0, -6 }),
vec({ -1, 0, -1, 0 }),
vec({ 1, 0, 0, 0 }),
vec({ 0, 1, 0, 0 }),
vec({ 0, 0, 1, 0 }),
vec({ 0, 0, 0, 1 }),
};
vector<vec> orthogonilizedB = gschmidt_and_reduce(B);
cout << "Orthogonalized b:"<< endl;
for (int i = 0; i < orthogonilizedB.size(); ++i) {
if (!orthogonilizedB[i].isZero()) {
for (auto coordinate: orthogonilizedB[i].v())
cout << coordinate << ", ";
cout << endl;
}
if (i == 2)
cout << "Orthogonal complement of b:" << endl;
}
return 0;
}
I2luY2x1ZGUgPHZlY3Rvcj4KI2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8YWxnb3JpdGhtPgojaW5jbHVkZSA8ZnVuY3Rpb25hbD4KI2luY2x1ZGUgPG51bWVyaWM+Cgp1c2luZyBuYW1lc3BhY2Ugc3RkOwoKbG9uZyBnY2QobG9uZyBhLCBsb25nIGIpIHsKICAgIGlmIChhIDwgMCB8fCBiIDwgMCkgcmV0dXJuIGdjZChhYnMoYSksIGFicyhiKSk7CiAgICBlbHNlIGlmIChtaW4oYSwgYikgPT0gMCkKICAgICAgICByZXR1cm4gbWF4KDFsLCBtYXgoYSwgYikpOwogICAgZWxzZSBpZiAoYSA9PSBiKQogICAgICAgIHJldHVybiBhOwogICAgZWxzZQogICAgICAgIHJldHVybiBnY2QobWluKGEsIGIpLCBtYXgoYSwgYikgLSBtaW4oYSwgYikpOwp9CgpzdHJ1Y3QgdmVjIHsKICAgIHZlYyh2ZWN0b3I8bG9uZz4gdikgOiB2Xyh2KSB7fQogICAgdmVjdG9yPGxvbmc+JiB2KCkgeyByZXR1cm4gdl87IH0KICAgIGNvbnN0IHZlY3Rvcjxsb25nPiYgdigpIGNvbnN0IHsgcmV0dXJuIHZfOyB9CgogICAgdmVjIG9wZXJhdG9yKyhjb25zdCB2ZWMmKSBjb25zdDsKICAgIHZlYyBvcGVyYXRvcioobG9uZykgY29uc3Q7CiAgICBsb25nIG9wZXJhdG9yKihjb25zdCB2ZWMmKSBjb25zdDsKCiAgICB2b2lkIHJlZHVjZUJ5R0NEKCk7CiAgICAKICAgIGJvb2wgaXNaZXJvKCkgY29uc3QgeyByZXR1cm4gdigpID09IHZlY3Rvcjxsb25nPih2KCkuc2l6ZSgpKTsgfQoKcHJpdmF0ZToKICAgIHZlY3Rvcjxsb25nPiB2XzsKICAgIGxvbmcgZ2NkKCkgY29uc3Q7Cn07Cgpsb25nCnZlYzo6Z2NkKCkgY29uc3QKewogICAgaWYgKHZfLmVtcHR5KCkpIHJldHVybiAxOwogICAgbG9uZyByZXMgPSB2X1swXTsKICAgIGZvciAoaW50IGkgPSAxOyBpIDwgdl8uc2l6ZSgpOyArK2kpCiAgICAgICAgcmVzID0gOjpnY2QocmVzLCB2X1tpXSk7CiAgICByZXR1cm4gcmVzOwp9Cgp2b2lkCnZlYzo6cmVkdWNlQnlHQ0QoKQp7CiAgICBsb25nIGRpdiA9IGdjZCgpOwogICAgZm9yIChhdXRvICZhOiB2XykgYSAvPSBkaXY7Cn0KCnZlYwp2ZWM6Om9wZXJhdG9yKyhjb25zdCB2ZWMmIHIpIGNvbnN0CnsKICAgIHZlY3Rvcjxsb25nPiByZXModigpLnNpemUoKSk7CiAgICB0cmFuc2Zvcm0odGhpcy0+dl8uYmVnaW4oKSwgdGhpcy0+dl8uZW5kKCksIHIudl8uYmVnaW4oKSwgcmVzLmJlZ2luKCksIHBsdXM8bG9uZz4oKSk7CiAgICByZXR1cm4gdmVjKHJlcyk7Cn0KCnZlYwp2ZWM6Om9wZXJhdG9yKihsb25nIGspIGNvbnN0CnsKICAgIHZlY3Rvcjxsb25nPiByZXModigpLnNpemUoKSk7CiAgICB0cmFuc2Zvcm0odGhpcy0+dl8uYmVnaW4oKSwgdGhpcy0+dl8uZW5kKCksIHJlcy5iZWdpbigpLCBiaW5kKG11bHRpcGxpZXM8bG9uZz4oKSwgcGxhY2Vob2xkZXJzOjpfMSwgaykpOwogICAgcmV0dXJuIHZlYyhyZXMpOwp9Cgpsb25nCnZlYzo6b3BlcmF0b3IqKGNvbnN0IHZlYyYgcikgY29uc3QKewogICAgcmV0dXJuIGlubmVyX3Byb2R1Y3Qodl8uYmVnaW4oKSwgdl8uZW5kKCksIHIudigpLmJlZ2luKCksIDBsKTsKfQoKdmVjIGdzY2htaWR0X2FuZF9yZWR1Y2UoY29uc3QgdmVjJiB3aGF0LCBjb25zdCB2ZWMmIG90aGVyKQp7CiAgICBsb25nIHNxTm9ybSA9IG90aGVyKm90aGVyOwogICAgdmVjIHJlcyA9IHdoYXQqc3FOb3JtICArIG90aGVyKih3aGF0Km90aGVyKSotMTsKICAgIHJlcy5yZWR1Y2VCeUdDRCgpOwogICAgcmV0dXJuIHJlczsKfQoKdmVjdG9yPHZlYz4KZ3NjaG1pZHRfYW5kX3JlZHVjZShjb25zdCB2ZWN0b3I8dmVjPiYgdnMpCnsKICAgIHZlY3Rvcjx2ZWM+IHJlczsKICAgIGZvciAoc2l6ZV90IGkgPSAwOyBpIDwgdnMuc2l6ZSgpOyArK2kpIHsKICAgICAgICB2ZWMgY3VyID0gdnNbaV07CiAgICAgICAgZm9yIChpbnQgayA9IDA7IGsgPCBpOyArK2spCiAgICAgICAgICAgIGN1ciA9IGdzY2htaWR0X2FuZF9yZWR1Y2UoY3VyLCByZXNba10pOwogICAgICAgIHJlcy5wdXNoX2JhY2soY3VyKTsKICAgIH0KICAgIHJldHVybiByZXM7Cn0KCmludCBtYWluKCkgewogICAgdmVjdG9yPHZlYz4gQSA9IHsKICAgICAgICB2ZWMoeyAzLCA1LCA0LCAtNCB9KSwKICAgICAgICB2ZWMoeyAtMiwgLTMsIC0yLCAxIH0pLAogICAgICAgIHZlYyh7IC01LCAtOSwgLTYsIDggfSksCiAgICAgICAgdmVjKHsgMSwgMCwgMCwgMCB9KSwKICAgICAgICB2ZWMoeyAwLCAxLCAwLCAwIH0pLAogICAgICAgIHZlYyh7IDAsIDAsIDEsIDAgfSksCiAgICAgICAgdmVjKHsgMCwgMCwgMCwgMSB9KSwKICAgIH07CiAgICB2ZWN0b3I8dmVjPiBvcnRob2dvbmlsaXplZEEgPSBnc2NobWlkdF9hbmRfcmVkdWNlKEEpOwogICAgY291dCA8PCAiT3J0aG9nb25hbGl6ZWQgYToiPDwgZW5kbDsKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgb3J0aG9nb25pbGl6ZWRBLnNpemUoKTsgKytpKSB7CiAgICAgICAgaWYgKCFvcnRob2dvbmlsaXplZEFbaV0uaXNaZXJvKCkpIHsKICAgICAgICAgICAgZm9yIChhdXRvIGNvb3JkaW5hdGU6IG9ydGhvZ29uaWxpemVkQVtpXS52KCkpCiAgICAgICAgICAgICAgICBjb3V0IDw8IGNvb3JkaW5hdGUgPDwgIiwgIjsKICAgICAgICAgICAgY291dCA8PCBlbmRsOwogICAgICAgIH0KICAgICAgICBpZiAoaSA9PSAyKQogICAgICAgICAgICBjb3V0IDw8ICJPcnRob2dvbmFsIGNvbXBsZW1lbnQgb2YgYToiIDw8IGVuZGw7CiAgICB9CgogICAgdmVjdG9yPHZlYz4gQiA9IHsKICAgICAgICB2ZWMoeyAtNCwgLTUsIC0zLCAzIH0pLAogICAgICAgIHZlYyh7IDIsIDcsIDAsIC02IH0pLAogICAgICAgIHZlYyh7IC0xLCAwLCAtMSwgMCB9KSwKICAgICAgICB2ZWMoeyAxLCAwLCAwLCAwIH0pLAogICAgICAgIHZlYyh7IDAsIDEsIDAsIDAgfSksCiAgICAgICAgdmVjKHsgMCwgMCwgMSwgMCB9KSwKICAgICAgICB2ZWMoeyAwLCAwLCAwLCAxIH0pLAogICAgfTsKICAgIHZlY3Rvcjx2ZWM+IG9ydGhvZ29uaWxpemVkQiA9IGdzY2htaWR0X2FuZF9yZWR1Y2UoQik7CiAgICBjb3V0IDw8ICJPcnRob2dvbmFsaXplZCBiOiI8PCBlbmRsOwogICAgZm9yIChpbnQgaSA9IDA7IGkgPCBvcnRob2dvbmlsaXplZEIuc2l6ZSgpOyArK2kpIHsKICAgICAgICBpZiAoIW9ydGhvZ29uaWxpemVkQltpXS5pc1plcm8oKSkgewogICAgICAgICAgICBmb3IgKGF1dG8gY29vcmRpbmF0ZTogb3J0aG9nb25pbGl6ZWRCW2ldLnYoKSkKICAgICAgICAgICAgICAgIGNvdXQgPDwgY29vcmRpbmF0ZSA8PCAiLCAiOwogICAgICAgICAgICBjb3V0IDw8IGVuZGw7CiAgICAgICAgfQogICAgICAgIGlmIChpID09IDIpCiAgICAgICAgICAgIGNvdXQgPDwgIk9ydGhvZ29uYWwgY29tcGxlbWVudCBvZiBiOiIgPDwgZW5kbDsKICAgIH0KICAgIHJldHVybiAwOwp9Cg==