From 078a2877c7dd4a17aa101ba2fdad08cf755a2fcc Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 4 Apr 2014 23:46:39 +0200 Subject: [PATCH] Add support for the GAP language --- lib/linguist/languages.yml | 10 + lib/linguist/samples.json | 5 + samples/GAP/Magic.gd | 307 ++++++++++++++ samples/GAP/Magic.gi | 534 ++++++++++++++++++++++++ samples/GAP/PackageInfo.g | 115 ++++++ samples/GAP/example.gd | 23 ++ samples/GAP/example.gi | 64 +++ samples/GAP/vspc.gd | 822 +++++++++++++++++++++++++++++++++++++ samples/GAP/vspc.gi | 651 +++++++++++++++++++++++++++++ 9 files changed, 2531 insertions(+) create mode 100644 samples/GAP/Magic.gd create mode 100644 samples/GAP/Magic.gi create mode 100644 samples/GAP/PackageInfo.g create mode 100644 samples/GAP/example.gd create mode 100644 samples/GAP/example.gi create mode 100644 samples/GAP/vspc.gd create mode 100644 samples/GAP/vspc.gi diff --git a/lib/linguist/languages.yml b/lib/linguist/languages.yml index 6eb2a378..e88bc963 100644 --- a/lib/linguist/languages.yml +++ b/lib/linguist/languages.yml @@ -620,6 +620,16 @@ Forth: extensions: - .4th +GAP: + type: programming + lexer: Text only + primary_extension: .g + extensions: + - .g + - .gap + - .gd + - .gi + GAS: type: programming group: Assembly diff --git a/lib/linguist/samples.json b/lib/linguist/samples.json index 6d26388a..8c7ff71f 100644 --- a/lib/linguist/samples.json +++ b/lib/linguist/samples.json @@ -129,6 +129,11 @@ ".forth", ".fth" ], + "GAP": [ + ".g", + ".gd", + ".gi" + ], "GAS": [ ".s" ], diff --git a/samples/GAP/Magic.gd b/samples/GAP/Magic.gd new file mode 100644 index 00000000..cdd8baec --- /dev/null +++ b/samples/GAP/Magic.gd @@ -0,0 +1,307 @@ +############################################################################# +## +## Magic.gd AutoDoc package +## +## Copyright 2013, Max Horn, JLU Giessen +## Sebastian Gutsche, University of Kaiserslautern +## +############################################################################# + + +#! @Description +#! This is the main function of the &AutoDoc; package. It can perform +#! any combination of the following three tasks: +#! +#! +#! It can (re)generate a scaffold for your package manual. +#! That is, it can produce two XML files in &GAPDoc; format to be used as part +#! of your manual: First, a file named doc/PACKAGENAME.xml +#! (with your package's name substituted) which is used as +#! main file for the package manual, i.e. this file sets the +#! XML DOCTYPE and defines various XML entities, includes +#! other XML files (both those generated by &AutoDoc; as well +#! as additional files created by other means), tells &GAPDoc; +#! to generate a table of content and an index, and more. +#! Secondly, it creates a file doc/title.xml containing a title +#! page for your documentation, with information about your package +#! (name, description, version), its authors and more, based +#! on the data in your PackageInfo.g. +#! +#! +#! It can scan your package for &AutoDoc; based documentation (by using &AutoDoc; +#! tags and the Autodoc command. +#! This will +#! produce further XML files to be used as part of the package manual. +#! +#! +#! It can use &GAPDoc; to generate PDF, text and HTML (with +#! MathJaX enabled) documentation from the &GAPDoc; XML files it +#! generated as well as additional such files provided by you. For +#! this, it invokes +#! to convert the XML sources, and it also instructs &GAPDoc; to copy +#! supplementary files (such as CSS style files) into your doc directory +#! (see ). +#! +#! +#! For more information and some examples, please refer to Chapter . +#!

+#! The parameters have the following meanings: +#! +#! +#! package_name +#! +#! The name of the package whose documentation should be(re)generated. +#! +#! +#! +#! option_record +#! +#! option_record can be a record with some additional options. +#! The following are currently supported: +#! +#! dir +#! +#! This should be a string containing a (relative) path or a +#! Directory() object specifying where the package documentation +#! (i.e. the &GAPDoc; XML files) are stored. +#!
+#! Default value: "doc/". +#!
+#! scaffold +#! +#! This controls whether and how to generate scaffold XML files +#! for the main and title page of the package's documentation. +#!

+#! The value should be either true, false or a +#! record. If it is a record or true (the latter is +#! equivalent to specifying an empty record), then this feature is +#! enabled. It is also enabled if opt.scaffold is missing but the +#! package's info record in PackageInfo.g has an AutoDoc entry. +#! In all other cases (in particular if opt.scaffold is +#! false), scaffolding is disabled. +#!

+#! +#! If opt.scaffold is a record, it may contain the following entries. +#! +#### TODO: mention merging with PackageInfo.AutoDoc! +#! +#! +#! includes +#! +#! A list of XML files to be included in the body of the main XML file. +#! If you specify this list and also are using &AutoDoc; to document +#! your operations with &AutoDoc; comments, +#! you can add AutoDocMainFile.xml to this list +#! to control at which point the documentation produced by &AutoDoc; +#! is inserted. If you do not do this, it will be added after the last +#! of your own XML files. +#! +#! +#! appendix +#! +#! This entry is similar to opt.scaffold.includes but is used +#! to specify files to include after the main body of the manual, +#! i.e. typically appendices. +#! +#! +#! bib +#! +#! The name of a bibliography file, in Bibtex or XML format. +#! If this key is not set, but there is a file doc/PACKAGENAME.bib +#! then it is assumed that you want to use this as your bibliography. +#! +#! +#### TODO: The 'entities' param is a bit strange. We should probably change it to be a bit more +#### general, as one might want to define other entities... For now, we do not document it +#### to leave us the choice of revising how it works. +#### +#### entities +#### +#### A list of package names or other entities which are used to define corresponding XML entities. +#### For example, if set to a list containing the string SomePackage, +#### then the following is added to the XML preamble: +####

SomePackage'>]]> +#### This allows you to write &SomePackage; in your documentation +#### to reference that package. If another type of entity is desired, one can simply add, +#### instead of a string, add a two entry list a to the list. It will be handled as +#### a[ 2 ]'>]]>, +#### so please be careful. +#### +#! +#! TitlePage +#! +#! A record whose entries are used to embellish the generated titlepage +#! for the package manual with extra information, such as a copyright +#! statement or acknowledgments. To this end, the names of the record +#! components are used as XML element names, and the values of the +#! components are outputted as content of these XML elements. For +#! example, you could pass the following record to set a custom +#! acknowledgements text: +#! +#! For a list of valid entries in the titlepage, please refer to the +#! &GAPDoc; manual, specifically section +#! and following. +#! +#! document_class +#! +#! Sets the document class of the resulting pdf. The value can either be a string +#! which has to be the name of the new document class, a list containing this string, or +#! a list of two strings. Then the first one has to be the document class name, the second one +#! the option string ( contained in [ ] ) in LaTeX. +#! +#! latex_header_file +#! +#! Replaces the standard header from &GAPDoc; completely with the header in this LaTeX file. +#! Please be careful here, and look at GAPDoc's latexheader.tex file for an example. +#! +#! gapdoc_latex_options +#! +#! Must be a record with entries which can be understood by SetGapDocLaTeXOptions. Each entry can be a string, which +#! will be given to &GAPDoc; directly, or a list containing of two entries: The first one must be the string "file", +#! the second one a filename. This file will be read and then its content is passed to &GAPDoc; as option with the name +#! of the entry. +#! +#! +#! +#! +#! +#! +#! autodoc +#! +#! This controls whether and how to generate addition XML documentation files +#! by scanning for &AutoDoc; documentation comments. +#!

+#! The value should be either true, false or a +#! record. If it is a record or true (the latter is +#! equivalent to specifying an empty record), then this feature is +#! enabled. It is also enabled if opt.autodoc is missing but the +#! package depends (directly) on the &AutoDoc; package. +#! In all other cases (in particular if opt.autodoc is +#! false), this feature is disabled. +#!

+#! +#! If opt.autodoc is a record, it may contain the following entries. +#! +#! +#! +#! files +#! +#! A list of files (given by paths relative to the package directory) +#! to be scanned for &AutoDoc; documentation comments. +#! Usually it is more convenient to use autodoc.scan_dirs, see below. +#! +#! +#! scan_dirs +#! +#! A list of subdirectories of the package directory (given as relative paths) +#! which &AutoDoc; then scans for .gi, .gd and .g files; all of these files +#! are then scanned for &AutoDoc; documentation comments. +#!
+#! Default value: [ "gap", "lib", "examples", "examples/doc" ]. +#!
+#! +#! level +#! +#! This defines the level of the created documentation. The default value is 0. +#! When parts of the manual are declared with a higher value +#! they will not be printed into the manual. +#! +#! +#### TODO: Document section_intros later on. +#### However, note that thanks to the new AutoDoc comment syntax, the only remaining +#### use for this seems to be the ability to specify the order of chapters and +#### sections. +#### section_intros +#### +#### TODO. +#### +#! +#!
+#! +#! +#! +#! gapdoc +#! +#! This controls whether and how to invoke &GAPDoc; to create HTML, PDF and text +#! files from your various XML files. +#!

