代數結構:群與體

然後、老師開始講授一些代數的法則,像是《結合律、交換律、分配律》等等規則。

問題是、教這些規則要幹嘛呢?好像有用又好像沒太多用處。

其實這些規則屬於《抽象代數》的範圍,整個抽象代數就是研究《代數法則》所形成的結構體系,以及在這些結構體系下的定理等等議題。

《代數》建構在《數論》之上,研究《數》的運算,然後擴充到非數字型《元素》的運算上面,形成一整套的《運算體系》。

在《抽象代數》的運算體系中,最基本且重要的體系為《群、體、環》等等結構。

群 (group)

群的定義

所謂的《群》,是具有《封閉性、結合性、單位元素、反元素》的一個《集合+運算》結構。

假如其中的運算用 ● 代表,那麼《群》應該具有下列性質:

  1. 封閉性:對於所有G中a, b,運算a●b的結果也在G中。
  2. 結合性:對於所有G中的a, b和c,等式 (a●b)●c = a●(b●c)成立。
  3. 單位元素:存在G中的一個元素e,使得對於所有G中的元素a,等式e●a = a●e = a成立。
  4. 反元素:對於每個G中的a,存在G中的一個元素b使得a●b = b●a = e,這裏的e是單位元素。

用數學符號的寫法,群 (G,)(G,\cdot) 應該具有下列特性:

  1. closability: a,bGabG\forall a,b \in G \;a \cdot b \in G
  2. associativity: a,b,cG(ab)c=a(bc)\forall a,b,c \in G\; (a\cdot b) \cdot c = a \cdot (b\cdot c)
  3. identity: aGae=ea=a\forall a \in G\; a \cdot e = e\cdot a=a
  4. inversability: aGa1Ga1a=aa1=e\forall a \in G \exists a^{-1}\in G\; a^{-1} \cdot a = a \cdot a^{-1} = e

如果在《群》當中加入《交換律》,那麼這個群就稱為一個《交換群》(commutative group),或者稱為《阿貝爾群》(abelian group)。

群的範例

舉例而言、《實數》的加法運算,具有《封閉性、結合性、單位元素 0與反元素 -x》,因此《實數與加法》就形成了一個群。

但是《自然數》(不包含負數)的加法運算,就沒有反元素(因為 -a 不在自然數內,所以《自然數與加法》就不算是一個群。

同理、《實數與乘法》、《有理數與乘法》都可以形成一個群,但是《整數與乘法》卻無法形成一個群 (因為反元素 1/n 不是整數)。

在線性代數當中,矩陣可以相加也可以相乘,其加法單位元素為一個全為 0 的矩陣。而且對於 n*n 矩陣的加法也符合《封閉性、結合性、單位元素、反元素》等等性質,因此 《2*2》的矩陣與加法形成一個群。

而乘法雖然有單位元素為 I,也就是對角線上全是1,其他部分全是 0 的矩陣。但是卻不一定有反元素,因為有些矩陣 A 不具有反矩陣 A1A^{-1},所以《矩陣與矩陣乘法》無法形成一個群。

於是《矩陣與乘法》自然就無法直接套用《群論》裡的那些定理,否則就可能會誤用數學定理,造成錯誤了!

對於更詳細的《群》之描述,請參考下列維基百科的文章:

《抽象代數》當中的元素不一定要是數字,運算也不一定會是數字運算,像是《幾何操作》也可以當成一種《運算》作用在《幾何物體》上。

這種想法讓《代數學》可以連結上《幾何學》!

例如在《歐氏幾何》體系中,《公理與定理》在《平移、旋轉、鏡射》等運算下不會改變,因此這些《元素與運算》就形成了《歐氏幾何》中的一個不變群!

於是我們可以用《不變群》的角度來分類幾何學,像是《歐氏幾何、雙曲幾何、橢圓幾何、微分幾何》等等。

如果一個類似群的結構,但是《沒有反元素》,那麼就稱之為《么半群》(Monoid) ,如果《連單位元素也沒有》,那麼就稱之為《半群》。

體 (Field)

在抽象代數中,體(Field)是一種可進行加、減、乘和除運算的代數結構。體的概念是數體以及四則運算的推廣。

在台灣、Field 翻譯為《體》,在中國則翻譯為《域》,以下我們將《兩者混用》,域和體都是指 Field 。

上述的群包含一個運算,而體則是包含兩個運算,像是《實數和加法與乘法》,就形成了一個《體結構》。

通常我們會將體的兩個運算,用加號與乘號代表,寫為《F, +, *》。

體的定義

一個體《F, +, *》必須滿足下列條件:

  1. 其中的 《F,+》形成一個《交換群》,《F-{0},*》也形成一個《交換群》。

  2. 而且《乘法對加法》還必須具有《分配律》,也就是 a(b+c)=ab+aca*(b+c)=a*b+a*c

這樣的一個《具有分配律的雙重交換群》結構 《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 這個物件中,於是我們就可以寫出一些簡單的使用範例如下:

檔案: example/fieldEx.js

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 等物件,來表達這些《代數結構》與對應的《數字結構》,這樣就能《用程式的語言表達數學的概念與運作邏輯》了!

results matching ""

    No results matching ""