留言板 留言板

11
|
19414视图
|
3个答复
|
15个总喜欢次数
查看组。。。
分享
分享此帖子:

非传递格里姆骰子:计算并可视化可能的获胜循环的完整集合

已发布10年前

今年圣诞节,我给自己买了一份有趣的数学礼物:一套10个非及物骰子,即格里姆骰子! 你可以自己买一套在这里.看看他们不切实际的辉煌:

非传递格里姆骰子:计算并可视化可能的获胜循环的完整集合

这些骰子具有一个迷人的特性,即它们的获胜关系(在“wining”的意义上=“rolls a higher number>50%of the time”)是非传递的。也就是说,如果骰子A赢了骰子B,骰子B赢了骰C,那么它实际上赢了一般来说,坚持A赢C。事实上,C可能赢A!

如果我们将格里姆骰子的5种颜色标记为红色、蓝色、黄色、橄榄色和洋红色,则有2个主要的非传递获胜循环:

  1. 按单词长度:红色打蓝色打橄榄色打黄色打洋红色打红色
  2. 按字母顺序:蓝色击败洋红色击败橄榄色击败红色击败黄色击败蓝色

这本身很简洁,也不直观,但当你把两个相同颜色的骰子掷在一起时,事情会变得更奇怪:单词长度循环颠倒,而字母周期(几乎)保持不变。

  1. 按字长(双精度):红色/红色输给蓝色/蓝色输给橄榄色/橄榄色输给黄色/黄色输给洋红色/洋红色输给红色/红色
  2. 按字母顺序(双精度):蓝色/蓝色击败洋红色/洋红色击败橄榄色/橄榄色输给红色/红色击败黄色/黄色击败蓝色/蓝色

使用Mathematica,我们可以计算获胜概率,并可视化循环:

非传递格里姆骰子:计算并可视化可能的获胜循环的完整集合

这4个周期是唯一被宣传的周期,但事实证明,只需使用集合中的10个骰子就可以形成更多的周期。

事实上,有298个这样的循环!以下是所有的情节1模循环

非传递格里姆骰子:计算并可视化可能的获胜循环的完整集合

所有2冰循环

非传递格里姆骰子:计算并可视化可能的获胜循环的完整集合

所有3-ie循环

在此处输入图像描述

在本文中,我们将详细介绍用于创建这些图和计算完整的可能循环集的Mathematica代码。

骰子建模

第一步是提供不同骰子颜色的简单表示,每个颜色都有一个独特的点状配置:

(*代表骰子、它们的名字和面值*)红色=骰子[“红色”]={{“红色”},{4,4,4,19}};蓝色=骰子[“蓝色”]={{“蓝色”},{2,2,7,7}};橄榄=骰子[“橄榄”]={{“橄榄”},{0,5,5,5,5,5}};黄色=骰子[“黄色”]={{“黄色”},{3,3,3,18}};洋红=骰子[“洋红”]={{“洋红“},{1,6,6,6}};

为了计算两个骰子中哪一个赢了另一个,以及赢的几率,我们在两个骰之间生成每一个可能的掷骰,并查看哪个骰子更经常出现在顶部:

(*计算两个骰子中哪一个会赢,包括赔率*)(*返回{赢家->输家,赔率}*)compareIce[{lName_,lVals_},{rName_,rVals_}]:=(rolls=元组[{lVals,rVals}];winDiff=总数[rolls/.{l_,r_}->符号[r-l]];赔率=1/2+Abs[winDiff]/(2*长度[rolls]);{如果[winDiff>0,rName->lName,lName->rName],N[bids,3]});

因此,我们可以看到,例如,红色在58%的时间内击败蓝色,黄色在56%的时间里击败洋红。

比较冰[红,蓝]比较器冰[品红色,黄色](*输出:{{“红色”}->{“蓝色”},0.583}{{“黄色”}->{“洋红色”},0.556}*)

非传递循环

我们已经能够用单个骰子验证和量化主要单词长度和字母周期:

byWordLength={{红色,蓝色},{蓝色,橄榄色},}橄榄色,黄色},黄色,洋红},红色}};byAlpha={{蓝色,品红色},{品红色,橄榄色},}橄榄色,}红色,黄色,}黄色,蓝色};按字长比较冰@@@通过Alpha比较冰@@@(*输出:{{{“红”}->{“蓝”},0.583},{{(蓝)}->}“橄榄”}{{{“蓝色”}->{“洋红色”},0.667},{{”洋红色“}->}”橄榄色“},0.722},}“橄榄色”}->{“红色”},0.694},[{”红色“}->{”黄色“}*)