+#! The value should be either true, false or a +#! record. If it is a record or true (the latter is +#! equivalent to specifying an empty record), then this feature is +#! enabled. It is also enabled if opt.gapdoc is missing. +#! In all other cases (in particular if opt.gapdoc is +#! false), this feature is disabled. +#!

+#! +#! If opt.gapdoc is a record, it may contain the following entries. +#! +#! +#! +#! +#### Note: 'main' is strictly speaking also used for the scaffold. +#### However, if one uses the scaffolding mechanism, then it is not +#### really necessary to specify a custom name for the main XML file. +#### Thus, the purpose of this parameter is to cater for packages +#### that have existing documentation using a different XML name, +#### and which do not wish to use scaffolding. +#### +#### This explain why we only allow specifying gapdoc.main. +#### The scaffolding code will still honor it, though, just in case. +#! main +#! +#! The name of the main XML file of the package manual. +#! This exists primarily to support packages with existing manual +#! which use a filename here which differs from the default. +#! In particular, specifying this is unnecessary when using scaffolding. +#!
+#! Default value: PACKAGENAME.xml. +#!
+#! +#! files +#! +#! A list of files (given by paths relative to the package directory) +#! to be scanned for &GAPDoc; documentation comments. +#! Usually it is more convenient to use gapdoc.scan_dirs, see below. +#! +#! +#! scan_dirs +#! +#! A list of subdirectories of the package directory (given as relative paths) +#! which &AutoDoc; then scans for .gi, .gd and .g files; all of these files +#! are then scanned for &GAPDoc; documentation comments. +#!
+#! Default value: [ "gap", "lib", "examples", "examples/doc" ]. +#!
+#! +#!
+#! +## This is the maketest part. Still under construction. +#! maketest +#! +#! The maketest item can be true or a record. When it is true, +#! a simple maketest.g is created in the main package directory, +#! which can be used to test the examples from the manual. As a record, +#! the entry can have the following entries itself, to specify some options. +#! +#! filename +#! +#! Sets the name of the test file. +#! +#! commands +#! +#! A list of strings, each one a command, which +#! will be executed at the beginning of the test file. +#! +#! +#! +#! +#! +#! +#! +#! +#! @Returns nothing +#! @Arguments package_name[, option_record ] +#! @ChapterInfo AutoDoc, The AutoDoc() function +DeclareGlobalFunction( "AutoDoc" ); + diff --git a/samples/GAP/Magic.gi b/samples/GAP/Magic.gi new file mode 100644 index 00000000..5202a1de --- /dev/null +++ b/samples/GAP/Magic.gi @@ -0,0 +1,534 @@ +############################################################################# +## +## Magic.gi AutoDoc package +## +## Copyright 2013, Max Horn, JLU Giessen +## Sebastian Gutsche, University of Kaiserslautern +## +############################################################################# + +# Check if a string has the given suffix or not. Another +# name for this would "StringEndsWithOtherString". +# For example, AUTODOC_HasSuffix("file.gi", ".gi") returns +# true while AUTODOC_HasSuffix("file.txt", ".gi") returns false. +BindGlobal( "AUTODOC_HasSuffix", +function(str, suffix) + local n, m; + n := Length(str); + m := Length(suffix); + return n >= m and str{[n-m+1..n]} = suffix; +end ); + +# Given a string containing a ".", , return its suffix, +# i.e. the bit after the last ".". For example, given "test.txt", +# it returns "txt". +BindGlobal( "AUTODOC_GetSuffix", +function(str) + local i; + i := Length(str); + while i > 0 and str[i] <> '.' do i := i - 1; od; + if i < 0 then return ""; fi; + return str{[i+1..Length(str)]}; +end ); + +# Check whether the given directory exists, and if not, attempt +# to create it. +BindGlobal( "AUTODOC_CreateDirIfMissing", +function(d) + local tmp; + if not IsDirectoryPath(d) then + tmp := CreateDir(d); # Note: CreateDir is currently undocumented + if tmp = fail then + Error("Cannot create directory ", d, "\n", + "Error message: ", LastSystemError().message, "\n"); + return false; + fi; + fi; + return true; +end ); + + +# Scan the given (by name) subdirs of a package dir for +# files with one of the given extensions, and return the corresponding +# filenames, as relative paths (relative to the package dir). +# +# For example, the invocation +# AUTODOC_FindMatchingFiles("AutoDoc", [ "gap/" ], [ "gi", "gd" ]); +# might return a list looking like +# [ "gap/AutoDocMainFunction.gd", "gap/AutoDocMainFunction.gi", ... ] +BindGlobal( "AUTODOC_FindMatchingFiles", +function (pkg, subdirs, extensions) + local d_rel, d, tmp, files, result; + + result := []; + + for d_rel in subdirs do + # Get the absolute path to the directory in side the package... + d := DirectoriesPackageLibrary( pkg, d_rel ); + if IsEmpty( d ) then + continue; + fi; + d := d[1]; + # ... but also keep the relative path (such as "gap") + d_rel := Directory( d_rel ); + + files := DirectoryContents( d ); + Sort( files ); + for tmp in files do + if not AUTODOC_GetSuffix( tmp ) in [ "g", "gi", "gd", "autodoc" ] then + continue; + fi; + if not IsReadableFile( Filename( d, tmp ) ) then + continue; + fi; + Add( result, Filename( d_rel, tmp ) ); + od; + od; + return result; +end ); + + +# AutoDoc(pkg[, opt]) +# +## Make this function callable with the package_name AutoDocWorksheet. +## Which will then create a worksheet! +InstallGlobalFunction( AutoDoc, +function( arg ) + local pkg, package_info, opt, scaffold, gapdoc, maketest, + autodoc, pkg_dir, doc_dir, doc_dir_rel, d, tmp, + title_page, tree, is_worksheet, position_document_class, i, gapdoc_latex_option_record; + + pkg := arg[1]; + + if LowercaseString( pkg ) = "autodocworksheet" then + is_worksheet := true; + package_info := rec( ); + pkg_dir := DirectoryCurrent( ); + else + is_worksheet := false; + package_info := PackageInfo( pkg )[ 1 ]; + pkg_dir := DirectoriesPackageLibrary( pkg, "" )[1]; + fi; + + if Length(arg) >= 2 then + opt := arg[2]; + else + opt := rec(); + fi; + + # Check for certain user supplied options, and if present, add them + # to the opt record. + tmp := function( key ) + local val; + val := ValueOption( key ); + if val <> fail then + opt.(key) := val; + fi; + end; + + tmp( "dir" ); + tmp( "scaffold" ); + tmp( "autodoc" ); + tmp( "gapdoc" ); + tmp( "maketest" ); + + # + # Setup the output directory + # + if not IsBound( opt.dir ) then + doc_dir := "doc"; + elif IsString( opt.dir ) or IsDirectory( opt.dir ) then + doc_dir := opt.dir; + else + Error( "opt.dir must be a string containing a path, or a directory object" ); + fi; + + if IsString( doc_dir ) then + # Record the relative version of the path + doc_dir_rel := Directory( doc_dir ); + + # We intentionally do not use + # DirectoriesPackageLibrary( pkg, "doc" ) + # because it returns an empty list if the subdirectory is missing. + # But we want to handle that case by creating the directory. + doc_dir := Filename(pkg_dir, doc_dir); + doc_dir := Directory(doc_dir); + + else + # TODO: doc_dir_rel = ... ? + fi; + + # Ensure the output directory exists, create it if necessary + AUTODOC_CreateDirIfMissing(Filename(doc_dir, "")); + + # Let the developer know where we are generating the documentation. + # This helps diagnose problems where multiple instances of a package + # are visible to GAP and the wrong one is used for generating the + # documentation. + # TODO: Using Info() instead of Print? + Print( "Generating documentation in ", doc_dir, "\n" ); + + # + # Extract scaffolding settings, which can be controlled via + # opt.scaffold or package_info.AutoDoc. The former has precedence. + # + if not IsBound(opt.scaffold) then + # Default: enable scaffolding if and only if package_info.AutoDoc is present + if IsBound( package_info.AutoDoc ) then + scaffold := rec( ); + fi; + elif IsRecord(opt.scaffold) then + scaffold := opt.scaffold; + elif IsBool(opt.scaffold) then + if opt.scaffold = true then + scaffold := rec(); + fi; + else + Error("opt.scaffold must be a bool or a record"); + fi; + + # Merge package_info.AutoDoc into scaffold + if IsBound(scaffold) and IsBound( package_info.AutoDoc ) then + AUTODOC_APPEND_RECORD_WRITEONCE( scaffold, package_info.AutoDoc ); + fi; + + if IsBound( scaffold ) then + AUTODOC_WriteOnce( scaffold, "TitlePage", true ); + AUTODOC_WriteOnce( scaffold, "MainPage", true ); + fi; + + + # + # Extract AutoDoc settings + # + if not IsBound(opt.autodoc) and not is_worksheet then + # Enable AutoDoc support if the package depends on AutoDoc. + tmp := Concatenation( package_info.Dependencies.NeededOtherPackages, + package_info.Dependencies.SuggestedOtherPackages ); + if ForAny( tmp, x -> LowercaseString(x[1]) = "autodoc" ) then + autodoc := rec(); + fi; + elif IsRecord(opt.autodoc) then + autodoc := opt.autodoc; + elif IsBool(opt.autodoc) and opt.autodoc = true then + autodoc := rec(); + fi; + + if IsBound(autodoc) then + if not IsBound( autodoc.files ) then + autodoc.files := [ ]; + fi; + + if not IsBound( autodoc.scan_dirs ) and not is_worksheet then + autodoc.scan_dirs := [ "gap", "lib", "examples", "examples/doc" ]; + elif not IsBound( autodoc.scan_dirs ) and is_worksheet then + autodoc.scan_dirs := [ ]; + fi; + + if not IsBound( autodoc.level ) then + autodoc.level := 0; + fi; + + PushOptions( rec( level_value := autodoc.level ) ); + + if not is_worksheet then + Append( autodoc.files, AUTODOC_FindMatchingFiles(pkg, autodoc.scan_dirs, [ "g", "gi", "gd" ]) ); + fi; + fi; + + # + # Extract GAPDoc settings + # + if not IsBound( opt.gapdoc ) then + # Enable GAPDoc support by default + gapdoc := rec(); + elif IsRecord( opt.gapdoc ) then + gapdoc := opt.gapdoc; + elif IsBool( opt.gapdoc ) and opt.gapdoc = true then + gapdoc := rec(); + fi; + + # + # Extract test settings + # + + if IsBound( opt.maketest ) then + if IsRecord( opt.maketest ) then + maketest := opt.maketest; + elif opt.maketest = true then + maketest := rec( ); + fi; + fi; + + if IsBound( gapdoc ) then + + if not IsBound( gapdoc.main ) then + gapdoc.main := pkg; + fi; + + # FIXME: the following may break if a package uses more than one book + if IsBound( package_info.PackageDoc ) and IsBound( package_info.PackageDoc[1].BookName ) then + gapdoc.bookname := package_info.PackageDoc[1].BookName; + elif not is_worksheet then + # Default: book name = package name + gapdoc.bookname := pkg; + + Print("\n"); + Print("WARNING: PackageInfo.g is missing a PackageDoc entry!\n"); + Print("Without this, your package manual will not be recognized by the GAP help system.\n"); + Print("You can correct this by adding the following to your PackageInfo.g:\n"); + Print("PackageDoc := rec(\n"); + Print(" BookName := ~.PackageName,\n"); + #Print(" BookName := \"", pkg, "\",\n"); + Print(" ArchiveURLSubset := [\"doc\"],\n"); + Print(" HTMLStart := \"doc/chap0.html\",\n"); + Print(" PDFFile := \"doc/manual.pdf\",\n"); + Print(" SixFile := \"doc/manual.six\",\n"); + Print(" LongTitle := ~.Subtitle,\n"); + Print("),\n"); + Print("\n"); + fi; + + if not IsBound( gapdoc.files ) then + gapdoc.files := []; + fi; + + if not IsBound( gapdoc.scan_dirs ) and not is_worksheet then + gapdoc.scan_dirs := [ "gap", "lib", "examples", "examples/doc" ]; + fi; + + if not is_worksheet then + Append( gapdoc.files, AUTODOC_FindMatchingFiles(pkg, gapdoc.scan_dirs, [ "g", "gi", "gd" ]) ); + fi; + + # Attempt to weed out duplicates as they may confuse GAPDoc (this + # won't work if there are any non-normalized paths in the list). + gapdoc.files := Set( gapdoc.files ); + + # Convert the file paths in gapdoc.files, which are relative to + # the package directory, to paths which are relative to the doc directory. + # For this, we assume that doc_dir_rel is normalized (e.g. + # it does not contains '//') and relative. + d := Number( Filename( doc_dir_rel, "" ), x -> x = '/' ); + d := Concatenation( ListWithIdenticalEntries(d, "../") ); + gapdoc.files := List( gapdoc.files, f -> Concatenation( d, f ) ); + fi; + + + # read tree + # FIXME: shouldn't tree be declared inside of an 'if IsBound(autodoc)' section? + tree := DocumentationTree( ); + + if IsBound( autodoc ) then + if IsBound( autodoc.section_intros ) then + AUTODOC_PROCESS_INTRO_STRINGS( autodoc.section_intros : Tree := tree ); + fi; + + AutoDocScanFiles( autodoc.files : PackageName := pkg, Tree := tree ); + fi; + + if is_worksheet then + # FIXME: We use scaffold and autodoc here without checking whether + # they are bound. Does that mean worksheets always use them? + if IsRecord( scaffold.TitlePage ) and IsBound( scaffold.TitlePage.Title ) then + pkg := scaffold.TitlePage.Title; + + elif IsBound( tree!.TitlePage.Title ) then + pkg := tree!.TitlePage.Title; + + elif IsBound( autodoc.files ) and Length( autodoc.files ) > 0 then + pkg := autodoc.files[ 1 ]; + + while Position( pkg, '/' ) <> fail do + Remove( pkg, 1 ); + od; + + while Position( pkg, '.' ) <> fail do + Remove( pkg, Length( pkg ) ); + od; + + else + Error( "could not figure out a title." ); + fi; + + if not IsString( pkg ) then + pkg := JoinStringsWithSeparator( pkg, " " ); + fi; + + gapdoc.main := ReplacedString( pkg, " ", "_" ); + gapdoc.bookname := ReplacedString( pkg, " ", "_" ); + fi; + + # + # Generate scaffold + # + gapdoc_latex_option_record := rec( ); + + if IsBound( scaffold ) then + ## Syntax is [ "class", [ "options" ] ] + if IsBound( scaffold.document_class ) then + position_document_class := PositionSublist( GAPDoc2LaTeXProcs.Head, "documentclass" ); + + if IsString( scaffold.document_class ) then + scaffold.document_class := [ scaffold.document_class ]; + fi; + + if position_document_class = fail then + Error( "something is wrong with the LaTeX header" ); + fi; + + GAPDoc2LaTeXProcs.Head := Concatenation( + GAPDoc2LaTeXProcs.Head{[ 1 .. PositionSublist( GAPDoc2LaTeXProcs.Head, "{", position_document_class ) ]}, + scaffold.document_class[ 1 ], + GAPDoc2LaTeXProcs.Head{[ PositionSublist( GAPDoc2LaTeXProcs.Head, "}", position_document_class ) .. Length( GAPDoc2LaTeXProcs.Head ) ]} ); + + if Length( scaffold.document_class ) = 2 then + + GAPDoc2LaTeXProcs.Head := Concatenation( + GAPDoc2LaTeXProcs.Head{[ 1 .. PositionSublist( GAPDoc2LaTeXProcs.Head, "[", position_document_class ) ]}, + scaffold.document_class[ 2 ], + GAPDoc2LaTeXProcs.Head{[ PositionSublist( GAPDoc2LaTeXProcs.Head, "]", position_document_class ) .. Length( GAPDoc2LaTeXProcs.Head ) ]} ); + fi; + fi; + + if IsBound( scaffold.latex_header_file ) then + GAPDoc2LaTeXProcs.Head := StringFile( scaffold.latex_header_file ); + fi; + + if IsBound( scaffold.gapdoc_latex_options ) then + if IsRecord( scaffold.gapdoc_latex_options ) then + for i in RecNames( scaffold.gapdoc_latex_options ) do + if not IsString( scaffold.gapdoc_latex_options.( i ) ) + and IsList( scaffold.gapdoc_latex_options.( i ) ) + and LowercaseString( scaffold.gapdoc_latex_options.( i )[ 1 ] ) = "file" then + scaffold.gapdoc_latex_options.( i ) := StringFile( scaffold.gapdoc_latex_options.( i )[ 2 ] ); + fi; + od; + + gapdoc_latex_option_record := scaffold.gapdoc_latex_options; + fi; + fi; + + if not IsBound( scaffold.includes ) then + scaffold.includes := [ ]; + fi; + + if IsBound( autodoc ) then + # If scaffold.includes is already set, then we add + # AutoDocMainFile.xml to it, but *only* if it not already + # there. This way, package authors can control where + # it is put in their includes list. + if not "AutoDocMainFile.xml" in scaffold.includes then + Add( scaffold.includes, "AutoDocMainFile.xml" ); + fi; + fi; + + if IsBound( scaffold.bib ) and IsBool( scaffold.bib ) then + if scaffold.bib = true then + scaffold.bib := Concatenation( pkg, ".bib" ); + else + Unbind( scaffold.bib ); + fi; + elif not IsBound( scaffold.bib ) then + # If there is a doc/PKG.bib file, assume that we want to reference it in the scaffold. + if IsReadableFile( Filename( doc_dir, Concatenation( pkg, ".bib" ) ) ) then + scaffold.bib := Concatenation( pkg, ".bib" ); + fi; + fi; + + AUTODOC_WriteOnce( scaffold, "index", true ); + + if IsBound( gapdoc ) then + if AUTODOC_GetSuffix( gapdoc.main ) = "xml" then + scaffold.main_xml_file := gapdoc.main; + else + scaffold.main_xml_file := Concatenation( gapdoc.main, ".xml" ); + fi; + fi; + + # TODO: It should be possible to only rebuild the title page. (Perhaps also only the main page? but this is less important) + if IsBound( scaffold.TitlePage ) then + if IsRecord( scaffold.TitlePage ) then + title_page := scaffold.TitlePage; + else + title_page := rec( ); + fi; + + AUTODOC_WriteOnce( title_page, "dir", doc_dir ); + AUTODOC_APPEND_RECORD_WRITEONCE( title_page, tree!.TitlePage ); + + if not is_worksheet then + AUTODOC_APPEND_RECORD_WRITEONCE( title_page, ExtractTitleInfoFromPackageInfo( pkg ) ); + fi; + + CreateTitlePage( title_page ); + fi; + + if IsBound( scaffold.MainPage ) and scaffold.MainPage <> false then + scaffold.dir := doc_dir; + scaffold.book_name := pkg; + CreateMainPage( scaffold ); + fi; + fi; + + # + # Run AutoDoc + # + if IsBound( autodoc ) then + WriteDocumentation( tree, doc_dir ); + fi; + + + # + # Run GAPDoc + # + if IsBound( gapdoc ) then + + # Ask GAPDoc to use UTF-8 as input encoding for LaTeX, as the XML files + # of the documentation are also in UTF-8 encoding, and may contain characters + # not contained in the default Latin 1 encoding. + SetGapDocLaTeXOptions( "utf8", gapdoc_latex_option_record ); + + MakeGAPDocDoc( doc_dir, gapdoc.main, gapdoc.files, gapdoc.bookname, "MathJax" ); + + CopyHTMLStyleFiles( Filename( doc_dir, "" ) ); + + # The following (undocumented) API is there for compatibility + # with old-style gapmacro.tex based package manuals. It + # produces a manual.lab file which those packages can use if + # they wish to link to things in the manual we are currently + # generating. This can probably be removed eventually, but for + # now, doing it does not hurt. + + # FIXME: It seems that this command does not work if pdflatex + # is not present. Maybe we should remove it. + + if not is_worksheet then + GAPDocManualLab( pkg ); + fi; + + fi; + + if IsBound( maketest ) then + + AUTODOC_WriteOnce( maketest, "filename", "maketest.g" ); + AUTODOC_WriteOnce( maketest, "folder", pkg_dir ); + AUTODOC_WriteOnce( maketest, "scan_dir", doc_dir ); + AUTODOC_WriteOnce( maketest, "files_to_scan", gapdoc.files ); + + if IsString( maketest.folder ) then + maketest.folder := Directory( maketest.folder ); + fi; + + if IsString( maketest.scan_dir ) then + maketest.scan_dir := Directory( maketest.scan_dir ); + fi; + + AUTODOC_WriteOnce( maketest, "commands", [ ] ); + AUTODOC_WriteOnce( maketest, "book_name", gapdoc.main ); + + CreateMakeTest( maketest ); + fi; + + return true; +end ); diff --git a/samples/GAP/PackageInfo.g b/samples/GAP/PackageInfo.g new file mode 100644 index 00000000..68e5ecdb --- /dev/null +++ b/samples/GAP/PackageInfo.g @@ -0,0 +1,115 @@ +############################################################################# +## +## PackageInfo.g for the package `cvec' Max Neunhoeffer +## +## (created from Frank Lübeck's PackageInfo.g template file) +## + +SetPackageInfo( rec( + +PackageName := "cvec", +Subtitle := "Compact vectors over finite fields", +Version := "2.5.1", +Date := "04/04/2014", # dd/mm/yyyy format + +## Information about authors and maintainers. +Persons := [ + rec( + LastName := "Neunhoeffer", + FirstNames := "Max", + IsAuthor := true, + IsMaintainer := false, + Email := "neunhoef@mcs.st-and.ac.uk", + WWWHome := "http://www-groups.mcs.st-and.ac.uk/~neunhoef/", + PostalAddress := Concatenation( [ + "School of Mathematics and Statistics\n", + "University of St Andrews\n", + "Mathematical Institute\n", + "North Haugh\n", + "St Andrews, Fife KY16 9SS\n", + "Scotland, UK" ] ), + Place := "St Andrews", + Institution := "University of St Andrews" + ), +], + +## Status information. Currently the following cases are recognized: +## "accepted" for successfully refereed packages +## "deposited" for packages for which the GAP developers agreed +## to distribute them with the core GAP system +## "dev" for development versions of packages +## "other" for all other packages +## +# Status := "accepted", +Status := "deposited", + +## You must provide the next two entries if and only if the status is +## "accepted" because is was successfully refereed: +# format: 'name (place)' +# CommunicatedBy := "Mike Atkinson (St. Andrews)", +#CommunicatedBy := "", +# format: mm/yyyy +# AcceptDate := "08/1999", +#AcceptDate := "", + +PackageWWWHome := "http://neunhoef.github.io/cvec/", +README_URL := Concatenation(~.PackageWWWHome, "README"), +PackageInfoURL := Concatenation(~.PackageWWWHome, "PackageInfo.g"), +ArchiveURL := Concatenation("https://github.com/neunhoef/cvec/", + "releases/download/v", ~.Version, + "/cvec-", ~.Version), +ArchiveFormats := ".tar.gz .tar.bz2", + +## Here you must provide a short abstract explaining the package content +## in HTML format (used on the package overview Web page) and an URL +## for a Webpage with more detailed information about the package +## (not more than a few lines, less is ok): +## Please, use 'GAP' and +## 'MyPKG' for specifing package names. +## +AbstractHTML := + "This package provides an implementation of compact vectors over finite\ + fields. Contrary to earlier implementations no table lookups are used\ + but only word-based processor arithmetic. This allows for bigger finite\ + fields and higher speed.", + +PackageDoc := rec( + BookName := "cvec", + ArchiveURLSubset := ["doc"], + HTMLStart := "doc/chap0.html", + PDFFile := "doc/manual.pdf", + SixFile := "doc/manual.six", + LongTitle := "Compact vectors over finite fields", +), + +Dependencies := rec( + GAP := ">=4.5.5", + NeededOtherPackages := [ + ["GAPDoc", ">= 1.2"], + ["IO", ">= 4.1"], + ["orb", ">= 4.2"], + ], + SuggestedOtherPackages := [], + ExternalConditions := [] +), + +AvailabilityTest := function() + if not "cvec" in SHOW_STAT() and + Filename(DirectoriesPackagePrograms("cvec"), "cvec.so") = fail then + #Info(InfoWarning, 1, "cvec: kernel cvec functions not available."); + return fail; + fi; + return true; +end, + +## *Optional*, but recommended: path relative to package root to a file which +## contains as many tests of the package functionality as sensible. +#TestFile := "tst/testall.g", + +## *Optional*: Here you can list some keyword related to the topic +## of the package. +Keywords := [] + +)); + + diff --git a/samples/GAP/example.gd b/samples/GAP/example.gd new file mode 100644 index 00000000..c285ea32 --- /dev/null +++ b/samples/GAP/example.gd @@ -0,0 +1,23 @@ +############################################################################# +## +#W example.gd +## +## This file contains a sample of a GAP declaration file. +## +DeclareProperty( "SomeProperty", IsLeftModule ); +DeclareGlobalFunction( "SomeGlobalFunction" ); + + +############################################################################# +## +#C IsQuuxFrobnicator() +## +## +## +## +## +## Tests whether R is a quux frobnicator. +## +## +## +DeclareSynonym( "IsQuuxFrobnicator", IsField and IsGroup ); diff --git a/samples/GAP/example.gi b/samples/GAP/example.gi new file mode 100644 index 00000000..c9c5e55d --- /dev/null +++ b/samples/GAP/example.gi @@ -0,0 +1,64 @@ +############################################################################# +## +#W example.gd +## +## This file contains a sample of a GAP implementation file. +## + + +############################################################################# +## +#M SomeOperation( ) +## +## performs some operation on +## +InstallMethod( SomeProperty, + "for left modules", + [ IsLeftModule ], 0, + function( M ) + if IsFreeLeftModule( M ) and not IsTrivial( M ) then + return true; + fi; + TryNextMethod(); + end ); + + + +############################################################################# +## +#F SomeGlobalFunction( ) +## +## A global variadic funfion. +## +InstallGlobalFunction( SomeGlobalFunction, function( arg ) + if Length( arg ) = 3 then + return arg[1] + arg[2] * arg[3]; + elif Length( arg ) = 2 then + return arg[1] - arg[2] + else + Error( "usage: SomeGlobalFunction( , [, ] )" ); + fi; + end ); + + +# +# A plain function. +# +SomeFunc := function(x, y) + local z, func, tmp, j; + z := x * 1.0; + y := 17^17 - y; + func := a -> a mod 5; + tmp := List( [1..50], func ); + while y > 0 do + for j in tmp do + Print(j, "\n"); + od; + repeat + y := y - 1; + until 0 < 1; + y := y -1; + od; + return z; +end; + \ No newline at end of file diff --git a/samples/GAP/vspc.gd b/samples/GAP/vspc.gd new file mode 100644 index 00000000..d381e6f1 --- /dev/null +++ b/samples/GAP/vspc.gd @@ -0,0 +1,822 @@ +############################################################################# +## +#W vspc.gd GAP library Thomas Breuer +## +## +#Y Copyright (C) 1997, Lehrstuhl D für Mathematik, RWTH Aachen, Germany +#Y (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland +#Y Copyright (C) 2002 The GAP Group +## +## This file declares the operations for vector spaces. +## +## The operations for bases of free left modules can be found in the file +## lib/basis.gd. +## + + +############################################################################# +## +#C IsLeftOperatorRing() +## +## +## +## +## +## +## +## +DeclareSynonym( "IsLeftOperatorRing", + IsLeftOperatorAdditiveGroup and IsRing and IsAssociativeLOpDProd ); +#T really? + + +############################################################################# +## +#C IsLeftOperatorRingWithOne() +## +## +## +## +## +## +## +## +DeclareSynonym( "IsLeftOperatorRingWithOne", + IsLeftOperatorAdditiveGroup and IsRingWithOne + and IsAssociativeLOpDProd ); +#T really? + + +############################################################################# +## +#C IsLeftVectorSpace( ) +#C IsVectorSpace( ) +## +## <#GAPDoc Label="IsLeftVectorSpace"> +## +## +## +## +## +## A vector space in &GAP; is a free left module +## (see ) over a division ring +## (see Chapter ). +##

