代數結構:群與體
然後、老師開始講授一些代數的法則,像是《結合律、交換律、分配律》等等規則。
問題是、教這些規則要幹嘛呢?好像有用又好像沒太多用處。
其實這些規則屬於《抽象代數》的範圍,整個抽象代數就是研究《代數法則》所形成的結構體系,以及在這些結構體系下的定理等等議題。
《代數》建構在《數論》之上,研究《數》的運算,然後擴充到非數字型《元素》的運算上面,形成一整套的《運算體系》。
在《抽象代數》的運算體系中,最基本且重要的體系為《群、體、環》等等結構。
群 (group)
群的定義
所謂的《群》,是具有《封閉性、結合性、單位元素、反元素》的一個《集合+運算》結構。
假如其中的運算用 ● 代表,那麼《群》應該具有下列性質:
- 封閉性:對於所有G中a, b,運算a●b的結果也在G中。
- 結合性:對於所有G中的a, b和c,等式 (a●b)●c = a●(b●c)成立。
- 單位元素:存在G中的一個元素e,使得對於所有G中的元素a,等式e●a = a●e = a成立。
- 反元素:對於每個G中的a,存在G中的一個元素b使得a●b = b●a = e,這裏的e是單位元素。
用數學符號的寫法,群 應該具有下列特性:
- closability:
- associativity:
- identity:
- inversability:
如果在《群》當中加入《交換律》,那麼這個群就稱為一個《交換群》(commutative group),或者稱為《阿貝爾群》(abelian group)。
群的範例
舉例而言、《實數》的加法運算,具有《封閉性、結合性、單位元素 0與反元素 -x》,因此《實數與加法》就形成了一個群。
但是《自然數》(不包含負數)的加法運算,就沒有反元素(因為 -a 不在自然數內,所以《自然數與加法》就不算是一個群。
同理、《實數與乘法》、《有理數與乘法》都可以形成一個群,但是《整數與乘法》卻無法形成一個群 (因為反元素 1/n 不是整數)。
在線性代數當中,矩陣可以相加也可以相乘,其加法單位元素為一個全為 0 的矩陣。而且對於 n*n
矩陣的加法也符合《封閉性、結合性、單位元素、反元素》等等性質,因此 《2*2》的矩陣與加法
形成一個群。
而乘法雖然有單位元素為 I,也就是對角線上全是1,其他部分全是 0 的矩陣。但是卻不一定有反元素,因為有些矩陣 A 不具有反矩陣 ,所以《矩陣與矩陣乘法》無法形成一個群。
於是《矩陣與乘法》自然就無法直接套用《群論》裡的那些定理,否則就可能會誤用數學定理,造成錯誤了!
對於更詳細的《群》之描述,請參考下列維基百科的文章:
《抽象代數》當中的元素不一定要是數字,運算也不一定會是數字運算,像是《幾何操作》也可以當成一種《運算》作用在《幾何物體》上。
這種想法讓《代數學》可以連結上《幾何學》!
例如在《歐氏幾何》體系中,《公理與定理》在《平移、旋轉、鏡射》等運算下不會改變,因此這些《元素與運算》就形成了《歐氏幾何》中的一個不變群!
於是我們可以用《不變群》的角度來分類幾何學,像是《歐氏幾何、雙曲幾何、橢圓幾何、微分幾何》等等。
如果一個類似群的結構,但是《沒有反元素》,那麼就稱之為《么半群》(Monoid) ,如果《連單位元素也沒有》,那麼就稱之為《半群》。
體 (Field)
在抽象代數中,體(Field)是一種可進行加、減、乘和除運算的代數結構。體的概念是數體以及四則運算的推廣。
在台灣、Field 翻譯為《體》,在中國則翻譯為《域》,以下我們將《兩者混用》,域和體都是指 Field 。
上述的群包含一個運算,而體則是包含兩個運算,像是《實數和加法與乘法》,就形成了一個《體結構》。
通常我們會將體的兩個運算,用加號與乘號代表,寫為《F, +, *》。
體的定義
一個體《F, +, *》必須滿足下列條件:
其中的 《F,+》形成一個《交換群》,《F-{0},*》也形成一個《交換群》。
而且《乘法對加法》還必須具有《分配律》,也就是 。
這樣的一個《具有分配律的雙重交換群》結構 《F, +, *》,就稱為體 (Field)。
體的範例
《實數與乘法和加法》,也就是《R, +, *》就是一個《體結構》。
同樣的《複數與乘法和加法》,也就是《C, +, *》,也形成一個體結構。
《有理數與乘法和加法》,也就是《Q, +, *》,也同樣是一個體結構。
但是《整數與乘法和加法》,則無法形成一個體結構。
不過如果將《自然數對某質數 p 取 mod 運算後的元素,與乘法和加法》結合起來,就可以形成一個《體結構》。
這種進行 mod 之後的體結構,稱為 《有限體》(finite field)或《伽羅瓦體》(Galois field) ,在密碼學上的 RSA 公開金鑰系統,就是在這種《體結構》上運作的加解密系統。
體結構中的加法單位元素通常寫為 0,乘法單位元素通常寫為 1。但是這不代表他們就一定是 0 或 1。
線性代數當中的向量沒有定義乘法,但是有內積與外積,其中一個原因是《向量的乘法運算無法形成一個群》,關於這點請參考下文:
環
而所謂的 《環結構》和《體結構》僅僅差一點點,差異是《環結構》的《乘法》,可以沒有反元素 (但是有封閉性、結合性、單位元素),也就是《F, *》是一個《么半群》(monoid),那麼這個《F, +, *》結構就稱為《環》。
舉例而言,像是整數的加法與乘法,就形成一個《環結構》,但是因為整數乘法反元素 1/n 有可能不是整數,所以《無法形成體結構》。
模組 field.js
抽象代數的定理
當我們對《代數結構》進行了詳細的區分,那麼就可以對各種結構進行數學推演,推演出來的《定理》就可以一層層的適用。
例如:《半群》的定理當然可以被套用在《群》結構裡面,因為一個群當然是個半群。
同樣的、在《環》當中成立的定理,也可以被套用在《體》上面,因為《體》也符合《環》的所有條件。
這就是為何要將《代數》抽象化的原因之一,因為同樣的定理,不需要證明兩次。
舉例而言、在《群論》裏面,有個 《拉格朗日定理》),證明了群漢子群之間的關係,敘述如下:
敘述:設 H 是有限群 G 的子群,則 H 的階整除 G 的階。
其中的 《階》代表群裡的元素個數), 這個定理的證明牽涉到了 陪集 與 子群 的概念。
只要我們知道某個《F, +》是個群,那我們就可以套用拉格朗日定理,而不需要重新證明了!
在《么半群》當中,有個定理稱為 克羅恩-羅德斯定理 (Krohn–Rhodes theorem),這個定理可以套用在任何的《么半群》上面,當然也可以套用在任何的《群》上面。
程式解析
檔案:lib/field.js
// module : Field & Group Theory
var F = require("./set");
F.Integer=require("./integer");
var eq = F.eq;
// ========== Group =================
// 注意: 箭頭函數會自動將 this 變數綁定到其定義時所在的物件,因此以下很多地方不能用箭頭函數。
// 參考: https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Functions/Arrow_functions
F.Group={
invOp:function(x,y) {
return this.op(x,this.inv(y));
},
power:function(x,n) {
var p=this.e;
for (var i=0;i<n;i++) {
p=this.op(p,x);
}
return p;
},
leftCoset:function(g, H) {
var set = new F.Set();
for (var i in H)
set.add(this.op(g,H[i]));
return set;
},
rightCoset:function(H, g) {
var set = new F.Set();
for (var i in H)
set.add(this.op(g,H[i]));
return set;
},
// ref:https://en.wikipedia.org/wiki/Group_(mathematics)
// 封閉性:For all a, b in G, a • b, is also in G
closability:function(a,b) {
var ab = this.op(a,b);
var close=this.has(ab);
return this.has(this.op(a,b));
},
// 結合性:For all a, b and c in G, (a • b) • c = a • (b • c).
associativity:function(a,b,c) {
var op = this.op.bind(this);
return eq(op(op(a,b),c), op(a,op(b,c)))
},
// 單位元素:Identity element
identity:function(a) {
return eq(this.op(this.e,a),a)
},
// 反元素:Inverse element
inversability:function(a) {
return eq(this.op(a,this.inv(a)),this.e);
},
}
// PermutationGroup
F.PermutationGroup={
op:function(x,y) {
var z = [];
for (var i in x)
z[i] = y[x[i]];
return z;
},
inv:function(x) {
var nx = [];
for (var i in x) {
nx[x[i]] = i;
}
return nx;
},
}
extend(F.PermutationGroup, F.Group);
// Cyclic Group : a group that is generated by a single element (g)
F.CyclicGroup={
G:[],
// g:g,
op:function(x,y) {
},
inv:function(x) {
},
create(g) {
var t = e;
for (var i=0; !t.eq(e); i++) {
G[i]=t;
t=op(g,G[i]);
}
}
}
extend(F.CyclicGroup, F.Group);
// NormalSubGroup : 正規子群
F.NormalSubGroup={
op:function(x,y) {
},
inv:function(x) {
},
normality(g,n) {
return this.has(g.op(n).op(g.inv()));
},
}
extend(F.NormalSubGroup, F.Group);
// Quotent Group : aggregating similar elements of a larger group using an equivalence relation that preserves the group structure
F.QuotentGroup={
eq:function(x,y) {
},
op:function(x,y) {
},
inv:function(x) {
},
}
extend(F.QuotentGroup, F.Group);
// Normal SubGroup : gH = Hg
// https://en.wikipedia.org/wiki/Normal_subgroup
F.NormalSubGroup={
op:function(x,y) {
},
inv:function(x) {
},
}
extend(F.NormalSubGroup, F.Group);
// 群同構第一定理: 給定 GG和 G ′ 兩個群,和 f : G → G ′ 群同態。則 Ker f 是一個 G 的正規子群。
// 群同構第二定理:給定群 G 、其正規子群 N、其子群 H,則 N ∩ H 是 H 的正規子群,且我們有群同構如下: H / ( H ∩ N ) ≃ H N / N
// 群同構第三定理: 給定群 G, N 和 M,M 為 G 的正規子群,滿足 M 包含於 N ,則 N / M 是 G / M 的正規子群,且有如下的群同構: ( G / M ) / ( N / M ) ≃ G / N .
// ========== Field =================
F.Field={
sub:function(x,y) { return this.addGroup.invOp(x,y) },
div:function(x,y) { return this.mulGroup.invOp(x,y) },
// mod:function(x,y) { return x.sub(x.div(y).mul(y)) },
power:function(x,n) { return this.mulGroup.power(x,n) },
init:function(addGroup, mulGroup) {
this.addGroup = addGroup;
this.mulGroup = mulGroup;
this.zero = addGroup.e;
this.add = function(x,y) { return this.addGroup.op(x,y) }
this.neg = function(x) { return this.addGroup.inv(x) }
this.one = mulGroup.e;
this.mul = function(x,y) { return this.mulGroup.op(x,y) }
this.inv = function(x) { return this.mulGroup.inv(x) }
this.power= function(x,n) { return this.mulGroup.power(x,n) }
this.eq = function(x,y) { return F.eq(x,y); }
this.neq = function(x,y) { return !this.eq(x,y); }
this.isZero = function(x) {
return this.field.eq(this, F.proto(this).zero)
}
this.isOne = function(x) {
return this.field.eq(this, F.proto(this).one)
}
this.gcd = function(x,y) {
if (y.isZero()) return x;
return gcd(y, mod(x,y));
}
},
ldistribute:function(a,b,c) {
return this.mul(a, this.add(b,c)).eq(this.add(this.mul(a,b), this.mul(a,c)));
},
rdistribute:function(a,b,c) {
return this.ldistribute(b,c,a);
},
associativity:function(a,b,c) {
return this.mul(a,this.mul(b,c)).eq(this.mul(this.mul(a,b),c));
},
}
F.Ring = F.Field; // Ring (環) : 可能沒有乘法單位元素和反元素的 Field
F.Module = F.Field;// Module(模) : (R +) is Ring, (R × M → M)
F.Ideal = F.Field; // Ideal (理想): 子環,且 i·r ∈ I (左理想), r·i ∈ I (右理想)
// ref : https://en.wikipedia.org/wiki/Group_homomorphism
// https://en.wikipedia.org/wiki/Fundamental_theorem_on_homomorphisms
// 同態:h(a • b) = h(a) x h(b)
F.homomorphism=function(h, g1, g2) {
var a=g1.random(), b=g2.random();
return eq(h(group1.op(a,b)), group2.op(h(a), h(b)))
}
// ref : https://en.wikipedia.org/wiki/Isomorphism
// https://en.wikipedia.org/wiki/Isomorphism_theorem
// 同構:h(a • b) = h(a) • h(b)
F.isomorphism=function(h1, h2, g1, g2) {
var a1=g1.random(), b1=g2.random();
var a2=g1.random(), b2=g2.random();
return homorphism(h1,g1,g2)&&homorphism(h2,g2,g1);
}
// ========== Float Field =================
F.FloatAddGroup={
e:0,
op:function(x,y) { return x+y },
inv:function(x) { return -x},
}
extend(F.FloatAddGroup, F.Group, F.Set.Float);
F.FloatMulGroup={
e:1,
op:function(x,y) { return x*y },
inv:function(x) { return 1/x},
}
extend(F.FloatMulGroup, F.Group, F.Set.Float);
F.FloatField=extend({}, F.Field, F.Set.Float);
F.FloatField.init(F.FloatAddGroup, F.FloatMulGroup);
// ========== Finite Field =================
F.FiniteAddGroup={
e:0,
op:function(x,y) { return (x+y)%this.n },
inv:function(x) { return (this.n-x) }
}
extend(F.FiniteAddGroup, F.Group);
F.FiniteMulGroup={
e:1,
op:function(x,y) { return (x*y)%this.n },
inv:function(x) { return this.invMap[x] },
setOrder:function(n) {
this.n = n;
let invMap = new Map();
for (var x=1; x<n; x++) {
var y = this.op(x,x);
invMap.set(x,y);
}
this.invMap = invMap;
}
}
extend(F.FiniteMulGroup, F.Group);
F.FiniteField=extend({}, F.Field);
F.FiniteField.create=function(n) {
var finiteField = extend(F.Finite(n), F.FiniteField);
var addGroup = extend(F.Finite(n), {n:n}, F.FiniteAddGroup);
var mulGroup = extend(F.Finite(n), {n:n}, F.FiniteMulGroup);
finiteField.init(addGroup, mulGroup);
mulGroup.setOrder(n);
return finiteField;
}
class MathObj {
constructor() {}
str() { return this.toString() }
}
F.MathObj = MathObj;
// =========== Field Object ==============
class FieldObj extends MathObj {
constructor(field) {
super();
this.field = field;
var p = Object.getPrototypeOf(this);
p.zero = field.zero;
p.one = field.one;
}
add(y) { return this.field.add(this,y) }
mul(y) { return this.field.mul(this,y) }
neg() { return this.field.neg(this) }
inv() { return this.field.inv(this) }
div(y) { return this.field.div(this,y) }
sub(y) { return this.field.sub(this,y) }
power(n) { return this.field.power(this,n) }
isZero(x) { return this.field.isZero(this) }
isOne(x) { return this.field.isOne(this) }
eq(y) { return this.field.eq(this, y) }
neq(y) { return this.field.neq(this, y) }
mod(y) { return this.field.mod(this, y) }
gcd(y) { return this.field.gcd(this, y) }
}
F.FieldObj = FieldObj;
// =========== Complex Field ==============
F.ComplexField=extend({}, F.Field);
class Complex extends FieldObj {
constructor(a,b) {
super(F.ComplexField);
this.a = a; this.b = b;
}
conj() { return new Complex(this.a, -1*this.b); }
str() {
var op = (this.b<0)?'':'+';
return this.a.str()+op+this.b.str()+'i';
}
toString() { return this.str() }
toPolar() {
var a=this.a, b=this.b, r=Math.sqrt(a*a+b*b);
var theta = Math.acos(a/r);
return {r:r, theta:theta}
}
power(k) {
var p = this.toPolar();
return Complex.polarToComplex(Math.pow(p.r,k), k*p.theta);
}
sqrt() {
return this.power(1/2);
}
static toComplex(o) {
if (F.isFloat(o))
return new Complex(o, 0);
else if (o instanceof Complex)
return o;
console.log('o=', o);
throw Error('toComplex fail');
}
static polarToComplex(r,theta) {
var a=r*Math.cos(theta), b=r*Math.sin(theta);
return new Complex(a, b);
}
static parse(s) {
var m = s.match(/^([^\+]*)(\+(.*))?$/);
var a = parseFloat(m[1]);
var b = typeof m[3]==='undefined'?1:parseFloat(m[3]);
return new Complex(a, b)
}
}
F.Complex = Complex;
var C = (a,b)=>new Complex(a,b);
var enumComplex=[C(1,0),C(0,1),C(0,0),C(2,3),C(-5,4),C(-10,-7)];
F.ComplexSet=new F.Set(enumComplex);
F.ComplexSet.has = (a)=>a instanceof Complex;
F.ComplexAddGroup={
e:new Complex(0,0),
op:function(x,y) {
x = Complex.toComplex(x), y=Complex.toComplex(y);
return new Complex(x.a+y.a, x.b+y.b)
},
inv:function(x) {
x = Complex.toComplex(x);
return new Complex(-x.a, -x.b)
}
}
extend(F.ComplexAddGroup, F.Group, F.ComplexSet);
F.ComplexMulGroup={
e:new Complex(1,0),
op:function(x,y) {
x = Complex.toComplex(x), y=Complex.toComplex(y);
return new Complex(x.a*y.a-x.b*y.b, x.a*y.b+x.b*y.a);
},
inv:function(x) {
x = Complex.toComplex(x);
var a=x.a,b=x.b, r=(a*a+b*b);
return new Complex(a/r, -b/r);
}
}
extend(F.ComplexMulGroup, F.Group, F.ComplexSet);
extend(F.ComplexField, F.ComplexSet);
F.ComplexField.init(F.ComplexAddGroup, F.ComplexMulGroup);
// =========== Ratio Field ==============
F.RatioField=extend({}, F.Field);
class Ratio extends FieldObj {
constructor(a,b) {
super(F.RatioField);
this.a = a; this.b = b;
}
reduce() {
var a = this.a, b=this.b;
var c = F.Integer.gcd(a, b);
return new Ratio(a/c, b/c);
}
toString() { return this.a+'/'+this.b; }
static parse(s) {
var m = s.match(/^(\d+)(\/(\d+))?$/);
var a = parseInt(m[1]);
var b = typeof m[3]==='undefined'?1:parseInt(m[3]);
return new Ratio(a, b)
}
}
F.Ratio = Ratio;
F.RatioAddGroup={
e:new Ratio(0,1),
op:function(x,y) { return new Ratio(x.a*y.b+x.b*y.a, x.b*y.b) },
inv:function(x) { return new Ratio(-x.a, x.b); },
}
extend(F.RatioAddGroup, F.Group);
F.RatioMulGroup={
e:new Ratio(1,1),
op:function(x,y) { return new Ratio(x.a*y.a, x.b*y.b) },
inv:function(x) { return new Ratio(x.b, x.a) },
}
extend(F.RatioMulGroup, F.Group);
F.RatioField.init(F.RatioAddGroup, F.RatioMulGroup);
// =========== Function Operation ==============
F.fneg=function(fx) { return function(v) {
return -1*fx(v);
}}
F.finv=function(fx) { return function(v) {
return 1/fx(v);
}}
F.fadd=function(fx,fy) { return function(v) {
return fx(v).add(fy(v));
}}
F.fsub=function(fx,fy) { return function(v) {
return fx(v).sub(fy(v));
}}
F.fmul=function(fx,fy) { return function(v) {
return fx(v).mul(fy(v));
}}
F.fdiv=function(fx,fy) { return function(v) {
return fx(v).div(fy(v));
}}
F.fcompose=function(fx,fy) { return function(v) {
return fx(fy(v));
}}
F.feval=function(f,x) { return f(x) }
// f=(x,y)=>x*y+x*x;
// f0=fa(f); f0([x,y]);
F.fa=function(f) {
return function(x) {
return f.apply(null, x);
}
}
// =========== Function Field ==============
F.FunctionField=extend({}, F.Field);
F.FunctionAddGroup={
e:function(x) { return 0 },
op:function(x,y) { return F.fadd(x,y) },
inv:function(x) { return F.fneg(x) },
}
extend(F.FunctionAddGroup, F.Group);
F.FunctionMulGroup={
e:function(x) { return f(x) },
op:function(x,y) { return F.fsub(x,y) },
inv:function(x) { return F.finv(x) },
}
extend(F.FunctionMulGroup, F.Group);
F.FunctionField.init(F.FunctionAddGroup, F.FunctionMulGroup);
// Function
F.isField=function(x) {
return F.isBool(x) || F.isNumber(x) || x instanceof F.FieldObj;
}
我們將此模組放進 rlab.Field 這個物件中,於是我們就可以寫出一些簡單的使用範例如下:
var R = require("../rlab");
var FF = R.FloatField;
var be = R.be;
be('FF:2+3=5',FF.add(2,3)===5);
be('FF:2^3=8',FF.power(2,3)===8);
var F7= R.FiniteField.create(7);
var a = 3, b=6;
be('F7:3+6=2', F7.add(a,b)===2);
be('F7:3*6=4', F7.mul(a,b)===4);
be('F7:closability(+)=> a+b in F7', F7.addGroup.closability(3,6));
be('F7:associativity(+)=>(a+b)+c=a+(b+c)', F7.addGroup.associativity(3,6,4));
be('F7:identity(+)=>a+0=a', F7.addGroup.identity(3));
be('F7:inversability(+)=a-a=0', F7.addGroup.inversability(3));
var C = R.ComplexField;
var c1 = new R.Complex(2,3);
be('C.has(c1)=true', C.has(c1));
be('C :c1==2+3i', c1.str()==='2+3i');
be('C :c1+c1=4+6i', C.add(c1,c1).str()==='4+6i');
be('C :c1*c1=-5+12i', C.mul(c1,c1).str()==='-5+12i');
be('C :(c1*c1)/c1=2+3i', C.div(C.mul(c1,c1),c1).str()==='2+3i');
var Q = R.RatioField;
var q1 = new R.Ratio(2,3);
be('Q:q1=2/3', q1.str()==='2/3');
be('Q:q1+q1=4/3', Q.add(q1,q1).reduce().str()==='4/3');
be('Q:q1-q1=0', Q.sub(q1,q1).a===0);
be('Q:q1*q1=4/9', Q.mul(q1,q1).str()==='4/9');
be('Q:q1/q1*q1=2/3', Q.mul(Q.div(q1,q1),q1).reduce().str()==='2/3');
be('Q:q1^3=8/27', q1.power(3).str()==='8/27');
var co = new R.Complex(2,3);
be('C:co=2+3i', co.str()==='2+3i');
be('C:co+co=4+6i', co.add(co).str()==='4+6i');
be('C:co*co=-5+12i', co.mul(co).str()==='-5+12i');
be('C:co/co=1+0i', co.div(co).str()==='1+0i');
be('C:co*co/co=2+3i', co.mul(co).div(co).str()==='2+3i');
var c1=p('1+2i'), c2=p('2+1i'), c3=p('10+0i');
print('%s * %s=%s', c1, c2, c1.mul(c2));
print('(%s)*3=%s', c1, c1.mul(3));
print('3 * 3=%s', p('3').mul(3));
var sqrt2 = Math.sqrt(2);
var c=new R.Complex(sqrt2, sqrt2);
print('c=%s', c);
print('c.toPolar=%j', c.toPolar().str());
print('c*c=%s', c.mul(c));
print('c^2=%s', c.power(2));
print('c^2.sqrt()=%s', c.power(2).sqrt());
var P2 = extend({e:[0,1]}, R.PermutationGroup);
print('[1,0].inv()=%j', P2.inv([1,0]));
var P3 = extend({e:[0,1,2]}, R.PermutationGroup);
print('[0,2,1].inv()=%j', P3.inv([0,2,1]));
print('[2,1,0].inv()=%j', P3.inv([2,1,0]));
print('[1,2,0].inv()=%j', P3.inv([1,2,0]));
print('[1,2,0]*[1,2,0].inv()=%j', P3.op([1,2,0], P3.inv([1,2,0])));
print('[1,2,0].inv()*[1,2,0]=%j', P3.op(P3.inv([1,2,0]),[1,2,0]));
var S2=[[0,1,2], [1,0,2]];
print('S2=', S2);
print('leftCoset([1,2,0], S2)=', P3.leftCoset([1,2,0],S2));
print('rightCoset([1,2,0], S2)=', P3.rightCoset(S2, [1,2,0]));
執行結果:
D:\Dropbox\github\rlab\example>node fieldEx.js
O:FF:2+3=5
O:FF:2^3=8
O:F7:3+6=2
O:F7:3*6=4
O:F7:closability(+)=> a+b in F7
O:F7:associativity(+)=>(a+b)+c=a+(b+c)
O:F7:identity(+)=>a+0=a
O:F7:inversability(+)=a-a=0
O:C.has(c1)=true
O:C :c1==2+3i
O:C :c1+c1=4+6i
O:C :c1*c1=-5+12i
O:C :(c1*c1)/c1=2+3i
O:Q:q1=2/3
O:Q:q1+q1=4/3
O:Q:q1-q1=0
O:Q:q1*q1=4/9
O:Q:q1/q1*q1=2/3
O:Q:q1^3=8/27
O:C:co=2+3i
O:C:co+co=4+6i
O:C:co*co=-5+12i
O:C:co/co=1+0i
O:C:co*co/co=2+3i
1+2i * 2+1i=0+5i
(1+2i)*3=3+6i
3 * 3=9
c=1.41+1.41i
c.toPolar="{r:2, theta:0.79}"
c*c=0+4.00i
c^2=0.00+4i
c^2.sqrt()=1.41+1.41i
[1,0].inv()=["1","0"]
[0,2,1].inv()=["0","2","1"]
[2,1,0].inv()=["2","1","0"]
[1,2,0].inv()=["2","0","1"]
[1,2,0]*[1,2,0].inv()=["0","1","2"]
[1,2,0].inv()*[1,2,0]=[0,1,2]
S2= [ [ 0, 1, 2 ], [ 1, 0, 2 ] ]
leftCoset([1,2,0], S2)= EnumSet { set: Set { [ 1, 2, 0 ], [ 0, 2, 1 ] }, enumHea
d: [] }
rightCoset([1,2,0], S2)= EnumSet { set: Set { [ 1, 2, 0 ], [ 0, 2, 1 ] }, enumHe
ad: [] }
小結
透過《群、體》等嚴格的數學結構,我們可以建構出對應的程式,雖然程式和數學的表達方式,有些時候不太一樣,但其表達的內容是非常一致的。
程式中比較難處理的,主要是關於《無窮大、不可數與精確度》的部分,所以在上述程式中,我們使用《浮點數》Float 代替實數,用《範圍很大的有限》來代替無限,然後用《電腦內部創建的型態,像是物件類的 Group, Field, Complex, Ratio, IntegerField, FloatField, ComplexField 等物件,來表達這些《代數結構》與對應的《數字結構》,這樣就能《用程式的語言表達數學的概念與運作邏輯》了!