我们可以表示和比较成对的骰子,就像它们都是一个36面骰子一样,每个面都对应于组成骰子的可能掷骰子的总数。这也让我们计算单词长度和字母双骰子循环的几率:

(*通过组合两个骰子创建一个新的“骰子”*)组合[{name1_,vals1},{name2_,vals2}]:={Join[name1,name2],Plus@@@Tuples[{vals1,vals2}]};double[die_]:=组合[die,die];compareDice@@@Map[double,byWordLength,{2}]compareDice@@@Map[double,byAlpha,{2}](*输出{{{“蓝色”,“蓝色”}->{“红色”,“红色”},0.590},{{(橄榄色),“橄榄色”}->{“蓝”,“蓝”}“},0.691}}{{{“蓝色”,“蓝色”}->{“洋红色”,“洋红色“},0.556},{{”洋红色“,”洋红色”}->{“橄榄”,“橄榄”}“},0.556}}*)

绘图

最好是可视化骰子之间的获胜关系,而不是仅仅打印出数据。Mathematica具有出色的绘图和可视化功能,因此这当然是可能的。

图形绘图在这里是个不错的选择。然而,它的默认视觉输出并不十分适合这个问题,因此我们需要进行一些定制。我们可以利用函数公开的各种挂钩,使我们能够指定自定义图形对象来表示关系图的顶点和边。

下面的代码将创建漂亮的图形图,其中顶点由适当颜色的骰子图标表示,边缘指向赢家->输家,并标有赢家的概率。