+## Whenever we talk about an F-vector space V then V is +## an additive group (see ) on which the +## division ring F acts via multiplication from the left such that +## this action and the addition in V are left and right distributive. +## The division ring F can be accessed as value of the attribute +## . +##

+## Vector spaces in &GAP; are always left vector spaces, +## and are +## synonyms. +## +## +## <#/GAPDoc> +## +DeclareSynonym( "IsLeftVectorSpace", + IsLeftModule and IsLeftActedOnByDivisionRing ); + +DeclareSynonym( "IsVectorSpace", IsLeftVectorSpace ); + +InstallTrueMethod( IsFreeLeftModule, + IsLeftModule and IsLeftActedOnByDivisionRing ); + + +############################################################################# +## +#F IsGaussianSpace( ) +## +## <#GAPDoc Label="IsGaussianSpace"> +## +## +## +## +## The filter (see ) +## for the row space (see ) +## or matrix space (see ) V +## over the field F, say, +## indicates that the entries of all row vectors or matrices in V, +## respectively, are all contained in F. +## In this case, V is called a Gaussian vector space. +## Bases for Gaussian spaces can be computed using Gaussian elimination for +## a given list of vector space generators. +## mats:= [ [[1,1],[2,2]], [[3,4],[0,1]] ];; +## gap> V:= VectorSpace( Rationals, mats );; +## gap> IsGaussianSpace( V ); +## true +## gap> mats[1][1][1]:= E(4);; # an element in an extension field +## gap> V:= VectorSpace( Rationals, mats );; +## gap> IsGaussianSpace( V ); +## false +## gap> V:= VectorSpace( Field( Rationals, [ E(4) ] ), mats );; +## gap> IsGaussianSpace( V ); +## true +## ]]> +## +## +## <#/GAPDoc> +## +DeclareFilter( "IsGaussianSpace", IsVectorSpace ); + +InstallTrueMethod( IsGaussianSpace, + IsVectorSpace and IsFullMatrixModule ); + +InstallTrueMethod( IsGaussianSpace, + IsVectorSpace and IsFullRowModule ); + + +############################################################################# +## +#C IsDivisionRing( ) +## +## <#GAPDoc Label="IsDivisionRing"> +## +## +## +## +## A division ring in &GAP; is a nontrivial associative algebra +## D with a multiplicative inverse for each nonzero element. +## In &GAP; every division ring is a vector space over a division ring +## (possibly over itself). +## Note that being a division ring is thus not a property that a ring can +## get, because a ring is usually not represented as a vector space. +##

