import std.stdio
, std.typecons
, std.traits
, std.algorithm
, std.range
, std.container
, conv = std.conv
, std.format;
void main() {
with(Reals)
(mul(add(one, one).add(one).add(one), one.add(one).add(one)).mul(inv(one.add(one).add(one))).mul(inv(one.add(zero))).sub(one)).toString.writeln();
with(Complex)
toString(add(one, one)).writeln();
with(Quaternion)
toString(add(xs!(one, zero).mul.sub(one), one.add(one).mul(one.add(one)))).writeln();
}
alias xs(args...) = args;
alias ids(args...) = args;
struct DivAlgebra(K) {
static:
K conj(K);
K zero();
K one();
bool isZero(K);
K add(K, K);
K sub(K, K);
K mul(K, K);
K inv(K);
string toString(K);
}
bool sigMatch(alias M, A)() {
enum memsM = __traits(allMembers, M);
foreach(m; memsM) {
if (is(typeof(__traits(getMember, m, M)) : typeof(__traits(getMember, m, A))))
return false;
}
return true;
}
/// "sig" or "prototype"
enum bool isDivAlgebra(alias mod)
= () {
alias K = mod.kind;
return
is(K)
&& sigMatch!(mod, DivAlgebra!K);
}()
;
template BareReals() {
/**/
template sig(Testant) {
enum bool sig = isDivAlgebra!Testant;
}/**/
public:
alias kind = float;
pure {
enum conj = (float x) => x;
@property {
float zero() { return 0.0f; }
float one() { return 1.0f; }
}
enum {
isZero = (float x) => x == 0.0f,
add = (float x, float y) => x + y,
sub = (float x, float y) => x - y,
mul = (float x, float y) => x * y,
inv = (float x) => 1.0f / x,
}
}
enum toString = (float x) => std.format.format("%g", x);
}
static if(isDivAlgebra!(BareReals!())) {
alias BareReals!() Reals;
}
/// functor "G"
template G(alias Alg)
if(isDivAlgebra!Alg) {
public:
alias A = Alg;
alias kind = Tuple!(A.kind, "r", A.kind, "i");
//static:
pure {
enum conj = (kind x) => kind(A.conj(x.r), A.sub(A.zero(), x.i));
auto zero() @property { return kind(A.zero, A.zero); }
auto one() @property { return kind(A.one, A.zero); }
enum {
isZero = (kind x) => A.isZero(x.r) && A.isZero(x.i),
add = (kind x, kind y) => kind( A.add(x.r, y.r), A.add(x.i, y.i) ),
sub = (kind x, kind y) => kind( A.sub(x.r, y.r), A.sub(x.i, y.i) ),
mul = (kind x, kind y) {
return kind(
A.sub( A.mul( x.r, y.r ), A.mul( A.conj(x.i), y.i ) )
, A.add( A.mul(x.r, y.i), A.mul(x.i, y.r) )
);
},
inv = (kind x) {
auto d = A.inv( A.add( A.mul(A.conj(x.i), x.i), A.mul(A.conj(x.r), x.r) ) );
return kind( A.mul(d, A.conj(x.r)), A.sub(A.zero(), A.mul(d, x.i)) );
},
}
}
enum toString = (kind x) => (A.toString(x.r) ~ ", " ~ A.toString(x.i));
}
/**/alias Complex = G!Reals;
alias Quaternion = G!Complex;/**/
static assert(isDivAlgebra!Reals && isDivAlgebra!Complex && isDivAlgebra!Quaternion);
alias id(alias token) = token;
aW1wb3J0IHN0ZC5zdGRpbwoJLCBzdGQudHlwZWNvbnMKCSwgc3RkLnRyYWl0cwoJLCBzdGQuYWxnb3JpdGhtCgksIHN0ZC5yYW5nZQoJLCBzdGQuY29udGFpbmVyCgksIGNvbnYgPSBzdGQuY29udgoJLCBzdGQuZm9ybWF0OwoKdm9pZCBtYWluKCkgewoJd2l0aChSZWFscykKCQkobXVsKGFkZChvbmUsIG9uZSkuYWRkKG9uZSkuYWRkKG9uZSksIG9uZS5hZGQob25lKS5hZGQob25lKSkubXVsKGludihvbmUuYWRkKG9uZSkuYWRkKG9uZSkpKS5tdWwoaW52KG9uZS5hZGQoemVybykpKS5zdWIob25lKSkudG9TdHJpbmcud3JpdGVsbigpOwoKCXdpdGgoQ29tcGxleCkKCQl0b1N0cmluZyhhZGQob25lLCBvbmUpKS53cml0ZWxuKCk7CgkJCgl3aXRoKFF1YXRlcm5pb24pCgkJdG9TdHJpbmcoYWRkKHhzIShvbmUsIHplcm8pLm11bC5zdWIob25lKSwgb25lLmFkZChvbmUpLm11bChvbmUuYWRkKG9uZSkpKSkud3JpdGVsbigpOwp9CgphbGlhcyB4cyhhcmdzLi4uKSA9IGFyZ3M7CmFsaWFzIGlkcyhhcmdzLi4uKSA9IGFyZ3M7CgpzdHJ1Y3QgRGl2QWxnZWJyYShLKSB7CnN0YXRpYzoKCUsgY29uaihLKTsKCUsgemVybygpOwoJSyBvbmUoKTsKCWJvb2wgaXNaZXJvKEspOwoJSyBhZGQoSywgSyk7CglLIHN1YihLLCBLKTsKCUsgbXVsKEssIEspOwoJSyBpbnYoSyk7CglzdHJpbmcgdG9TdHJpbmcoSyk7Cn0KCmJvb2wgc2lnTWF0Y2goYWxpYXMgTSwgQSkoKSB7CgllbnVtIG1lbXNNID0gX190cmFpdHMoYWxsTWVtYmVycywgTSk7Cglmb3JlYWNoKG07IG1lbXNNKSB7CgkJaWYgKGlzKHR5cGVvZihfX3RyYWl0cyhnZXRNZW1iZXIsIG0sIE0pKSA6IHR5cGVvZihfX3RyYWl0cyhnZXRNZW1iZXIsIG0sIEEpKSkpCgkJCXJldHVybiBmYWxzZTsKCX0KCXJldHVybiB0cnVlOwp9CgovLy8gInNpZyIgb3IgInByb3RvdHlwZSIKZW51bSBib29sIGlzRGl2QWxnZWJyYShhbGlhcyBtb2QpCgk9ICgpIHsKCQkJYWxpYXMgSyA9IG1vZC5raW5kOwoJCQlyZXR1cm4KCQkJCWlzKEspCgkJCQkmJiBzaWdNYXRjaCEobW9kLCBEaXZBbGdlYnJhIUspOwoJfSgpCgk7CgoKdGVtcGxhdGUgQmFyZVJlYWxzKCkgewoJLyoqLwoJdGVtcGxhdGUgc2lnKFRlc3RhbnQpIHsKCQllbnVtIGJvb2wgc2lnID0gaXNEaXZBbGdlYnJhIVRlc3RhbnQ7Cgl9LyoqLwoJCgkKcHVibGljOgoJYWxpYXMga2luZCA9IGZsb2F0OwoJCnB1cmUgewoJZW51bSBjb25qID0gKGZsb2F0IHgpID0+IHg7CgkKCUBwcm9wZXJ0eSB7CgkJZmxvYXQgemVybygpIHsgcmV0dXJuIDAuMGY7IH0KCQkKCQlmbG9hdCBvbmUoKSB7IHJldHVybiAxLjBmOyB9Cgl9CgkKCWVudW0gewoJCWlzWmVybyA9IChmbG9hdCB4KSA9PiB4ID09IDAuMGYsCgkKCQlhZGQgPSAoZmxvYXQgeCwgZmxvYXQgeSkgPT4geCArIHksCgkKCQlzdWIgPSAoZmxvYXQgeCwgZmxvYXQgeSkgPT4geCAtIHksCgkJCgkJbXVsID0gKGZsb2F0IHgsIGZsb2F0IHkpID0+IHggKiB5LAoJCQoJCWludiA9IChmbG9hdCB4KSA9PiAxLjBmIC8geCwKCX0KfQkKCgllbnVtIHRvU3RyaW5nID0gKGZsb2F0IHgpID0+IHN0ZC5mb3JtYXQuZm9ybWF0KCIlZyIsIHgpOwp9CgoKc3RhdGljIGlmKGlzRGl2QWxnZWJyYSEoQmFyZVJlYWxzISgpKSkgewoJYWxpYXMgQmFyZVJlYWxzISgpIFJlYWxzOwp9CgovLy8gZnVuY3RvciAiRyIKdGVtcGxhdGUgRyhhbGlhcyBBbGcpCglpZihpc0RpdkFsZ2VicmEhQWxnKSB7CgkKcHVibGljOgoJCglhbGlhcyBBID0gQWxnOwoJCglhbGlhcyBraW5kID0gVHVwbGUhKEEua2luZCwgInIiLCBBLmtpbmQsICJpIik7CgkKCS8vc3RhdGljOgpwdXJlIHsKCWVudW0gY29uaiA9IChraW5kIHgpID0+IGtpbmQoQS5jb25qKHguciksIEEuc3ViKEEuemVybygpLCB4LmkpKTsKCQoJYXV0byB6ZXJvKCkgQHByb3BlcnR5IHsgcmV0dXJuIGtpbmQoQS56ZXJvLCBBLnplcm8pOyB9CgkKCWF1dG8gb25lKCkgQHByb3BlcnR5IHsgcmV0dXJuIGtpbmQoQS5vbmUsIEEuemVybyk7IH0KCQoKCWVudW0gewoJCWlzWmVybyA9IChraW5kIHgpID0+IEEuaXNaZXJvKHgucikgJiYgQS5pc1plcm8oeC5pKSwKCQkKCQlhZGQgPSAoa2luZCB4LCBraW5kIHkpID0+IGtpbmQoIEEuYWRkKHguciwgeS5yKSwgQS5hZGQoeC5pLCB5LmkpICksCgkJc3ViID0gKGtpbmQgeCwga2luZCB5KSA9PiBraW5kKCBBLnN1Yih4LnIsIHkuciksIEEuc3ViKHguaSwgeS5pKSApLAoJCQoJCW11bCA9IChraW5kIHgsIGtpbmQgeSkgewoJCQlyZXR1cm4ga2luZCgKCQkJCUEuc3ViKCBBLm11bCggeC5yLCB5LnIgKSwgQS5tdWwoIEEuY29uaih4LmkpLCB5LmkgKSApCgkJCQksIEEuYWRkKCBBLm11bCh4LnIsIHkuaSksIEEubXVsKHguaSwgeS5yKSApCgkJCSk7CgkJfSwKCQkKCQlpbnYgPSAoa2luZCB4KSB7CgkJCWF1dG8gZCA9IEEuaW52KCBBLmFkZCggQS5tdWwoQS5jb25qKHguaSksIHguaSksIEEubXVsKEEuY29uaih4LnIpLCB4LnIpICkgKTsKCQkJcmV0dXJuIGtpbmQoIEEubXVsKGQsIEEuY29uaih4LnIpKSwgQS5zdWIoQS56ZXJvKCksIEEubXVsKGQsIHguaSkpICk7CgkJfSwKCQkKCX0KfQoJCgllbnVtIHRvU3RyaW5nID0gKGtpbmQgeCkgPT4gKEEudG9TdHJpbmcoeC5yKSB+ICIsICIgfiBBLnRvU3RyaW5nKHguaSkpOwp9CgoKLyoqL2FsaWFzIENvbXBsZXggPSBHIVJlYWxzOwphbGlhcyBRdWF0ZXJuaW9uID0gRyFDb21wbGV4Oy8qKi8KCnN0YXRpYyBhc3NlcnQoaXNEaXZBbGdlYnJhIVJlYWxzICYmIGlzRGl2QWxnZWJyYSFDb21wbGV4ICYmIGlzRGl2QWxnZWJyYSFRdWF0ZXJuaW9uKTsKCmFsaWFzIGlkKGFsaWFzIHRva2VuKSA9IHRva2VuOwoKCgoKCg==