范畴域和态射(Morphisms)是范畴论的基本概念。 在范畴论中,范畴是元素的域(又名集合),以及态射(或箭头又名映射,又名函数)它们之间的集合。 在这些文章中,我们取箭头、函数或映射作为态射的基本单位。 这些态射针对范畴内每个域中的元素之间的关系进行编码,并且可将它们组合成更复杂的态射。
集合是数学中的基本概念,它们在范畴论中起着关键作用。 在范畴论中,我们将它们称为用于定义特定“种类”元素的域。 典型情况,如果我们研究域范畴,范畴的“元素”将是域本身。 这些域,通常但又并非总是,继续包含构成态射基础的其它元素。 此范畴中的态射将是域之间的函数,这些函数是一个域的每个元素与另一个域的唯一元素相关联的规则。 例如,如果我们有两个域 A 和 B,则从 A 到 B 的态射将是一个规则,它将 A 的每个元素分配给 B 的唯一元素。当态射从 A 转运到 B 时,A 被称为“本域”,而 B 是“协域”。 本域中的所有元素都将与协域中的至少一个元素有关系。 本域中的任何元素都不会保持“未映射”状态。 然而,协域中的某些元素可能是“未映射”的。 这经常表示如下。
//+------------------------------------------------------------------+ //| ELEMENT CLASS | //+------------------------------------------------------------------+ class CElement { protected: int cardinal; vector element; public: bool Cardinality(int Value) { if(Value>=0 && Value<INT_MAX) { cardinal=Value; element.Init(cardinal); return(true); } return(false); } int Cardinality() { return(cardinal); } double Get(int Index) { if(Index>=0 && Index<Cardinality()) { return(element[Index]); } return(EMPTY_VALUE); } bool Set(int Index,double Value) { if(Index>=0 && Index<Cardinality()) { element[Index]=Value; return(true); } return(false); } CElement(void) { Cardinality(0); }; ~CElement(void) {}; };
故此,从上面的清单中,我们可以从定义一个元素开始。 这是一个域的基本单位,您可以把它当作一个“集合的成员”。 该单元可以采用任何数据类型,无论是双精度型还是整数型,不过若要满足更复杂的数据类型和运算时,向量类型将更加灵活。 它允许可扩展性。 其大小,'cardinal' 参数受到保护,只能通过 Cardinality()' 函数访问或修改。 保护其访问可确保无论何时修改向量,都会相应调整其大小。 向量 “element” 本身也受到保护,以防止无效的索引错误。 故此,仅允许通过 “Get()” 和 “Set()” 函数进行访问。 'Set()' 函数还返回一个布尔值来验证赋值是否成功。
//+------------------------------------------------------------------+ //| DOMAIN CLASS | //+------------------------------------------------------------------+ class CDomain { protected: int cardinal; CElement elements[]; public: bool Cardinality(int Value) { if(Value>=0 && Value<INT_MAX) { cardinal=Value; ArrayResize(elements,cardinal); return(true); } return(false); } int Cardinality() { return(cardinal); } bool Get(int Index,CElement &Element) { if(Index>=0 && Index<Cardinality()) { Element=elements[Index]; return(true); } return(false); } bool Set(int Index,CElement &Value,bool IsNew=false) { if(Index>=0 && Index<Cardinality()) { if(!IsNew||New(Value)<0) { elements[Index]=Value; return(true); }} return(false); } //only unique elements allowed int New(CElement &Value) { bool _new=-1; // for(int o=0; o<cardinal; o++) { if(ElementMatch(Value,elements[o])) { _new=o; break; } } return(_new); } CDomain(void) { Cardinality(0); }; ~CDomain(void) {}; };
因此,其内包括元素的域类,已在上面介绍过了。 它的主要变量 “elements[]” 和它的大小 “cardinal” 如同上述在元素类中一样受到保护。 这里略有不同的是添加了 “New()” 方法。 该函数帮助检查所要添加到域中的新对象,并确保它们的唯一性。 范畴域仅包含唯一对象。 不允许有重复。
由于我们有这两个类,我们可以尝试构造一些域。 我们来尝试一个偶数和一个奇数域。 我们可以运行一个脚本来引用这些类。 脚本清单如下所示。
//+------------------------------------------------------------------+ //| INPUTS | //+------------------------------------------------------------------+ input int __domain_elements=3; input int __domain_morphisms=5; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //Declare a sets of natural even & odd numbers CDomain _evens,_odds; CreateNumberDomain(_evens,__domain_elements,2); CreateNumberDomain(_odds,__domain_elements,2,1); printf(__FUNCSIG__+" evens are... "+PrintDomain(_evens)); printf(__FUNCSIG__+" odds are... "+PrintDomain(_odds)); }
创建数字函数是一种使用自然数填充域的简单方法。 所有代码都附在文末,但为清楚起见,此处展示出它的设置。
'PrintSet()' 函数是我们经常提到的一种资源丰富的方法。 它简单地令我们能使用相应的括号和逗号查看域的内容,精心将元素向量结构与整体域结构分离。 如果我们运行上面的脚本,这就是我们应该看到的。
2022.12.08 18:49:13.890 ct_1 (EURGBP.ln,MN1) void OnStart() evens are... {(2.0),(4.0),(6.0),(8.0),(10.0),(12.0),(14.0)}
2022.12.08 18:49:13.890 ct_1 (EURGBP.ln,MN1) void OnStart() odds are... {(1.0),(3.0),(5.0),(7.0),(9.0),(11.0),(13.0)}
在括号中都是每个域的各种元素,因为它们是向量数据类型,这意味着它们本身可以有多个条目。 若发生这种情况时,在每个带有括号的条目之间出现逗号,如此来帮助定义元素边界的位置。
态射也是范畴论中的一个重要概念,它们为域中元素之间的关系进行编码。 根据范畴论规则,每个态射将域中的一个元素映射到协域中的一个元素。 这些函数可以组合成更复杂的态射,它们可以用来研究集合的性质,以及它们与其它集合的关系,正如我们将看到的。
通览伊始,态射有 5 种主要类型,可用于描述给定类别中对象之间的关系。 一些最常见的类型是:
- 单态:这些是单射(injective)态射,这意味着它们将源域中的每个元素映射到协域中的唯一对象。 不会有两个态射映射到协域中的同一对象。 在这种情况下,您也许有一些对象在目标中无映射。
- 表态:这些是漫射(surjective)态射,这意味着域中的元素映射到协域中的所有元素。 换言之,协域中没有任何元素会保持无映射。 在这种实例下,协域中的元素通常少于源集合中的元素。
- 同构:同构是双射(bijective)态射,这意味着它们在源和目标范畴中的对象之间建立一对一的对应关系。 它们既是单射的,也是漫射的,因为源集合和目标集合具有相同数量的对象。
- 自同态:自同态是从元素到自身的态射。 它构成了一个恒等映射,即一组链接回域的自同态。
- 自同构:自同构是同构和自同态的映射组合。
我们看看如何以 MQL 实现态射类,以及它与域的分组作为同态。
//+------------------------------------------------------------------+ //| MORPHISM CLASS | //+------------------------------------------------------------------+ class CMorphism { public: int domain; int codomain; CElement morphism; bool Morph(CDomain &D,CDomain &C,CElement &DE,CElement &CE,bool Add=true) { int _d=D.New(DE),_c=C.New(CE); // if(_d>=0 && _c>=0) { if(DE.Cardinality()==CE.Cardinality()) { domain=_d; codomain=_c; morphism.Cardinality(DE.Cardinality()); if(Add) { for(int c=0;c<morphism.Cardinality();c++) { morphism.Set(c,CE.Get(c)-DE.Get(c)); } } else { for(int c=0;c<morphism.Cardinality();c++) { if(DE.Get(c)!=0.0){ morphism.Set(c,CE.Get(c)/DE.Get(c)); } } } } } return(false); } CMorphism(void){ domain=-1; codomain=-1; }; ~CMorphism(void){}; };
态射类是非常基本的,只有域和协域索引参数以及一个 “Morph” 函数,本文当中我们不会关注该函数。 此处省略了对相应域集合和协域集合的引用,因为它们列在伞形同态类中,如下所示。
//+------------------------------------------------------------------+ //| HOMO-MORPHISM CLASS | //+------------------------------------------------------------------+ class CHomomorphism { protected: int cardinal; CMorphism morphism[]; public: bool init; CDomain domain; CDomain codomain; bool Cardinality(int DomainIndex,int CodomainIndex,bool Add=true) { bool _morphed=true; if ( !init ) { _morphed=false; return(_morphed); } if ( DomainIndex<0 || DomainIndex>=domain.Cardinality() || CodomainIndex<0 || CodomainIndex>=codomain.Cardinality() ) { _morphed=false; return(_morphed); } for(int m=0;m<cardinal;m++) { if(DomainIndex==morphism[m].domain) { _morphed=false; break; } } if(_morphed) { cardinal++; ArrayResize(morphism,cardinal); CElement _de,_ce; if(domain.Get(DomainIndex,_de) && codomain.Get(CodomainIndex,_ce)) { morphism[cardinal-1].Morph(domain,codomain,_de,_ce,Add); } } return(_morphed); }; int Cardinality() { return(cardinal); }; bool Get(int Index,CMorphism &Morphism) { if(Index>=0 && Index<Cardinality()) { return(true); } return(false); }; bool Set(int Index,CMorphism &Value) { if ( Index>=0 && Index<Cardinality() && Value.domain>=0 && Value.domain<domain.Cardinality() && Value.codomain>=0 && Value.codomain<codomain.Cardinality() ) { if(!MorphismMatch(Index,Value,morphism,Cardinality())) { morphism[Index]=Value; return(true); } } return(false); }; void Init(CDomain &Domain,CDomain &Codomain) { domain=Domain; codomain=Codomain; init=true; } CHomomorphism(void){ init=false; cardinal=0; }; ~CHomomorphism(void){}; };