+## The field of coefficients is stored as the value of the attribute +## of D. +## +## +## <#/GAPDoc> +## +DeclareSynonymAttr( "IsDivisionRing", + IsMagmaWithInversesIfNonzero + and IsLeftOperatorRingWithOne + and IsLeftVectorSpace + and IsNonTrivial + and IsAssociative + and IsEuclideanRing ); + + +############################################################################# +## +#A GeneratorsOfLeftVectorSpace( ) +#A GeneratorsOfVectorSpace( ) +## +## <#GAPDoc Label="GeneratorsOfLeftVectorSpace"> +## +## +## +## +## +## For an F-vector space V, +## returns a list of vectors in +## V that generate V as an F-vector space. +## GeneratorsOfVectorSpace( FullRowSpace( Rationals, 3 ) ); +## [ [ 1, 0, 0 ], [ 0, 1, 0 ], [ 0, 0, 1 ] ] +## ]]> +## +## +## <#/GAPDoc> +## +DeclareSynonymAttr( "GeneratorsOfLeftVectorSpace", + GeneratorsOfLeftOperatorAdditiveGroup ); + +DeclareSynonymAttr( "GeneratorsOfVectorSpace", + GeneratorsOfLeftOperatorAdditiveGroup ); + + +############################################################################# +## +#A CanonicalBasis( ) +## +## <#GAPDoc Label="CanonicalBasis"> +## +## +## +## +## If the vector space V supports a canonical basis then +## returns this basis, +## otherwise fail is returned. +##