(*跟踪绘图中应使用的颜色*)colors[“Red”]=红色;colors[“Blue”]=蓝色;colors[“橄榄”]=绿色;颜色[“黄色”]=黄色;colors[“洋红色”]=紫色;(*绘制彩色矩形以表示图形顶点处的骰子*)getVertex[center_,names_]:=(数字骰子=长度@名称;位置={-0.08+#,0.08+#}&/@范围[0.04*(numDice-1)/2,0.04*(numDice-1)/2,004];转置[{colors/@names,Rectangle[center+#1,center+#2,RoundingRadius->0.02]&@@@positions}]);(*为图形边缘绘制一个格式正确的标记箭头*)获取边缘=({灰色,如果[#3==0.5,线[#1],箭头[#1,0.15]],黑色,插图[#3,平均值[#1],背景->白色]}&);(*给定一个骰子对列表,创建一个格式良好的图赢得关系和赔率*)plotDice[对_]:=GraphPlot[compareDice@@@对,顶点渲染功能->获取顶点,EdgeRenderingFunction->获取边缘];

让我们直观地看一下单循环和双循环:

在此处输入图像描述

非常整洁!除了方向和顺序上的各种奇怪之处外,这些情节也很吸引人。顶点的精确位置可以通过GraphPlot的VertexCoordinateRules参数指定,但默认布局足以满足我们的目的。

更多周期

我们使用相同颜色的单骰子和双骰子查看了主要的5色循环。不过,这只是开始。例如,除了5色循环外,还存在各种较小的循环:

在此处输入图像描述

这些较小的循环有多少?更大的周期呢?那么,由两种不同颜色组成的双打圈又如何呢?或者甚至由3个骰子组成的循环?我们想计算每个可能的循环可以使用一组中的10个骰子来创建。

我们解决这一问题的总体方法是生成有向图,对特定大小的唯一骰子集(单个骰子、成对骰子或三重骰子)之间的所有获胜关系进行编码,然后在这些图中搜索循环。

需要注意的是(我们不会在这里证明),对于格里姆骰子来说,任何一对骰子都能击败任何一个骰子,任何三重骰子都可以击败任何一对或单个骰子。因此,将此计算拆分为单个骰子、对和三元组的单独桶是可以接受的。就竞争骰子的数量而言,不存在异质循环。

单骰子

人们可能会假设,单骰子的周期最容易计算。事实上,单骰子带来了两个独特的挑战,而双骰子和三骰子则没有。具体来说,在一组10个骰子中,我们可能会发现大小达到10的循环。但由于我们只有5种颜色,一旦一个循环变为长度6或更长,我们就必须在循环中有2个相同颜色的节点。我们需要确保区分每种颜色的两个副本。

为了捕捉到我们手头上每种颜色都有2份的事实,我们将使用一点破解。每种颜色的“第二个”副本将表示为与一个特殊的“白色”模具的组合,该模具具有1个面,并且始终滚动0。

(*虚拟“白色”模具用于区分相同颜色模具的两个实例*)白色=骰子[“白色”]={{“白色”},{0}};(*绘制时,只需使白色骰子不可见*)colors[“White”]=透明;(*10个骰子中所有不同的单骰子*)allDice[1]=加入[allColors,组合@@@Tuples[{allColors,{white}}]];

为了开始构建实际的关系图,我们将定义几个帮助函数。第一个用于创建定向边缘Mathematica在以下情况下使用的值图表在第二个函数中调用。边缘从“获胜di(c)e”指向“失败di(c)e”。

(*请注意,如果两个骰子相等,则此处不返回边*)getGraphEdge[left_,right_]:=({relationship,iods}=compareDice[左,右];如果[ost!=1/2,relationship/.Rule->DirectedEdge]);(*构建获胜关系图n个骰子元组*)makeGraph[n_]:=图[Cases[getGraphEdge@@@子集[allDice[n],{2}],DirectedEdge[__]]];

现在,我们可以生成单骰子关系的完整图形,并让Mathematica计算最大大小为10的所有循环。在最后一步中,请注意,我们需要对循环列表进行重复数据消除,以消除那些仅因包含虚拟“白色”模具而唯一的循环。

diceGraph[1]=生成图[1];(*内置函数DeleteDuplicatesBy仅存在在Mathematica 10+*中)deDupeBy[expr_,f_]:=值[GroupBy[expr,f,First]];(*计算可以由包含的10个骰子制成*)周期[1]=deDupeBy[FindCycle[diceGraph[1],10,All],排序[(#/.{e_,“白色”}->{e})]&];CountsBy[周期[1],长度]周期[1]//长度(*输出:<|3 -> 5, 4 -> 5, 5 -> 2, 6 -> 15, 7 -> 20, 8 -> 20, 9 -> 10, 10 -> 3|>80*)

我们看到总共有80个独特的单模周期,大小从3到10不等。

一对骰子

骰子对是最简单的情况。

对于成对(和以上),我们不需要考虑循环中不同的相同节点的可能性。证明:在任何两个相同的节点之间,必须至少有两个其他节点(如果只有一个节点,它将同时被任意一侧的相同节点击败和失去),因此具有相同节点的完整循环的长度必须至少为6(两个相同节点+每侧的两个分离节点)。当每个节点由一对骰子组成时,这需要至少12个骰子。因为我们只有10个骰子,这是不可能的。

这样就不需要假模,也不需要在末端进行重复数据消除。

我们需要考虑的唯一额外问题是,一个计算周期可能包含2个以上特定颜色的骰子。这种循环在我们的场景中是无效的,因为我们只使用了集合中的10个骰子。我们将更新帮助程序并添加一些额外的筛选以消除此类循环。

最后,对于成对,我们只需要搜索长度为5的循环。

(*所有唯一的骰子对*)allDice[2]=扁平[表格[combine@@allColors[[{i,j}]],{i,1,长度[allColors]},{j,i,长度[allColors]}],1];(*已更新以避免在节点之间创建边组合使用两种以上的任何颜色*)获取图形边缘[left_,right_]:=如果[FreeQ[Tally[Join[left[[1]],right[[1]]],{_,count_}/;计数>2],{relationship,iods}=compareDice[左,右];如果[ost!=1/2,relationship/.Rule->DirectedEdge]];(*检查给定的完整循环是否使用2个以上任何特定颜色*)有效周期[cyc_]:=FreeQ[Tally[Flatten[cyc/.DirectedEdge[a_,_]:>a]],{_,count_}/;计数>2];(*计算能够由包含的10个骰子制成*)diceGraph[2]=生成图[2];cycles[2]=选择[FindCycle[diceGraph[2],5,All],isValidCycle];计数依据[周期[2],长度]周期[2]//长度(*输出:<|3 -> 55, 4 -> 89, 5 -> 25|>169*)

有169个使用骰子对的独特循环。

骰子的三倍

三元组是我们需要考虑的最大组。至少需要3个节点才能形成一个循环,如果这些节点每个包含4个或更多骰子,那么我们的10个骰子集就不够了。

类似地,我们只需要在这里搜索长度为3的循环——一个4个三元组的循环需要比我们更多的骰子。

我们首先扩展骰子组合函数来处理三元组,建立所有这些唯一的三元组并生成它们的获胜关系图。请注意,所有3个骰子颜色相同的任何三元组都是无效的,应该进行过滤。

(*扩展到处理三元组*)组合[die1,die2,die3]:=组合[die 1,combine[die 2,die 3]];(*所有独特的骰子三连*)allDice[3]=选择[扁平[表格[combine@@allColors[[{i,j,k}]],{i,1,长度[allColors]},{j,i,长度[allColors]},{k,j,长度[allColors]}],2],长度@接头@#[[1]] != 1 &];diceGraph[3]=生成图形[3];

从这里开始,计算三个循环应该像再次调用FindCycle一样简单。不幸的是,当人们尝试这样做时,Mathematica(似乎)会无限旋转。三元组的关系图是30个节点和208条边——虽然不算小,但也不算大。我不知道为什么FindCycle会有问题。奇怪的是,如果你只要求1个周期,FindCycley会立即找到1个周期;但如果你只需要2个周期,就有问题了,更不用说全部了。

因此,我们需要手动搜索此图中的3个循环。下面的代码可以做到这一点。

(*对于图中的每条边,收集潜在的第二条边例如,对于边A->B,找到所有对{{A->B、B->X}、{A->B、B->Y}、…}*)边缘空隙=压扁[EdgeList[diceGraph[3]]/。定向边缘[a,b_]:>({定向边缘[a,b],#}和/@边列表[diceGraph[3],定向边[b,_]]),1];(*找到并验证3个循环的第三个和最后一个边缘。例如,给定{A->B,B->C},检查C->A是否存在,以及循环A->B->C->A有效*)完整循环[DirectedEdge[a_,b_],DirectedEdge[c_,d_]]:=(lastEdge=定向边缘[d,a];如果[MemberQ[EdgeList[diceGraph[3],lastEdge](cycle={DirectedEdge[a,b],DirectedEdge[c,d],lastEdge};如果[isValidCycle[cycle],母猪[周期]])]);

这使我们能够计算周期,尽管我们确实需要对其进行重复数据消除(与FindCycle不同,我们的手动代码不够智能,无法实现周期A->B->C->A与周期B->C->A->B相同)。

循环[3]=deDupeBy[Reap[Scan[completeCycle@@#&,edgePirs]][2,1]],排序];计数依据[周期[3],长度](*输出:<|3 -> 49|>*)

共有49个三向旋回。这使得在一组10粒格里姆骰子中总共有298个独特的非传递周期。

绘制所有循环!

最后,每一个可能循环的有趣部分-制作巨型情节!

为了绘制一个周期,我们只需要稍微修改一下数据,以便它能与早期的plotDice一起工作。

(*“组合”单个模具是no-op*)组合[{name1_,vals1}]:={name1,vals1};(*绘制单个非及物骰子循环*)打印周期[cyc_]:=plotDice[cyc/.DirectedEdge[l_,r_]:>{combine@@(dice/@l),combine@@(dice/@r)}];

以下是几个示例图:

在此处输入图像描述

要生成文章顶部链接的完整图,我们只需要

(*绘制所有内容!*)plotCycle/@周期[1]plotCycle/@周期[2]plotCycle/@周期[3]

本文中的所有代码都是GitHub要点在这里.这是我的转载原始博客.

3个答复
排序依据:

林肯在他的笔记本中提供了数学家詹姆斯·格里姆的写作链接。任何想要物理骰子的人都可以在https://mathsgear.co.uk/collections/dice/products/nont-transive-grime-dice。我第一次看到格里姆骰子是在皇家学会的一次演讲中当数学出错时会发生什么?-和马特·帕克。我已将视频提示为Matt关于非传递骰子的讨论的开始,但我强烈建议您观看并分享整个演示文稿。AFAICT,非及物系统几乎从未在高中课堂上讨论过;有一个例子来让人了解情况,并在Mathematica中可视化,这是相当好的。谢谢,林肯!

在此处输入图像描述--你赢得了特色贡献者徽章 在此处输入图像描述你的特殊帖子被选为我们的编辑专栏员工推荐 http://wolfr.am/StaffPicks网站您的个人资料现在由一个特色贡献者徽章并显示在特色贡献者委员会。谢谢!

发布者:仲裁小组

这段代码的可读性令人鼓舞!

对此讨论的答复
可以使用标记语法.
回复预览
附件
删除
放弃

组摘要 组摘要