Austin Schuh | 405fa6c | 2015-09-06 18:13:55 -0700 | [diff] [blame^] | 1 | (* |
| 2 | |
| 3 | Unfolding Convex Polytopes |
| 4 | |
| 5 | Version 1.0 Beta |
| 6 | February, 1992 |
| 7 | |
| 8 | Copyright (c) 1992 by |
| 9 | Makoto Namiki |
| 10 | |
| 11 | This package contains Mathematica implementations |
| 12 | of unfolding 3-dimsional polytope. |
| 13 | |
| 14 | This package is copyright 1992 by Makoto Namiki. |
| 15 | This package may be copied in its entirety for |
| 16 | nonprofit purposes only. Sale, other than for |
| 17 | the direct cost of the media, is prohibited. |
| 18 | This copyright notice must accompany all copies. |
| 19 | |
| 20 | The authors make no representations, express or |
| 21 | implied, with respond to this documentation, of |
| 22 | the software it describes and contains, including |
| 23 | without limitations, any implied warranties of |
| 24 | mechantability or fitness for a particular purpose, |
| 25 | all of which are expressly disclaimed. The authors |
| 26 | shall in no event be liable for any indirect, |
| 27 | incidental, or consequential damages. |
| 28 | |
| 29 | This beta release is designed to run under |
| 30 | Version 1.2 & 2.0 of Mathematica. Any comments, |
| 31 | bug reports, or requests to get on the |
| 32 | UnfoldPolytope mailing list should be |
| 33 | forwarded to: |
| 34 | |
| 35 | Makoto Namiki |
| 36 | Department of Information Science, |
| 37 | Tokyo Institute of Technology, Tokyo |
| 38 | 2-12-1 Oh-okayama, Meguro-ku |
| 39 | Tokyo 145, Japan |
| 40 | |
| 41 | +81-3-3726-1111 (Ex. 4131) |
| 42 | namiki@titisna.is.titech.ac.jp |
| 43 | |
| 44 | *) |
| 45 | |
| 46 | BeginPackage["UnfoldPolytope`"] |
| 47 | |
| 48 | UnfoldPolytope::usage="UnfoldPolytope[facets] gives graphics of unfoldings of a polytope which is given as a list of facets."; |
| 49 | |
| 50 | OrderFacets::usage="OrderFacets[facets] returns a correctly order lists of facets."; |
| 51 | |
| 52 | ProperSubsetQ::usage="ProperSubsetQ[t,s] returns True if t is a proper subset of s."; |
| 53 | |
| 54 | MakeEdgesFromFacets::usage="MakeEdgesFromFacets[faces] returns a cordinats of lower faces and a adjacency of faces."; |
| 55 | |
| 56 | MakeFacetsFromZerosets::usage="MakeFacetsFromZerosets[v,z] returns a list of facets consisting of cordinates of vertices, where v denotes a list of vertices and z denotes a list of zerosets."; |
| 57 | |
| 58 | MakeAdjTable::usage="MakeAdjTable[n,l] or MakeAdjTable[n,l,costs] return an adjacency table where l denotes a list of unordered pairs consist of {1,2,...,n} and a costs denotes an adjacency cost."; |
| 59 | |
| 60 | BreadthFirstSearch::usage="BreadthFirstSearch[adj_list,n] gives a incidence matrix representing a tree of a graph obtained by breadth first search from a vertex n, where this graph is given as a incidence matrix of adj_list."; |
| 61 | |
| 62 | DepthFirstSearch::usage="DepththFirstSearch[adj_list,n] gives a incidence matrix representing a tree of a graph obtained by depth first search from a vertex n, where this graph is given as a incidence matrix of adj_list."; |
| 63 | |
| 64 | IntersectionOfList::usage="IntersectionOfList[{l_1,l_2,...l_n}] returns a Intersection[l_1,l_2,...,l_n]."; |
| 65 | |
| 66 | SelectLeaf::usage="SelectLeaf[adj_Mat] returns {i,j} such that node i is a child of node j for adjacent matrix adj_Mat."; |
| 67 | |
| 68 | ProjectVertex::usage="ProjectVetex[v1,v2,v3,v4] returns coordinates which is a projection of v4 onto affine space {v1,v2,v3} around the line {v1,v2}."; |
| 69 | |
| 70 | ProjectFaces::usage="ProjectFaces[child,parent,faces,vervect] argument child is a list of faces, parent is a face, and faces is a list of all faces. This procedure project faces of child onto a face of parent by using ProjectVertices."; |
| 71 | |
| 72 | IntersectOfFaces::usage="IntersectOfFaces[f1_List,f2_List] returns veticeswhich commonly belong to f1 and f2."; |
| 73 | |
| 74 | VectEQ::usage="VectEQ[v1,v2] returns True if v1 == v2 otherwise False"; |
| 75 | |
| 76 | Unfold::usage="Unfold[sptree,tree,maxf] open one of a leaf of Tree of Facet."; |
| 77 | |
| 78 | Zonotope::usage="Zonotope[vlist] returns a list extreme points of zonotope which is defined by vlist, a list of vectors."; |
| 79 | |
| 80 | VerticalVector::usage="VerticalVector[maxf_List] returns a list of Vertical vector of each face."; |
| 81 | |
| 82 | OrderFace::usage="OrderFace[facet]: reorder a facet correctly. |
| 83 | where argument facet consits of {v_1,v_2,..,v_n} |
| 84 | ,v_i is a cordinat of a vetex."; |
| 85 | |
| 86 | Begin["`private`"] |
| 87 | |
| 88 | UnfoldPolytope[facets_List]:= |
| 89 | Block[{odfacets,edg,faAdj,vertices,veAdj, |
| 90 | t,tree,cotree,sptree,i,tr,vervec}, |
| 91 | odfacets = facets; |
| 92 | {edg,faAdj} = MakeEdgesFromFacets[odfacets]; |
| 93 | vertices = Union[Flatten[facets,1]]; |
| 94 | veAdj = Flatten[{Position[vertices,#[[1]]], |
| 95 | Position[vertices,#[[2]]]}]& /@ edg; |
| 96 | t = BreadthFirstSearch[MakeAdjTable[Length[vertices],veAdj],1]; |
| 97 | tree = Flatten[Position[veAdj,#]& /@ Position[t,1]]; |
| 98 | cotree = Complement[Table[i,{i,1,Length[edg]}],tree]; |
| 99 | sptree = MakeAdjTable[Length[odfacets],faAdj[[cotree]]]; |
| 100 | tr = Table[{i},{i,Length[facets]}]; |
| 101 | vervec = VerticalVector[odfacets]; |
| 102 | Show[Graphics3D[Polygon /@ odfacets],Boxed->False]; |
| 103 | Do[{sptree,tr,odfacets,vervec} = Unfold[sptree,tr,N[odfacets],vervec]; |
| 104 | Show[Graphics3D[(Polygon /@ odfacets)],Boxed->False]; |
| 105 | ,{i,1,Length[odfacets]-1}]; |
| 106 | Show[Graphics3D[(Polygon /@ odfacets)],Boxed->False,ViewPoint->vervec[[1]][[1]]]; |
| 107 | ]; |
| 108 | |
| 109 | |
| 110 | OrderFacets[facets_List]:= |
| 111 | Block[{i,edges,facetsAdj,f,out,cyc,cand,cand2cyc,ff}, |
| 112 | {edges,facetsAdj} = MakeEdgesFromFacets[facets]; |
| 113 | out = {}; |
| 114 | For[i=1,i<=Length[facets],i++, |
| 115 | f = edges[[Transpose[Position[facetsAdj,i]][[1]]]]; |
| 116 | cand = Drop[f,1]; |
| 117 | cyc = {First[f]}; |
| 118 | ff = {}; |
| 119 | While[(cand2cyc = Select[cand,(Length[Intersection[Last[cyc],#]]==1)&]) != {}, |
| 120 | AppendTo[ff,Intersection[Last[cyc],cand2cyc[[1]]][[1]]]; |
| 121 | AppendTo[cyc,cand2cyc[[1]]]; |
| 122 | cand = Complement[cand,{cand2cyc[[1]]}]; |
| 123 | ]; |
| 124 | AppendTo[ff,Intersection[Last[cyc],First[cyc]][[1]]]; |
| 125 | AppendTo[out,ff]; |
| 126 | ]; |
| 127 | Return[out]; |
| 128 | ]; |
| 129 | |
| 130 | NonNegativeVectorQ[v_List]:= |
| 131 | Block[{i}, |
| 132 | For[i=1, i<= Length[v], ++i, |
| 133 | If [v[[i]] < 0, Return[False]]; |
| 134 | ]; |
| 135 | Return[True]; |
| 136 | ]; |
| 137 | |
| 138 | |
| 139 | MakeEdgesFromFacets[l_List] := |
| 140 | Block[{i,j,lf={},adj={}}, |
| 141 | For[i=1,i<Length[l],i++, |
| 142 | For[j=i+1,j<=Length[l],j++, |
| 143 | If[Length[Intersection[l[[i]],l[[j]]]] == 2, |
| 144 | AppendTo[lf,Intersection[l[[i]],l[[j]]]]; |
| 145 | AppendTo[adj,{i,j}]; |
| 146 | ]; |
| 147 | ]; |
| 148 | ]; |
| 149 | Return[{lf,adj}]; |
| 150 | ]; |
| 151 | |
| 152 | MakeFacetsFromZerosets[v_List,z_List]:= |
| 153 | Block[{i,j,flist,maxf,flag,out}, |
| 154 | flist = Transpose[Position[z,#]][[1]]& /@ Union[Flatten[z]]; |
| 155 | maxf = {}; |
| 156 | For[i=1,i<=Length[flist],i++, |
| 157 | flag = 0; |
| 158 | For[j=1,j<=Length[flist],j++, |
| 159 | If[ProperSubsetQ[flist[[i]],flist[[j]]], |
| 160 | flag = 1, |
| 161 | If[SubsetQ[flist[[i]],flist[[j]]] && i<j, |
| 162 | flag = 1; |
| 163 | ]; |
| 164 | ]; |
| 165 | ]; |
| 166 | If[flag == 0, |
| 167 | AppendTo[maxf,flist[[i]]]; |
| 168 | ]; |
| 169 | ]; |
| 170 | (* Return[maxf]; *) |
| 171 | out = v[[#]]& /@ (MakeOrder[#,z]& /@ maxf); |
| 172 | Return[out]; |
| 173 | ]; |
| 174 | |
| 175 | MakeOrder[ver_List,zerova_List]:= |
| 176 | Block[{candidates, cycle ,candidate2cycle}, |
| 177 | candidates = Drop[ver,1]; |
| 178 | cycle = { First[ver] }; |
| 179 | (* when one is list, comparing needs other is list *) |
| 180 | While[{} != (candidate2cycle = Select[candidates,AdjQ[Last[cycle],#,zerova] &]), |
| 181 | AppendTo[cycle,candidate2cycle[[1]]]; |
| 182 | candidates = Complement[candidates,candidate2cycle[[{1}]]]; |
| 183 | ]; |
| 184 | While[{} != (candidate2cycle = Select[candidates,AdjQ[First[cycle],#,zerova] &]), |
| 185 | PrependTo[cycle,candidate2cycle[[1]]]; |
| 186 | candidates = Complement[candidates,candidate2cycle[[{1}]]]; |
| 187 | ]; |
| 188 | cycle |
| 189 | ]; |
| 190 | |
| 191 | |
| 192 | AdjQ[i_Integer,j_Integer,l_List]:= |
| 193 | Block[{subface}, |
| 194 | subface=Intersection[l[[i]],l[[j]]]; |
| 195 | Length[Select[l,SubsetQ[subface,#]&]]==2]; |
| 196 | |
| 197 | ProperSubsetQ[s_List,t_List]:= |
| 198 | Length[s]==Length[Intersection[s,t]] && Length[s]<Length[t]; |
| 199 | |
| 200 | SubsetQ[s_List,t_List]:= |
| 201 | Length[s]==Length[Intersection[s,t]]; |
| 202 | |
| 203 | MakeAdjTable[n_Integer,l_List]:= |
| 204 | Block[{t=Table[Table[0,{n}],{n}],i}, |
| 205 | For[i=1,i<=Length[l],i++, |
| 206 | t[[l[[i,1]],l[[i,2]]]] = 1; |
| 207 | t[[l[[i,2]],l[[i,1]]]] = 1; |
| 208 | ]; |
| 209 | Return[t]; |
| 210 | ]; |
| 211 | |
| 212 | MakeAdjTable[n_Integer,l_List,c_List]:= |
| 213 | Block[{t=Table[Table[0,{n}],{n}],i}, |
| 214 | For[i=1,i<=Length[l],i++, |
| 215 | t[[l[[i,1]],l[[i,2]]]] = c[[i]]; |
| 216 | t[[l[[i,2]],l[[i,1]]]] = c[[i]]; |
| 217 | ]; |
| 218 | Return[t]; |
| 219 | ]; |
| 220 | |
| 221 | BreadthFirstSearch[adj_?MatrixQ,n_Integer]:= |
| 222 | Block[{out={},search,find={},output, |
| 223 | i,obj,cd,l=Length[adj]}, |
| 224 | search = {n}; |
| 225 | While[search != {}, |
| 226 | obj = search[[1]]; |
| 227 | search = Drop[search,1]; |
| 228 | cd = {}; |
| 229 | For[i=1, i<=l, i++, |
| 230 | If[adj[[obj,i]] != 0, AppendTo[cd,i]]; |
| 231 | ]; |
| 232 | cd = Complement[cd,search]; |
| 233 | cd = Complement[cd,find]; |
| 234 | For[i=1, i<=Length[cd],i++, |
| 235 | AppendTo[search,cd[[i]]]; |
| 236 | AppendTo[out,{obj,cd[[i]]}]; |
| 237 | AppendTo[out,{cd[[i]],obj}]; |
| 238 | ]; |
| 239 | AppendTo[find,obj]; |
| 240 | ]; |
| 241 | Return[MakeAdjTable[l,out]]; |
| 242 | ]; |
| 243 | |
| 244 | DepthFirstSearch[adj_?MatrixQ,n_Integer]:= |
| 245 | Block[{out={},search,find={},output, |
| 246 | i,obj,cd,l=Length[adj]}, |
| 247 | search = {n}; |
| 248 | While[search != {}, |
| 249 | obj = search[[1]]; |
| 250 | search = Drop[search,1]; |
| 251 | cd = {}; |
| 252 | For[i=1, i<=l, i++, |
| 253 | If[adj[[obj,i]] != 0, AppendTo[cd,i]]; |
| 254 | ]; |
| 255 | cd = Complement[cd,search]; |
| 256 | cd = Complement[cd,find]; |
| 257 | search = Flatten[Append[cd,search]]; |
| 258 | For[i=1, i<=Length[cd],i++, |
| 259 | AppendTo[out,{obj,cd[[i]]}]; |
| 260 | AppendTo[out,{cd[[i]],obj}]; |
| 261 | ]; |
| 262 | AppendTo[find,obj]; |
| 263 | ]; |
| 264 | Return[MakeAdjTable[l,out]]; |
| 265 | ]; |
| 266 | |
| 267 | |
| 268 | IntersectionOfList[l_List]:= |
| 269 | Block[{}, |
| 270 | If[Length[l]==1,Return[l[[1]]], |
| 271 | Return[Intersection[l[[1]], |
| 272 | IntersectionOfList[Drop[l,{1}]]]]; |
| 273 | ]; |
| 274 | ]; |
| 275 | |
| 276 | Maximals[l_List]:= |
| 277 | Block[{i,maximals={}}, |
| 278 | Do[If[MaximalQ[i,l], |
| 279 | AppendTo[maximals,l[[i]]] |
| 280 | ], {i,Length[l]} |
| 281 | ]; |
| 282 | maximals] |
| 283 | |
| 284 | MaximalQ[i_Integer,l_List]:= |
| 285 | Block[{candidate}, |
| 286 | candidate=l[[i]]; |
| 287 | Length[Union[Select[l,ProperSubsetQ[candidate,#]&]]]==0] |
| 288 | |
| 289 | SubsetQ[s_List,t_List]:= |
| 290 | Length[s]==Length[Intersection[s,t]]; |
| 291 | |
| 292 | Is[s_List]:= |
| 293 | Block[{}, |
| 294 | If [Length[s] == 1, |
| 295 | Return[s[[1]]], |
| 296 | Return[Intersection[s[[1]],Is[Drop[s,1]]]] |
| 297 | ]; |
| 298 | ]; |
| 299 | |
| 300 | SelectLeaf[g_List]:= |
| 301 | Block[{size,i,j,deg,child,par,cp}, |
| 302 | size = Length[g]; |
| 303 | For[i=2,i<=size,i++, |
| 304 | deg = 0; |
| 305 | child = i; |
| 306 | For[j=1,j<=size,j++, |
| 307 | If[g[[i]][[j]] > 0, |
| 308 | deg = deg + 1; |
| 309 | par = j; |
| 310 | ]; |
| 311 | ]; |
| 312 | If[deg == 1, |
| 313 | Return[{child,par}]; |
| 314 | ]; |
| 315 | ]; |
| 316 | ] |
| 317 | |
| 318 | ProjectFaces[child_List,par_Integer,face_List,vervec_List]:= |
| 319 | Block[{v1,v2,nch,i,fl}, |
| 320 | {v1,v2} = IntersectOfFaces[face[[child[[1]]]],face[[par]]]; |
| 321 | For[i=1, i<=Length[face[[par]]], ++i, |
| 322 | If[!VectEQ[face[[par]][[i]],v1] && !VectEQ[face[[par]][[i]],v2], |
| 323 | v3 = face[[par]][[i]]; |
| 324 | Break[]; |
| 325 | ]; |
| 326 | ]; |
| 327 | fl = {}; |
| 328 | For[i=1, i<=Length[child], i++, |
| 329 | AppendTo[fl,ProjectVertex[v1,v2,v3,#,vervec]& /@ face[[child[[i]]]]]; |
| 330 | ]; |
| 331 | Return[fl]; |
| 332 | ] |
| 333 | |
| 334 | IntersectOfFaces[f1_List,f2_List]:= |
| 335 | Block[{i,j,lvect}, |
| 336 | lvect = {}; |
| 337 | For[i=1,i<=Length[f1],i++, |
| 338 | For[j=1,j<=Length[f2],j++, |
| 339 | If[VectEQ[f1[[i]],f2[[j]]],AppendTo[lvect,f1[[i]]]]; |
| 340 | ]; |
| 341 | ]; |
| 342 | Return[{lvect[[1]],lvect[[2]]}]; |
| 343 | ] |
| 344 | |
| 345 | VectEQ[v1_List,v2_List]:= |
| 346 | Block[{i}, |
| 347 | For[i=1,i<=Length[v1],i++, |
| 348 | If[v1[[i]] != v2[[i]],Return[False]]; |
| 349 | ]; |
| 350 | Return[True]; |
| 351 | ] |
| 352 | |
| 353 | |
| 354 | ProjectVertex[v1_List,v2_List,v3_List,v4_List,a_List]:= |
| 355 | Block[{x,y}, |
| 356 | If [N[a[[1]].v4] <= a[[2]] + 10^(-10), |
| 357 | x = (v2-v1).(v2-v4)/(v2-v1).(v2-v1)*v1 + (v1-v2).(v1-v4)/(v1-v2).(v1-v2)*v2; |
| 358 | y = (v2-v1).(v2-v3)/(v2-v1).(v2-v1)*v1 + (v1-v2).(v1-v3)/(v1-v2).(v1-v2)*v2; |
| 359 | Return[x + Sqrt[(v4-x).(v4-x)/(y-v3).(y-v3)]*(y-v3)] |
| 360 | ]; |
| 361 | If [N[a[[1]].v4] >= a[[2]] - 10^(-10), |
| 362 | x = (v2-v1).(v2-v4)/(v2-v1).(v2-v1)*v1 + (v1-v2).(v1-v4)/(v1-v2).(v1-v2)*v2; |
| 363 | y = (v2-v1).(v2-v3)/(v2-v1).(v2-v1)*v1 + (v1-v2).(v1-v3)/(v1-v2).(v1-v2)*v2; |
| 364 | Return[x + Sqrt[(v4-x).(v4-x)/(y-v3).(y-v3)]*(v3-y)] |
| 365 | ]; |
| 366 | ] |
| 367 | |
| 368 | Unfold[sptree1_List,tree1_List,maxf1_List,vervec_List]:= |
| 369 | Block[{j,child,par,posch,ch,of,pospa,sptree=sptree1,tree=tree1,maxf=maxf1,vv=vervec}, |
| 370 | {child, par} = SelectLeaf[sptree]; |
| 371 | sptree[[child,par]] = -1; |
| 372 | sptree[[par,child]] = -1; |
| 373 | |
| 374 | {posch} = Transpose[Position[tree,child]][[1]]; |
| 375 | ch = tree[[posch]]; |
| 376 | of = ProjectFaces[ch,par,maxf,vv[[par]]]; |
| 377 | For[j=1, j<=Length[ch],j++, |
| 378 | maxf[[ch[[j]]]] = of[[j]]; |
| 379 | ]; |
| 380 | {pospa} = Transpose[Position[tree,par]][[1]]; |
| 381 | tree[[pospa]] = (AppendTo[tree[[pospa]],#]& /@ ch)[[Length[ch]]]; |
| 382 | tree = Drop[tree,{posch}]; |
| 383 | Return[{sptree,tree,maxf,vv}]; |
| 384 | ] |
| 385 | |
| 386 | Zonotope[vectors_List]:= |
| 387 | Block[{vlist}, |
| 388 | vlist = Sum[(#)[[i]],{i,Length[#]}]& /@ ((vectors * (#)&) /@ Pow[Length[vectors]]); |
| 389 | Return[vlist]; |
| 390 | ] |
| 391 | |
| 392 | Pow[n_Integer]:= |
| 393 | Block[{p,a,b}, |
| 394 | If[n == 1, Return[{{1},{-1}}] |
| 395 | ]; |
| 396 | p = Pow[n-1]; |
| 397 | a = Append[#,1]& /@ p; |
| 398 | b = Append[#,-1]& /@ p; |
| 399 | Return[(AppendTo[a,#]& /@ b)[[Length[b]]]]; |
| 400 | ] |
| 401 | |
| 402 | NonEmptyFaces[zerova_List]:= |
| 403 | Map[Function[Transpose[Position[zerova,#]][[1]]],Union[Flatten[zerova]]] |
| 404 | |
| 405 | VerticalVector[maxf_List]:= |
| 406 | Block[{i,vervec,a1,a2,x,y,z,b,v,vv={}}, |
| 407 | For[i=1,i<=Length[maxf],i++, |
| 408 | a1 = maxf[[i]][[3]]-maxf[[i]][[2]]; |
| 409 | a2 = maxf[[i]][[1]]-maxf[[i]][[3]]; |
| 410 | Clear[x,y,z]; |
| 411 | vervec = {x,y,z}; |
| 412 | {vervec} = vervec /. Solve[{a1.vervec == 0, a2.vervec == 0}]; |
| 413 | x = 1; y = 1; z = 1; |
| 414 | b = vervec.maxf[[i]][[1]]; |
| 415 | v = Complement[Union[Flatten[maxf,1]],maxf[[i]]][[1]]; |
| 416 | If[v.vervec > b, vervec = -vervec; b = -b]; |
| 417 | AppendTo[vv,{vervec,b}]; |
| 418 | ]; |
| 419 | Return[vv]; |
| 420 | ] |
| 421 | |
| 422 | End[] |
| 423 | EndPackage[] |