+## The defining property of a canonical basis is that its vectors are +## uniquely determined by the vector space. +## If canonical bases exist for two vector spaces over the same left acting +## domain (see ) then the equality of +## these vector spaces can be decided by comparing the canonical bases. +##

+## The exact meaning of a canonical basis depends on the type of V. +## Canonical bases are defined for example for Gaussian row and matrix +## spaces (see ). +##

+## If one designs a new kind of vector spaces +## (see ) and +## defines a canonical basis for these spaces then the +## method one installs +## (see ) +## must not call . +## On the other hand, one probably should install a +## method that simply calls , +## the value of the method +## (see  and +## ) +## being CANONICAL_BASIS_FLAGS. +## vecs:= [ [ 1, 2, 3 ], [ 1, 1, 1 ], [ 1, 1, 1 ] ];; +## gap> V:= VectorSpace( Rationals, vecs );; +## gap> B:= CanonicalBasis( V ); +## CanonicalBasis( ) +## gap> BasisVectors( B ); +## [ [ 1, 0, -1 ], [ 0, 1, 2 ] ] +## ]]> +## +## +## <#/GAPDoc> +## +DeclareAttribute( "CanonicalBasis", IsFreeLeftModule ); + + +############################################################################# +## +#F IsRowSpace( ) +## +## <#GAPDoc Label="IsRowSpace"> +## +## +## +## +## A row space in &GAP; is a vector space that consists of +## row vectors (see Chapter ). +## +## +## <#/GAPDoc> +## +DeclareSynonym( "IsRowSpace", IsRowModule and IsVectorSpace ); + + +############################################################################# +## +#F IsGaussianRowSpace( ) +## +## +## +## +## +## A row space is Gaussian if the left acting domain contains all +## scalars that occur in the vectors. +## Thus one can use Gaussian elimination in the calculations. +##

+## (Otherwise the space is non-Gaussian. +## We will need a flag for this to write down methods that delegate from +## non-Gaussian spaces to Gaussian ones.) +## +## +## +## +DeclareSynonym( "IsGaussianRowSpace", IsGaussianSpace and IsRowSpace ); + + +############################################################################# +## +#F IsNonGaussianRowSpace( ) +## +## +## +## +## +## If an F-vector space V is in the filter +## then this expresses that V +## consists of row vectors (see ) such +## that not all entries in these row vectors are contained in F +## (so Gaussian elimination cannot be used to compute an F-basis +## from a list of vector space generators), +## and that V is handled via the mechanism of nice bases +## (see ) in the following way. +## Let K be the field spanned by the entries of all vectors in +## V. +## Then the value of V is +## a basis B of the field extension K / ( K \cap F ), +## and the value of v \in V +## is defined by replacing each entry of v by the list of its +## B-coefficients, and then forming the concatenation. +##

+## So the associated nice vector space is a Gaussian row space +## (see ). +## +## +## +DeclareHandlingByNiceBasis( "IsNonGaussianRowSpace", + "for non-Gaussian row spaces" ); + + +############################################################################# +## +#F IsMatrixSpace( ) +## +## <#GAPDoc Label="IsMatrixSpace"> +## +## +## +## +## A matrix space in &GAP; is a vector space that consists of matrices +## (see Chapter ). +## +## +## <#/GAPDoc> +## +DeclareSynonym( "IsMatrixSpace", IsMatrixModule and IsVectorSpace ); + + +############################################################################# +## +#F IsGaussianMatrixSpace( ) +## +## +## +## +## +## A matrix space is Gaussian if the left acting domain contains all +## scalars that occur in the vectors. +## Thus one can use Gaussian elimination in the calculations. +##

+## (Otherwise the space is non-Gaussian. +## We will need a flag for this to write down methods that delegate from +## non-Gaussian spaces to Gaussian ones.) +## +## +## +DeclareSynonym( "IsGaussianMatrixSpace", IsGaussianSpace and IsMatrixSpace ); + + +############################################################################# +## +#F IsNonGaussianMatrixSpace( ) +## +## +## +## +## +## If an F-vector space V is in the filter +## +## then this expresses that V consists of matrices +## (see ) +## such that not all entries in these matrices are contained in F +## (so Gaussian elimination cannot be used to compute an F-basis +## from a list of vector space generators), +## and that V is handled via the mechanism of nice bases +## (see ) in the following way. +## Let K be the field spanned by the entries of all vectors in V. +## The value of V is irrelevant, +## and the value of v \in V +## is defined as the concatenation of the rows of v. +##

+## So the associated nice vector space is a (not necessarily Gaussian) +## row space (see ). +## +## +## +DeclareHandlingByNiceBasis( "IsNonGaussianMatrixSpace", + "for non-Gaussian matrix spaces" ); + + +############################################################################# +## +#A NormedRowVectors( ) . . . normed vectors in a Gaussian row space +## +## <#GAPDoc Label="NormedRowVectors"> +## +## +## +## +## For a finite Gaussian row space V +## (see , ), +## returns a list of those nonzero +## vectors in V that have a one in the first nonzero component. +##

