diff --git a/Gemfile b/Gemfile index ef35f9c..256e288 100644 --- a/Gemfile +++ b/Gemfile @@ -9,3 +9,7 @@ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } gem "jekyll" gem "webrick", "~> 1.8" + +gem "jekyll-pseudocode-latex" + +gem 'jekyll-scholar', group: :jekyll_plugins diff --git a/Gemfile.lock b/Gemfile.lock index c9ed5cd..4938ce3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,8 +3,21 @@ GEM specs: addressable (2.8.0) public_suffix (>= 2.0.2, < 5.0) + bibtex-ruby (6.1.0) + latex-decode (~> 0.0) + racc (~> 1.7) + citeproc (1.0.10) + namae (~> 1.0) + citeproc-ruby (1.1.14) + citeproc (~> 1.0, >= 1.0.9) + csl (~> 1.6) colorator (1.1.0) concurrent-ruby (1.1.9) + csl (1.6.0) + namae (~> 1.0) + rexml + csl-styles (1.0.1.11) + csl (~> 1.0) em-websocket (0.5.2) eventmachine (>= 0.12.9) http_parser.rb (~> 0.6.0) @@ -31,22 +44,33 @@ GEM rouge (~> 3.0) safe_yaml (~> 1.0) terminal-table (~> 2.0) + jekyll-pseudocode-latex (0.1.1) + jekyll (>= 3.0) jekyll-sass-converter (2.1.0) sassc (> 2.0.1, < 3.0) + jekyll-scholar (7.1.3) + bibtex-ruby (~> 6.0) + citeproc-ruby (~> 1.0) + csl-styles (~> 1.0) + jekyll (~> 4.0) jekyll-watch (2.2.1) listen (~> 3.0) kramdown (2.3.1) rexml kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) + latex-decode (0.4.0) liquid (4.0.3) listen (3.7.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) mercenary (0.4.0) + namae (1.2.0) + racc (~> 1.7) pathutil (0.16.2) forwardable-extended (~> 2.6) public_suffix (4.0.6) + racc (1.8.1) rb-fsevent (0.11.0) rb-inotify (0.10.1) ffi (~> 1.0) @@ -70,6 +94,8 @@ PLATFORMS DEPENDENCIES jekyll + jekyll-pseudocode-latex + jekyll-scholar webrick (~> 1.8) BUNDLED WITH diff --git a/_bibliography/bibliofabio.bib b/_bibliography/bibliofabio.bib new file mode 100644 index 0000000..07e6c08 --- /dev/null +++ b/_bibliography/bibliofabio.bib @@ -0,0 +1,46 @@ +@article{PSCToolkit, +title = {Parallel Sparse Computation Toolkit}, +journal = {Software Impacts}, +volume = {15}, +pages = {100463}, +year = {2023}, +issn = {2665-9638}, +doi = {https://doi.org/10.1016/j.simpa.2022.100463}, +url = {https://www.sciencedirect.com/science/article/pii/S2665963822001476}, +author = {Pasqua D’Ambra and Fabio Durastante and Salvatore Filippone}, +keywords = {Linear solvers, Algebraic preconditioners, HPC, GPU, Heterogeneous computing}, +abstract = {This paper presents a new software framework for solving large and sparse linear systems on current hybrid architectures, from small servers to high-end supercomputers, embedding multi-core CPUs and Nvidia GPUs at the node level. The framework has a modular structure and is composed of three main components, which separate basic functionalities for managing distributed sparse matrices and executing some sparse matrix computations involved in iterative Krylov projection methods, eventually exploiting multi-threading and CUDA-based programming models, from the functionalities for setup and application of different types of one-level and multi-level algebraic preconditioners.} +} +@article {MR1003940, + AUTHOR = {Chronopoulos, A. T. and Gear, C. W.}, + TITLE = {On the efficient implementation of preconditioned {$s$}-step + conjugate gradient methods on multiprocessors with memory + hierarchy}, + JOURNAL = {Parallel Comput.}, + FJOURNAL = {Parallel Computing. Systems \& Applications}, + VOLUME = {11}, + YEAR = {1989}, + NUMBER = {1}, + PAGES = {37--53}, + ISSN = {0167-8191,1872-7336}, + MRCLASS = {65W05}, + MRNUMBER = {1003940}, + DOI = {10.1016/0167-8191(89)90062-8}, + URL = {https://doi.org/10.1016/0167-8191(89)90062-8}, +} +@article {MR3846291, + AUTHOR = {Carson, Erin C.}, + TITLE = {The adaptive {$s$}-step conjugate gradient method}, + JOURNAL = {SIAM J. Matrix Anal. Appl.}, + FJOURNAL = {SIAM Journal on Matrix Analysis and Applications}, + VOLUME = {39}, + YEAR = {2018}, + NUMBER = {3}, + PAGES = {1318--1338}, + ISSN = {0895-4798,1095-7162}, + MRCLASS = {65F10 (65F50 65G50 65Y05 65Y20)}, + MRNUMBER = {3846291}, +MRREVIEWER = {Kees\ Vuik}, + DOI = {10.1137/16M1107942}, + URL = {https://doi.org/10.1137/16M1107942}, +} diff --git a/_bibliography/bibliofabio2.bib b/_bibliography/bibliofabio2.bib new file mode 100644 index 0000000..3284604 --- /dev/null +++ b/_bibliography/bibliofabio2.bib @@ -0,0 +1,111 @@ +@article {MR4130854, + AUTHOR = {Benzi, Michele and Bertaccini, Daniele and Durastante, Fabio + and Simunec, Igor}, + TITLE = {Non-local network dynamics via fractional graph {L}aplacians}, + JOURNAL = {J. Complex Netw.}, + FJOURNAL = {Journal of Complex Networks}, + VOLUME = {8}, + YEAR = {2020}, + NUMBER = {3}, + PAGES = {cnaa017, 29}, + ISSN = {2051-1310,2051-1329}, + MRCLASS = {05C50 (05C90)}, + MRNUMBER = {4130854}, + DOI = {10.1093/comnet/cnaa017}, + URL = {https://doi.org/10.1093/comnet/cnaa017}, +} +@article {MR4340667, + AUTHOR = {Arrigo, Francesca and Durastante, Fabio}, + TITLE = {Mittag-{L}effler functions and their applications in network + science}, + JOURNAL = {SIAM J. Matrix Anal. Appl.}, + FJOURNAL = {SIAM Journal on Matrix Analysis and Applications}, + VOLUME = {42}, + YEAR = {2021}, + NUMBER = {4}, + PAGES = {1581--1601}, + ISSN = {0895-4798,1095-7162}, + MRCLASS = {91D30 (05C50 15A16)}, + MRNUMBER = {4340667}, + DOI = {10.1137/21M1407276}, + URL = {https://doi.org/10.1137/21M1407276}, +} +@article {MR4216832, + AUTHOR = {Cipolla, Stefano and Durastante, Fabio and Tudisco, Francesco}, + TITLE = {Nonlocal {P}age{R}ank}, + JOURNAL = {ESAIM Math. Model. Numer. Anal.}, + FJOURNAL = {ESAIM. Mathematical Modelling and Numerical Analysis}, + VOLUME = {55}, + YEAR = {2021}, + NUMBER = {1}, + PAGES = {77--97}, + ISSN = {2822-7840,2804-7214}, + MRCLASS = {05C82 (60J20 68R10 94C15)}, + MRNUMBER = {4216832}, +MRREVIEWER = {Hai\ Yan\ Chen}, + DOI = {10.1051/m2an/2020071}, + URL = {https://doi.org/10.1051/m2an/2020071}, +} +@article {MR2736969, + AUTHOR = {Estrada, Ernesto and Higham, Desmond J.}, + TITLE = {Network properties revealed through matrix functions}, + JOURNAL = {SIAM Rev.}, + FJOURNAL = {SIAM Review}, + VOLUME = {52}, + YEAR = {2010}, + NUMBER = {4}, + PAGES = {696--714}, + ISSN = {0036-1445,1095-7200}, + MRCLASS = {05C82 (05C50 91D30 94C15)}, + MRNUMBER = {2736969}, +MRREVIEWER = {Stephen\ J.\ Young}, + DOI = {10.1137/090761070}, + URL = {https://doi.org/10.1137/090761070}, +} +@article {MR3829156, + AUTHOR = {Arioli, Mario and Benzi, Michele}, + TITLE = {A finite element method for quantum graphs}, + JOURNAL = {IMA J. Numer. Anal.}, + FJOURNAL = {IMA Journal of Numerical Analysis}, + VOLUME = {38}, + YEAR = {2018}, + NUMBER = {3}, + PAGES = {1119--1163}, + ISSN = {0272-4979,1464-3642}, + MRCLASS = {65N30 (05C10 35R02 81Q35)}, + MRNUMBER = {3829156}, + DOI = {10.1093/imanum/drx029}, + URL = {https://doi.org/10.1093/imanum/drx029}, +} +@article {MR4131346, + AUTHOR = {Lim, Lek-Heng}, + TITLE = {Hodge {L}aplacians on graphs}, + JOURNAL = {SIAM Rev.}, + FJOURNAL = {SIAM Review}, + VOLUME = {62}, + YEAR = {2020}, + NUMBER = {3}, + PAGES = {685--715}, + ISSN = {0036-1445,1095-7200}, + MRCLASS = {58A14 (05C50 20G10)}, + MRNUMBER = {4131346}, + DOI = {10.1137/18M1223101}, + URL = {https://doi.org/10.1137/18M1223101}, +} +@article {MR4783080, + AUTHOR = {Ribando-Gros, Emily and Wang, Rui and Chen, Jiahui and Tong, + Yiying and Wei, Guo-Wei}, + TITLE = {Combinatorial and {H}odge {L}aplacians: similarities and + differences}, + JOURNAL = {SIAM Rev.}, + FJOURNAL = {SIAM Review}, + VOLUME = {66}, + YEAR = {2024}, + NUMBER = {3}, + PAGES = {575--601}, + ISSN = {0036-1445,1095-7200}, + MRCLASS = {05C50 (58A14 65M60 97-02)}, + MRNUMBER = {4783080}, + DOI = {10.1137/22M1482299}, + URL = {https://doi.org/10.1137/22M1482299}, +} diff --git a/_bibliography/bibliofabio3.bib b/_bibliography/bibliofabio3.bib new file mode 100644 index 0000000..549c947 --- /dev/null +++ b/_bibliography/bibliofabio3.bib @@ -0,0 +1,65 @@ +@article {MR4516169, + AUTHOR = {Aceto, Lidia and Durastante, Fabio}, + TITLE = {Efficient computation of the {W}right function and its + applications to fractional diffusion-wave equations}, + JOURNAL = {ESAIM Math. Model. Numer. Anal.}, + FJOURNAL = {ESAIM. Mathematical Modelling and Numerical Analysis}, + VOLUME = {56}, + YEAR = {2022}, + NUMBER = {6}, + PAGES = {2181--2196}, + ISSN = {2822-7840,2804-7214}, + MRCLASS = {65D20 (26A33 33F10 44A10 65D30)}, + MRNUMBER = {4516169}, + DOI = {10.1051/m2an/2022069}, + URL = {https://doi.org/10.1051/m2an/2022069}, +} +@article {MR3989621, + AUTHOR = {Aceto, L. and Bertaccini, D. and Durastante, F. and Novati, + P.}, + TITLE = {Rational {K}rylov methods for functions of matrices with + applications to fractional partial differential equations}, + JOURNAL = {J. Comput. Phys.}, + FJOURNAL = {Journal of Computational Physics}, + VOLUME = {396}, + YEAR = {2019}, + PAGES = {470--482}, + ISSN = {0021-9991,1090-2716}, + MRCLASS = {65F60 (15A16)}, + MRNUMBER = {3989621}, +MRREVIEWER = {Jo\~ao\ Ribeiro\ Cardoso}, + DOI = {10.1016/j.jcp.2019.07.009}, + URL = {https://doi.org/10.1016/j.jcp.2019.07.009}, +} +@article {MR4268683, + AUTHOR = {Garrappa, Roberto and Giusti, Andrea and Mainardi, Francesco}, + TITLE = {Variable-order fractional calculus: a change of perspective}, + JOURNAL = {Commun. Nonlinear Sci. Numer. Simul.}, + FJOURNAL = {Communications in Nonlinear Science and Numerical Simulation}, + VOLUME = {102}, + YEAR = {2021}, + PAGES = {Paper No. 105904, 16}, + ISSN = {1007-5704,1878-7274}, + MRCLASS = {26A33 (31A10 44A10)}, + MRNUMBER = {4268683}, +MRREVIEWER = {Subhadarshan\ Sahoo}, + DOI = {10.1016/j.cnsns.2021.105904}, + URL = {https://doi.org/10.1016/j.cnsns.2021.105904}, +} +@article {MR4617155, + AUTHOR = {Garrappa, Roberto and Giusti, Andrea}, + TITLE = {A computational approach to exponential-type variable-order + fractional differential equations}, + JOURNAL = {J. Sci. Comput.}, + FJOURNAL = {Journal of Scientific Computing}, + VOLUME = {96}, + YEAR = {2023}, + NUMBER = {3}, + PAGES = {Paper No. 63, 19}, + ISSN = {0885-7474,1573-7691}, + MRCLASS = {65L06 (34A08 44A10)}, + MRNUMBER = {4617155}, +MRREVIEWER = {Jianfei\ Huang}, + DOI = {10.1007/s10915-023-02283-6}, + URL = {https://doi.org/10.1007/s10915-023-02283-6}, +} diff --git a/_bibliography/bibliography.bib b/_bibliography/bibliography.bib new file mode 100644 index 0000000..e69de29 diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..e2498bd --- /dev/null +++ b/_config.yml @@ -0,0 +1,11 @@ +plugin: + - pseudocode + - jekyll-scholar +site-css: + - "/assets/css/pseudocode.css" +scholar: + style: modern-language-association + locale: it + source: _bibliography + sort_by: author + order: ascending diff --git a/_layouts/default.html b/_layouts/default.html index 2e75750..d91d16a 100644 --- a/_layouts/default.html +++ b/_layouts/default.html @@ -6,10 +6,29 @@ {{ page.title }} + + +
@@ -31,4 +50,4 @@ - \ No newline at end of file + diff --git a/_plugins/jekyll-scholar.rb b/_plugins/jekyll-scholar.rb new file mode 100644 index 0000000..af88e6d --- /dev/null +++ b/_plugins/jekyll-scholar.rb @@ -0,0 +1 @@ +require 'jekyll/scholar' diff --git a/_plugins/jekyll/scholar.rb b/_plugins/jekyll/scholar.rb new file mode 100644 index 0000000..aadc3e7 --- /dev/null +++ b/_plugins/jekyll/scholar.rb @@ -0,0 +1,33 @@ + +require 'jekyll' + +require 'optparse' + +require 'bibtex' +require 'citeproc/ruby' +require 'csl/styles' + +require 'jekyll/scholar/version' +require 'jekyll/scholar/defaults' +require 'jekyll/scholar/utilities' + +require 'jekyll/scholar/converters/bibtex' +require 'jekyll/scholar/tags/bibliography' +require 'jekyll/scholar/tags/bibliography_count' +require 'jekyll/scholar/tags/bibtex' +require 'jekyll/scholar/tags/cite' +require 'jekyll/scholar/tags/cite_details' +require 'jekyll/scholar/tags/details_link' +require 'jekyll/scholar/tags/nocite' +require 'jekyll/scholar/tags/quote' +require 'jekyll/scholar/tags/reference' +require 'jekyll/scholar/generators/details' + +require 'jekyll/scholar/plugins/markdown_links' +require 'jekyll/scholar/plugins/superscript' +require 'jekyll/scholar/plugins/smallcaps' +require 'jekyll/scholar/plugins/italics' +require 'jekyll/scholar/plugins/textit' +require 'jekyll/scholar/plugins/lowercase' +require 'jekyll/scholar/plugins/textregistered' +require 'jekyll/scholar/plugins/tiny' diff --git a/_plugins/jekyll/scholar/converters/bibtex.rb b/_plugins/jekyll/scholar/converters/bibtex.rb new file mode 100644 index 0000000..16edc85 --- /dev/null +++ b/_plugins/jekyll/scholar/converters/bibtex.rb @@ -0,0 +1,47 @@ +module Jekyll + class Scholar + class BibTeXConverter < Converter + include Scholar::Utilities + + safe true + priority :highest + + attr_reader :config + + @pattern = (/bib(tex)?$/i).freeze + @extension = '.html'.freeze + + class << self + attr_reader :pattern, :extension + end + + def initialize(config = {}) + super + @config = Scholar.defaults.merge(@config['scholar'] || {}) + @markdown = Jekyll::Converters::Markdown.new(config) + end + + def matches(extension) + extension =~ BibTeXConverter.pattern + end + + def output_ext(extension) + BibTeXConverter.extension + end + + def convert(content) + content = BibTeX.parse(content, :strict => true, :include => [:meta_content], + :filter => config['bibtex_filters']).map do |b| + if b.respond_to?(:to_citeproc) + render_bibliography b + else + b.is_a?(BibTeX::MetaContent) ? b.to_s : '' + end + end + + @markdown.convert(content.join("\n")) + end + + end + end +end diff --git a/_plugins/jekyll/scholar/defaults.rb b/_plugins/jekyll/scholar/defaults.rb new file mode 100644 index 0000000..ed4c8b1 --- /dev/null +++ b/_plugins/jekyll/scholar/defaults.rb @@ -0,0 +1,108 @@ +module Jekyll + class Scholar + @defaults = { + # Style used for citations and bibliographies + 'style' => 'apa', + # Sets languages used in bibliography + 'locale' => 'en', + + # Keys used to sort bibliography + 'sort_by' => 'none', + # Order used to sort biobliography + 'order' => 'ascending', + 'group_by' => 'none', + 'group_order' => 'ascending', + # HTML tags used for bibliography group names + 'bibliography_group_tag' => 'h2,h3,h4,h5', + # HTML tag used for list of bibliography entries + 'bibliography_list_tag' => 'ol', + # HTML tag used for individual bibliography entries + 'bibliography_item_tag' => 'li', + # Attributes applied to HTML tag for list of bibliography entries + 'bibliography_list_attributes' => {}, + # Attributes applied to HTML tag for bibliography entries + 'bibliography_item_attributes' => {}, + + # Name of folder references files are stored in + 'source' => './_bibliography', + # Name of default references file + 'bibliography' => 'references.bib', + + # The repository folder with your entries' attachemnts, slides, etc. + 'repository' => nil, + + # Delimiter for files in repositories; + # this character may not be part of your entry keys! + 'repository_file_delimiter' => '.', + + 'bibtex_options' => { :strip => false, :parse_months => true }, + 'bibtex_filters' => [ :smallcaps, :superscript, :italics, :textit, :lowercase, :textregistered, :tiny, :latex ], + 'raw_bibtex_filters' => [ ], + 'bibtex_skip_fields' => [ :abstract, :month_numeric ], + 'bibtex_quotes' => ['{', '}'], + + 'replace_strings' => true, + 'join_strings' => true, + # Remove duplicate entries from bibliography + 'remove_duplicates' => false, + + 'details_dir' => 'bibliography', + 'details_layout' => 'bibtex.html', + 'details_link' => 'Details', + + # 'details_permalink': URL template for generating the filenames of the details pages. + # + # Example: if we had a citation key 'ruby': + # '/:details_dir/:year/:key:extension' would produce: + # '/bibliography/2008/ruby.html' if global permalinks end in .html + # '/bibliography/2008/ruby/index.html' if global permalinks end in "/" or are set to "pretty" + # + # Valid template parameters: + # ":details_dir" The value of the details_dir field in the scholar config + # ":key" The bibtex citation key. + # ":doi" The DOI. If the DOI is missing or blank, this returns the citation key. + # ":extension" Either of ".html" or "/index.html" depending upon the global permalink setting. + # Template parameters can also include any key defined in the bibtex file, e.g. ":year", ":title", etc. + # Bibtex keys such as 'title' are slugified in the same way as Jekyll treats blog post titles. + 'details_permalink' => '/:details_dir/:key:extension', + + 'bibliography_class' => 'bibliography', + 'bibliography_template' => '{{reference}}', + + 'reference_tagname' => 'span', + 'missing_reference' => '(missing reference)', + + 'details_link_class' => 'details', + + 'query' => '@*', + + 'cite_class' => 'citation', + + 'type_names' => { + 'article' => 'Journal Articles', + 'book' => 'Books', + 'incollection' => 'Book Chapters', + 'inproceedings' => 'Conference Articles', + 'thesis' => 'Theses', + 'mastersthesis' => 'Master\'s Theses', + 'phdthesis' => 'PhD Theses', + 'manual' => 'Manuals', + 'techreport' => 'Technical Reports', + 'misc' => 'Miscellaneous', + 'unpublished' => 'Unpublished', + }, + 'type_aliases' => { + 'phdthesis' => 'thesis', + 'mastersthesis' => 'thesis', + }, + 'type_order' => [], + + 'month_names' => nil + + }.freeze + + class << self + attr_reader :defaults + end + end +end diff --git a/_plugins/jekyll/scholar/generators/details.rb b/_plugins/jekyll/scholar/generators/details.rb new file mode 100644 index 0000000..b9e0f22 --- /dev/null +++ b/_plugins/jekyll/scholar/generators/details.rb @@ -0,0 +1,68 @@ +module Jekyll + class Scholar + + class Details < Page + include Scholar::Utilities + + def initialize(site, base, dir, entry) + @site, @base, @dir, @entry = site, base, dir, entry + + @config = Scholar.defaults.merge(site.config['scholar'] || {}) + + # Specify a temporary filename for now based upon the citation key. Jekyll + # will modify this according to the URL template below + @name = entry.key.to_s.gsub(/[:\s]+/, '_') + @name << '.html' + + process(@name) + read_yaml(File.join(base, '_layouts'), config['details_layout']) + + data.merge!(reference_data(entry)) + data['title'] = data['entry']['title'] if data['entry'].has_key?('title') + end + + def url + # Reuse the logic in the utilities module for deciding URLs + details_path_for(@entry) + end + end + + class DetailsGenerator < Generator + include Scholar::Utilities + + safe true + priority :high + + attr_reader :config + + def generate(site) + @site, @config = site, Scholar.defaults.merge(site.config['scholar'] || {}) + + # Check for removed option and warn if it is set + if @config.include? 'use_raw_bibtex_entry' + Jekyll.logger.warn('Jekyll-scholar:', + 'Option `use_raw_bibtex_entry` is no longer supported') + end + + if generate_details? + entries.each do |entry| + details = Details.new(site, site.source, File.join('', details_path), entry) + details.render(site.layouts, site.site_payload) + details.write(site.dest) + + site.pages << details + + site.regenerator.add_dependency( + site.in_source_dir(details.path), + bibtex_path + ) + end + + end + end + + end + + + end +end diff --git a/_plugins/jekyll/scholar/plugins/italics.rb b/_plugins/jekyll/scholar/plugins/italics.rb new file mode 100644 index 0000000..d8bb10c --- /dev/null +++ b/_plugins/jekyll/scholar/plugins/italics.rb @@ -0,0 +1,13 @@ +module Jekyll + class Scholar + class Italics < BibTeX::Filter + def apply(value) + # Use of \g<1> pattern back-reference to allow for capturing nested {} groups. + # The first (outermost) capture of $1 is used. + value.to_s.gsub(/\\emph(\{(?:[^{}]|\g<1>)*\})/) { + "#{$1[1..-2]}" + } + end + end + end +end diff --git a/_plugins/jekyll/scholar/plugins/lowercase.rb b/_plugins/jekyll/scholar/plugins/lowercase.rb new file mode 100644 index 0000000..cdb53ea --- /dev/null +++ b/_plugins/jekyll/scholar/plugins/lowercase.rb @@ -0,0 +1,13 @@ +module Jekyll + class Scholar + class Lowercase < BibTeX::Filter + def apply(value) + # Use of \g<1> pattern back-reference to allow for capturing nested {} groups. + # The first (outermost) capture of $1 is used. + value.to_s.gsub(/\\lowercase(\{(?:[^{}]|\g<1>)*\})/) { + "#{$1[1..-2].downcase}" + } + end + end + end +end diff --git a/_plugins/jekyll/scholar/plugins/markdown_links.rb b/_plugins/jekyll/scholar/plugins/markdown_links.rb new file mode 100644 index 0000000..3bc3415 --- /dev/null +++ b/_plugins/jekyll/scholar/plugins/markdown_links.rb @@ -0,0 +1,25 @@ +# Contributed by @mfenner +# See https://github.com/inukshuk/jekyll-scholar/issues/30 + +require 'uri' + +URL_PATTERN = Regexp.compile([ + '\\\\href\\\\{([^\\\\}]+)\\\\}\\\\{([^\\\\}]+)\\\\}', + URI.regexp(['http', 'https', 'ftp']) +].join('|')) + +module Jekyll + class Scholar + class Markdown < BibTeX::Filter + def apply(value) + value.to_s.gsub(URL_PATTERN) { + if $1 + "[#{$2}](#{$1})" + else + "[#{$&}](#{$&})" + end + } + end + end + end +end diff --git a/_plugins/jekyll/scholar/plugins/smallcaps.rb b/_plugins/jekyll/scholar/plugins/smallcaps.rb new file mode 100644 index 0000000..b953f9e --- /dev/null +++ b/_plugins/jekyll/scholar/plugins/smallcaps.rb @@ -0,0 +1,13 @@ +module Jekyll + class Scholar + class Smallcaps < BibTeX::Filter + def apply(value) + # Use of \g<1> pattern back-reference to allow for capturing nested {} groups. + # The first (outermost) capture of $1 is used. + value.to_s.gsub(/\\textsc(\{(?:[^{}]|\g<1>)*\})/) { + "#{$1[1..-2]}" + } + end + end + end +end diff --git a/_plugins/jekyll/scholar/plugins/superscript.rb b/_plugins/jekyll/scholar/plugins/superscript.rb new file mode 100644 index 0000000..721ba4e --- /dev/null +++ b/_plugins/jekyll/scholar/plugins/superscript.rb @@ -0,0 +1,13 @@ +module Jekyll + class Scholar + class Superscript < BibTeX::Filter + def apply(value) + # Use of \g<1> pattern back-reference to allow for capturing nested {} groups. + # The first (outermost) capture of $1 is used. + value.to_s.gsub(/\\textsuperscript(\{(?:[^{}]|\g<1>)*\})/) { + "#{$1[1..-2]}" + } + end + end + end +end diff --git a/_plugins/jekyll/scholar/plugins/textit.rb b/_plugins/jekyll/scholar/plugins/textit.rb new file mode 100644 index 0000000..3ecca91 --- /dev/null +++ b/_plugins/jekyll/scholar/plugins/textit.rb @@ -0,0 +1,13 @@ +module Jekyll + class Scholar + class Textit < BibTeX::Filter + def apply(value) + # Use of \g<1> pattern back-reference to allow for capturing nested {} groups. + # The first (outermost) capture of $1 is used. + value.to_s.gsub(/\\textit(\{(?:[^{}]|\g<1>)*\})/) { + "#{$1[1..-2]}" + } + end + end + end +end diff --git a/_plugins/jekyll/scholar/plugins/textregistered.rb b/_plugins/jekyll/scholar/plugins/textregistered.rb new file mode 100644 index 0000000..8b039a9 --- /dev/null +++ b/_plugins/jekyll/scholar/plugins/textregistered.rb @@ -0,0 +1,13 @@ +module Jekyll + class Scholar + class Textregistered < BibTeX::Filter + def apply(value) + # Use of \g<1> pattern back-reference to allow for capturing nested {} groups. + # The first (outermost) capture of $1 is used. + value.to_s.gsub(/\\textregistered/) { + "®" + } + end + end + end +end diff --git a/_plugins/jekyll/scholar/plugins/tiny.rb b/_plugins/jekyll/scholar/plugins/tiny.rb new file mode 100644 index 0000000..bd951ae --- /dev/null +++ b/_plugins/jekyll/scholar/plugins/tiny.rb @@ -0,0 +1,13 @@ +module Jekyll + class Scholar + class Tiny < BibTeX::Filter + def apply(value) + # Use of \g<1> pattern back-reference to allow for capturing nested {} groups. + # The first (outermost) capture of $1 is used. + value.to_s.gsub(/\\tiny(\{(?:[^{}]|\g<1>)*\})/) { + "#{$1[1..-2]}" + } + end + end + end +end diff --git a/_plugins/jekyll/scholar/tags/bibliography.rb b/_plugins/jekyll/scholar/tags/bibliography.rb new file mode 100644 index 0000000..2eb8e44 --- /dev/null +++ b/_plugins/jekyll/scholar/tags/bibliography.rb @@ -0,0 +1,82 @@ +module Jekyll + class Scholar + class BibliographyTag < Liquid::Tag + include Scholar::Utilities + + def initialize(tag_name, arguments, tokens) + super + + @config = Scholar.defaults.dup + + optparse(arguments) + end + + def render(context) + set_context_to context + + # Add bibtex files to dependency tree. + update_dependency_tree + + items = cited_entries + + if group? + groups = group(items) + bibliography = render_groups(groups) + else + items = items[offset..max] if limit_entries? + bibliography = render_items(items) + end + + bibliography + end + + def render_groups(groups) + def group_renderer(groupsOrItems,keys,order,tags) + if keys.count == 0 + csl_renderer(true) + render_items(groupsOrItems) + else + groupsOrItems + .sort do |e1,e2| + if (order.first || group_order.last) =~ /^(desc|reverse)/i + group_compare(keys.first,e2[0],e1[0]) + else + group_compare(keys.first,e1[0],e2[0]) + end + end + .map do |e| + bibhead = content_tag(tags.first || group_tags.last, + group_name(keys.first, e[0]), + :class => config['bibliography_class']) + bibentries = group_renderer(e[1], keys.drop(1), order.drop(1), tags.drop(1)) + bibhead + "\n" + bibentries + end + .join("\n") + end + end + group_renderer(groups,group_keys,group_order,group_tags) + end + + def render_items(items) + bibliography = items.compact.each_with_index.map { |entry, index| + reference = bibliography_tag(entry, index + 1) + + if generate_details? && generate_details_link? + reference << link_to(details_link_for(entry), + config['details_link'], :class => config['details_link_class']) + end + + content_tag config['bibliography_item_tag'], reference, config['bibliography_item_attributes'] + }.join("\n") + + content_tag bibliography_list_tag, bibliography, + { :class => config['bibliography_class'] }.merge(config['bibliography_list_attributes']) + + end + + end + + end +end + +Liquid::Template.register_tag('bibliography', Jekyll::Scholar::BibliographyTag) diff --git a/_plugins/jekyll/scholar/tags/bibliography_count.rb b/_plugins/jekyll/scholar/tags/bibliography_count.rb new file mode 100644 index 0000000..afe1a53 --- /dev/null +++ b/_plugins/jekyll/scholar/tags/bibliography_count.rb @@ -0,0 +1,29 @@ +module Jekyll + class Scholar + + class BibliographyCountTag < Liquid::Tag + include Scholar::Utilities + + def initialize(tag_name, arguments, tokens) + super + + @config = Scholar.defaults.dup + + optparse(arguments) + end + + def render(context) + set_context_to context + + # Add bibtex files to dependency tree. + update_dependency_tree + + cited_entries.size + end + + end + + end +end + +Liquid::Template.register_tag('bibliography_count', Jekyll::Scholar::BibliographyCountTag) diff --git a/_plugins/jekyll/scholar/tags/bibtex.rb b/_plugins/jekyll/scholar/tags/bibtex.rb new file mode 100644 index 0000000..9d8454f --- /dev/null +++ b/_plugins/jekyll/scholar/tags/bibtex.rb @@ -0,0 +1,26 @@ +module Jekyll + class Scholar + class BibTeXTag < Liquid::Block + include Scholar::Utilities + + def initialize(tag_name, arguments, tokens) + super + + @config = Scholar.defaults.dup + @keys, arguments = split_arguments arguments + + optparse(arguments) + end + + def render(context) + set_context_to context + + BibTeX.parse(super, bibtex_options).map { |entry| + reference_tag entry + }.join("\n") + end + end + end +end + +Liquid::Template.register_tag('bibtex', Jekyll::Scholar::BibTeXTag) diff --git a/_plugins/jekyll/scholar/tags/cite.rb b/_plugins/jekyll/scholar/tags/cite.rb new file mode 100644 index 0000000..a210792 --- /dev/null +++ b/_plugins/jekyll/scholar/tags/cite.rb @@ -0,0 +1,28 @@ +module Jekyll + class Scholar + + class CiteTag < Liquid::Tag + include Scholar::Utilities + + attr_reader :pages + + def initialize(tag_name, arguments, tokens) + super + + @config = Scholar.defaults.dup + @keys, arguments = split_arguments(arguments) + + optparse(arguments) + end + + def render(context) + set_context_to context + cite keys + end + + end + + end +end + +Liquid::Template.register_tag('cite', Jekyll::Scholar::CiteTag) diff --git a/_plugins/jekyll/scholar/tags/cite_details.rb b/_plugins/jekyll/scholar/tags/cite_details.rb new file mode 100644 index 0000000..2cc6e37 --- /dev/null +++ b/_plugins/jekyll/scholar/tags/cite_details.rb @@ -0,0 +1,27 @@ +module Jekyll + class Scholar + + class CiteDetailsTag < Liquid::Tag + include Scholar::Utilities + + def initialize(tag_name, arguments, tokens) + super + + @config = Scholar.defaults.dup + @keys, arguments = split_arguments arguments + + optparse(arguments) + end + + def render(context) + set_context_to context + keys.map { |key| + cite_details key, text + }.join("\n") + end + end + + end +end + +Liquid::Template.register_tag('cite_details', Jekyll::Scholar::CiteDetailsTag) diff --git a/_plugins/jekyll/scholar/tags/details_link.rb b/_plugins/jekyll/scholar/tags/details_link.rb new file mode 100644 index 0000000..9f88cc7 --- /dev/null +++ b/_plugins/jekyll/scholar/tags/details_link.rb @@ -0,0 +1,25 @@ +module Jekyll + class Scholar + + class DetailsLinkTag < Liquid::Tag + include Scholar::Utilities + + def initialize(tag_name, arguments, tokens) + super + + @config = Scholar.defaults.dup + @keys, arguments = split_arguments arguments + + optparse(arguments) + end + + def render(context) + set_context_to context + details_link keys[0] + end + end + + end +end + +Liquid::Template.register_tag('details_link', Jekyll::Scholar::DetailsLinkTag) diff --git a/_plugins/jekyll/scholar/tags/nocite.rb b/_plugins/jekyll/scholar/tags/nocite.rb new file mode 100644 index 0000000..3d5c2fd --- /dev/null +++ b/_plugins/jekyll/scholar/tags/nocite.rb @@ -0,0 +1,28 @@ +module Jekyll + class Scholar + + class NoCiteTag < Liquid::Tag + include Scholar::Utilities + + attr_reader :pages + + def initialize(tag_name, arguments, tokens) + super + + @config = Scholar.defaults.dup + @keys, arguments = split_arguments(arguments) + + optparse(arguments) + end + + def render(context) + set_context_to context + nocite keys + end + + end + + end +end + +Liquid::Template.register_tag('nocite', Jekyll::Scholar::NoCiteTag) diff --git a/_plugins/jekyll/scholar/tags/quote.rb b/_plugins/jekyll/scholar/tags/quote.rb new file mode 100644 index 0000000..4a340b6 --- /dev/null +++ b/_plugins/jekyll/scholar/tags/quote.rb @@ -0,0 +1,36 @@ +module Jekyll + class Scholar + + class QuoteTag < Liquid::Block + include Scholar::Utilities + + attr_reader :pages + + def initialize(tag_name, arguments, tokens) + super + + @config = Scholar.defaults.dup + @keys, arguments = split_arguments arguments + + optparse(arguments) + end + + def render(context) + set_context_to context + + quote = super.strip.gsub(/\n\n/, '

').gsub(/\n/, '
') + quote = content_tag :p, quote + + citation = cite keys + + quote << content_tag(:cite, citation) + + content_tag :blockquote, quote + end + + end + + end +end + +Liquid::Template.register_tag('quote', Jekyll::Scholar::QuoteTag) diff --git a/_plugins/jekyll/scholar/tags/reference.rb b/_plugins/jekyll/scholar/tags/reference.rb new file mode 100644 index 0000000..d5e3461 --- /dev/null +++ b/_plugins/jekyll/scholar/tags/reference.rb @@ -0,0 +1,27 @@ +module Jekyll + class Scholar + + class ReferenceTag < Liquid::Tag + include Scholar::Utilities + + def initialize(tag_name, arguments, tokens) + super + + @config = Scholar.defaults.dup + @keys, arguments = split_arguments arguments + + optparse(arguments) + end + + def render(context) + set_context_to context + keys.map { |key| + reference_tag bibliography[key] + }.join("\n") + end + end + + end +end + +Liquid::Template.register_tag('reference', Jekyll::Scholar::ReferenceTag) diff --git a/_plugins/jekyll/scholar/utilities.rb b/_plugins/jekyll/scholar/utilities.rb new file mode 100644 index 0000000..3b4a284 --- /dev/null +++ b/_plugins/jekyll/scholar/utilities.rb @@ -0,0 +1,880 @@ +module Jekyll + class Scholar + require 'date' + + # Load styles into static memory. + # They should be thread safe as long as they are + # treated as being read-only. + STYLES = {} + + LOCALES = {} + + # Utility methods used by several Scholar plugins. The methods in this + # module may depend on the presence of #config, #bibtex_files, and + # #site readers + module Utilities + + + attr_reader :config, :site, :context, :prefix, :text, :offset, :max + + + def split_arguments(arguments) + + tokens = arguments.strip.split(/\s+/) + + args = tokens.take_while { |a| !a.start_with?('-') } + opts = (tokens - args).join(' ') + + [args, opts] + end + + def optparse(arguments) + return if arguments.nil? || arguments.empty? + + parser = OptionParser.new do |opts| + + opts.on('-c', '--cited') do |cited| + @cited = true + end + + opts.on('-C', '--cited_in_order') do |cited| + @cited, @skip_sort = true, true + end + + opts.on('--clear') do |cited| + @clear = true + end + + opts.on('-r', '--remove_duplicates [MATCH_FIELDS]') do |match_field| + @remove_duplicates = true + @match_fields = match_field.split(/,\s+/) if not match_field.nil? + end + + opts.on('-A', '--suppress_author') do |cited| + @suppress_author = true + end + + opts.on('-f', '--file FILE') do |file| + @bibtex_files ||= [] + @bibtex_files << file + end + + opts.on('-q', '--query QUERY') do |query| + @query = query + end + + opts.on('-h', '--bibliography_list_tag TAG') do |tag| + @bibliography_list_tag = tag + end + + opts.on('-p', '--prefix PREFIX') do |prefix| + @prefix = prefix + end + + opts.on('-t', '--text TEXT') do |text| + @text = text + end + + opts.on('-l', '--locator LOCATOR') do |locator| + locators << locator + end + + opts.on('-L', '--label LABEL') do |label| + labels << label + end + + opts.on('-o', '--offset OFFSET') do |offset| + @offset = offset.to_i + end + + opts.on('-m', '--max MAX') do |max| + @max = max.to_i + end + + opts.on('-s', '--style STYLE') do |style| + @style = style + end + + opts.on('-g', '--group_by GROUP') do |group_by| + @group_by = group_by + end + + opts.on('-G', '--group_order ORDER') do |group_order| + self.group_order = group_order + end + + opts.on('-O', '--type_order ORDER') do |type_order| + @group_by = type_order + end + + opts.on('-T', '--template TEMPLATE') do |template| + @bibliography_template = template + end + end + + argv = arguments.split(/(\B-[cCfhqptTsgGOlLomAr]|\B--(?:cited(_in_order)?|clear|bibliography_list_tag|file|query|prefix|text|style|group_(?:by|order)|type_order|template|locator|label|offset|max|suppress_author|remove_duplicates|))/) + + parser.parse argv.map(&:strip).reject(&:empty?) + end + + def bibliography_list_tag + if @bibliography_list_tag.nil? + config['bibliography_list_tag'] + else + @bibliography_list_tag + end + end + + def allow_locale_overrides? + !!config['allow_locale_overrides'] + end + + + def match_fields + @match_fields ||= [] + end + + def locators + @locators ||= [] + end + + def labels + @labels ||= [] + end + + def bibtex_files + if config['bibliography'].include? '*' + @bibtex_files ||= Dir.glob(File.join(config["source"], config['bibliography'])).collect do |f| + Pathname(f).relative_path_from(Pathname(config['source'])).to_s + end + end + @bibtex_files ||= [config['bibliography']] + end + + # :nodoc: backwards compatibility + def bibtex_file + bibtex_files[0] + end + + def bibtex_options + @bibtex_options ||= + (config['bibtex_options'] || {}).symbolize_keys + end + + def bibtex_filters + config['bibtex_filters'] ||= [] + end + + def raw_bibtex_filters + config['raw_bibtex_filters'] ||= [] + end + + def bibtex_paths + bibtex_files.map { |file| + interpolated_file = interpolate file + extend_path interpolated_file + } + end + + # :nodoc: backwards compatibility + def bibtex_path + bibtex_paths[0] + end + + def bibliography + paths = bibtex_paths + + # Clear @bibliography if sources change! See #282 + unless @paths.nil? || @paths == paths + @bibliography = nil + end + + unless @bibliography + @bibliography = BibTeX::Bibliography.parse( + paths.reduce('') { |s, p| s << IO.read(p) }, + bibtex_options + ) + + @paths = paths + + @bibliography.replace_strings if replace_strings? + @bibliography.join if join_strings? && replace_strings? + + # Remove duplicate entries + @bibliography.uniq!(*match_fields) if remove_duplicates? + end + + @bibliography + end + + def bibliography_stale? + end + + + def query + interpolate @query + end + + def entries + sort bibliography[query || config['query']].select { |x| x.instance_of? BibTeX::Entry} + end + + def offset + @offset ||= 0 + end + + def max + @max.nil? ? -1 : @max + offset - 1 + end + + def limit_entries? + !offset.nil? || !max.nil? + end + + def sort(unsorted) + return unsorted if skip_sort? + + sorted = unsorted.sort do |e1, e2| + sort_keys + .map.with_index do |key, idx| + v1 = e1[key].nil? ? BibTeX::Value.new : e1[key] + v2 = e2[key].nil? ? BibTeX::Value.new : e2[key] + if (sort_order[idx] || sort_order.last) =~ /^(desc|reverse)/i + v2 <=> v1 + else + v1 <=> v2 + end + end + .find { |c| c != 0 } || 0 + end + + sorted + end + + def sort_keys + return @sort_keys unless @sort_keys.nil? + + @sort_keys = Array(config['sort_by']) + .map { |key| key.to_s.split(/\s*,\s*/) } + .flatten + .map { |key| key == 'month' ? 'month_numeric' : key } + end + + def sort_order + return @sort_order unless @sort_order.nil? + + @sort_order = Array(config['order']) + .map { |key| key.to_s.split(/\s*,\s*/) } + .flatten + end + + def group_by + @group_by = interpolate(@group_by) || config['group_by'] + end + + def group? + group_by != 'none' + end + + def group(ungrouped) + def grouper(items, keys, order) + groups = items.group_by do |item| + group_value(keys.first, item) + end + + if keys.count == 1 + groups + else + groups.merge(groups) do |key, items| + grouper(items, keys.drop(1), order.drop(1)) + end + end + end + + grouper(ungrouped, group_keys, group_order) + end + + + def group_keys + return @group_keys unless @group_keys.nil? + + @group_keys = Array(group_by) + .map { |key| key.to_s.split(/\s*,\s*/) } + .flatten + .map { |key| key == 'month' ? 'month_numeric' : key } + end + + def group_order + self.group_order = config['group_order'] if @group_order.nil? + @group_order + end + + def group_order=(value) + @group_order = Array(value) + .map { |key| key.to_s.split(/\s*,\s*/) } + .flatten + end + + def group_compare(key,v1,v2) + case key + when 'type' + o1 = type_order.find_index(v1) + o2 = type_order.find_index(v2) + if o1.nil? && o2.nil? + 0 + elsif o1.nil? + 1 + elsif o2.nil? + -1 + else + o1 <=> o2 + end + else + v1 <=> v2 + end + end + + def group_value(key,item) + case key + when 'type' + type_aliases[item.type.to_s] || item.type.to_s + else + value = item[key] + if value.numeric? + value.to_i + elsif value.date? + value.to_date + else + value.to_s + end + end + end + + def group_tags + return @group_tags unless @group_tags.nil? + + @group_tags = Array(config['bibliography_group_tag']) + .map { |key| key.to_s.split(/\s*,\s*/) } + .flatten + end + + def group_name(key,value) + case key + when 'type' + type_names[value] || value.to_s + when 'month_numeric' + month_names[value] || "(unknown)" + else + value.to_s + end + end + + def type_order + @type_order ||= config['type_order'] + end + + def type_aliases + @type_aliases ||= Scholar.defaults['type_aliases'].merge(config['type_aliases']) + end + + def type_names + @type_names ||= Scholar.defaults['type_names'].merge(config['type_names']) + end + + def month_names + return @month_names unless @month_names.nil? + + @month_names = config['month_names'].nil? ? Date::MONTHNAMES : [nil] + config['month_names'] + end + + def remove_duplicates? + @remove_duplicates || config['remove_duplicates'] + end + + def suppress_author? + !!@suppress_author + end + + def repository? + !config['repository'].nil? && !config['repository'].empty? + end + + def repository + @repository ||= load_repository + end + + def load_repository + repo = Hash.new { |h,k| h[k] = {} } + + return repo unless repository? + + # ensure that the base directory format is literally + # the same as the entries that are in the directory + base = Dir[site.source][0] + + Dir[File.join(site.source, repository_path, '**/*')].each do |path| + parts = Pathname(path).relative_path_from(Pathname(File.join(base, repository_path))) + parts = parts.to_path.split(repository_file_delimiter, 2) + repo[parts[0]][parts[1]] = + Pathname(path).relative_path_from(Pathname(base)) + end + + repo + end + + def repository_path + config['repository'] + end + + def repository_file_delimiter + config['repository_file_delimiter'] + end + + def replace_strings? + config['replace_strings'] + end + + def join_strings? + config['join_strings'] + end + + def cited_only? + !!@cited + end + + def clear? + !!@clear + end + + def skip_sort? + @skip_sort || config['sort_by'] == 'none' + end + + def extend_path(name) + if name.nil? || name.empty? + name = config['bibliography'] + end + + # Return as is if it is an absolute path + # Improve by using Pathname from stdlib? + return name if name.start_with?('/') && File.exist?(name) + + name = File.join scholar_source, name + name << '.bib' if File.extname(name).empty? && !File.exist?(name) + name + end + + def scholar_source + source = config['source'] + + # Improve by using Pathname from stdlib? + return source if source.start_with?('/') && File.exist?(source) + + File.join site.source, source + end + + def relative + config['relative'] + end + + def reference_tag(entry, index = nil) + return missing_reference unless entry + + entry = entry.convert(*bibtex_filters) unless bibtex_filters.empty? + reference = render_bibliography entry, index + + content_tag reference_tagname, reference, + :id => [prefix, entry.key].compact.join('-') + end + + def style + interpolate(@style)|| config['style'] + end + + def missing_reference + config['missing_reference'] + end + + def reference_tagname + config['reference_tagname'] || :span + end + + def bibliography_template + @bibliography_template || config['bibliography_template'] + end + + def liquid_template + return @liquid_template if @liquid_template + Liquid::Template.register_filter(Jekyll::Filters) + + tmp = bibliography_template + + case + when tmp.nil?, tmp.empty? + tmp = '{{reference}}' + when site.layouts.key?(tmp) + tmp = site.layouts[tmp].content + end + + @liquid_template = Liquid::Template.parse(tmp) + end + + def bibliography_tag(entry, index) + return missing_reference unless entry + + liquid_template.render( + reference_data(entry,index) + .merge(site.site_payload) + .merge({ + 'index' => index, + 'page' => context.registers[:page], + 'details' => details_link_for(entry) + }), + { + :registers => context.registers, + :filters => [Jekyll::Filters] + }) + end + + def reference_data(entry, index = nil) + { + 'entry' => liquidify(entry), + 'reference' => reference_tag(entry, index), + 'key' => entry.key, + 'type' => entry.type.to_s, + 'link' => repository_link_for(entry), + 'links' => repository_links_for(entry) + } + end + + def liquidify(entry) + e = {} + + e['key'] = entry.key + e['type'] = entry.type.to_s + + conv_opts = { quotes: config['bibtex_quotes'] } + if !raw_bibtex_filters.empty? + conv_opts[:filter] = *raw_bibtex_filters + end + + if entry.field_names(config['bibtex_skip_fields']).empty? + e['bibtex'] = entry.to_s(conv_opts) + else + tmp = entry.dup + + config['bibtex_skip_fields'].each do |name| + tmp.delete name if tmp.field?(name) + end + + e['bibtex'] = tmp.to_s(conv_opts) + end + + #e['raw_bibtex'] = "{%raw%}#{e['bibtex']}{%endraw%}" + + entry.fields.each do |key, value| + value = value.convert(*bibtex_filters) unless bibtex_filters.empty? + e[key.to_s] = value.to_s + + if value.is_a?(BibTeX::Names) + e["#{key}_array"] = arr = [] + value.each.with_index do |name, idx| + parts = {} + name.each_pair do |k, v| + e["#{key}_#{idx}_#{k}"] = v.to_s + parts[k.to_s] = v.to_s + end + arr << parts + end + end + end + + e + end + + def generate_details_link? + if !config['details_link'] then + return false + end + return true + end +# + def generate_details? + site.layouts.key?(File.basename(config['details_layout'], '.html')) + end + + def repository_link_for(entry, base = base_url) + name = entry.key.to_s.dup + name.gsub!(/[:\s]+/, '_') + links = repository[name] + url = links['pdf'] || links['ps'] + + return unless url + + File.join(base, url) + end + + def repository_links_for(entry, base = base_url) + name = entry.key.to_s.dup + name.gsub!(/[:\s]+/, '_') + Hash[repository[name].map { |ext, url| + [ext, File.join(base, url)] + }] + end + + def details_link_for(entry, base = base_url) + File.join(base, details_path_for(entry)) + end + + def details_path_for(entry) + # Expand the details_permalink template into the complete URL for this entry. + + # First generate placeholders for all items in the bibtex entry + url_placeholders = {} + entry.fields.each_pair do |k, v| + value = v.to_s.dup + value = Jekyll::Utils::slugify(value, :mode => 'pretty') unless k == :doi + url_placeholders[k] = value + end + # Maintain the same URLs are previous versions of jekyll-scholar + # by replicating the way that it processed the key. + url_placeholders[:key] = entry.key.to_s.gsub(/[:\s]+/, '_') + url_placeholders[:details_dir] = details_path + + # Autodetect the appropriate file extension based upon the site config, + # using the same rules as previous versions of jekyll-scholar. Users can + # override these settings by defining a details_permalink + # without the :extension field. + if (site.config['permalink'] == 'pretty') || (site.config['permalink'].end_with? '/') + url_placeholders[:extension] = '/' + else + url_placeholders[:extension] = '.html' + end + + # Overwrite 'doi' key with the citation key if DOI field is empty or missing + if !entry.has_field?('doi') || entry.doi.empty? + url_placeholders[:doi] = url_placeholders[:key] + end + + URL.new( + template: config['details_permalink'], + placeholders: url_placeholders + ).to_s + end + + def base_url + @base_url ||= ( + site.config['baseurl'] || site.config['base_url'] || '' + ).to_s + end + + def details_path + config['details_dir'] + end + + def csl_renderer(force = false) + return @csl_renderer if @csl_renderer && !force + + @csl_renderer = CiteProc::Ruby::Renderer.new :format => 'html', + :style => style, :locale => config['locale'] + end + + def render_citation(items) + csl_renderer.render items.zip(locators.zip(labels)).map { |entry, (locator, label)| + cited_keys << entry.key + cited_keys.uniq! + + item = citation_item_for entry, citation_number(entry.key) + item.locator = locator + item.label = label unless label.nil? + + item + }, styles(style).citation + end + + def render_bibliography(entry, index = nil) + begin + original_locale = csl_renderer.locale + csl_renderer.locale = locales(entry.language) + rescue + # Locale failed to load; just use original one! + end if allow_locale_overrides? && + entry['language'] != csl_renderer.locale.language + + csl_renderer.render citation_item_for(entry, index), + styles(style).bibliography + ensure + csl_renderer.locale = original_locale unless original_locale.nil? + end + + def citation_item_for(entry, citation_number = nil) + CiteProc::CitationItem.new id: entry.id do |c| + c.data = CiteProc::Item.new entry.to_citeproc + c.data[:'citation-number'] = citation_number + c.data.suppress! 'author' if suppress_author? + end + end + + def cited_keys + context['cited'] = context.environments.first['page']['cited'] ||= [] + end + + def citation_number(key) + (context['citation_numbers'] ||= {})[key] ||= cited_keys.length + end + + def link_target_for(key) + "#{relative}##{[prefix, key].compact.join('-')}" + end + + def cite(keys) + items = keys.map do |key| + if bibliography.key?(key) + entry = bibliography[key] + entry = entry.convert(*bibtex_filters) unless bibtex_filters.empty? + else + return missing_reference + end + end + + link_to link_target_for(keys[0]), render_citation(items), {class: config['cite_class']} + end + + def nocite(keys) + items = keys.map do |key| + if bibliography.key?(key) + entry = bibliography[key] + cited_keys << entry.key + cited_keys.uniq! + else + return missing_reference + end + end + end + + def cite_details(key, text) + if bibliography.key?(key) + link_to details_link_for(bibliography[key]), text || config['details_link'] + else + missing_reference + end + end + + def details_link(key) + if bibliography.key?(key) + details_link_for(bibliography[key]) + else + raise Exception.new "Could not find entry for key '%s'" % key + end + end + + def content_tag(name, content_or_attributes, attributes = {}) + if content_or_attributes.is_a?(Hash) + content, attributes = nil, content_or_attributes + else + content = content_or_attributes + end + + attributes = attributes.map { |k,v| %Q(#{k}="#{v}") } + + if content.nil? + "<#{[name, attributes].flatten.compact.join(' ')}/>" + else + "<#{[name, attributes].flatten.compact.join(' ')}>#{content}" + end + end + + def link_to(href, content, attributes = {}) + content_tag :a, content || href, attributes.merge(:href => href) + end + + def cited_references + context && cited_keys + end + + def keys + # De-reference keys (in case they are variables) + # We need to do this every time, to support for loops, + # where the context can change for each invocation. + Array(@keys).map do |key| + context[key] || key + end + end + + def interpolate(string) + return unless string + + string.gsub(/{{\s*([\w\.]+)\s*}}/) do |match| + context[$1] || match + end + end + + def set_context_to(context) + @context, @site, page, = context, *context.registers.values_at(:site, :page) + config.merge!(site.config['scholar'] || {}) + config.merge!(page['scholar'] || {}) + self + end + + def load_style(uri) + begin + style = CSL::Style.load uri + rescue CSL::ParseError => error + # Try to resolve local style paths + # relative to Jekyll's source directory + site_relative_style = File.join(site.source, uri) + + raise error unless File.exist?(site_relative_style) + style = CSL::Style.load site_relative_style + end + + if style.independent? + style + else + style.independent_parent + end + end + + def styles(style) + STYLES[style] ||= load_style(style) + end + + def locales(lang) + LOCALES[lang] ||= CSL::Locale.load(lang) + end + + def update_dependency_tree + # Add bibtex files to dependency tree + if context.registers[:page] and context.registers[:page].key? "path" + bibtex_paths.each do |bibtex_path| + site.regenerator.add_dependency( + site.in_source_dir(context.registers[:page]["path"]), + bibtex_path + ) + end + end + end + + def cited_entries + items = entries + if cited_only? + items = if skip_sort? + cited_references.uniq.map do |key| + items.detect { |e| e.key == key } + end + else + entries.select do |e| + cited_references.include? e.key + end + end + + # See #90 + cited_keys.clear if clear? + end + + items + end + end + + end +end diff --git a/_plugins/jekyll/scholar/version.rb b/_plugins/jekyll/scholar/version.rb new file mode 100644 index 0000000..f8a1d2d --- /dev/null +++ b/_plugins/jekyll/scholar/version.rb @@ -0,0 +1,5 @@ +module Jekyll + class Scholar + VERSION = '7.1.3'.freeze + end +end diff --git a/_plugins/pseudocode.rb b/_plugins/pseudocode.rb new file mode 100644 index 0000000..e0a36a7 --- /dev/null +++ b/_plugins/pseudocode.rb @@ -0,0 +1,181 @@ +require 'jekyll' +require 'liquid' +require 'rexml/document' + +module Jekyll + class PseudocodeBlock < Liquid::Block + @@number = 0 + + def initialize(tag_name, text, tokens) + super + end + + def render(context) + content = super + @@number += 1 + content = process_pseudocode(content) + "

#{content}
" + end + + def process_pseudocode(content) + open_divs = [] + indent_level = 0 + content_lines = content.strip.split("\n") + html_lines = [] + + call_pattern = /\\CALL\{(.*?)\}\{(.*?)\}/ + + replace_calls = lambda do |statement| + statement.gsub(call_pattern) { |match| "#{Regexp.last_match(1)}(#{Regexp.last_match(2)})" } + end + + wrap_math_expressions = lambda do |statement| + statement.gsub(/\$(.*?)\$/, '\\(\1\\)') + end + + process_control_statement = lambda do |keyword, condition| + condition = wrap_math_expressions.call(condition) + additional_keyword = keyword == "if" ? "then" : "do" + if keyword == "for" + condition = condition.gsub(/\\TO/, 'to') + end + "
#{keyword.downcase} (#{condition}) #{additional_keyword}" + end + + content_lines.each do |line| + stripped_line = line.strip + + case stripped_line + when /\\begin{algorithm}/ + html_lines << "
" + open_divs << 'algorithm' + when /\\end{algorithm}/ + if open_divs.last == 'algorithm' + html_lines << "
" + open_divs.pop + end + when /\\caption{(.*?)}/ + caption = stripped_line.match(/\\caption{(.*?)}/)[1] + html_lines[-1] = "
Algorithm #{caption}
" + when /\\begin{algorithmic}/ + html_lines << "
" + open_divs << 'algorithmic' + when /\\end{algorithmic}/ + if open_divs.last == 'algorithmic' + html_lines << "
" + open_divs.pop + end + when /\\PROCEDURE{(.*?)}{(.*?)}/ + procedure_name = stripped_line.match(/\\PROCEDURE{(.*?)}{(.*?)}/)[1] + params = stripped_line.match(/\\PROCEDURE{(.*?)}{(.*?)}/)[2] + params = wrap_math_expressions.call(params) + html_lines << "
procedure #{procedure_name}(#{params})" + open_divs << 'procedure' + indent_level += 1 + when /\\ENDPROCEDURE/ + if open_divs.last == 'procedure' + indent_level -= 1 + html_lines << "
end procedure
" + open_divs.pop + end + when /\\IF{(.*?)}/ + condition = stripped_line.match(/\\IF{(.*?)}/)[1] + statement = process_control_statement.call('if', condition) + html_lines << statement + open_divs << 'if' + indent_level += 1 + when /\\ENDIF/ + if open_divs.last == 'if' + indent_level -= 1 + html_lines << "
end if
" + open_divs.pop + end + when /\\FOR{(.*?)}/ + loop = stripped_line.match(/\\FOR{(.*?)}/)[1] + statement = process_control_statement.call('for', loop) + html_lines << statement + open_divs << 'for' + indent_level += 1 + when /\\ENDFOR/ + if open_divs.last == 'for' + indent_level -= 1 + html_lines << "
end for
" + open_divs.pop + end + when /\\FOREACH{(.*?)}/ + loop = stripped_line.match(/\\FOREACH{(.*?)}/)[1] + statement = "
for each (#{wrap_math_expressions.call(loop)}) do" + html_lines << statement + open_divs << 'foreach' + indent_level += 1 + when /\\ENDFOREACH/ + if open_divs.last == 'foreach' + indent_level -= 1 + html_lines << "
end for each
" + open_divs.pop + end + when /\\WHILE{(.*?)}/ + condition = stripped_line.match(/\\WHILE{(.*?)}/)[1] + statement = process_control_statement.call('while', condition) + html_lines << statement + open_divs << 'while' + indent_level += 1 + when /\\ENDWHILE/ + if open_divs.last == 'while' + indent_level -= 1 + html_lines << "
end while
" + open_divs.pop + end + when /\\REPEAT{(.*?)}/ + condition = stripped_line.match(/\\REPEAT{(.*?)}/)[1] + statement = process_control_statement.call('repeat', condition) + html_lines << statement + open_divs << 'repeat' + indent_level += 1 + when /\\ENDREPEAT/ + if open_divs.last == 'repeat' + indent_level -= 1 + html_lines << "
end repeat
" + open_divs.pop + end + when /\\ELSEIF{(.*?)}/ + condition = stripped_line.match(/\\ELSEIF{(.*?)}/)[1] + statement = process_control_statement.call('elseif', condition) + html_lines << statement + if open_divs.last == 'if' + open_divs.pop + open_divs << 'elseif' + end + when /\\ELSE/ + html_lines << "
else" + if open_divs.last == 'if' || open_divs.last == 'elseif' + open_divs.pop + open_divs << 'else' + end + when /\\STATE{(.*?)}/ + statement = stripped_line.match(/\\STATE{(.*?)}/)[1] + statement = replace_calls.call(statement) + statement = wrap_math_expressions.call(statement) + html_lines << "
#{statement}
" + when /\\STATE\s+(.*)/ + statement = stripped_line.match(/\\STATE\s+(.*)/)[1] + statement = replace_calls.call(statement) + statement = wrap_math_expressions.call(statement) + html_lines << "
#{statement}
" + when /\\CALL{(.*?)}{(.*?)}/ + call = stripped_line.match(/\\CALL{(.*?)}{(.*?)}/)[1] + params = stripped_line.match(/\\CALL{(.*?)}{(.*?)}/)[2] + html_lines << "
#{call}(#{params})
" + else + html_lines << "
#{replace_calls.call(wrap_math_expressions.call(stripped_line))}
" + end + end + + open_divs.reverse_each { |div| html_lines << "
" } + + html_lines.join("\n") + end + end +end + +Liquid::Template.register_tag('pseudocode', Jekyll::PseudocodeBlock) diff --git a/assets/css/pseudocode.css b/assets/css/pseudocode.css new file mode 100644 index 0000000..bb1bdd9 --- /dev/null +++ b/assets/css/pseudocode.css @@ -0,0 +1,104 @@ +.ps-root { +font-family: CMR; +font-size: 20px; +font-weight: 100; +-webkit-font-smoothing: antialiased !important; +} + +.ps-root .ps-algorithm { +margin: .8em 0; +border-top: 3px solid #000; +border-bottom: 2px solid #000; +} + +.ps-root .ps-algorithm.with-caption { +border-bottom: 2px solid #000; +} + +.ps-root .ps-indent-1 { +margin-left: 1em; +} + +.ps-root .ps-indent-2 { +margin-left: 2em; +} + +.ps-root .ps-indent-3 { +margin-left: 3em; +} + +.ps-root .ps-indent-4 { +margin-left: 4em; +} + +.ps-root .ps-indent-5 { +margin-left: 5em; +} + + +.ps-root .ps-caption { +display: block; +border-bottom: 2px solid #000; +margin-top: 4px!important; +margin-bottom: 0.5em; +} + +.ps-root .MathJax, .ps-root .MathJax_CHTML { +text-indent: 0; +font-size: 1em !important; +} + +.ps-root .ps-line { +margin: 0; +padding: 0; +line-height: 1.2; +} + +.ps-root .ps-funcname { +font-family: CMR; +font-weight: 400; +font-style: normal; +text-transform: none; +} + +.ps-root .ps-keyword { +font-family: CMR; +font-weight: 700; +font-style: normal; +text-transform: none; +} + +.ps-root .ps-comment { +font-family: CMR; +font-weight: 400; +font-style: normal; +text-transform: none; +} + +.ps-root .ps-linenum { +font-size: .8em; +line-height: 1em; +width: 1.6em; +text-align: right; +display: inline-block; +position: relative; +padding-right: .3em; +} + +.ps-root .ps-algorithmic.with-linenum .ps-line.ps-code { +text-indent: -1.6em; +} + +.ps-root .ps-algorithmic.with-linenum .ps-line.ps-code > span { +text-indent: 0; +} + +.ps-root .ps-algorithmic.with-scopelines .ps-block { +border-left-style: solid; +border-left-width: .1em; +padding-left: .6em; +} + +.ps-root .ps-algorithmic.with-scopelines > .ps-block { +border-left: none; +} diff --git a/assets/css/style.css b/assets/css/style.css index 2e7f124..d460908 100644 --- a/assets/css/style.css +++ b/assets/css/style.css @@ -110,6 +110,10 @@ text-justify: inter-word; } +.ReducedBottom{ + margin-bottom: 2px; +} + .footerSize{ height: 30vh; width: 100%; @@ -159,5 +163,18 @@ li { font-size: 23px; text-align: Left; line-height: 125%; +} +.li3col { column-count: 3; + font-size: 18px; +} +figure { + text-align: center; +} +figcaption { + font-family: CMR; + font-size: 17px; + text-align: center; + line-height: 125%; + column-count: 1; } diff --git a/assets/images/graph1.png b/assets/images/graph1.png new file mode 100644 index 0000000..76af24f Binary files /dev/null and b/assets/images/graph1.png differ diff --git a/assets/images/graph2.png b/assets/images/graph2.png new file mode 100644 index 0000000..31db347 Binary files /dev/null and b/assets/images/graph2.png differ diff --git a/fabiodurastante.html b/fabiodurastante.html index af33355..6513e04 100644 --- a/fabiodurastante.html +++ b/fabiodurastante.html @@ -5,7 +5,8 @@ date: Ottobre 2024 --- -

Questa pagina è parte del documento sullo Scrivere una Tesi in Analisi Numerica. +

Questa pagina è parte del documento sullo Scrivere una Tesi in Analisi Numerica. I suggerimenti e le referenze contenute qui sono relative ad argomenti + che sto investigando al momento o di interesse attuale. Altre idee annesse o connesse a queste macroaree possono sicuramente essere discusse e valutate.

1   Algoritmi per l'Algebra Lineare in Ambiente HPC

@@ -28,14 +29,142 @@

Supercomputer Leonardo -
Fig.2 - Esempio di partizionamento del grafo di una matrice sparse e corrispondente partizionamento nei processi delel righe della matrice.
+
Fig.2 - Esempio di partizionamento del grafo di una matrice sparse e corrispondente partizionamento nei processi delle righe della matrice.

-Questo ambiente di lavoro richiede ora, oltre le operazioni di macchina necessarie a compiere operazioni come il prodotto matrice vettore \( \mathbf{y} \gets \alpha A \mathbf{x} + \beta \mathbf{y}\) o il prodotto scalare \( \langle \mathbf{x},\mathbf{y} \rangle \), delle operazioni di comunicazione necessarie a scambiare tra i diversi processi i dati su cui compiere le operazioni. La differenza in queste due procedure è che il calcolo è estremamente più efficiente della comunicazione. +Questo ambiente di lavoro richiede ora, oltre le operazioni di macchina necessarie a compiere operazioni come il prodotto matrice vettore \( \mathbf{y} \gets \alpha A \mathbf{x} + \beta \mathbf{y}\) o il prodotto scalare \( \langle \mathbf{x},\mathbf{y} \rangle \), delle operazioni di comunicazione necessarie a scambiare tra i diversi processi i dati su cui compiere le operazioni. La differenza in queste due procedure è che il calcolo è estremamente più efficiente della comunicazione.
+ +Ma dove avvengono le comunicazioni? Scriviamo la versione più semplice possibile del gradiente coniugato. +

+ +{% pseudocode %} +\begin{algorithm} +\caption{Standard Conjugate Gradient} +\begin{algorithmic} +\STATE Input: \(A \in \mathbb{R}^{n \times n}\) SPD, \(\mathbf{b} \in \mathbb{R}^n\), soluzione iniziale \(\mathbf{x}_0 \in \mathbb{R}^n\), tolleranza \(\varepsilon\) +\STATE Output: Soluzione approssimata \(\mathbf{x}\) + +\STATE $\mathbf{r}_0 \gets \mathbf{b} - A \mathbf{x}_0$ +\STATE $\mathbf{p}_0 \gets \mathbf{r}_0$ +\STATE $k \gets 0$ + +\WHILE{ Norma residuo maggiore di \(\varepsilon\) } + \STATE $\mathbf{v} = A \mathbf{p}_k$ + \STATE $\alpha_k \gets \frac{\mathbf{r}_k^T \mathbf{r}_k}{\mathbf{p}_k^T \mathbf{v}}$ + \STATE $\mathbf{x}_{k+1} \gets \mathbf{x}_k + \alpha_k \mathbf{p}_k$ + \STATE $\mathbf{r}_{k+1} \gets \mathbf{r}_k - \alpha_k \mathbf{v}$ + \STATE $\beta_k \gets \frac{\mathbf{r}_{k+1}^T \mathbf{r}_{k+1}}{\mathbf{r}_k^T \mathbf{r}_k}$ + \STATE $\mathbf{p}_{k+1} \gets \mathbf{r}_{k+1} + \beta_k \mathbf{p}_k$ + \STATE $k \gets k + 1$ +\ENDWHILE +\end{algorithmic} +\end{algorithm} +{% endpseudocode %} +

+In questa versione dell'algoritmo le comunicazioni avvengono nel calcolo del prodotto matrice vettore \( \mathbf{v} = A \mathbf{p}_k \) e nel calcolo dei prodotti scalari per ottenere \(\alpha_k\) e \(\beta_k\). +Per tentare di ridurre le comunicazioni possiamo "raccogliere insieme" più passi formando il cosìddetto \(s\)-step CG:

+{% pseudocode %} +\begin{algorithm} +\caption{s-step Conjugate Gradient Method} +\begin{algorithmic}[1] +\STATE {Input:} SPD \(A \in \mathbb{R}^{n \times n}\), \(\mathbf{b} \in \mathbb{R}^n\), soluzione iniziale \(\mathbf{x}_0 \in \mathbb{R}^n\), numero di step \(s\), tolleranza \(\varepsilon\) +\STATE {Output:} Solution vector \(\mathbf{x}\) + +\STATE $\mathbf{r}_0 \gets \mathbf{b} - A \mathbf{x}_0$ +\STATE $\mathbf{p}_0 \gets \mathbf{r}_0$ +\STATE $k \gets 0$ + +\WHILE{Non abbiamo raggiunto la convergenza} + \STATE % Generazione dei blocchi: Calcoliamo \(s\) passi alla volta + \FOR{$j = 0$ to $s-1$} + \STATE $\alpha_{k+j} \gets \frac{\mathbf{r}_{k+j}^T \mathbf{r}_{k+j}}{\mathbf{p}_{k+j}^T A \mathbf{p}_{k+j}}$ + \STATE $\mathbf{x}_{k+j+1} \gets \mathbf{x}_{k+j} + \alpha_{k+j} \mathbf{p}_{k+j}$ + \STATE $\mathbf{r}_{k+j+1} \gets \mathbf{r}_{k+j} - \alpha_{k+j} A \mathbf{p}_{k+j}$ + \IF{L'ultimo residuo ha norma minore di \(\varepsilon\)} + \STATE break + \ENDIF + \ENDFOR + + \STATE % Aggiorniamo le direzioni: + \STATE Formiamo i blocchi \(\mathbf{R}_k = [\mathbf{r}_k, \mathbf{r}_{k+1}, \dots, \mathbf{r}_{k+s-1}]\) and \(\mathbf{P}_k = [\mathbf{p}_k, \mathbf{p}_{k+1}, \dots, \mathbf{p}_{k+s-1}]\) + \STATE Ortogonalizziamo le colonne di \(\mathbf{R}_k\) e \(\mathbf{P}_k\) + + \STATE \FOR{$j = 0$ to $s-1$} + \STATE $\beta_{k+j} \gets \frac{\mathbf{r}_{k+j+1}^T \mathbf{r}_{k+j+1}}{\mathbf{r}_{k+j}^T \mathbf{r}_{k+j}}$ + \STATE $\mathbf{p}_{k+j+1} \gets \mathbf{r}_{k+j+1} + \beta_{k+j} \mathbf{p}_{k+j}$ + \ENDFOR + + \STATE $k \gets k + s$ +\ENDWHILE +\end{algorithmic} +\end{algorithm} +{% endpseudocode %} +

+Questa versione riduce il numero di comunicazioni, poiché riduce il numero di prodotti scalari, tuttavia paga di instabilità numerica a causa dell'ortogonalizzazione ritardata dopo \(s\) passi. +Trovare metodi per gestire queste instabilità, scegliere il passo e scrivere varianti del gradiente coniugato (e degli altri metodi di Krylov come GMRES o BiCGstab) è un'area di intensa ricerca. +Una tesi sull'argomento, a seconda del livello tra laurea triennale e magistrale si può focalizzare sullo studio delle proprietà matematica e +numeriche di queste varianti, la loro applicazione a problemi di interesse, aspetti implementativi all'interno della suite di librerie per il calcolo parallelo PSCToolkit, fino alla ricerca di +approcci e formulazioni alternative.
+Competenze necessarie: algebra lineare numerica, programmazione con MATLAB;
Competenze consigliate: calcolo parallelo;
+Corsi suggeriti: Calcolo Scientifico, Istituzioni di Analisi Numerica (se alla magistrale). +

+ + +{% bibliography --file bibliofabio %}

2   Modellistica e Algoritmi per le Reti Complesse

+

+L'ambito della ricerca in Reti Complesse si concentra sullo studio di sistemi costituiti da un elevato numero di elementi interconnessi (nodi) e dalle relazioni tra loro (archi), +con l'obiettivo di analizzare e comprendere la struttura e le dinamiche dei sistemi reali complessi. Le reti complesse si manifestano in una vasta gamma di contesti, come le reti +sociali, le reti biologiche (ad esempio, interazioni tra proteine), le reti di trasporto e le reti tecnologiche (come Internet). I modelli matematici usati per descriverle includono +il modello di rete casuale di Erdős-Rényi, le reti small-world di Watts-Strogatz e le reti a scala libera di Barabási-Albert, che descrivono come molte reti reali presentino nodi +altamente connessi (hub). L'analisi di reti complesse si avvale di algoritmi per rilevare comunità, analizzare la centralità dei nodi, trovare percorsi ottimali o modellare la diffusione +di informazioni o epidemie all'interno della rete. Questa ricerca ha applicazioni in campi quali la biologia, la sociologia, l'informatica, la fisica e l'economia, offrendo strumenti per +comprendere la struttura e il comportamento di sistemi complessi e interdipendenti. +

+ +
+ Rete Stradale di Pisa 1 + Rete Stradale di Pisa 1 +
Fig.3 - Esempio di un fenomeno di trasporto sulla rete stradale di Pisa.
+
+ +

+Una tesi sull'argomento si può focalizzare sia sugli aspetti modellistici, e.g., la definizione e lo studio delle proprietà di modelli differenziali discreti, +sia sugli aspetti algoritmici, e.g., calcolo di funzioni di matrici, soluzione di equazioni differenziali definite sui grafi o algoritmi per l'estrazione di informazioni quali +quelle di comunità e cluster da una rete.
+Competenze necessarie: algebra lineare numerica, proprietà e soluzioni di ODE, programmazione con MATLAB;
Competenze consigliate: matrici non negative;
+Corsi suggeriti: Calcolo Scientifico, Metodi Numerici per le ODE, Metodi Numerici per le Catene di Markov, Metodi Numerici per le PDE, Istituzioni di Analisi Numerica (se alla magistrale). +

+ +{% bibliography --file bibliofabio2 %} +

3   Soluzione Numerica di Equazioni alle Derivate Parziali Frazionarie

+

+L'ambito della ricerca in equazioni alle derivate frazionarie esplora estensioni delle classiche equazioni differenziali, introducendo derivate di ordine non intero, ovvero derivate frazionarie. +Si consideri ad esempio la derivata di Riemann-Liouville che è una delle definizioni classiche di derivata frazionaria, che estende il concetto di derivata a ordini non interi. +Viene definita attraverso un'integrazione convolutiva, utilizzando la formula integrale generalizzata della funzione, e permette di calcolare derivate di ordine frazionario (non intero) +di una funzione: +\[ +D_t^\alpha f(t) = \frac{1}{\Gamma(n - \alpha)} \frac{\mathrm{d}^n}{\mathrm{d}t^n} \int_{a}^{t} (t - \tau)^{n-\alpha-1} f(\tau) \, \mathrm{d}\tau, \quad \alpha \in \mathbb{R}_+,\; n = \lceil \alpha \rceil. +\] +Le equazioni differenziali definite in termini di questi operatori sono particolarmente efficaci nel modellare fenomeni complessi caratterizzati da memoria e dinamiche non locali, dove l'evoluzione +di un sistema non dipende solo dal suo stato attuale ma anche dalla sua storia passata. Le derivate frazionarie permettono di descrivere processi come la diffusione anomala, che si osserva in materiali +porosi, nei mercati finanziari o in sistemi biologici, e sono ampiamente utilizzate nella fisica dei mezzi continui, nell'economia, nell'ingegneria e nella biologia. Le equazioni frazionarie consentono +anche di modellare fenomeni di viscoelasticità, trasporto di cariche, e sistemi complessi con dinamiche a lungo termine. La ricerca si concentra sia sugli aspetti teorici, come l'analisi dell'esistenza +e unicità delle soluzioni, sia sugli algoritmi numerici per risolvere tali equazioni, data la loro complessità intrinseca. Lo sviluppo di metodi efficienti per risolvere equazioni alle derivate +frazionarie è cruciale per la simulazione di molti sistemi reali, dove i modelli tradizionali a derivate intere risultano inadeguati. +

+ +

+Una tesi sull'argomento è tipicamente focalizzata sulla definizione di strategie per la discretizzazione di equazioni di questo tipo e sulla costruzione di solutori efficienti per i +problemi discreti così ottenuti.
+Competenze necessarie: algebra lineare numerica, proprietà e soluzioni di ODE e PDE, programmazione con MATLAB;
+Corsi suggeriti: Calcolo Scientifico, Metodi Numerici per le ODE, Metodi Numerici per le PDE, Istituzioni di Analisi Numerica (se alla magistrale). +

+ +{% bibliography --file bibliofabio3 %} diff --git a/favicon.ico b/favicon.ico index 4746ce6..c451e71 100644 Binary files a/favicon.ico and b/favicon.ico differ diff --git a/index.html b/index.html index 402ae3d..3f7e4ab 100644 --- a/index.html +++ b/index.html @@ -27,7 +27,9 @@

2   Quali sono le competenze che devo avere?

-

+

+ Per scrivere una tesi in analisi numerica, è necessario padroneggiare un insieme di competenze tecniche e teoriche, che vanno dalla comprensione della matematica avanzata alla capacità di implementare algoritmi efficienti in linguaggi di programmazione di vario tipo. +

2.1   Va bene, ma dal punto di vista pratico?

@@ -46,13 +48,13 @@

Per quello che riguarda il corso di laurea magistrale si tratta dei corsi di:

-

- Istituzioni di Analisi Numerica
- Metodi Numerici per la Grafica
- Metodi Numerici per la PDE
- Metodi Numerici per le Catene di Markov
- Aspetti Matematica nella Computazione Quantistica
-

+

3   Di cosa ci occupiamo in dipartimento?