1################################################################################
2##
3##  simpcomp / io.gi
4##
5##  simpcomp IO functions
6##
7##  $Id$
8##
9################################################################################
10
11#make list to dense string (not containing any spaces
12SCIntFunc.ListToDenseString:=function(item)
13	if(IsStringRep(item)) then
14		return Concatenation(["\"",item,"\""]);
15	elif(IsList(item) and not IsStringRep(item)) then
16		return Concatenation("[",
17      JoinStringsWithSeparator(List(item,SCIntFunc.ListToDenseString),","),"]");
18	else
19		return String(item);
20	fi;
21end;
22
23
24
25
26#parsing variables
27SCIntFunc.parseDelim:=',';
28SCIntFunc.parseOpenstruct:='[';
29SCIntFunc.parseClosestruct:=']';
30SCIntFunc.parseArray:=['0','1','2','3','4','5','6','7','8','9',' ',',',
31  '[',']','\'','\"'];
32SCIntFunc.parseChar:='\'';
33SCIntFunc.parseString:='\"';
34SCIntFunc.parseEscape:='\\';
35
36#reader functions for reading xml (pc)data
37SCIntFunc.ReadInteger:=
38function(string)
39	if IsEmptyString(string) or not ForAll(string,x->IsDigitChar(x) or x='-') then
40		Info(InfoSimpcomp,1,"SCIntFunc.ReadInteger: error reading from string \"",
41      string,"\".");
42		return fail;
43	else
44		return Int(string);
45	fi;
46end;
47
48SCIntFunc.ReadBoolean:=
49function(string)
50	local b;
51	b:=SCIntFunc.ReadInteger(string);
52	if(b<>fail) then
53		if(b=0) then
54			return false;
55		elif(b=1) then
56			return true;
57		fi;
58	fi;
59	Info(InfoSimpcomp,1,"SCIntFunc.ReadBoolean: error reading from string \"",
60    string,"\".");
61	return fail;
62end;
63
64SCIntFunc.BooleanToString:=
65function(b)
66	if(b=false) then
67		return "0";
68	elif(b=true) then
69		return "1";
70	else
71		return "2";
72	fi;
73end;
74
75SCIntFunc.ReadString:=
76function(string)
77	return String(string);
78end;
79
80
81SCIntFunc.ReadArray:=
82function(string)
83	local p,ret,ReadArrayInteger,ReadArrayString,ReadArrayArray;
84
85	ReadArrayInteger:=function(arr,pos)
86		local p,int;
87
88		int:=[];
89
90		for p in [pos..Length(arr)] do
91			if(IsDigitChar(arr[p]) or arr[p]='-') then
92				Add(int,arr[p]);
93			else
94				break;
95			fi;
96		od;
97
98		if(int=[] or (p=Length(arr) and not arr[Length(arr)]=']')) then
99			Info(InfoSimpcomp,1,"ReadArrayInteger: error reading from string \"",
100        arr,"\" at position ",pos,".");
101			return [fail,pos];
102		else
103			return [Int(int),p];
104		fi;
105	end;
106
107	ReadArrayString:=function(arr,pos)
108		local p,int,delim,escape,str;
109
110		str:=[];
111		escape:=false;
112		delim:=arr[pos];
113		for p in [pos+1..Length(arr)] do
114			if(arr[p]=SCIntFunc.parseEscape) then
115				escape:=true;
116				continue;
117			fi;
118
119			if(escape) then
120				Add(str,arr[p]);
121				escape:=false;
122			elif(arr[p]=delim) then
123				return [str,p+1];
124			else
125				Add(str,arr[p]);
126			fi;
127		od;
128
129		Info(InfoSimpcomp,1,"ReadArrayString: error reading from string \"",
130      arr,"\" at position ",pos,".");
131		return [fail,pos];
132	end;
133
134	ReadArrayArray:=function(arr,pos)
135		local p,int,ret,a,range;
136
137		a:=[];
138		range:=false;
139		p:=pos+1;
140		while p<=Length(arr) do
141			if(arr[p]=' ' or arr[p]=',') then
142				p:=p+1;
143				continue;
144			fi;
145
146			if(range and not (IsDigitChar(arr[p]) or arr[p]='-')) then
147				return fail;
148			fi;
149
150			if(not range and arr[p]=']') then
151				return [a,p+1];
152			elif(arr[p]='[') then
153				ret:=ReadArrayArray(arr,p);
154			elif(IsDigitChar(arr[p]) or arr[p]='-') then
155				ret:=ReadArrayInteger(arr,p);
156			elif(arr[p]='\'' or arr[p]='\"') then
157				ret:=ReadArrayString(arr,p);
158			elif(arr[p]='.' and p<Length(arr) and arr[p+1]='.') then
159				range:=true;
160				p:=p+2;
161				continue;
162			else
163				Info(InfoSimpcomp,1,"ReadArrayArray: unknown type in string \"",
164          arr,"\" at position ",pos,".");
165				ret:=fail;
166			fi;
167
168			if(ret=fail or ret[1]=fail) then
169				return fail;
170			fi;
171
172			if(not range) then
173				Add(a,ret[1]);
174				p:=ret[2];
175			else
176				range:=[a[Length(a)]..ret[1]];
177				a[Length(a)]:=range;
178				p:=ret[2];
179				range:=false;
180			fi;
181		od;
182
183		return fail;
184	end;
185
186
187	for p in [1..Length(string)] do
188		if(string[p]=' ') then
189			continue;
190		fi;
191
192		if(string[p]='[') then
193			ret:=ReadArrayArray(string,p);
194			if(ret=fail) then
195				return fail;
196			else
197				return ret[1];
198			fi;
199		else
200			break;
201		fi;
202	od;
203
204	Info(InfoSimpcomp,1,"SCIntFunc.ReadArray: no starting sequence found ",
205    "in string \"",string,"\".");
206	return fail;
207end;
208
209SCIntFunc.ReadPerm:=
210function(arr)
211	local a;
212	a:=SCIntFunc.ReadArray(arr);
213	if(a<>fail) then
214		return PermList(a);
215	else
216		return fail;
217	fi;
218end;
219
220SCIntFunc.PermToString:=
221function(p)
222	return SCIntFunc.ListToDenseString(ListPerm(p));
223end;
224
225
226SCIntFunc.ReadPermGroup:=
227function(arr)
228	local a,g;
229	a:=SCIntFunc.ReadArray(arr);
230
231	if(a<>fail) then
232		if a <> [] and a<>[[]] then
233			if(IsString(a[1]) and a[1]<>[]) then
234				if(a[2]<>[]) then
235					g:=Group(List(a[2],x->PermList(x)));
236				else
237					g:=Group(());
238				fi;
239				SetStructureDescription(g,a[1]);
240				SetName(g,a[1]);
241				return g;
242			else
243				return Group(List(a,x->PermList(x)));
244			fi;
245		else
246			return Group(());
247		fi;
248	else
249		return fail;
250	fi;
251end;
252
253SCIntFunc.PermGroupToString:=
254function(g)
255	if(HasName(g) and Name(g)<>"") then
256		return String([Name(g),List(GeneratorsOfGroup(g),x->ListPerm(x))]);
257	else
258		return String([StructureDescription(g),
259      List(GeneratorsOfGroup(g),x->ListPerm(x))]);
260	fi;
261end;
262
263
264
265
266
267#position object (gets splitted into elements when serialized to xml,
268#as opposed to list)
269SCPositionalObjectFamily:=NewFamily("SCPositionalObjectFamily",
270  SCIsPositionalObject and IsPositionalObjectRep and IsMutable);
271SCPositionalObjectType:=NewType(SCPositionalObjectFamily,SCIsPositionalObject);
272
273#create positional object from list
274SCIntFunc.SCPositionalObjectFromList:=
275function(list)
276	return Objectify(SCPositionalObjectType,rec(data:=list));
277end;
278
279#methods for positional object
280InstallMethod(
281	\[\],"for SCPositionalObject",
282	[SCIsPositionalObject,IsInt],
283function(po, pos)
284	 return po!.data[pos];
285end);
286
287InstallMethod(
288	IsBound\[\],"for SCPositionalObject",
289	[SCIsPositionalObject,IsInt],
290function(po, pos)
291	return IsBound(po!.data[pos]);
292end);
293
294InstallMethod(
295	\[\]\:\=,"for SCPositionalObject",
296	[SCIsPositionalObject and IsMutable,IsInt,IsObject],
297function(po, pos, val)
298	po!.data[pos]:=val;
299end);
300
301InstallMethod(
302	Unbind\[\],"for SCPositionalObject",
303	[SCIsPositionalObject and IsMutable,IsInt],
304function(po, pos)
305	Unbind(po!.data[pos]);
306end);
307
308InstallMethod(
309	Length,"for SCPositionalObject",
310	[SCIsPositionalObject],
311function(po)
312	return Length(po!.data);
313end);
314
315InstallMethod(
316	ViewObj,"for SCPositionalObject",
317	[SCIsPositionalObject],
318function(po)
319	ViewObj(po!.data);
320end);
321
322InstallMethod(
323	PrintObj,"for SCPositionalObject",
324	[SCIsPositionalObject],
325function(po)
326	PrintObj(po!.data);
327end);
328
329
330#serialize object to xml
331SCIntFunc.SCObjectToXML:=
332function(object,name,ident)
333	local type,prefix,subitems,processed;
334
335	if(object=fail) then
336		return "";
337	fi;
338
339	processed:=false;
340	for type in RecNames(SCIntFunc.SCXMLIOHandlers) do
341		if(not SCIntFunc.SCXMLIOHandlers.(type)[1](object)) then
342			continue;
343		else
344			prefix:=Concatenation(ListWithIdenticalEntries(ident,"\t"));
345
346			if(SCIntFunc.SCXMLIOHandlers.(type)[4]=true) then
347				#atomic type
348				return Concatenation([prefix,"<",String(name)," type=\"",type,"\">",
349          SCIntFunc.SCXMLIOHandlers.(type)[2](object),"</",name,">\n"]);
350			else
351				#compound type
352				return Concatenation([prefix,"<",String(name)," type=\"",type,"\">\n",
353          SCIntFunc.SCXMLIOHandlers.(type)[2](object,ident),prefix,"</",name,
354          ">\n"]);
355			fi;
356		fi;
357	od;
358
359	Info(InfoSimpcomp,3,"SCIntFunc.SCObjectToXML: ignoring property ",name,
360    " -- unknown type.");
361	return "";
362end;
363
364
365#element reading handler for xml reader
366SCIntFunc.SCXMLElementHandler:=
367function(target,pos,root)
368	local type,content,c,value,data,lpos;
369
370	if(root.name="PCDATA" or root.name="XMLPI" or
371      root.name="XMLCOMMENT" or root.name="Ignore") then
372		#ignore processing instructions & comments
373		return 0;
374	fi;
375
376	#assume type string
377	type:="SCString";
378	value:=fail;
379
380	if "attributes" in RecNames(root) and "type" in RecNames(root.attributes) then
381		type:=root.attributes.type;
382	fi;
383
384
385	if(type="SCEmpty") then
386		return 1;
387	fi;
388
389
390	if(not type in RecNames(SCIntFunc.SCXMLIOHandlers)) then
391		Info(InfoSimpcomp,3,"SCIntFunc.SCXMLElementHandler: warning, ignoring ",
392      "unknown type \"",type,"\".");
393		return 0;
394	fi;
395
396	value:=fail;
397	if(SCIntFunc.SCXMLIOHandlers.(type)[4]=true) then
398		#atomic content
399		content:=fail;
400		for c in root.content do
401			if c.name="PCDATA" then
402				content:=c.content;
403				break;
404			fi;
405		od;
406
407		if(content=fail) then
408			Info(InfoSimpcomp,1,"SCIntFunc.SCXMLElementHandler: getting content of ",
409        "xml node ",root," failed.");
410			return -1;
411		fi;
412
413		value:=SCIntFunc.SCXMLIOHandlers.(type)[3](content);
414	else
415		#xml content
416		value:=SCIntFunc.SCXMLIOHandlers.(type)[3](root);
417	fi;
418
419	if(value=fail) then
420		Info(InfoSimpcomp,1,"SCIntFunc.SCXMLElementHandler: I/O handler ",
421      "for property ",root.name," failed.");
422		return -1;
423	fi;
424
425	if(IsRecord(target)) then
426		target.(root.name):=value;
427	elif(IsList(target)) then
428		target[pos]:=value;
429	else
430		Info(InfoSimpcomp,1,"SCIntFunc.SCXMLElementHandler: target object ",
431      "neither of Record nor of List type. target=",target,".");
432		return -1;
433	fi;
434
435	return 1;
436end;
437
438#deserialize xml to object
439SCIntFunc.SCXMLToObject:=
440function(xml)
441	local n,tree,items,pos;
442
443	if(IsEmptyString(xml)) then
444		return [];
445	fi;
446	tree:=ParseTreeXMLString(xml);
447	if(tree=fail) then
448		Info(InfoSimpcomp,1,"SCIntFunc.SCXMLToObject: parsing xml ",
449      "input string failed.");
450		return fail;
451	fi;
452	if tree.name="WHOLEDOCUMENT" then
453		#start processing
454		items:=[];
455		pos:=1;
456		for n in tree.content do
457			if(SCIntFunc.SCXMLElementHandler(items,pos,n)>0) then
458				pos:=pos+1;
459
460			fi;
461		od;
462		return items;
463	fi;
464
465	Info(InfoSimpcomp,1,"SCIntFunc.SCXMLToObject: xml document root not found.");
466	return fail;
467end;
468
469
470#serialize record to xml
471SCIntFunc.RecordToXML:=
472function(object,ident)
473	local key,subitems;
474
475	if(not IsRecord(object)) then
476		Info(InfoSimpcomp,1,"SCIntFunc.RecordToXML: first argument must be ",
477      "of type Record.");
478		return "";
479	fi;
480
481	subitems:="";
482	for key in RecNames(object) do
483		Append(subitems,SCIntFunc.SCObjectToXML(object.(key),key,ident+1));
484	od;
485	return subitems;
486end;
487
488
489#deserialize record from xml
490SCIntFunc.RecordFromXML:=
491function(root)
492	local c,r;
493	r:=rec();
494	for c in root.content do
495		SCIntFunc.SCXMLElementHandler(r,1,c);
496	od;
497	return r;
498end;
499
500
501#serialize positional object to xml
502SCIntFunc.PositionalObjectToXML:=
503function(object,ident)
504	local key,subitems,prefix;
505	subitems:="";
506
507	if(not SCIsPositionalObject(object)) then
508		Info(InfoSimpcomp,1,"SCIntFunc.PositionalObjectToXML: first argument ",
509      "must be of type SCPositionalObject.");
510		return "";
511	fi;
512
513
514	prefix:=Concatenation(ListWithIdenticalEntries(ident,"\t"));
515	for key in [1..Length(object)] do
516		if(not IsBound(object[key])) then
517			Append(subitems,Concatenation(prefix,
518        "\t<Entry type=\"SCEmpty\"></Entry>\n"));
519		else
520			Append(subitems,SCIntFunc.SCObjectToXML(object[key],"Entry",ident+1));
521		fi;
522	od;
523	return subitems;
524end;
525
526
527#deserialize positional object from xml
528SCIntFunc.PositionalObjectFromXML:=
529function(root)
530	local c,po,pos;
531	po:=[];
532	pos:=1;
533	for c in root.content do
534		if(SCIntFunc.SCXMLElementHandler(po,pos,c)>0) then
535			pos:=pos+1;
536		fi;
537	od;
538	return SCIntFunc.SCPositionalObjectFromList(po);
539end;
540
541
542
543#serialize fp group to xml
544SCIntFunc.FpGroupToXML:=
545function(object,ident)
546	local key,subitems,prefix;
547	subitems:="";
548
549	if(not IsFpGroup(object)) then
550		Info(InfoSimpcomp,1,"SCIntFunc.FpGroupToXML: first argument must be ",
551      "of type FpGroup.");
552		return "";
553	fi;
554
555
556	prefix:=Concatenation(ListWithIdenticalEntries(ident,"\t"));
557
558	Append(subitems,Concatenation(prefix,"\t<Generators type=\"SCArray\">",
559    String(List(GeneratorsOfGroup(object),String)),"</Generators>\n"));
560	Append(subitems,Concatenation(prefix,"\t<Relators type=\"SCArray\">",
561    String(List(RelatorsOfFpGroup(object),String)),"</Relators>\n"));
562
563	#return subitems;
564	return "";
565end;
566
567
568#deserialize fp group from xml
569SCIntFunc.FpGroupFromXML:=
570function(root)
571	local c,po,pos;
572	po:=[];
573	pos:=1;
574	for c in root.content do
575		if(SCIntFunc.SCXMLElementHandler(po,pos,c)>0) then
576			pos:=pos+1;
577		fi;
578	od;
579	return [];
580end;
581
582
583#serialize simplicial complex object to xml
584SCIntFunc.SCSimplicialComplexToXML:=
585function(object,ident)
586	local key,subitems,prefix;
587	subitems:="";
588
589	if(not SCIsSimplicialComplex(object)) then
590		Info(InfoSimpcomp,1,"SCIsSimplicialComplex: first argument must be of ",
591      "type SCSimplicialComplex.");
592		return "";
593	fi;
594
595	prefix:=Concatenation(ListWithIdenticalEntries(ident,"\t"));
596	subitems:="";
597
598	#legacy format v1
599	#for key in SCPropertiesNames(object) do
600	#	Append(subitems,SCIntFunc.SCObjectToXML(SCPropertyByName(object,key),
601  # key,ident+1));
602	#od;
603
604	#new format v2
605	for key in KnownAttributesOfObject(object) do
606		Append(subitems,SCIntFunc.SCObjectToXML(object!.(key),key,ident+1));
607	od;
608
609	return subitems;
610end;
611
612
613#deserialize simplicial complex object from xml, legacy format 1
614SCIntFunc.SCSimplicialComplexFromXMLv1Legacy:=rec(
615Facets:=SCFacetsEx,
616Faces:=SCFaceLatticeEx,
617VertexLabels:=SCFacetsEx,
618StronglyConnected:=SCIsStronglyConnected,
619Connected:=SCIsConnected,
620Generators:=SCGeneratorsEx,
621MinimalNonFaces:=SCMinimalNonFacesEx,
622Pure:=SCIsPure,
623PM:=SCIsPseudoManifold,
624CentrallySymmetric:=SCIsCentrallySymmetric,
625CohomologyBasis:=SCCohomologyBasis,
626HomologyBasis:=SCHomologyBasis,
627);
628
629SCIntFunc.SCSimplicialComplexFromXMLv1:=
630function(root)
631	local props,key,fkey,sc;
632
633	props:=SCIntFunc.RecordFromXML(root);
634	sc:=SCIntFunc.SCNew();
635
636	for key in RecNames(props) do
637		if(IsBound(SCIntFunc.SCSimplicialComplexFromXMLv1Legacy.(key))) then
638			fkey:=SCIntFunc.SCSimplicialComplexFromXMLv1Legacy.(key);
639		elif(IsBound(SCIntFunc.SCPropertyHandlers.(key))) then
640			fkey:=SCIntFunc.SCPropertyHandlers.(key);
641		else
642			fkey:=EvalString(key);
643		fi;
644		if(Setter(fkey)=false or Setter(fkey)=fail) then
645			Info(InfoSimpcomp,2,"SCIntFunc.SCSimplicialComplexFromXMLv1: legacy ",
646        "format, skipped loading attribute '",key,"'");
647			continue;
648		fi;
649		Setter(fkey)(sc,props.(key));
650	od;
651
652	return sc;
653end;
654
655
656#deserialize simplicial complex object from xml, format 2
657SCIntFunc.SCSimplicialComplexFromXMLv2:=
658function(root)
659	local props,key,sc;
660
661	props:=SCIntFunc.RecordFromXML(root);
662	sc:=SCIntFunc.SCNew();
663
664	for key in RecNames(props) do
665		Setter(EvalString(key))(sc,props.(key));
666	od;
667
668	return sc;
669end;
670
671
672
673#serialize library repository object to xml
674SCIntFunc.SCLibraryRepositoryToXML:=
675function(object,ident)
676	local key,subitems,prefix;
677	subitems:="";
678
679	if(not SCIsLibRepository(object)) then
680		Info(InfoSimpcomp,1,"SCIntFunc.SCLibraryRepositoryToXML: first argument ",
681      "must be of type SCLibRepository.");
682		return "";
683	fi;
684
685	prefix:=Concatenation(ListWithIdenticalEntries(ident,"\t"));
686	subitems:="";
687	for key in SCPropertiesNames(object) do
688		if(key="Loaded") then continue; fi;
689		Append(subitems,SCIntFunc.SCObjectToXML(SCPropertyByName(object,key),
690      key,ident+1));
691	od;
692	return subitems;
693end;
694
695
696#deserialize library repository object from xml
697SCIntFunc.SCLibraryRepositoryFromXML:=
698function(root)
699	local props;
700
701	props:=SCIntFunc.RecordFromXML(root);
702
703	if(props=fail) then
704		return fail;
705	fi;
706
707	return SCIntFunc.LibRepositoryEmptyWithAttributes(props);
708end;
709
710
711
712################################################################################
713##<#GAPDoc Label="SCLoad">
714## <ManSection>
715## <Func Name="SCLoad" Arg="filename"/>
716## <Returns>simplicial complex of type <C>SCSimplicialComplex</C> upon
717## success, <K>fail</K> otherwise.</Returns>
718## <Description>
719## Loads a simplicial complex stored in a binary format (using
720## <C>IO_Pickle</C>) from a file specified in <Arg>filename</Arg> (as string).
721## If <Arg>filename</Arg> does not end in <C>.scb</C>, this suffix is
722## appended to the file name.
723## <Example>
724## gap> c:=SCBdSimplex(3);;
725## gap> SCSave(c,"/tmp/bddelta3");
726## true
727## gap> d:=SCLoad("/tmp/bddelta3");
728## [SimplicialComplex
729##
730##  Properties known: AutomorphismGroup, AutomorphismGroupOrder,
731##                    AutomorphismGroupStructure, AutomorphismGroupTransitivity,
732##                    Chi, Dim, F, Facets, Generators, HasBoundary, Homology,
733##                    IsConnected, IsStronglyConnected, Name, TopologicalType,
734##                    SCVertices.
735##
736##  Name="S^2_4"
737##  Dim=2
738##  TopologicalType="S^2"
739##  Chi=2
740##  F=[4, 6, 4]
741##  Homology=[[0, []], [0, []], [1, []]]
742##  AutomorphismGroupStructure="S4"
743##
744## /SimplicialComplex]
745## gap> c=d;
746## </Example>
747## </Description>
748## </ManSection>
749##<#/GAPDoc>
750################################################################################
751InstallGlobalFunction(SCLoad,
752	function(filename)
753
754	local lf,fh,c;
755
756	if(not IsString(filename)) then
757		Info(InfoSimpcomp,1,"SCLoad: first argument must be of type String.");
758		return fail;
759	fi;
760
761	#try to detect format (xml,binary) by extension
762	if(Length(filename)>2 and
763    filename{[Length(filename)-2..Length(filename)]}=".sc") then
764		Info(InfoSimpcomp,2,"SCLoad: assuming XML format for file '",
765      filename,"', falling back to SCLoadXML.");
766		return SCLoadXML(filename);
767	fi;
768
769	lf:=ShallowCopy(filename);
770	if(Length(filename)<4 or
771    filename{[Length(filename)-3..Length(filename)]}<>".scb") then
772		Append(lf,".scb");
773	fi;
774
775	fh:=IO_File(lf,"r");
776
777	if(fh=fail) then
778		Info(InfoSimpcomp,1,"SCLoad: Error opening file '",lf,"' for reading.");
779		return fail;
780	fi;
781
782	#unpickle
783	c:=IO_Unpickle(fh);
784
785	IO_Close(fh);
786
787	if(c=IO_Error) then
788		Info(InfoSimpcomp,1,"SCLoad: Error loading simplicial complex from file '",
789      lf,"'.");
790		return fail;
791	else
792		return c;
793	fi;
794
795end);
796
797
798################################################################################
799##<#GAPDoc Label="SCLoadXML">
800## <ManSection>
801## <Func Name="SCLoadXML" Arg="filename"/>
802## <Returns>simplicial complex of type <C>SCSimplicialComplex</C> upon
803## success, <K>fail</K> otherwise.</Returns>
804## <Description>
805## Loads a simplicial complex stored in XML format from a file specified in
806## <Arg>filename</Arg> (as string). If <Arg>filename</Arg> does not end in
807## <C>.sc</C>, this suffix is appended to the file name.
808## <Example>
809## gap> c:=SCBdSimplex(3);;
810## gap> SCSaveXML(c,"/tmp/bddelta3");
811## true
812## gap> d:=SCLoadXML("/tmp/bddelta3");
813## [SimplicialComplex
814##
815##  Properties known: AutomorphismGroup, AutomorphismGroupOrder,
816##                    AutomorphismGroupStructure, AutomorphismGroupTransitivity,
817##                    Chi, Dim, F, Facets, Generators, HasBoundary, Homology,
818##                    IsConnected, IsStronglyConnected, Name, TopologicalType,
819##                    SCVertices.
820##
821##  Name="S^2_4"
822##  Dim=2
823##  TopologicalType="S^2"
824##  Chi=2
825##  F=[4, 6, 4]
826##  Homology=[[0, []], [0, []], [1, []]]
827##  AutomorphismGroupStructure="S4"
828##
829## /SimplicialComplex]
830## gap> c=d;
831## </Example>
832## </Description>
833## </ManSection>
834##<#/GAPDoc>
835################################################################################
836InstallGlobalFunction(SCLoadXML,
837	function(filename)
838
839	local data,obj,lf;
840
841	if(not IsString(filename)) then
842		Info(InfoSimpcomp,1,"SCLoadXML: first argument must be of type String.");
843		return fail;
844	fi;
845
846	lf:=ShallowCopy(filename);
847	if(Length(filename)<3 or
848    filename{[Length(filename)-2..Length(filename)]}<>".sc") then
849		Append(lf,".sc");
850	fi;
851
852	data:=StringFile(lf);
853	if(data=fail or IsEmptyString(data)) then
854		Info(InfoSimpcomp,1,"SCLoadXML: error reading file \"",lf,"\".");
855		return fail;
856	fi;
857
858	obj:=SCIntFunc.SCXMLToObject(data);
859
860	if(obj=fail or Length(obj)<1 or not SCIsSimplicialComplex(obj[1])) then
861		Info(InfoSimpcomp,1,"SCLoadXML: error loading simplicial complex from file.");
862		return fail;
863	fi;
864
865	return obj[1];
866end);
867
868
869
870################################################################################
871##<#GAPDoc Label="SCSave">
872## <ManSection>
873## <Func Name="SCSave" Arg="complex, filename"/>
874## <Returns><K>true</K> upon success, <K>fail</K> otherwise.</Returns>
875## <Description>
876## Saves a simplicial complex in a binary format (using <C>IO_Pickle</C>) to
877## a file specified in <Arg>filename</Arg> (as string). If <Arg>filename</Arg>
878## does not end in <C>.scb</C>, this suffix is appended to the file name.
879## <Example>
880## gap> c:=SCBdSimplex(3);;
881## gap> SCSave(c,"/tmp/bddelta3");
882## true
883## </Example>
884## </Description>
885## </ManSection>
886##<#/GAPDoc>
887################################################################################
888InstallGlobalFunction(SCSave,
889	function(complex,filename)
890
891	local fh,lf;
892
893	if(not SCIsSimplicialComplex(complex) or not IsString(filename)) then
894		Info(InfoSimpcomp,1,"SCSave: first argument must be of type ",
895      "SCSimplicialComplex, second of type String.");
896		return fail;
897	fi;
898
899	lf:=ShallowCopy(filename);
900	if(Length(filename)>2 and
901    filename{[Length(filename)-2..Length(filename)]}=".sc") then
902		Append(lf,"b");
903	fi;
904
905	if(Length(lf)<4 or lf{[Length(lf)-3..Length(lf)]}<>".scb") then
906		Append(lf,".scb");
907	fi;
908
909	Info(InfoSimpcomp,3,"SCSave: Saving simplicial complex to file '",lf,"'.");
910	fh:=IO_File(lf,"w");
911
912	if(fh=fail) then
913		Info(InfoSimpcomp,1,"SCSave: Error opening file '",lf,"' for writing.");
914		return fail;
915	fi;
916
917	#pickle
918	if(IO_Pickle(fh,complex)<>IO_OK) then
919		Info(InfoSimpcomp,1,"SCSave: Error saving simplicial complex to file '",
920      lf,"'.");
921		IO_Close(fh);
922		return fail;
923	else
924		IO_Close(fh);
925		return true;
926	fi;
927end);
928
929
930################################################################################
931##<#GAPDoc Label="SCSaveXML">
932## <ManSection>
933## <Func Name="SCSaveXML" Arg="complex, filename"/>
934## <Returns><K>true</K> upon success, <K>fail</K> otherwise.</Returns>
935## <Description>
936## Saves a simplicial complex <Arg>complex</Arg> to a file specified by
937## <Arg>filename</Arg> (as string) in XML format. If <Arg>filename</Arg> does
938## not end in <C>.sc</C>, this suffix is appended to the file name.
939## <Example>
940## gap> c:=SCBdSimplex(3);;
941## gap> SCSaveXML(c,"/tmp/bddelta3");
942## true
943## </Example>
944## </Description>
945## </ManSection>
946##<#/GAPDoc>
947################################################################################
948InstallGlobalFunction(SCSaveXML,
949	function(complex,filename)
950
951	local buf,lf;
952
953	if(not SCIsSimplicialComplex(complex) or not IsString(filename)) then
954		Info(InfoSimpcomp,1,"SCSaveXML: first argument must be of type ",
955      "SCSimplicialComplex, second of type String.");
956		return fail;
957	fi;
958
959	lf:=ShallowCopy(filename);
960
961	if(Length(filename)>3 and
962    filename{[Length(filename)-3..Length(filename)]}=".scb") then
963		lf:=lf{[1..Length(lf)-1]};
964	fi;
965
966	if(Length(lf)<3 or lf{[Length(lf)-2..Length(lf)]}<>".sc") then
967		Append(lf,".sc");
968	fi;
969
970	Info(InfoSimpcomp,3,"SCSaveXML: saving simplicial complex to file '",lf,"'.");
971
972	buf:=Concatenation("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
973	SCIntFunc.SCObjectToXML(complex,"SimplicialComplexV2",0));
974
975	if(FileString(lf,buf)=fail) then
976		Info(InfoSimpcomp,1,"SCSaveXML: file \"",filename,"\" not writeable!");
977		return fail;
978	else
979		return true;
980	fi;
981end);
982
983
984SCIntFunc.SCGetSimplicialComplexAttributesXMLEx:=
985function(sc,attrs)
986	local buf,pname,prop,ptype;
987
988	if(Length(attrs)>0 and not ForAll(attrs,IsString)) then
989		Info(InfoSimpcomp,1,"SCIntFunc.SCGetSimplicialComplexAttributesXMLEx: ",
990      "invalid attribute list.");
991		return fail;
992	fi;
993
994	buf:="";
995
996	for pname in Intersection(SCPropertiesNames(sc),attrs) do
997		prop:=SCPropertyByName(sc,pname);
998		Append(buf,SCIntFunc.SCObjectToXML(prop,pname,1));
999	od;
1000
1001	return buf;
1002end;
1003
1004
1005SCIntFunc.SCGetSimplicialComplexAttributesXML:=
1006function(sc,attrs)
1007	local buf;
1008
1009	buf:=SCIntFunc.SCGetSimplicialComplexAttributesXMLEx(sc,attrs);
1010	if(buf=fail) then return fail; fi;
1011
1012	return Concatenation(["<SimplicialComplex>\n",buf,"</SimplicialComplex>\n\n"]);
1013end;
1014
1015################################################################################
1016##<#GAPDoc Label="SCExportMacaulay2">
1017## <ManSection>
1018## <Func Name="SCExportMacaulay2" Arg="complex, ring,  filename [, alphalabels]"/>
1019## <Returns><K>true</K> upon success, <K>fail</K> otherwise.</Returns>
1020## <Description>
1021## Exports the facet list of a given simplicial complex <Arg>complex</Arg> in
1022## <C>Macaulay2</C> format to a file specified by <Arg>filename</Arg>. The
1023## argument <Arg>ring</Arg> can either be the ring of integers (specified by
1024## <C>Integers</C>) or the ring of rationals (sepcified by <C>Rationals</C>).
1025## The optional boolean argument <Arg>alphalabels</Arg> labels the complex
1026## with characters from <M>a, \dots ,z</M> in the exported file if a value of
1027## <K>true</K> is supplied, while the standard labeling of the vertices is
1028## <M>v_1, \dots ,v_n</M> where <M>n</M> is the number of vertices of
1029## <Arg>complex</Arg>. If <Arg>complex</Arg> has more than <M>26</M>
1030## vertices, the argument <Arg>alphalabels</Arg> is ignored.
1031## <Example>
1032## gap> c:=SCBdCrossPolytope(4);;
1033## gap> SCExportMacaulay2(c,Integers,"/tmp/bdbeta4.m2");
1034## true
1035## </Example>
1036## </Description>
1037## </ManSection>
1038##<#/GAPDoc>
1039################################################################################
1040InstallGlobalFunction(SCExportMacaulay2,
1041function(arg)
1042	local complex,filename,ring,alpha,buf,i,s,v,verts,lut,facets;
1043
1044	if(Length(arg)<3 or Length(arg)>4 or not SCIsSimplicialComplex(arg[1]) or
1045      (not IsIntegers(arg[2]) and not IsRationals(arg[2])) or
1046      not IsStringRep(arg[3])) then
1047			Info(InfoSimpcomp,1,"SCExportMacaulay2: invalid arguments, first",
1048        "argument must be of type SCSimplicialComplex, seconds a ring ",
1049        "(Integers or Rationals), third a string.");
1050			return fail;
1051	fi;
1052
1053	complex:=arg[1];
1054	ring:=arg[2];
1055	filename:=arg[3];
1056
1057	if(SCIsEmpty(complex)) then
1058		Info(InfoSimpcomp,1,"SCExportMacaulay2: empty complex, duh.");
1059		return true;
1060	fi;
1061
1062	if(Length(arg)=4 and IsBool(arg[4]) and arg[4]=true) then
1063		alpha:=true;
1064	else
1065		alpha:=false;
1066	fi;
1067
1068
1069	buf:=["-- simpcomp export of complex ",SCName(complex),
1070    "\n\nloadPackage \"SimplicialComplexes\";\n\nR = "];
1071
1072	if(IsIntegers(ring)) then
1073		Add(buf,"ZZ[");
1074	else
1075		Add(buf,"QQ[");
1076	fi;
1077
1078	verts:=Union(SCSkelEx(complex,0));
1079
1080	#dump variables
1081	if(Length(verts)<27 and alpha) then
1082		lut:=["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o",
1083      "p","q","r","s","t","u","v","w","x","y","z"];
1084		Add(buf,Concatenation("a..",lut[Length(verts)]));
1085	else
1086		lut:=[1..Length(verts)];
1087		for i in [1..Length(verts)] do
1088			Add(buf,Concatenation("v",String(i)));
1089			if(i<Length(verts)) then
1090				Add(buf,", ");
1091			fi;
1092		od;
1093	fi;
1094	Add(buf,"];\nFacets = {");
1095
1096	facets:=SCFacetsEx(complex);
1097	for s in [1..Length(facets)] do
1098		for v in [1..Length(facets[s])] do
1099			if not alpha then
1100				Add(buf,Concatenation("v",String(lut[Position(verts,facets[s][v])])));
1101			else
1102				Add(buf,String(lut[Position(verts,facets[s][v])]));
1103			fi;
1104
1105			if(v<Length(facets[s])) then
1106				Add(buf,"*");
1107			elif(s<Length(facets)) then
1108				Add(buf,", ");
1109			fi;
1110		od;
1111	od;
1112	Add(buf,"}\n");
1113
1114	Add(buf,"complex = simplicialComplex Facets;\n\n-- end of export");
1115
1116	if(FileString(filename,String(Concatenation(buf)))=fail) then
1117		Info(InfoSimpcomp,1,"SCExportMacaulay2: file \"",filename,
1118      "\" not writeable!");
1119		return fail;
1120	else
1121		return true;
1122	fi;
1123
1124end);
1125
1126
1127################################################################################
1128##<#GAPDoc Label="SCExportPolymake">
1129## <ManSection>
1130## <Func Name="SCExportPolymake" Arg="complex, filename"/>
1131## <Returns><K>true</K> upon success, <K>fail</K> otherwise.</Returns>
1132## <Description>
1133## Exports the facet list with vertex labels of a given simplicial complex
1134## <Arg>complex</Arg> in <C>polymake</C> format to a file specified by
1135## <Arg>filename</Arg>. Currently, only the export in the format of
1136## <C>polymake</C> version 2.3 is supported.
1137## <Example>
1138## gap> c:=SCBdCrossPolytope(4);;
1139## gap> SCExportPolymake(c,"/tmp/bdbeta4.poly");
1140## true
1141## </Example>
1142## </Description>
1143## </ManSection>
1144##<#/GAPDoc>
1145################################################################################
1146InstallGlobalFunction(SCExportPolymake,
1147function(complex,filename)
1148	local buf,i,s,v,verts;
1149
1150	buf:=["_application topaz\n_version 2.3\n_type SimplicialComplex\n\nFACETS\n"];
1151
1152	verts:=SCVertices(complex);
1153
1154	for s in SCFacetsEx(complex) do
1155		Add(buf,"{ ");
1156		for v in s do
1157			Append(buf,[String(Position(verts,v)-1)," "]);
1158		od;
1159		Add(buf,"}\n");
1160	od;
1161
1162	#print vertex labels
1163	Add(buf,"\nVERTEX_LABELS\n");
1164
1165	for i in [1..Length(verts)] do
1166		Add(buf,SCIntFunc.ListToDenseString(verts[i]));
1167		if(i<Length(verts)) then Add(buf," "); fi;
1168	od;
1169	Add(buf,"\n\n");
1170
1171	if(FileString(filename,String(Concatenation(buf)))=fail) then
1172		Info(InfoSimpcomp,1,"SCExportPolymake: file \"",filename,"\" not ",
1173      "writeable!");
1174		return fail;
1175	else
1176		return true;
1177	fi;
1178
1179end);
1180
1181
1182################################################################################
1183##<#GAPDoc Label="SCExportRecognizer">
1184## <ManSection>
1185## <Func Name="SCExportPolymake" Arg="complex, filename"/>
1186## <Returns><K>true</K> upon success, <K>fail</K> otherwise.</Returns>
1187## <Description>
1188## Exports the gluings of the tetrahedra of a given combinatorial
1189## <M>3</M>-manifold <Arg>complex</Arg> in a format compatible with Matveev's
1190## <M>3</M>-manifold software <C>Recognizer</C>.
1191## <Example>
1192## gap> c:=SCBdCrossPolytope(4);;
1193## gap> SCExportRecognizer(c,"/tmp/bdbeta4.mv");
1194## true
1195## </Example>
1196## </Description>
1197## </ManSection>
1198##<#/GAPDoc>
1199################################################################################
1200InstallGlobalFunction(SCExportRecognizer,
1201function(complex,filename)
1202	local buf,i,dim,pm,facets,done,j,k,l,elm,trig,f3;
1203
1204	dim := SCDim(complex);
1205	pm := SCIsPseudoManifold(complex);
1206	if dim <> 3 or pm <> true then
1207		Info(InfoSimpcomp,1,"SCExportRecognizer: input must be a 3-dimensional ",
1208      "weak pseudomanifold.");
1209		return fail;
1210	fi;
1211
1212	buf:=["triangulation\n"];
1213	facets := SCFacetsEx(complex);
1214	if facets = fail then
1215		return fail;
1216	fi;
1217	f3 := Size(facets);
1218	done := List([1..f3],x->[false,false,false,false]);
1219	for i in [1..f3] do
1220		for j in [4,3,2,1] do
1221			if done[i][j] = true then continue; fi;
1222			elm := [1..4];
1223			Remove(elm,j);
1224			Append(buf,["t",String(i),"(",String(elm[1]),",",String(elm[2]),",",
1225        String(elm[3]),") - "]);
1226			trig := facets[i]{elm};
1227			for k in [i+1..f3] do
1228				if IsSubset(facets[k],trig) then
1229					elm := [Position(facets[k],trig[1]),Position(facets[k],trig[2]),
1230            Position(facets[k],trig[3])];
1231					Append(buf,["t",String(k),"(",String(elm[1]),",",String(elm[2]),",",
1232            String(elm[3]),"),\n"]);
1233					for l in [1..4] do
1234						if not l in elm then
1235							done[k][l] := true;
1236							break;
1237						fi;
1238					od;
1239					break;
1240				fi;
1241			od;
1242		od;
1243	od;
1244	Add(buf,"end\n");
1245	if(FileString(filename,String(Concatenation(buf)))=fail) then
1246		Info(InfoSimpcomp,1,"SCExportRecognizer: file \"",filename,
1247      "\" not writeable!");
1248		return fail;
1249	else
1250		return true;
1251	fi;
1252
1253end);
1254
1255################################################################################
1256##<#GAPDoc Label="SCExportJavaView">
1257## <ManSection>
1258## <Func Name="SCExportJavaView" Arg="complex, file, coords"/>
1259## <Returns><K>true</K> on success, <K>fail</K> otherwise.</Returns>
1260## <Description>
1261## Exports the 2-skeleton of the given simplicial complex <Arg>complex</Arg>
1262## (or the facets if the complex is of dimension 2 or less) in <C>JavaView</C>
1263## format (file name suffix <C>.jvx</C>) to a file specified by
1264## <Arg>filename</Arg> (as string). The list <Arg>coords</Arg> must contain a
1265## <M>3</M>-tuple of real coordinates for each vertex of <Arg>complex</Arg>,
1266## either as tuple of length three containing the coordinates (Warning:
1267## as &GAP; only has rudimentary support for floating point values, currently
1268## only integer numbers can be used as coordinates when providing
1269## <Arg>coords</Arg> as list of <M>3</M>-tuples) or as string of the form
1270## <C>"x.x y.y z.z"</C> with decimal numbers <C>x.x</C>, <C>y.y</C>,
1271## <C>z.z</C> for the three coordinates (i.e. <C>"1.0 0.0 0.0"</C>).
1272## <Example>
1273## gap> coords:=[[1,0,0],[0,1,0],[0,0,1]];;
1274## gap> SCExportJavaView(SCBdSimplex(2),"/tmp/triangle.jvx",coords);
1275## true
1276## </Example>
1277## </Description>
1278## </ManSection>
1279##<#/GAPDoc>
1280################################################################################
1281InstallGlobalFunction(SCExportJavaView,
1282function(complex,filename,coords)
1283	local buf,v,f,verts,vertices,trigs,i,name,fl,dim;
1284
1285	if(SCIsEmpty(complex)) then
1286		Info(InfoSimpcomp,1,"SCExportJavaView: empty complex, nothing to do.");
1287		return true;
1288	fi;
1289
1290	buf:=[];
1291	dim:=SCDim(complex);
1292	if(dim=fail) then
1293		return fail;
1294	fi;
1295
1296	if(dim<3) then
1297		trigs:=SCFacetsEx(complex);
1298	else
1299		trigs:=SCSkelEx(complex,2);
1300	fi;
1301
1302	verts:=Union(SCSkelEx(complex,0));
1303
1304	if(trigs=fail or verts=fail or Length(verts)<>Length(coords)) then
1305		if(Length(verts)<>Length(coords)) then
1306			Info(InfoSimpcomp,1,"SCExportJavaView: vertex count must match ",
1307        "coordinate count.");
1308		fi;
1309		return fail;
1310	fi;
1311
1312	name:=SCPropertyByName(complex,"Name");
1313
1314	if(name=fail) then
1315		name:="Unnamed simplcicial complex";
1316	fi;
1317
1318
1319	Append(buf,Concatenation("\
1320	<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"no\"?>\n\
1321	<!DOCTYPE jvx-model SYSTEM \"http://www.javaview.de/rsrc/jvx.dtd\">\n\
1322	<jvx-model>\n\
1323		<meta generator=\"<Package>simpcomp</Package>\"/>\n\
1324		<meta dtd=\"1.11.001\"/>\n\
1325		<meta date=\"\"/>\n\
1326		<version type=\"dump\">1.0</version>\n\
1327		<title>",name,"</title>\n\
1328		<geometries>\n"));
1329
1330	Append(buf,Concatenation("\
1331	<geometry name=\"",String(verts),"\">\n\
1332		<pointSet point=\"show\" dim=\"3\">\n\
1333			<points num=\"",String(Length(verts)),"\">\n"));
1334
1335	vertices:=[];
1336	for v in [1..Length(verts)] do
1337		if(not IsString(coords[v])) then
1338			#coordinates as list
1339			vertices[v]:=Concatenation("<p name=\"",String(verts[v]),"\">");
1340
1341			#convert to floating point
1342			for i in [1..3] do
1343
1344				if(not IsInt(coords[v][i])) then
1345					Info(InfoSimpcomp,1,"SCExportJavaView: currently only integer ",
1346            "coordinates are supported when passed as list of coordinate ",
1347            "tuples. Use list of strings instead.");
1348					return fail;
1349				fi;
1350
1351				fl:=ShallowCopy(String(coords[v][i]));
1352
1353				if(PositionSublist(fl,".")=fail) then
1354					Append(fl,".0");
1355				fi;
1356
1357				Append(vertices[v],fl);
1358
1359				if(i<3) then
1360					Append(vertices[v]," ");
1361				fi;
1362			od;
1363
1364			Append(vertices[v],"</p>");
1365		else
1366			#coordinates as string
1367			vertices[v]:=Concatenation("<p name=\"",String(verts[v]),"\">",
1368        coords[v],"</p>");
1369		fi;
1370		Append(buf,Concatenation("\t\t\t",vertices[v],"\n"));
1371	od;
1372
1373
1374	Append(buf,Concatenation("\
1375				<thickness>4.0</thickness>\n\
1376				<color type=\"rgb\">255 0 0</color>\n\
1377				<colorTag type=\"rgb\">255 0 255</colorTag>\n\
1378				<labelAtt font=\"text\" horAlign=\"head\" name=\"SansSerif\" verAlign=\"middle\" style=\"plain\" visible=\"show\">\n\
1379					<xOffset>0</xOffset>\n\
1380					<yOffset>0</yOffset>\n\
1381					<size>20</size>\n\
1382					<color type=\"rgb\">0 0 0</color>\n\
1383				</labelAtt>\n\
1384			</points>\n\
1385		</pointSet>\n\
1386		<faceSet color=\"show\" edge=\"show\" face=\"show\">\n\
1387			<faces num=\"",String(Length(trigs)),"\">\n"));
1388
1389	for f in trigs do
1390		Append(buf,"\t\t\t<f>");
1391		for v in [1..Length(f)] do
1392			if(v>1) then Append(buf," "); fi;
1393			Append(buf,String(Position(verts,f[v])-1));
1394		od;
1395		Append(buf,"</f>\n");
1396	od;
1397
1398	Append(buf,"\
1399				<color type=\"rgb\">0 255 0</color>\n\
1400				<colorTag type=\"rgb\">255 0 255</colorTag>\n\
1401				<creaseAngle>3.2</creaseAngle>\n\
1402			</faces>\n\
1403			<neighbours num=\"1\">\n\
1404				<nb>-1 -1 -1</nb>\n\
1405			</neighbours>\n\
1406			<edges>\n\
1407				<thickness>1.0</thickness>\n\
1408				<color type=\"rgb\">0 0 0</color>\n\
1409				<colorTag type=\"rgb\">255 0 255</colorTag>\n\
1410			</edges>\n\
1411			<colors num=\"1\" type=\"rgb\">\n\
1412				<c>119 236 158</c>\n\
1413			</colors>\n\
1414		</faceSet>\n\
1415		<center visible=\"hide\">\n\
1416			<p>0.0 0.0 0.0</p>\n\
1417		</center>\n\
1418		<material>\n\
1419			<ambientIntensity>0.2</ambientIntensity>\n\
1420			<diffuse>\n\
1421				<color type=\"rgb\">204 204 204</color>\n\
1422			</diffuse>\n\
1423			<emissive>\n\
1424				<color type=\"rgb\">0 0 0</color>\n\
1425			</emissive>\n\
1426			<shininess>10.0</shininess>\n\
1427			<specular>\n\
1428				<color type=\"rgb\">255 255 255</color>\n\
1429			</specular>\n\
1430			<transparency visible=\"show\">0.5</transparency>\n\
1431		</material>\n\
1432	</geometry>\n\
1433	</geometries>\n\
1434	</jvx-model>\n");
1435
1436	if(FileString(filename,buf)=fail) then
1437		Info(InfoSimpcomp,1,"SCExportJavaView: filename \"",filename,
1438      "\" not writeable!");
1439		return fail;
1440	else
1441		return true;
1442	fi;
1443
1444end);
1445
1446################################################################################
1447##<#GAPDoc Label="SCExportLatexTable">
1448## <ManSection>
1449## <Func Name="SCExportLatexTable" Arg="complex, filename, itemsperline"/>
1450## <Returns><K>true</K> on success, <K>fail</K> otherwise.</Returns>
1451## <Description>
1452## Exports the facet list of a given simplicial complex <Arg>complex</Arg>
1453## (or any list given as first argument) in form of a &LaTeX; table to a file
1454## specified by <Arg>filename</Arg>. The argument <Arg>itemsperline</Arg>
1455## specifies how many columns the exported table should have. The faces are
1456## exported in the format <M>\langle v_1,\dots,v_k \rangle</M>.
1457## <Example>
1458## gap> c:=SCBdSimplex(5);;
1459## gap> SCExportLatexTable(c,"/tmp/bd5simplex.tex",5);
1460## </Example>
1461## </Description>
1462## </ManSection>
1463##<#/GAPDoc>
1464################################################################################
1465InstallGlobalFunction(SCExportLatexTable,
1466function(complex,filename,itemsperline)
1467	local i,j,buf,facets;
1468
1469	if(not SCIsSimplicialComplex(complex) and not IsList(complex)) then
1470		Info(InfoSimpcomp,1,"SCExportLatexTable: first argument must be of type ",
1471      "SCSimplicialComplex or a list of faces.");
1472		return fail;
1473	fi;
1474
1475	if(SCIsSimplicialComplex(complex)) then
1476		facets:=SCFacets(complex);
1477	else
1478		facets:=complex;
1479	fi;
1480
1481	if(facets=fail) then
1482		return fail;
1483	fi;
1484
1485	buf:=Concatenation(["\\begin{tabular}{",
1486    Concatenation(ListWithIdenticalEntries(itemsperline,"l")),"}\n"]);
1487
1488	for i in [1..Length(facets)] do
1489		Append(buf,"$\\langle ");
1490
1491		for j in [1..Length(facets[i])-1] do
1492			Append(buf,
1493        Concatenation([SCIntFunc.ListToDenseString(facets[i][j]),"\\,"]));
1494		od;
1495		Append(buf,SCIntFunc.ListToDenseString(facets[i][Length(facets[i])]));
1496
1497
1498		Append(buf," \\rangle$");
1499
1500		if(i=Length(facets)) then
1501			Append(buf,".");
1502			Append(buf,
1503        Concatenation(ListWithIdenticalEntries(-(i mod itemsperline) mod itemsperline,"&")));
1504			Append(buf,"\n");
1505			break;
1506		fi;
1507
1508		if(i mod itemsperline=0) then
1509			Append(buf,",\\\\\n\n");
1510		else
1511			Append(buf,", &\n");
1512		fi;
1513	od;
1514
1515	Append(buf,"\\end{tabular}");
1516	buf:=ReplacedString(buf,"\"","");
1517
1518	if(FileString(filename,buf)=fail) then
1519		Info(InfoSimpcomp,1,"SCExportLatexTable: file \"",filename,
1520      "\" not writeable!");
1521		return fail;
1522	fi;
1523
1524	return true;
1525end);
1526
1527
1528SCIntFunc.SCPrintSCToString:=
1529function(sc)
1530	local buf,props,prop,p;
1531
1532	buf:="[SimplicialComplex\n\n";
1533
1534	Append(buf," Properties known: ");
1535	props:=List(SCPropertiesNames(sc));
1536	Sort(props);
1537
1538	for p in [1..Length(props)] do
1539		Append(buf,props[p]);
1540		if(p=Length(props)) then
1541			Append(buf,".\n");
1542		else
1543			Append(buf,", ");
1544		fi;
1545	od;
1546
1547	for p in ["Facets","Faces","Incidences"] do
1548		if(p in props) then
1549			prop:=SCPropertyByName(sc,p);
1550			if(IsStringRep(prop)) then
1551				Append(buf,Concatenation([" ",p,"=\"",prop,"\"\n"]));
1552			else
1553				Append(buf,Concatenation([" ",p,"=",String(prop),"\n"]));
1554			fi;
1555		fi;
1556	od;
1557
1558	for p in SortedList(Difference(props,["Facets","Faces","Incidences"])) do
1559		prop:=SCPropertyByName(sc,p);
1560		if(IsStringRep(prop)) then
1561			Append(buf,Concatenation([" ",p,"=\"",prop,"\"\n"]));
1562		else
1563			Append(buf,Concatenation([" ",p,"=",String(prop),"\n"]));
1564		fi;
1565	od;
1566
1567	Append(buf,"\n/SimplicialComplex]\n");
1568	return buf;
1569end;
1570
1571
1572################################################################################
1573##<#GAPDoc Label="SCImportPolymake">
1574## <ManSection>
1575## <Func Name="SCImportPolymake" Arg="filename"/>
1576## <Returns>simplicial complex of type <C>SCSimplicialComplex</C> upon
1577## success, <K>fail</K> otherwise.</Returns>
1578## <Description>
1579## Imports the facet list of a <C>topaz</C> <C>polymake</C> file specified by
1580## <Arg>filename</Arg> (discarding any vertex labels) and creates a
1581## simplicial complex object from these facets.
1582## <Example>
1583## gap> c:=SCBdCrossPolytope(4);;
1584## gap> SCExportPolymake(c,"/tmp/bdbeta4.poly");
1585## gap> d:=SCImportPolymake("/tmp/bdbeta4.poly");
1586## [SimplicialComplex
1587##
1588## Properties known: Chi, Dim, Facets, SCVertices.
1589##
1590##  Name="unnamed complex m"
1591##  Dim=3
1592##
1593## /SimplicialComplex]
1594## gap> c=d;
1595## </Example>
1596## </Description>
1597## </ManSection>
1598##<#/GAPDoc>
1599################################################################################
1600InstallGlobalFunction(SCImportPolymake,
1601function(filename)
1602	local file,lines,fpos,lidx,v,verts,s,facets,sc;
1603
1604	file:=StringFile(filename);
1605
1606	if(file=fail) then
1607		Info(InfoSimpcomp,1,"SCImportPolymake: error reading file \"",
1608      filename,"\".");
1609		return fail;
1610	fi;
1611
1612
1613	lines:=SplitString(file,"\n");
1614	Apply(lines,NormalizedWhitespace);
1615
1616	fpos:=Position(lines,"VERTICES_IN_FACETS");
1617	if(fpos=fail) then
1618		fpos:=Position(lines,"FACETS");
1619	fi;
1620
1621
1622	if(fpos=fail) then
1623		Info(InfoSimpcomp,1,"SCImportPolymake: could neither find section ",
1624      "VERTICES_IN_FACETS nor section FACETS in polymake file.");
1625		return fail;
1626	fi;
1627
1628	facets:=[];
1629	for lidx in [fpos+1..Length(lines)] do
1630		if(not IsBound(lines[lidx]) or IsEmptyString(lines[lidx]) or
1631      lines[lidx]=" ") then
1632			break;
1633		fi;
1634		verts:=SplitString(lines[lidx]," ","{}");
1635		s:=[];
1636		for v in verts do
1637			if(IsEmpty(v)) then continue; fi;
1638			Add(s,Rat(v));
1639		od;
1640		Add(facets,s+1);
1641	od;
1642
1643	sc:=SCFromFacets(facets);
1644
1645	if(sc<>fail) then
1646		SCRename(sc,Concatenation("polymake import '",filename,"'"));
1647	fi;
1648
1649	return sc;
1650end);
1651
1652
1653
1654#general io pickling function
1655SCIntFunc.GeneralPicklerIgnoreList:=[
1656"ComputedSCHomalgBoundaryMatricess", "ComputedSCHomalgCoboundaryMatricess",
1657  "ComputedSCHomalgHomologys", "ComputedSCHomalgCohomologys"
1658];
1659SCIntFunc.GeneralPickler:=
1660function(f,c,id)
1661	local p;
1662
1663	# write SCSimplicialComplex tag
1664	IO_AddToPickled(c);
1665	if IO_Write(f,id) = fail then
1666		IO_FinalizePickled();
1667		return IO_Error;
1668	fi;
1669
1670	# write number of attributes
1671	if IO_WriteSmallInt(f,Length(KnownAttributesOfObject(c))) = IO_Error then
1672		IO_FinalizePickled();
1673		return IO_Error;
1674	fi;
1675
1676	# pickle all attributes
1677	for p in KnownAttributesOfObject(c) do
1678		if(p in SCIntFunc.GeneralPicklerIgnoreList) then
1679			Info(InfoSimpcomp,3,"SCIntFunc.GeneralPickler: ignoring attribute ",p,
1680        " as it is in ignore list (no pickler available).");
1681			continue;
1682		fi;
1683
1684		# write attribute name
1685		if(IO_Pickle(f,p)<>IO_OK) then
1686			IO_FinalizePickled();
1687			return IO_Error;
1688		fi;
1689
1690		# write attribute value
1691		if(IO_Pickle(f,c!.(p))<>IO_OK) then
1692			IO_FinalizePickled();
1693			return IO_Error;
1694		fi;
1695	od;
1696
1697	IO_FinalizePickled();
1698	return IO_OK;
1699end;
1700
1701#general io unpickling function
1702SCIntFunc.GeneralUnpickler:=
1703function(f,c)
1704    local i,len,name,ob;
1705
1706    # read number of attributes
1707    len:=IO_ReadSmallInt(f);
1708    if len = IO_Error then
1709        Info(InfoSimpcomp,1,"SCIntFunc.GeneralUnpickler: Error during ",
1710          "unpicking of attribute name");
1711        return c;
1712    fi;
1713
1714    # do unpickling
1715    IO_AddToUnpickled(c);
1716    for i in [1..len] do
1717        # read attribute name
1718    	name:=IO_Unpickle(f);
1719        if name = IO_Error or not(IsString(name)) then
1720            Info(InfoSimpcomp,1,"SCIntFunc.GeneralUnpickler: Error while ",
1721                "unpicking attribute name");
1722        fi;
1723
1724        # read attribute value
1725        ob:=IO_Unpickle(f);
1726        if IO_Result(ob) then
1727            if ob = IO_Error then
1728                Info(InfoSimpcomp,1,"SCIntFunc.GeneralUnpickler: Error while ",
1729                  "unpicking attribute value of '",name,"'");
1730            fi;
1731        else
1732	    Setter(EvalString(name))(c,ob);
1733        fi;
1734    od;
1735    IO_FinalizeUnpickled();
1736end;
1737
1738
1739#pickler for SCSimplicialComplex
1740InstallMethod(IO_Pickle, "for SCSimplicialComplex",
1741[ IsFile, SCIsSimplicialComplex ],
1742function(f,c)
1743	return SCIntFunc.GeneralPickler(f,c,"SCSC");
1744end);
1745
1746
1747# unpickler for SCSimplicialComplex
1748IO_Unpicklers.SCSC:=
1749function(f)
1750    local c;
1751
1752    # SCSimplicialComplex
1753    c:=SCIntFunc.SCNew();
1754
1755    SCIntFunc.GeneralUnpickler(f,c);
1756    return c;
1757end;
1758
1759# pickler for SCLibraryRepository
1760InstallMethod(IO_Pickle, "for SCLibRepository",
1761[ IsFile, SCIsLibRepository ],
1762function(f,lr)
1763	IO_AddToPickled(lr);
1764
1765	# write SCLibRepository tag
1766	if IO_Write(f,"SCLR") = fail then
1767		IO_FinalizePickled();
1768		return IO_Error;
1769	fi;
1770
1771	if(IO_Pickle(f,lr!.Properties)<>IO_OK) then
1772		IO_FinalizePickled();
1773		return IO_Error;
1774	fi;
1775
1776	IO_FinalizePickled();
1777	return IO_OK;
1778end);
1779
1780
1781# unpickler for SCLibraryRepository
1782IO_Unpicklers.SCLR:=
1783function(f)
1784    local prop;
1785
1786    #get library properties
1787    prop:=IO_Unpickle(f);
1788
1789    if IO_Result(prop) then
1790    	if prop = IO_Error then
1791    		Info(InfoSimpcomp,1,"IO_Unpicklers.SCLR: Error while unpicking ",
1792          "library repository. Delete file complexes.idx and complexes.idxb ",
1793          "and recreate them with SCLibInit.");
1794    		return IO_Error;
1795    	fi;
1796    else
1797    	return SCIntFunc.LibRepositoryEmptyWithAttributes(prop);
1798    fi;
1799end;
1800
1801#handler functions for file load/save operations
1802SCIntFunc.SCXMLIOHandlers:=
1803rec(
1804	SCSimplicialComplex:=[SCIsSimplicialComplex,
1805    SCIntFunc.SCSimplicialComplexToXML,SCIntFunc.SCSimplicialComplexFromXMLv1,
1806    false],
1807	SCSimplicialComplexV2:=[SCIsSimplicialComplex,
1808    SCIntFunc.SCSimplicialComplexToXML,SCIntFunc.SCSimplicialComplexFromXMLv2,
1809    false],
1810	SCLibraryRepository:=[SCIsLibRepository,SCIntFunc.SCLibraryRepositoryToXML,
1811    SCIntFunc.SCLibraryRepositoryFromXML,false],
1812	SCRecord:=[IsRecord,SCIntFunc.RecordToXML,SCIntFunc.RecordFromXML,false],
1813	SCPositionalObject:=[SCIsPositionalObject,SCIntFunc.PositionalObjectToXML,
1814    SCIntFunc.PositionalObjectFromXML,false],
1815	SCInteger:=[IsInt,String,SCIntFunc.ReadInteger,true],
1816	SCBoolean:=[IsBool,SCIntFunc.BooleanToString,SCIntFunc.ReadBoolean,true],
1817	SCString:=[IsStringRep,String,SCIntFunc.ReadString,true],
1818	SCArray:=[IsList,SCIntFunc.ListToDenseString,SCIntFunc.ReadArray,true],
1819	SCPerm:=[IsPerm,SCIntFunc.PermToString,SCIntFunc.ReadPerm,true],
1820	SCPermGroup:=[IsPermGroup,SCIntFunc.PermGroupToString,SCIntFunc.ReadPermGroup,
1821    true],
1822	SCFpGroup:=[IsFpGroup,SCIntFunc.FpGroupToXML,SCIntFunc.FpGroupFromXML,false]
1823);
1824
1825
1826################################################################################
1827
1828################################################################################
1829##<#GAPDoc Label="SCExportSnapPy">
1830## <ManSection>
1831## <Func Name="SCExportSnapPy" Arg="complex, filename"/>
1832## <Returns><K>true</K> upon success, <K>fail</K> otherwise.</Returns>
1833## <Description>
1834## Exports the facet list and orientability of a given combinatorial
1835## <M>3</M>-pseudomanifold <Arg>complex</Arg> in <C>SnapPy</C> format to a
1836## file specified by <Arg>filename</Arg>.
1837## <Example>
1838## gap> SCLib.SearchByAttribute("Dim=3 and F=[8,28,56,28]");
1839## gap> c:=SCLib.Load(last[1][1]);;
1840## gap> SCExportSnapPy(c,"/tmp/M38.tri");
1841## true
1842## </Example>
1843## </Description>
1844## </ManSection>
1845##<#/GAPDoc>
1846################################################################################
1847InstallGlobalFunction(SCExportSnapPy,
1848function(complex,filename)
1849	local curvertex,buf,dim,name,orient,lks,i,pmflag,lksconn,kleinb,torus,
1850    sphere,lktype,neighbors,gluings,cusps,j,k,trig,remoteidx,verts,facets;
1851
1852	dim:=SCDim(complex);
1853	if dim=fail then
1854		return fail;
1855	fi;
1856
1857	if dim<>3 then
1858		Info(InfoSimpcomp,1,"SCExportSnapPy: argument must be a 3-dimensional ",
1859      "simplicial complex.");
1860		return fail;
1861	fi;
1862
1863	kleinb:=0;
1864	torus:=0;
1865	sphere:=0;
1866
1867	if SCIsManifold(complex) then
1868		sphere:=SCNumFaces(complex,0);
1869		lktype:=ListWithIdenticalEntries(sphere,0);
1870	fi;
1871
1872	if sphere=0 then
1873
1874		lks:=SCLinks(complex,0);
1875		pmflag:=true;
1876		for i in [1..Size(lks)] do
1877			if not SCIsManifold(lks[i]) then
1878				pmflag:=false;
1879				break;
1880			fi;
1881		od;
1882
1883		if pmflag<>true then
1884			Info(InfoSimpcomp,1,"SCExportSnapPy: argument must be a combinatorial ",
1885        "3-pseudomanifold.");
1886			return fail;
1887		fi;
1888
1889		lksconn:=true;
1890		for i in [1..Size(lks)] do
1891			if not SCIsConnected(lks[i]) then
1892				lksconn:=false;
1893				break;
1894			fi;
1895		od;
1896
1897		if lksconn<>true then
1898			Info(InfoSimpcomp,1,"SCExportSnapPy: argument must be a combinatorial ",
1899        "3-pseudomanifold with connected links.");
1900			return fail;
1901		fi;
1902
1903		lktype:=[];
1904		for i in [1..Size(lks)] do
1905			if SCEulerCharacteristic(lks[i])=2 then
1906				lktype[i]:=0;
1907				sphere:=sphere+1;
1908			elif SCEulerCharacteristic(lks[i])=0 then
1909				if SCIsOrientable(lks[i]) then
1910					lktype[i]:=1;
1911					torus:=torus+1;
1912				else
1913					lktype[i]:=2;
1914					kleinb:=kleinb+1;
1915				fi;
1916			else
1917				Info(InfoSimpcomp,1,"SCExportSnapPy: argument must be a combinatorial ",
1918          "3-pseudomanifold with links of type S^2, T^2 or K^2.");
1919				return fail;
1920			fi;
1921		od;
1922
1923	fi;
1924
1925	name:=SCName(complex);
1926	if name=fail then
1927		return fail;
1928	fi;
1929
1930	buf:=["% Triangulation\n"];
1931	Append(buf,[name,"\nunknown 0.0\n"]);
1932
1933	orient:=SCIsOrientable(complex);
1934	if orient=fail then
1935		return fail;
1936	fi;
1937
1938	if orient=true then
1939		Append(buf,["oriented_manifold\nCS_unknown\n\n"]);
1940	else
1941		Append(buf,["nonorientable_manifold\nCS_unknown\n\n"]);
1942	fi;
1943
1944	verts:=SCVertices(complex);
1945
1946	Append(buf,[String(torus)," ",String(kleinb),"\n"]);
1947	for i in [1..SCNumFaces(complex,0)] do
1948		if lktype[i]=0 then
1949			#Append(buf,["        internal   0 0\n"]);
1950			continue;
1951		elif lktype[i]=1 then
1952			Append(buf,["        torus   0 0\n"]);
1953		elif lktype[i]=2 then
1954			Append(buf,["        Klein bottle   0 0\n"]);
1955		fi;
1956	od;
1957
1958	neighbors:=[];
1959	gluings:=[];
1960	cusps:=[];
1961	facets:=SCFacets(complex);
1962	if facets=fail then
1963		return fail;
1964	fi;
1965	for j in [1..Size(facets)] do
1966		neighbors[j]:=[];
1967		gluings[j]:=[];
1968		cusps[j]:=[];
1969		for trig in Combinations(facets[j],3) do
1970			curvertex:=Difference(facets[j],trig)[1];
1971			k:=Position(facets[j],curvertex);
1972			for i in [1..Size(facets)] do
1973				if facets[i] = facets[j] then continue; fi;
1974				if IsSubset(facets[i],trig) then
1975					remoteidx:=Position(facets[i],Difference(facets[i],trig)[1]);
1976					neighbors[j][k]:=i-1;
1977					gluings[j][k]:=[];
1978					gluings[j][k][k]:=remoteidx-1;
1979					gluings[j][k][Position(facets[j],trig[1])]:=
1980            Position(facets[i],trig[1])-1;
1981					gluings[j][k][Position(facets[j],trig[2])]:=
1982            Position(facets[i],trig[2])-1;
1983					gluings[j][k][Position(facets[j],trig[3])]:=
1984            Position(facets[i],trig[3])-1;
1985					cusps[j][k]:=curvertex-1;
1986					break;
1987				fi;
1988			od;
1989		od;
1990	od;
1991
1992	Append(buf,["\n",String(SCNumFaces(complex,dim)),"\n"]);
1993	for i in [1..Size(facets)] do
1994		Append(buf,["    ",String(neighbors[i][1]),"    ",
1995      String(neighbors[i][2]),"    ",String(neighbors[i][3]),"    ",
1996      String(neighbors[i][4]),"\n"]);
1997		Append(buf,["    ",String(gluings[i][1][1]),String(gluings[i][1][2]),
1998      String(gluings[i][1][3]),String(gluings[i][1][4])," ",
1999      String(gluings[i][2][1]),String(gluings[i][2][2]),
2000      String(gluings[i][2][3]),String(gluings[i][2][4])," ",
2001      String(gluings[i][3][1]),String(gluings[i][3][2]),
2002      String(gluings[i][3][3]),String(gluings[i][3][4])," ",
2003      String(gluings[i][4][1]),String(gluings[i][4][2]),
2004      String(gluings[i][4][3]),String(gluings[i][4][4]),"\n"]);
2005		Append(buf,["    ",String(cusps[i][1]),"    ",String(cusps[i][2]),"    ",
2006      String(cusps[i][3]),"    ",String(cusps[i][4]),"\n"]);
2007		Append(buf,["    0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0\n"]);
2008		Append(buf,["    0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0\n"]);
2009		Append(buf,["    0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0\n"]);
2010		Append(buf,["    0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0\n"]);
2011		Append(buf,["    0  0\n\n"]);
2012	od;
2013
2014	if(FileString(filename,String(Concatenation(buf)))=fail) then
2015		Info(InfoSimpcomp,1,"SCExportSnapPy: file \"",filename,"\" not writeable!");
2016		return fail;
2017	else
2018		return true;
2019	fi;
2020
2021end);
2022