+## The result list can be used as action domain for the action of a matrix +## group via , which yields the natural action on +## one-dimensional subspaces of V +## (see also ). +## vecs:= NormedRowVectors( GF(3)^2 ); +## [ [ 0*Z(3), Z(3)^0 ], [ Z(3)^0, 0*Z(3) ], [ Z(3)^0, Z(3)^0 ], +## [ Z(3)^0, Z(3) ] ] +## gap> Action( GL(2,3), vecs, OnLines ); +## Group([ (3,4), (1,2,4) ]) +## ]]> +## +## +## <#/GAPDoc> +## +DeclareAttribute( "NormedRowVectors", IsGaussianSpace ); + + +############################################################################# +## +#A TrivialSubspace( ) +## +## <#GAPDoc Label="TrivialSubspace"> +## +## +## +## +## For a vector space V, returns the +## subspace of V that consists of the zero vector in V. +## V:= GF(3)^3;; +## gap> triv:= TrivialSubspace( V ); +## +## gap> AsSet( triv ); +## [ [ 0*Z(3), 0*Z(3), 0*Z(3) ] ] +## ]]> +## +## +## <#/GAPDoc> +## +DeclareSynonymAttr( "TrivialSubspace", TrivialSubmodule ); + + +############################################################################# +## +#F VectorSpace( , [, ][, "basis"] ) +## +## <#GAPDoc Label="VectorSpace"> +## +## +## +## +## For a field F and a collection gens of vectors, +## returns the F-vector space spanned by +## the elements in gens. +##

+## The optional argument zero can be used to specify the zero element +## of the space; zero must be given if gens is empty. +## The optional string "basis" indicates that gens is known to +## be linearly independent over F, in particular the dimension of the +## vector space is immediately set; +## note that need not return the basis formed by +## gens if the string "basis" is given as an argument. +## +## V:= VectorSpace( Rationals, [ [ 1, 2, 3 ], [ 1, 1, 1 ] ] ); +## +## ]]> +## +## +## <#/GAPDoc> +## +DeclareGlobalFunction( "VectorSpace" ); + + +############################################################################# +## +#F Subspace( , [, "basis"] ) . subspace of generated by +#F SubspaceNC( , [, "basis"] ) +## +## <#GAPDoc Label="Subspace"> +## +## +## +## +## +## For an F-vector space V and a list or collection +## gens that is a subset of V, +## returns the F-vector space spanned by +## gens; if gens is empty then the trivial subspace +## (see ) of V is returned. +## The parent (see ) of the returned vector space +## is set to V. +##

+## does the same as , +## except that it omits the check whether gens is a subset of +## V. +##

+## The optional string "basis" indicates that gens is known to +## be linearly independent over F. +## In this case the dimension of the subspace is immediately set, +## and both and do +## not check whether gens really is linearly independent and +## whether gens is a subset of V. +## +## V:= VectorSpace( Rationals, [ [ 1, 2, 3 ], [ 1, 1, 1 ] ] );; +## gap> W:= Subspace( V, [ [ 0, 1, 2 ] ] ); +## +## ]]> +## +## +## <#/GAPDoc> +## +DeclareSynonym( "Subspace", Submodule ); + +DeclareSynonym( "SubspaceNC", SubmoduleNC ); + + +############################################################################# +## +#O AsVectorSpace( , ) . . . . . . . . . view as -vector space +## +## <#GAPDoc Label="AsVectorSpace"> +## +## +## +## +## Let F be a division ring and D a domain. +## If the elements in D form an F-vector space then +## returns this F-vector space, +## otherwise fail is returned. +##

+## can be used for example to view a given +## vector space as a vector space over a smaller or larger division ring. +## V:= FullRowSpace( GF( 27 ), 3 ); +## ( GF(3^3)^3 ) +## gap> Dimension( V ); LeftActingDomain( V ); +## 3 +## GF(3^3) +## gap> W:= AsVectorSpace( GF( 3 ), V ); +## +## gap> Dimension( W ); LeftActingDomain( W ); +## 9 +## GF(3) +## gap> AsVectorSpace( GF( 9 ), V ); +## fail +## ]]> +## +## +## <#/GAPDoc> +## +DeclareSynonym( "AsVectorSpace", AsLeftModule ); + + +############################################################################# +## +#O AsSubspace( , ) . . . . . . . . . . . view as subspace of +## +## <#GAPDoc Label="AsSubspace"> +## +## +## +## +## Let V be an F-vector space, and U a collection. +## If U is a subset of V such that the elements of U +## form an F-vector space then returns this +## vector space, with parent set to V +## (see ). +## Otherwise fail is returned. +## V:= VectorSpace( Rationals, [ [ 1, 2, 3 ], [ 1, 1, 1 ] ] );; +## gap> W:= VectorSpace( Rationals, [ [ 1/2, 1/2, 1/2 ] ] );; +## gap> U:= AsSubspace( V, W ); +## +## gap> Parent( U ) = V; +## true +## gap> AsSubspace( V, [ [ 1, 1, 1 ] ] ); +## fail +## ]]> +## +## +## <#/GAPDoc> +## +DeclareOperation( "AsSubspace", [ IsVectorSpace, IsCollection ] ); + + +############################################################################# +## +#F Intersection2Spaces( , , ) +## +## +## +## +## +## is a function that takes two arguments V and W which must +## be finite dimensional vector spaces, +## and returns the intersection of V and W. +##

+## If the left acting domains are different then let F be their +## intersection. +## The intersection of V and W is computed as intersection of +## AsStruct( F, V ) and +## AsStruct( F, V ). +##

+## If the left acting domains are equal to F then the intersection of +## V and W is returned either as F-Substruct +## with the common parent of V and W or as +## F-Struct, in both cases with known basis. +##

+## This function is used to handle the intersections of two vector spaces, +## two algebras, two algebras-with-one, two left ideals, two right ideals, +## two two-sided ideals. +## +## +## +DeclareGlobalFunction( "Intersection2Spaces" ); + + +############################################################################# +## +#F FullRowSpace( , ) +## +## <#GAPDoc Label="FullRowSpace"> +## +## +## +## +## +## For a field F and a nonnegative integer n, +## returns the F-vector space that +## consists of all row vectors (see ) of +## length n with entries in F. +##

+## An alternative to construct this vector space is via +## F^n. +## FullRowSpace( GF( 9 ), 3 ); +## ( GF(3^2)^3 ) +## gap> GF(9)^3; # the same as above +## ( GF(3^2)^3 ) +## ]]> +## +## +## <#/GAPDoc> +## +DeclareSynonym( "FullRowSpace", FullRowModule ); +DeclareSynonym( "RowSpace", FullRowModule ); + + +############################################################################# +## +#F FullMatrixSpace( , , ) +## +## <#GAPDoc Label="FullMatrixSpace"> +## +## +## +## +## +## For a field F and two positive integers m and n, +## returns the F-vector space that +## consists of all m by n matrices +## (see ) with entries in F. +##

+## If m = n then the result is in fact an algebra +## (see ). +##

+## An alternative to construct this vector space is via +## F^[m,n]. +## FullMatrixSpace( GF(2), 4, 5 ); +## ( GF(2)^[ 4, 5 ] ) +## gap> GF(2)^[ 4, 5 ]; # the same as above +## ( GF(2)^[ 4, 5 ] ) +## ]]> +## +## +## <#/GAPDoc> +## +DeclareSynonym( "FullMatrixSpace", FullMatrixModule ); +DeclareSynonym( "MatrixSpace", FullMatrixModule ); +DeclareSynonym( "MatSpace", FullMatrixModule ); + + +############################################################################# +## +#C IsSubspacesVectorSpace( ) +## +## <#GAPDoc Label="IsSubspacesVectorSpace"> +## +## +## +## +## The domain of all subspaces of a (finite) vector space or of all +## subspaces of fixed dimension, as returned by +## (see ) lies in the category +## . +## D:= Subspaces( GF(3)^3 ); +## Subspaces( ( GF(3)^3 ) ) +## gap> Size( D ); +## 28 +## gap> iter:= Iterator( D );; +## gap> NextIterator( iter ); +## +## gap> NextIterator( iter ); +## +## gap> IsSubspacesVectorSpace( D ); +## true +## ]]> +## +## +## <#/GAPDoc> +## +DeclareCategory( "IsSubspacesVectorSpace", IsDomain ); + + +############################################################################# +## +#M IsFinite( ) . . . . . . . . . . . . . . . . . for a subspaces domain +## +## Returns `true' if is finite. +## We allow subspaces domains in `IsSubspacesVectorSpace' only for finite +## vector spaces. +## +InstallTrueMethod( IsFinite, IsSubspacesVectorSpace ); + + +############################################################################# +## +#A Subspaces( [, ] ) +## +## <#GAPDoc Label="Subspaces"> +## +## +## +## +## Called with a finite vector space v, +## returns the domain of all subspaces of V. +##

+## Called with V and a nonnegative integer k, +## returns the domain of all k-dimensional +## subspaces of V. +##

+## Special and methods are +## provided for these domains. +## +## +## +## <#/GAPDoc> +## +DeclareAttribute( "Subspaces", IsLeftModule ); +DeclareOperation( "Subspaces", [ IsLeftModule, IsInt ] ); + + +############################################################################# +## +#F IsSubspace( , ) +## +## +## +## +## +## check that U is a vector space that is contained in V +## +## +## +## +DeclareGlobalFunction( "IsSubspace" ); + + +############################################################################# +## +#A OrthogonalSpaceInFullRowSpace( ) +## +## +## +## +## +## For a Gaussian row space U over F, +## +## returns a complement of U in the full row space of same vector +## dimension as U over F. +## +## +## +DeclareAttribute( "OrthogonalSpaceInFullRowSpace", IsGaussianSpace ); + + +############################################################################# +## +#P IsVectorSpaceHomomorphism( ) +## +## +## +## +## +## A mapping f is a vector space homomorphism (or linear mapping) +## if the source and range are vector spaces +## (see ) +## over the same division ring D +## (see ), +## and if f( a + b ) = f(a) + f(b) and f( s * a ) = s * f(a) +## hold for all elements a, b in the source of f and +## s \in D. +## +## +## +DeclareProperty( "IsVectorSpaceHomomorphism", IsGeneralMapping ); + + +############################################################################# +## +#E + diff --git a/samples/GAP/vspc.gi b/samples/GAP/vspc.gi new file mode 100644 index 00000000..b7a88871 --- /dev/null +++ b/samples/GAP/vspc.gi @@ -0,0 +1,651 @@ +############################################################################# +## +#W vspc.gi GAP library Thomas Breuer +## +## +#Y Copyright (C) 1997, Lehrstuhl D für Mathematik, RWTH Aachen, Germany +#Y (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland +#Y Copyright (C) 2002 The GAP Group +## +## This file contains generic methods for vector spaces. +## + + +############################################################################# +## +#M SetLeftActingDomain( , ) +## +## check whether the left acting domain of the external left set +## knows that it is a division ring. +## This is used, e.g., to tell a free module over a division ring +## that it is a vector space. +## +InstallOtherMethod( SetLeftActingDomain, + "method to set also 'IsLeftActedOnByDivisionRing'", + [ IsAttributeStoringRep and IsLeftActedOnByRing, IsObject ],0, + function( extL, D ) + if HasIsDivisionRing( D ) and IsDivisionRing( D ) then + SetIsLeftActedOnByDivisionRing( extL, true ); + fi; + TryNextMethod(); + end ); + + +############################################################################# +## +#M IsLeftActedOnByDivisionRing( ) +## +InstallMethod( IsLeftActedOnByDivisionRing, + "method for external left set that is left acted on by a ring", + [ IsExtLSet and IsLeftActedOnByRing ], + function( M ) + if IsIdenticalObj( M, LeftActingDomain( M ) ) then + TryNextMethod(); + else + return IsDivisionRing( LeftActingDomain( M ) ); + fi; + end ); + + +############################################################################# +## +#F VectorSpace( , [, ][, "basis"] ) +## +## The only difference between `VectorSpace' and `FreeLeftModule' shall be +## that the left acting domain of a vector space must be a division ring. +## +InstallGlobalFunction( VectorSpace, function( arg ) + if Length( arg ) = 0 or not IsDivisionRing( arg[1] ) then + Error( "usage: VectorSpace( , [, ][, \"basis\"] )" ); + fi; + return CallFuncList( FreeLeftModule, arg ); + end ); + + +############################################################################# +## +#M AsSubspace( , ) . . . . . . . for a vector space and a collection +## +InstallMethod( AsSubspace, + "for a vector space and a collection", + [ IsVectorSpace, IsCollection ], + function( V, C ) + local newC; + + if not IsSubset( V, C ) then + return fail; + fi; + newC:= AsVectorSpace( LeftActingDomain( V ), C ); + if newC = fail then + return fail; + fi; + SetParent( newC, V ); + UseIsomorphismRelation( C, newC ); + UseSubsetRelation( C, newC ); + + return newC; + end ); + + +############################################################################# +## +#M AsLeftModule( , ) . . . . . . for division ring and vector space +## +## View the vector space as a vector space over the division ring . +## +InstallMethod( AsLeftModule, + "method for a division ring and a vector space", + [ IsDivisionRing, IsVectorSpace ], + function( F, V ) + + local W, # the space, result + base, # basis vectors of field extension + gen, # loop over generators of 'V' + b, # loop over 'base' + gens, # generators of 'V' + newgens; # extended list of generators + + if Characteristic( F ) <> Characteristic( LeftActingDomain( V ) ) then + + # This is impossible. + return fail; + + elif F = LeftActingDomain( V ) then + + # No change of the left acting domain is necessary. + return V; + + elif IsSubset( F, LeftActingDomain( V ) ) then + + # Check whether 'V' is really a space over the bigger field, + # that is, whether the set of elements does not change. + base:= BasisVectors( Basis( AsField( LeftActingDomain( V ), F ) ) ); + for gen in GeneratorsOfLeftModule( V ) do + for b in base do + if not b * gen in V then + + # The field extension would change the set of elements. + return fail; + + fi; + od; + od; + + # Construct the space. + W:= LeftModuleByGenerators( F, GeneratorsOfLeftModule(V), Zero(V) ); + + elif IsSubset( LeftActingDomain( V ), F ) then + + # View 'V' as a space over a smaller field. + # For that, the list of generators must be extended. + gens:= GeneratorsOfLeftModule( V ); + if IsEmpty( gens ) then + W:= LeftModuleByGenerators( F, [], Zero( V ) ); + else + + base:= BasisVectors( Basis( AsField( F, LeftActingDomain( V ) ) ) ); + newgens:= []; + for b in base do + for gen in gens do + Add( newgens, b * gen ); + od; + od; + W:= LeftModuleByGenerators( F, newgens ); + + fi; + + else + + # View 'V' first as space over the intersection of fields, + # and then over the desired field. + return AsLeftModule( F, + AsLeftModule( Intersection( F, + LeftActingDomain( V ) ), V ) ); + + fi; + + UseIsomorphismRelation( V, W ); + UseSubsetRelation( V, W ); + return W; + end ); + + +############################################################################# +## +#M ViewObj( ) . . . . . . . . . . . . . . . . . . . view a vector space +## +## print left acting domain, if known also dimension or no. of generators +## +InstallMethod( ViewObj, + "for vector space with known generators", + [ IsVectorSpace and HasGeneratorsOfLeftModule ], + function( V ) + Print( "" ); + end ); + +InstallMethod( ViewObj, + "for vector space with known dimension", + [ IsVectorSpace and HasDimension ], + 1, # override method for known generators + function( V ) + Print( "" ); + end ); + +InstallMethod( ViewObj, + "for vector space", + [ IsVectorSpace ], + function( V ) + Print( "" ); + end ); + + +############################################################################# +## +#M PrintObj( ) . . . . . . . . . . . . . . . . . . . for a vector space +## +InstallMethod( PrintObj, + "method for vector space with left module generators", + [ IsVectorSpace and HasGeneratorsOfLeftModule ], + function( V ) + Print( "VectorSpace( ", LeftActingDomain( V ), ", ", + GeneratorsOfLeftModule( V ) ); + if IsEmpty( GeneratorsOfLeftModule( V ) ) and HasZero( V ) then + Print( ", ", Zero( V ), " )" ); + else + Print( " )" ); + fi; + end ); + +InstallMethod( PrintObj, + "method for vector space", + [ IsVectorSpace ], + function( V ) + Print( "VectorSpace( ", LeftActingDomain( V ), ", ... )" ); + end ); + + +############################################################################# +## +#M \/( , ) . . . . . . . . . factor of a vector space by a subspace +#M \/( , ) . . . . . . factor of a vector space by a subspace +## +InstallOtherMethod( \/, + "method for vector space and collection", + IsIdenticalObj, + [ IsVectorSpace, IsCollection ], + function( V, vectors ) + if IsVectorSpace( vectors ) then + TryNextMethod(); + else + return V / Subspace( V, vectors ); + fi; + end ); + +InstallOtherMethod( \/, + "generic method for two vector spaces", + IsIdenticalObj, + [ IsVectorSpace, IsVectorSpace ], + function( V, W ) + return ImagesSource( NaturalHomomorphismBySubspace( V, W ) ); + end ); + + +############################################################################# +## +#M Intersection2Spaces( , , ) +## +InstallGlobalFunction( Intersection2Spaces, + function( AsStructure, Substructure, Structure ) + return function( V, W ) + local inters, # intersection, result + F, # coefficients field + gensV, # list of generators of 'V' + gensW, # list of generators of 'W' + VW, # sum of 'V' and 'W' + B; # basis of 'VW' + + if LeftActingDomain( V ) <> LeftActingDomain( W ) then + + # Compute the intersection as vector space over the intersection + # of the coefficients fields. + # (Note that the characteristic is the same.) + F:= Intersection2( LeftActingDomain( V ), LeftActingDomain( W ) ); + return Intersection2( AsStructure( F, V ), AsStructure( F, W ) ); + + elif IsFiniteDimensional( V ) and IsFiniteDimensional( W ) then + + # Compute the intersection of two spaces over the same field. + gensV:= GeneratorsOfLeftModule( V ); + gensW:= GeneratorsOfLeftModule( W ); + if IsEmpty( gensV ) then + if Zero( V ) in W then + inters:= V; + else + inters:= []; + fi; + elif IsEmpty( gensW ) then + if Zero( V ) in W then + inters:= W; + else + inters:= []; + fi; + else + # Compute a common coefficient space. + VW:= LeftModuleByGenerators( LeftActingDomain( V ), + Concatenation( gensV, gensW ) ); + B:= Basis( VW ); + + # Construct the coefficient subspaces corresponding to 'V' and 'W'. + gensV:= List( gensV, x -> Coefficients( B, x ) ); + gensW:= List( gensW, x -> Coefficients( B, x ) ); + + # Construct the intersection of row spaces, and carry back to VW. + inters:= List( SumIntersectionMat( gensV, gensW )[2], + x -> LinearCombination( B, x ) ); + + # Construct the intersection space, if possible with a parent. + if HasParent( V ) and HasParent( W ) + and IsIdenticalObj( Parent( V ), Parent( W ) ) then + inters:= Substructure( Parent( V ), inters, "basis" ); + elif IsEmpty( inters ) then + inters:= Substructure( V, inters, "basis" ); + SetIsTrivial( inters, true ); + else + inters:= Structure( LeftActingDomain( V ), inters, "basis" ); + fi; + + # Run implications by the subset relation. + UseSubsetRelation( V, inters ); + UseSubsetRelation( W, inters ); + fi; + + # Return the result. + return inters; + + else + TryNextMethod(); + fi; + end; +end ); + + +############################################################################# +## +#M Intersection2( , ) . . . . . . . . . . . . . for two vector spaces +## +InstallMethod( Intersection2, + "method for two vector spaces", + IsIdenticalObj, + [ IsVectorSpace, IsVectorSpace ], + Intersection2Spaces( AsLeftModule, SubspaceNC, VectorSpace ) ); + + +############################################################################# +## +#M ClosureLeftModule( , ) . . . . . . . . . closure of a vector space +## +InstallMethod( ClosureLeftModule, + "method for a vector space with basis, and a vector", + IsCollsElms, + [ IsVectorSpace and HasBasis, IsVector ], + function( V, w ) + local B; # basis of 'V' + + # We can test membership easily. + B:= Basis( V ); +#T why easily? + if Coefficients( B, w ) = fail then + + # In the case of a vector space, we know a basis of the closure. + B:= Concatenation( BasisVectors( B ), [ w ] ); + V:= LeftModuleByGenerators( LeftActingDomain( V ), B ); + UseBasis( V, B ); + + fi; + return V; + end ); + + +############################################################################# +## +## Methods for collections of subspaces of a vector space +## + + +############################################################################# +## +#R IsSubspacesVectorSpaceDefaultRep( ) +## +## is the representation of domains of subspaces of a vector space , +## with the components 'structure' (with value ) and 'dimension' +## (with value either the dimension of the subspaces in the domain +## or the string '\"all\"', which means that the domain contains all +## subspaces of ). +## +DeclareRepresentation( + "IsSubspacesVectorSpaceDefaultRep", + IsComponentObjectRep, + [ "dimension", "structure" ] ); +#T not IsAttributeStoringRep? + + +############################################################################# +## +#M PrintObj( ) . . . . . . . . . . . . . . . . . for a subspaces domain +## +InstallMethod( PrintObj, + "method for a subspaces domain", + [ IsSubspacesVectorSpace and IsSubspacesVectorSpaceDefaultRep ], + function( D ) + if IsInt( D!.dimension ) then + Print( "Subspaces( ", D!.structure, ", ", D!.dimension, " )" ); + else + Print( "Subspaces( ", D!.structure, " )" ); + fi; + end ); + + +############################################################################# +## +#M Size( ) . . . . . . . . . . . . . . . . . . . for a subspaces domain +## +## The number of $k$-dimensional subspaces in a $n$-dimensional space over +## the field with $q$ elements is +## $$ +## a(n,k) = \prod_{i=0}^{k-1} \frac{q^n-q^i}{q^k-q^i} = +## \prod_{i=0}^{k-1} \frac{q^{n-i}-1}{q^{k-i}-1}. +## $$ +## We have the recursion +## $$ +## a(n,k+1) = a(n,k) \frac{q^{n-i}-1}{q^{i+1}-1}. +## $$ +## +## (The number of all subspaces is $\sum_{k=0}^n a(n,k)$.) +## +InstallMethod( Size, + "method for a subspaces domain", + [ IsSubspacesVectorSpace and IsSubspacesVectorSpaceDefaultRep ], + function( D ) + + local k, + n, + q, + size, + qn, + qd, + ank, + i; + + if D!.dimension = "all" then + + # all subspaces of the space + n:= Dimension( D!.structure ); + + q:= Size( LeftActingDomain( D!.structure ) ); + size:= 1; + qn:= q^n; + qd:= q; + + # $a(n,0)$ + ank:= 1; + + for k in [ 1 .. Int( (n-1)/2 ) ] do + + # Compute $a(n,k)$. + ank:= ank * ( qn - 1 ) / ( qd - 1 ); + qn:= qn / q; + qd:= qd * q; + + size:= size + ank; + + od; + + size:= 2 * size; + + if n mod 2 = 0 then + + # Add the number of spaces of dimension $n/2$. + size:= size + ank * ( qn - 1 ) / ( qd - 1 ); + fi; + + else + + # number of spaces of dimension 'k' only + n:= Dimension( D!.structure ); + if D!.dimension < 0 or + n < D!.dimension then + return 0; + elif n / 2 < D!.dimension then + k:= n - D!.dimension; + else + k:= D!.dimension; + fi; + + q:= Size( LeftActingDomain( D!.structure ) ); + size:= 1; + + qn:= q^n; + qd:= q; + for i in [ 1 .. k ] do + size:= size * ( qn - 1 ) / ( qd - 1 ); + qn:= qn / q; + qd:= qd * q; + od; + + fi; + + # Return the result. + return size; + end ); + + +############################################################################# +## +#M Enumerator( ) . . . . . . . . . . . . . . . . for a subspaces domain +## +## Use the iterator to compute the elements list. +#T This is not allowed! +## +InstallMethod( Enumerator, + "method for a subspaces domain", + [ IsSubspacesVectorSpace and IsSubspacesVectorSpaceDefaultRep ], + function( D ) + local iter, # iterator for 'D' + elms; # elements list, result + + iter:= Iterator( D ); + elms:= []; + while not IsDoneIterator( iter ) do + Add( elms, NextIterator( iter ) ); + od; + return elms; + end ); +#T necessary? + + +############################################################################# +## +#M Iterator( ) . . . . . . . . . . . . . . . . . for a subspaces domain +## +## uses the subspaces iterator for full row spaces and the mechanism of +## associated row spaces. +## +BindGlobal( "IsDoneIterator_Subspaces", + iter -> IsDoneIterator( iter!.associatedIterator ) ); + +BindGlobal( "NextIterator_Subspaces", function( iter ) + local next; + next:= NextIterator( iter!.associatedIterator ); + next:= List( GeneratorsOfLeftModule( next ), + x -> LinearCombination( iter!.basis, x ) ); + return Subspace( iter!.structure, next, "basis" ); + end ); + +BindGlobal( "ShallowCopy_Subspaces", + iter -> rec( structure := iter!.structure, + basis := iter!.basis, + associatedIterator := ShallowCopy( + iter!.associatedIterator ) ) ); + +InstallMethod( Iterator, + "for a subspaces domain", + [ IsSubspacesVectorSpace and IsSubspacesVectorSpaceDefaultRep ], + function( D ) + local V; # the vector space + + V:= D!.structure; + return IteratorByFunctions( rec( + IsDoneIterator := IsDoneIterator_Subspaces, + NextIterator := NextIterator_Subspaces, + ShallowCopy := ShallowCopy_Subspaces, + structure := V, + basis := Basis( V ), + associatedIterator := Iterator( + Subspaces( FullRowSpace( LeftActingDomain( V ), + Dimension( V ) ), + D!.dimension ) ) ) ); + end ); + + +############################################################################# +## +#M Subspaces( , ) +## +InstallMethod( Subspaces, + "for a vector space, and an integer", + [ IsVectorSpace, IsInt ], + function( V, dim ) + if IsFinite( V ) then + return Objectify( NewType( CollectionsFamily( FamilyObj( V ) ), + IsSubspacesVectorSpace + and IsSubspacesVectorSpaceDefaultRep ), + rec( + structure := V, + dimension := dim + ) + ); + else + TryNextMethod(); + fi; + end ); + + +############################################################################# +## +#M Subspaces( ) +## +InstallMethod( Subspaces, + "for a vector space", + [ IsVectorSpace ], + function( V ) + if IsFinite( V ) then + return Objectify( NewType( CollectionsFamily( FamilyObj( V ) ), + IsSubspacesVectorSpace + and IsSubspacesVectorSpaceDefaultRep ), + rec( + structure := V, + dimension := "all" + ) + ); + else + TryNextMethod(); + fi; + end ); + + +############################################################################# +## +#F IsSubspace( , ) . . . . . . . . . . . . . . . . . check <= +## +InstallGlobalFunction( IsSubspace, function( V, U ) + return IsVectorSpace( U ) and IsSubset( V, U ); +end ); + + +############################################################################# +## +#M IsVectorSpaceHomomorphism( ) +## +InstallMethod( IsVectorSpaceHomomorphism, + [ IsGeneralMapping ], + function( map ) + local S, R, F; + S:= Source( map ); + if not IsVectorSpace( S ) then + return false; + fi; + R:= Range( map ); + if not IsVectorSpace( R ) then + return false; + fi; + F:= LeftActingDomain( S ); + return ( F = LeftActingDomain( R ) ) and IsLinearMapping( F, map ); + end ); + + +############################################################################# +## +#E +