diff --git a/.gitignore b/.gitignore index 584b59d80..ce9af351c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,9 @@ /doc/gen_modules/ /doc/generated/ /doc/auto_examples/ +/doc/sg_execution_times.rst __pycache__ __cache__ -*_cache \ No newline at end of file +*_cache +**/.DS_Store \ No newline at end of file diff --git a/doc/_static/images/landingpage/compatible.png b/doc/_static/images/landingpage/compatible.png new file mode 100644 index 000000000..dcb10602b Binary files /dev/null and b/doc/_static/images/landingpage/compatible.png differ diff --git a/doc/_static/images/landingpage/compatible.webp b/doc/_static/images/landingpage/compatible.webp new file mode 100644 index 000000000..6b3959c46 Binary files /dev/null and b/doc/_static/images/landingpage/compatible.webp differ diff --git a/doc/_static/images/landingpage/ease.png b/doc/_static/images/landingpage/ease.png new file mode 100644 index 000000000..98399ce20 Binary files /dev/null and b/doc/_static/images/landingpage/ease.png differ diff --git a/doc/_static/images/landingpage/ease.webp b/doc/_static/images/landingpage/ease.webp new file mode 100644 index 000000000..aa1cf3baf Binary files /dev/null and b/doc/_static/images/landingpage/ease.webp differ diff --git a/doc/_static/images/landingpage/energy.png b/doc/_static/images/landingpage/energy.png new file mode 100644 index 000000000..f308b8d58 Binary files /dev/null and b/doc/_static/images/landingpage/energy.png differ diff --git a/doc/_static/images/landingpage/energy.webp b/doc/_static/images/landingpage/energy.webp new file mode 100644 index 000000000..5af6f0b16 Binary files /dev/null and b/doc/_static/images/landingpage/energy.webp differ diff --git a/doc/_static/images/landingpage/finance.png b/doc/_static/images/landingpage/finance.png new file mode 100644 index 000000000..3ca892e5e Binary files /dev/null and b/doc/_static/images/landingpage/finance.png differ diff --git a/doc/_static/images/landingpage/finance.webp b/doc/_static/images/landingpage/finance.webp new file mode 100644 index 000000000..9f3adfdfc Binary files /dev/null and b/doc/_static/images/landingpage/finance.webp differ diff --git a/doc/_static/images/landingpage/healthcare.png b/doc/_static/images/landingpage/healthcare.png new file mode 100644 index 000000000..0de4da579 Binary files /dev/null and b/doc/_static/images/landingpage/healthcare.png differ diff --git a/doc/_static/images/landingpage/healthcare.webp b/doc/_static/images/landingpage/healthcare.webp new file mode 100644 index 000000000..ecd6fb8a9 Binary files /dev/null and b/doc/_static/images/landingpage/healthcare.webp differ diff --git a/doc/_static/images/landingpage/hero.png b/doc/_static/images/landingpage/hero.png new file mode 100644 index 000000000..7c6eb90e5 Binary files /dev/null and b/doc/_static/images/landingpage/hero.png differ diff --git a/doc/_static/images/landingpage/hero.webp b/doc/_static/images/landingpage/hero.webp new file mode 100644 index 000000000..b6dc05e9b Binary files /dev/null and b/doc/_static/images/landingpage/hero.webp differ diff --git a/doc/_static/images/landingpage/inrialogo.png b/doc/_static/images/landingpage/inrialogo.png new file mode 100644 index 000000000..e25e3eadf Binary files /dev/null and b/doc/_static/images/landingpage/inrialogo.png differ diff --git a/doc/_static/images/landingpage/inrialogo.webp b/doc/_static/images/landingpage/inrialogo.webp new file mode 100644 index 000000000..b7103eda9 Binary files /dev/null and b/doc/_static/images/landingpage/inrialogo.webp differ diff --git a/doc/_static/images/landingpage/modular.png b/doc/_static/images/landingpage/modular.png new file mode 100644 index 000000000..9a044c5bd Binary files /dev/null and b/doc/_static/images/landingpage/modular.png differ diff --git a/doc/_static/images/landingpage/modular.webp b/doc/_static/images/landingpage/modular.webp new file mode 100644 index 000000000..79fcdb94e Binary files /dev/null and b/doc/_static/images/landingpage/modular.webp differ diff --git a/doc/_static/images/landingpage/performance.png b/doc/_static/images/landingpage/performance.png new file mode 100644 index 000000000..91499185b Binary files /dev/null and b/doc/_static/images/landingpage/performance.png differ diff --git a/doc/_static/images/landingpage/performance.webp b/doc/_static/images/landingpage/performance.webp new file mode 100644 index 000000000..513af948c Binary files /dev/null and b/doc/_static/images/landingpage/performance.webp differ diff --git a/doc/_static/scripts/instantpage.min.js b/doc/_static/scripts/instantpage.min.js new file mode 100644 index 000000000..bcaf9c025 --- /dev/null +++ b/doc/_static/scripts/instantpage.min.js @@ -0,0 +1,14 @@ +/*! instant.page v5.1.0 - (C) 2019 Alexandre Dieulot - https://instant.page/license */ +document.addEventListener("DOMContentLoaded", function () { + const supportsPrefetch = document.createElement("link").relList.supports("prefetch"); + if (!supportsPrefetch) return; + const links = document.querySelectorAll("a[href]"); + links.forEach(link => { + link.addEventListener("mouseover", () => { + const prefetch = document.createElement("link"); + prefetch.rel = "prefetch"; + prefetch.href = link.href; + document.head.appendChild(prefetch); + }); + }); +}); \ No newline at end of file diff --git a/doc/_static/scripts/lazyload.js b/doc/_static/scripts/lazyload.js new file mode 100644 index 000000000..941974b7e --- /dev/null +++ b/doc/_static/scripts/lazyload.js @@ -0,0 +1,14 @@ +document.addEventListener("DOMContentLoaded", function () { + document.querySelectorAll("img").forEach(function (img) { + const src = img.getAttribute("src") || ""; + if ( + src.includes("logo.svg") || + img.classList.contains("hero-gallery-img") + ) { + // Don't lazy-load logo or hero image + return; + } + img.setAttribute("loading", "lazy"); + }); + document.body.classList.add("ready"); +}); \ No newline at end of file diff --git a/doc/_static/style.css b/doc/_static/style.css index 3deebf01f..8055c1f12 100644 --- a/doc/_static/style.css +++ b/doc/_static/style.css @@ -1,24 +1,405 @@ -.announcement { - background-color: #1f77b4; +/* Math formula centering */ +div.math mjx-container { + text-align: center; } -.sidebar-version { +/* Define primary colors */ +:root { + --pst-color-primary: #4791c5; + /* skglm blue */ + --pst-color-secondary: #ec9b4c; + /* skglm orange */ + --pst-color-link: var(--pst-color-primary); + --pst-color-link-hover: #336b96; + /* darker blue on hover */ + --pst-color-inline-code: #2c608f; + /* deep blue for code */ + --pst-color-inline-code-background: #f0f8ff; + /* very pale blue */ + --pst-color-announcement-background: #fff7ec; + /* soft orange */ + --pst-color-announcement-text: var(--pst-color-primary); +} + +/* Light theme overrides */ +html[data-theme="light"] { + --pst-color-primary: #4791c5; + --pst-color-secondary: #ec9b4c; + --pst-color-link: var(--pst-color-primary); + --pst-color-link-hover: #336b96; + --pst-color-inline-code: #2c608f; + --pst-color-inline-code-background: #f0f8ff; + --pst-color-announcement-background: #fff7ec; + --pst-color-secondary-bg: #F8FAFC; +} + +/* Dark theme overrides */ +html[data-theme="dark"] { + --pst-color-primary: #79b8e6; + --pst-color-secondary: #ec9b4c; + --pst-color-link: var(--pst-color-primary); + --pst-color-link-hover: #a1cbe9; + --pst-color-inline-code: #79b8e6; + --pst-color-inline-code-background: #2e2e2e; + --pst-color-announcement-background: #2e2e2e; + --pst-color-secondary-bg: #383838; +} + +/* Inline code styling */ +code { + color: var(--pst-color-inline-code); + background-color: var(--pst-color-inline-code-background); + padding: 0.2em 0.4em; + border-radius: 4px; + font-family: monospace; +} + +/* Remove underline from rubric elements */ +.rubric { + border-bottom: none !important; + padding-bottom: 0 !important; + margin-bottom: 0 !important; +} + +/* Hide Search Matches Button */ +#searchbox .highlight-link { + display: none; +} + +.highlighted #searchbox .highlight-link { + display: block; +} + +/* Site Speed Setting */ +img { + max-width: 100%; + height: auto; + display: block; +} + +body { + opacity: 0; + transition: opacity 0.3s ease; +} + +body.ready { + opacity: 1; +} + +/*-------------------------------------------------------------*/ +/*Landing Page Layout*/ + + +/* Override style for top-level heading */ +/* Hide only the first h1 visually */ +/* Hide only the

directly inside the landing section on the index page */ +section#skglm>h1 { + position: absolute; + left: -9999px; +} + +/* Universal image background and border reset for landing images */ +.hero-gallery-img, +.feature-icon, +.application-icon, +.sponsor-logo { + background-color: transparent !important; + border: none; +} + + +/*Hero Section Layout*/ + +.hero-title { + font-size: 3rem; + font-weight: 800; + color: var(--pst-color-primary); + margin-bottom: 1rem; + margin-top: 0; +} + +/* Hero Section Layout */ +.hero-container { display: flex; - flex-direction: row; align-items: center; justify-content: space-between; + flex-wrap: wrap; + padding: 0; + background-color: var(--pst-color-background); + color: var(--pst-color-text); +} + +/* Text Block */ +.hero-text { + flex: 1; + min-width: 300px; + padding: 0.5rem; +} + +/* Paragraph Styling */ +.hero-description { + font-size: 1.25rem; + line-height: 1.6; + max-width: 40rem; + color: var(--pst-color-text); +} + +/* Optional orange emphasis text */ +.highlight-orange, +.rst-content .orange { + color: var(--pst-color-secondary); +} + +/* Buttons */ +.hero-buttons { + margin-top: 1.5rem; +} + +.hero-buttons a { + padding: 0.75rem 1.25rem; + background-color: var(--pst-color-primary); + color: white; + border-radius: 6px; + text-decoration: none; + font-weight: 600; + display: inline-block; + transition: background-color 0.2s ease; +} + +.hero-buttons a:hover { + color: var(--pst-color-secondary); + background-color: var(--pst-color-link-hover); +} - padding-left: var(--sidebar-item-spacing-horizontal); - padding-right: var(--sidebar-item-spacing-horizontal); - margin-top: 0px; +/* Gallery Section */ +.hero-gallery { + flex: 1; + min-width: 300px; + text-align: center; + background-color: transparent !important; + padding: 4rem; } -.sidebar-version-selected>* { +.hero-gallery-img { + max-width: 100%; + height: auto; + border-radius: 2rem; + transition: transform 0.2s ease; +} + +.hero-gallery-img:hover { + transform: scale(1.03); +} + +.highlight-orange, +.rst-content .highlight-orange { + color: var(--pst-color-secondary); +} + + +/* Key Features Section */ +/* Section spacing (replaces
and margin-top) */ +.section-spacer { + margin-top: 3rem; +} + +/* Title */ +.section-title { + font-size: 2.5rem; + font-weight: 600; + color: var(--pst-color-text); + text-align: center; + margin-bottom: 0.25rem; +} + +/* Subtitle paragraph */ +.section-subtitle { + font-size: 1.25rem; + font-weight: 400; + color: var(--pst-color-text-muted, #4a4a4a); + max-width: 52rem; + margin: 0 auto 2.5rem auto; + text-align: center; +} + +/* Optional: add fallback for muted text in dark mode */ +html[data-theme="dark"] .section-subtitle { + color: #c0c0c0; +} + + + +/* Feature grid styles */ +.features-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 2rem 3rem; + margin-top: 2rem; +} + +.feature-box { + background-color: var(--pst-color-secondary-bg); + padding: 0.5rem; + border-radius: 1rem; + height: 100%; display: flex; align-items: center; - padding: 0.25em; - border-radius: 0.25rem; - background-color: #ff7f0e; - color: white; - pointer-events: none; + gap: 1.5rem; +} + +.feature-icon { + margin-left: 0.5rem !important; + width: 4.5rem; + height: 4.5rem; +} + +.feature-title { + font-size: 1.2rem; + color: var(--pst-color-primary); + margin-bottom: 0.5rem; + margin-top: 0; + font-weight: 600; +} + +.feature-text { + padding-right: 1rem !important; +} + +html[data-theme="dark"] .feature-box { + background-color: #2e2e2e; +} + +/* Support us section */ + + +.support-box { + background-color: var(--pst-color-secondary-bg); + padding: 2rem; + border-radius: 8px; + text-align: center; + margin-top: 1.5rem; +} + +html[data-theme="dark"] .support-box { + background-color: #2e2e2e; +} + +.support-title { + font-size: 1.2rem; + font-weight: 600; + color: var(--pst-color-primary); + margin: 0 0 0.5rem 0; +} + + +/* Citation block styling inside support-box */ +.support-box pre { + font-size: 0.85rem; + background-color: var(--pst-color-inline-code-background); + color: var(--pst-color-inline-code); + padding: 1rem 2rem !important; + border-radius: 6px; + overflow-x: auto; + text-align: left; + white-space: pre-wrap; + word-break: break-word; + max-width: 100%; + max-width: calc(100% - 4rem) !important; + margin: 1rem auto 0 auto !important; +} + +html[data-theme="light"] .highlight { + background: var(--pst-color-secondary-bg) !important; +} + +html[data-theme="dark"] .support-box pre { + background-color: #2e2e2e; + padding: 1rem 2rem; + max-width: calc(100% - 4rem); + margin: 1rem auto 0 auto; } + + +/* Applications Grid Section */ +.applications-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 2rem; + max-width: 1000px; + margin: 0 auto; + text-align: center; +} + +.application-box { + background-color: var(--pst-color-secondary-bg); + padding: 1.5rem !important; + border-radius: 1rem; + margin: 1.5rem; +} + +html[data-theme="dark"] .application-box { + background-color: #2e2e2e; +} + +.application-icon { + height: 6rem; + margin: 0 auto; +} + +.application-title { + font-size: 1.2rem; + color: var(--pst-color-primary); + margin-bottom: 0.5rem; + margin-top: 0; + font-weight: 600; +} + +.application-text { + text-align: left; + padding-right: 1rem !important; +} + + +/* Sponsor banner styles */ +.sponsor-banner { + margin-top: 4rem; + padding: 1.5rem 2rem; + background-color: var(--pst-color-secondary-bg); + display: flex; + align-items: center; + justify-content: center; + gap: 1rem; + flex-wrap: wrap; + border-radius: 8px; + font-size: 1.1rem; + color: var(--pst-color-text); + text-align: center; +} + +.sponsor-logo { + height: 1.5rem; + vertical-align: baseline; + display: inline-block; + margin-bottom: 0rem; +} + +html[data-theme="dark"] .sponsor-banner { + background-color: #2e2e2e; +} + +.sponsor-inline { + display: flex; + align-items: flex-end; + justify-content: center; + gap: 1rem; + flex-wrap: wrap; + line-height: 1.2; + height: 100%; +} + + +.sponsor-inline>p { + margin: 0; + display: flex; + align-items: flex-end; +} \ No newline at end of file diff --git a/doc/_static/switcher.json b/doc/_static/switcher.json new file mode 100644 index 000000000..f7ad4e840 --- /dev/null +++ b/doc/_static/switcher.json @@ -0,0 +1,13 @@ +[ + { + "version": "dev", + "name": "0.5dev", + "url": "https://contrib.scikit-learn.org/skglm/", + "preferred": true + }, + { + "version": "0.3.1", + "name": "v0.3.1", + "url": "https://contrib.scikit-learn.org/skglm/stable/" + } +] diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html new file mode 100644 index 000000000..2c13f1816 --- /dev/null +++ b/doc/_templates/layout.html @@ -0,0 +1,7 @@ +{% extends "!layout.html" %} + +{% block extrahead %} +{{ super() }} + + +{% endblock %} \ No newline at end of file diff --git a/doc/api.rst b/doc/api.rst index 5ad56081b..b03757301 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -1,7 +1,10 @@ -.. _api_documentation: +.. _api: + +.. meta:: + :description: Browse the skglm API documentation covering estimators (Lasso, ElasticNet, Cox), penalties (L1, SCAD, MCP), datafits (Logistic, Poisson), and optimized solvers. ================= -API Documentation +API ================= .. currentmodule:: skglm diff --git a/doc/conf.py b/doc/conf.py index 18b78cc5d..7b85dfb89 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -18,8 +18,8 @@ from datetime import date import sphinx_gallery # noqa -import sphinx_bootstrap_theme # noqa from numpydoc import numpydoc, docscrape # noqa +import pydata_sphinx_theme # noqa from skglm import __version__ as version @@ -41,12 +41,12 @@ # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +# sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +# needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom @@ -65,6 +65,7 @@ 'sphinx.ext.linkcode', 'gh_substitutions', 'myst_parser', + 'sphinx_sitemap', # custom ext, see ./sphinxext/gh_substitutions.py ] @@ -78,114 +79,101 @@ # generate autosummary even if no references autosummary_generate = True -# Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] html_css_files = ["style.css"] -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# source_suffix = ['.rst', '.md'] source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. master_doc = 'index' -# General information about the project. project = u'skglm' copyright = f'2022-{date.today().year}, skglm developers' author = u'skglm developers' -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -# version = u'0.1.dev0' -# The full version, including alpha/beta/rc tags. release = version -# release = u'0.1.dev0' -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. language = 'en' -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. exclude_patterns = ['_build'] -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False +# pygments_style = 'sphinx' -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +todo_include_todos = False -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +html_baseurl = 'https://contrib.scikit-learn.org/skglm/' -# If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False +extensions.append("sphinxext.opengraph") -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = False +# OpenGraph config +ogp_site_url = html_baseurl +ogp_image = "https://contrib.scikit-learn.org/skglm/_static/images/logo.svg" +ogp_description_length = 250 +ogp_type = "website" # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'furo' +html_theme = 'pydata_sphinx_theme' + + +version_match = "stable" if is_stable_doc else "dev" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. html_theme_options = { - "light_css_variables": { - "color-brand-primary": "#991b1b", - "color-brand-content": "#991b1b", - "font-stack": 'ui-sans-serif, system-ui', - "color-background-secondary": "#fafafa" - }, - "dark_css_variables": { - "color-brand-primary": "#fca5a5", - "color-brand-content": "#fca5a5", + # Navbar configuration + "navbar_align": "left", + "navbar_start": ["navbar-logo"], + "navbar_center": ["navbar-nav"], + "navbar_end": [ + "navbar-icon-links", + "theme-switcher", + "version-switcher", + ], + + # other configurations + "icon_links": [ + { + "name": "GitHub", + "url": "https://github.com/scikit-learn-contrib/skglm", + "icon": "fab fa-github", + "type": "fontawesome", + }, + ], + "version_dropdown": True, + "switcher": { + # NOTE: must be a URL and not a path relative to doc + "json_url": "https://raw.githubusercontent.com/floriankozikowski/skglm/refs/heads/documentation-update/doc/_static/switcher.json", + "version_match": version_match, }, + "navigation_with_keys": True, + "search_bar_text": "Search skglm docs...", "footer_icons": [ { "name": "GitHub", "url": "https://github.com/scikit-learn-contrib/skglm", - "html": """ - - - - """, - "class": "", + "icon": "fa-brands fa-github", }, ], + # site speed improvements + "collapse_navigation": True, + "navigation_depth": 2, +} + +# add sidebars if necessary (e.g. if more tutorials are being added) +html_sidebars = { + "index": [], + "getting_started": [], + "tutorials": [], + "tutorials/*": [], + "auto_examples/*": [], + "api": [], # not applied for subpages as it is useful here + "contribute": [], + "changes": [], + "changes/*": [] } # Enable asciimath parsing in MathJax and configure the HTML renderer to output @@ -194,15 +182,20 @@ # to Latex. # [1]: https://pypi.org/project/py-asciimath/ mathjax3_config = { - "loader": { - "load": ['input/asciimath'] - }, + "loader": { + "load": ['input/asciimath'] + }, } mathjax_inline = ['`', '`'] mathjax_display = ['`', '`'] html_static_path = ['_static'] -html_js_files = ["scripts/asciimath-defines.js"] +html_js_files = [ + "scripts/asciimath-defines.js", + "switcher.json", + "scripts/lazyload.js", + "scripts/instantpage.min.js", +] # -- Options for copybutton --------------------------------------------- # complete explanation of the regex expression can be found here @@ -218,7 +211,7 @@ html_title = f"skglm {version} documentation" # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. @@ -237,25 +230,15 @@ # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. -#html_extra_path = [] +html_extra_path = ['robots.txt'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' +# html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -html_sidebars = { - "**": [ - "sidebar/brand.html", - "sidebar/version_toggler.html", # version toggler template - "sidebar/search.html", - "sidebar/navigation.html", - ] -} +# html_use_smartypants = True # these variables will be available in the sphinx templates html_context = { @@ -266,59 +249,57 @@ # when it's the dev version of the documentation, put a banner to warn the user # and a link to switch to the dev version of doc if not is_stable_doc: - html_theme_options = { - "announcement": ( - "You are viewing the documentation of the dev version of " - "skglm which contains WIP features. " - "View " - "stable version." - ) - } + html_theme_options["announcement"] = ( + "You are viewing the documentation of the dev version of " + "skglm which contains WIP features. " + "View " + "stable version." + ) # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_domain_indices = True +# html_domain_indices = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. html_show_sourcelink = False # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +# html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True +# html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# html_file_suffix = None # Language to be used for generating the HTML full-text search index. # Sphinx supports the following languages: # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' -#html_search_language = 'en' +# html_search_language = 'en' # A dictionary with options for the search language support, empty by default. # Now only 'ja' uses this config value -#html_search_options = {'type': 'default'} +# html_search_options = {'type': 'default'} # The name of a javascript file (relative to the configuration directory) that # implements a search results scorer. If empty, the default will be used. -#html_search_scorer = 'scorer.js' +# html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. htmlhelp_basename = 'skglmdoc' @@ -351,23 +332,23 @@ # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +# latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +# latex_show_pagerefs = False # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = False # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_domain_indices = True +# latex_domain_indices = True # -- Options for manual page output --------------------------------------- @@ -380,7 +361,7 @@ ] # If true, show URL addresses after external links. -#man_show_urls = False +# man_show_urls = False # -- Options for Texinfo output ------------------------------------------- @@ -395,16 +376,16 @@ ] # Documents to append as an appendix to all manuals. -#texinfo_appendices = [] +# texinfo_appendices = [] # If false, no module index is generated. -#texinfo_domain_indices = True +# texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' +# texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False +# texinfo_no_detailmenu = False # Example configuration for intersphinx: refer to the Python standard library. @@ -430,6 +411,9 @@ 'doc_module': ('skglm', 'sklearn', 'benchopt'), 'examples_dirs': '../examples', 'gallery_dirs': 'auto_examples', + 'download_all_examples': False, + 'run_stale_examples': True, + 'remove_config_comments': True, 'reference_url': { 'skglm': None, } diff --git a/doc/contribute.rst b/doc/contribute.rst index dd0629f47..ae60525fa 100644 --- a/doc/contribute.rst +++ b/doc/contribute.rst @@ -1,6 +1,10 @@ .. _contribute: -Contribute to ``skglm`` +.. meta:: + :description: Contribute to skglm by reporting bugs, suggesting features, or submitting pull requests. Join us in making skglm even better! + :og:title: Contribute to skglm + +Contribute ======================= ``skglm`` is a continuous endeavour that relies on community efforts to last and evolve. diff --git a/doc/getting_started.rst b/doc/getting_started.rst index f26472720..2cc4dfcad 100644 --- a/doc/getting_started.rst +++ b/doc/getting_started.rst @@ -1,7 +1,10 @@ .. _getting_started: +.. meta:: + :description: Learn how to fit Lasso and custom GLM estimators with skglm, a modular Python library compatible with scikit-learn. Includes examples and code snippets. + =============== -Getting started +Start =============== --------------- @@ -31,7 +34,7 @@ Fitting a Lasso estimator ------------------------- Let's start first by generating a toy dataset and splitting it to train and test sets. -For that, we will use ``scikit-learn`` +For that, we will use ``scikit-learn`` `make_regression `_ .. code-block:: python @@ -42,7 +45,7 @@ For that, we will use ``scikit-learn`` # generate toy data X, y = make_regression(n_samples=100, n_features=1000) - + # split data X_train, X_test, y_train, y_test = train_test_split(X, y) @@ -52,7 +55,7 @@ Then let's fit ``skglm`` :ref:`Lasso ` estimator and prints its sco # import estimator from skglm import Lasso - + # init and fit estimator = Lasso() estimator.fit(X_train, y_train) @@ -63,7 +66,7 @@ Then let's fit ``skglm`` :ref:`Lasso ` estimator and prints its sco .. note:: - - The first fit after importing ``skglm`` has an overhead as ``skglm`` uses `Numba `_ + - The first fit after importing ``skglm`` has an overhead as ``skglm`` uses `Numba `_ The subsequent fits will achieve top speed since Numba compilation is cached. ``skglm`` has several other ``scikit-learn`` compatible estimators. @@ -138,7 +141,7 @@ and pass it to ``GeneralizedLinearEstimator``. Explore the list of supported :re .. important:: - - It is possible to create your own datafit and penalties. Check the tutorials on :ref:`how to add a custom datafit ` + - It is possible to create your own datafit and penalties. Check the tutorials on :ref:`how to add a custom datafit ` and :ref:`how to add a custom penalty `. diff --git a/doc/index.rst b/doc/index.rst index f95e5c3e4..702b5051c 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -1,79 +1,214 @@ + .. skglm documentation master file, created by sphinx-quickstart on Mon May 23 16:22:52 2016. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -========= -``skglm`` -========= -*— A fast and modular scikit-learn replacement for regularized GLMs —* +.. meta:: + :og:title: skglm: Fast, Scalable & Flexible Regularized GLMs and Sparse Modeling for Python + :description: skglm is the fastest, most modular Python library for regularized GLMs—fully scikit-learn compatible for advanced statistical modeling. + :og:image: _static/images/logo.svg + :og:url: https://contrib.scikit-learn.org/skglm/ + :keywords: Generalized Linear Models, GLM, scikit-learn, Lasso, ElasticNet, Cox, modular, efficient, regularized + :page-layout: full + +skglm +====== +.. container:: hero-container + + .. container:: hero-text + + .. rubric:: skglm + :class: hero-title + + + .. container:: hero-description + + .. raw:: html + + The fastest and most modular Python package for regularized Generalized Linear Models — designed for researchers and engineers who demand speed, structure, and scikit-learn compatibility. + + .. container:: hero-buttons + + `Get Started `_ + + .. container:: hero-gallery + + .. image:: _static/images/landingpage/hero.webp + :alt: Illustration showing modeling in skglm logo style + :class: hero-gallery-img + :target: auto_examples/index.html + + +.. container:: section-spacer + + .. container:: section-intro + + .. rubric:: Simple. Modular. Powerful. + :class: section-title + + .. container:: section-subtitle + + Everything you need to build fast, flexible, and scalable GLMs — in one modular library. + +.. container:: features-grid + + .. container:: feature-box + + .. image:: _static/images/landingpage/ease.webp + :alt: Ease icon + :class: feature-icon + + .. container:: feature-text + + .. rubric:: Easy to Use + :class: feature-title + + Get started in minutes with an intuitive API, comprehensive examples, and out-of-the-box estimators. + + .. container:: feature-box + + .. image:: _static/images/landingpage/modular.webp + :alt: Modular icon + :class: feature-icon + + .. container:: feature-text + + .. rubric:: Modular Design + :class: feature-title + + Compose custom estimators from interchangeable datafits and penalties tailored to your use case. + + .. container:: feature-box + + .. image:: _static/images/landingpage/performance.webp + :alt: Performance icon + :class: feature-icon + + .. container:: feature-text + + .. rubric:: Speed + :class: feature-title + + Solve large-scale problems with lightning-fast solvers — up to 100× faster than ``scikit-learn``. + + .. container:: feature-box + + .. image:: _static/images/landingpage/compatible.webp + :alt: Compatibility icon + :class: feature-icon + + .. container:: feature-text + + .. rubric:: Plug & Extend + :class: feature-title + + Fully scikit-learn compatible and ready for custom research and production workflows. + +.. container:: section-spacer + + .. container:: section-intro + + .. rubric:: Support Us + :class: section-title + + .. container:: support-box + + .. rubric:: Citation + :class: support-title + Using ``skglm`` in your work? You are free to use it. It is licensed under + `BSD 3-Clause `_. + As the result of perseverant academic research, the best way to support its development is by citing it. + :: + @inproceedings{skglm, + title = {Beyond L1: Faster and better sparse models with skglm}, + author = {Q. Bertrand and Q. Klopfenstein and P.-A. Bannier + and G. Gidel and M. Massias}, + booktitle = {NeurIPS}, + year = {2022}, + } + + @article{moufad2023skglm, + title = {skglm: improving scikit-learn for regularized Generalized Linear Models}, + author = {Moufad, Badr and Bannier, Pierre-Antoine and Bertrand, Quentin + and Klopfenstein, Quentin and Massias, Mathurin}, + year = {2023} + } + + .. container:: support-box + + .. rubric:: Contributions + :class: support-title + Contributions, improvements, and bug reports are always welcome. Help us make ``skglm`` better! + + .. container:: hero-buttons + + `How to Contribute `_ + +.. container:: section-spacer + + .. container:: section-intro --------- + .. rubric:: Real-World Applications + :class: section-title + .. container:: section-subtitle -``skglm`` is a Python package that offers **fast estimators** for regularized Generalized Linear Models (GLMs) -that are **100% compatible with** ``scikit-learn``. It is **highly flexible** and supports a wide range of GLMs. -You get to choose from ``skglm``'s already-made estimators or **customize your own** by combining the available datafits and penalties. + ``skglm`` drives impactful solutions across diverse sectors with its fast, modular approach to regularized GLMs and sparse modeling. + Find various advanced topics in our `Tutorials `_ and `Examples `_ sections. -Get a hands-on glimpse on ``skglm`` through the :ref:`Getting started page `. + .. container:: applications-grid + .. container:: application-box -Why ``skglm``? --------------- + .. image:: _static/images/landingpage/healthcare.webp + :alt: Healthcare icon + :class: application-icon -``skglm`` is specifically conceived to solve regularized GLMs. -It supports many missing models in ``scikit-learn`` and ensures high performance. + .. container:: application-text -There are several reasons to opt for ``skglm`` among which: + .. rubric:: Healthcare + :class: application-title -.. list-table:: - :widths: 20 80 + Enhance clinical trial analytics and early biomarker discovery by efficiently analyzing high-dimensional biological data and features like cox regression modeling. - * - **Speed** - - Fast solvers able to tackle large datasets, either dense or sparse, with millions of features **up to 100 times faster** than ``scikit-learn`` - * - **Modularity** - - User-friendly API that enables **composing custom estimators** with any combination of its existing datafits and penalties - * - **Extensibility** - - Flexible design that makes it **simple and easy to implement new datafits and penalties**, a matter of few lines of code - * - **Compatibility** - - Estimators **fully compatible with the** ``scikit-learn`` **API** and drop-in replacements of its GLM estimators + .. container:: application-box + .. image:: _static/images/landingpage/finance.webp + :alt: Finance icon + :class: application-icon -Installing ``skglm`` --------------------- + .. container:: application-text -``skglm`` is available on PyPi. Get the latest version of the package by running + .. rubric:: Finance + :class: application-title -.. code-block:: shell + Conduct transparent and interpretable risk modeling with scalable, robust sparse regression across vast datasets. - $ pip install -U skglm + .. container:: application-box -It is also available on conda-forge and can be installed using, for instance: + .. image:: _static/images/landingpage/energy.webp + :alt: Energy icon + :class: application-icon -.. code-block:: shell + .. container:: application-text - $ conda install -c conda-forge skglm + .. rubric:: Energy + :class: application-title -With ``skglm`` being installed, Get the first steps with the package via the :ref:`Getting started section `. -Other advanced topics and uses-cases are covered in :ref:`Tutorials `. + Optimize real-time electricity forecasting and load analysis by processing large time-series datasets for predictive maintenance and anomaly detection. +.. container:: sponsor-banner -Cite ----- + .. container:: sponsor-inline -``skglm`` is the result of perseverant research. It is licensed under -`BSD 3-Clause `_. -You are free to use it and if you do so, please cite -.. code-block:: bibtex + This project is made possible thanks to the support of - @inproceedings{skglm, - title = {Beyond L1: Faster and better sparse models with skglm}, - author = {Q. Bertrand and Q. Klopfenstein and P.-A. Bannier - and G. Gidel and M. Massias}, - booktitle = {NeurIPS}, - year = {2022}, - } + .. image:: _static/images/landingpage/inrialogo.webp + :alt: Inria logo + :class: sponsor-logo + :target: https://www.inria.fr/en .. it is mandatory to keep the toctree here although it doesn't show up in the page diff --git a/doc/robots.txt b/doc/robots.txt new file mode 100644 index 000000000..30c8b8231 --- /dev/null +++ b/doc/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Sitemap: https://contrib.scikit-learn.org/skglm/sitemap.xml \ No newline at end of file diff --git a/doc/tutorials/add_datafit.rst b/doc/tutorials/add_datafit.rst index 2258bba38..d52474f51 100644 --- a/doc/tutorials/add_datafit.rst +++ b/doc/tutorials/add_datafit.rst @@ -1,8 +1,9 @@ -:orphan: - .. _how_to_add_custom_datafit: -How to add a custom datafit +.. meta:: + :description: Tutorial on creating and implementing a custom datafit in skglm. Step-by-step guide includes deriving gradients, Hessians, and an example with Poisson datafit. + +How to Add a Custom Datafit ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Motivated by generalized linear models but not limited to it, ``skglm`` solves problems of the form diff --git a/doc/tutorials/add_penalty.rst b/doc/tutorials/add_penalty.rst index 62a2a3bba..00bc04653 100644 --- a/doc/tutorials/add_penalty.rst +++ b/doc/tutorials/add_penalty.rst @@ -2,7 +2,10 @@ .. _how_to_add_custom_penalty: -How to add a custom penalty +.. meta:: + :description: Step-by-step tutorial on adding custom penalties in skglm. Covers implementation details, proximal operators, and optimality conditions using the L1 penalty. + +How to Add a Custom Penalty ~~~~~~~~~~~~~~~~~~~~~~~~~~~ skglm supports any arbitrary proximable penalty. diff --git a/doc/tutorials/alpha_max.rst b/doc/tutorials/alpha_max.rst index 8c105f87d..4565c3509 100644 --- a/doc/tutorials/alpha_max.rst +++ b/doc/tutorials/alpha_max.rst @@ -1,7 +1,10 @@ .. _alpha_max: +.. meta:: + :description: Tutorial explaining the critical regularization strength (alpha_max) in skglm. Learn conditions for zero solutions in L1-regularized optimization problems. + ========================================================== -Critical regularization strength above which solution is 0 +Critical Regularization Strength above which Solution is 0 ========================================================== This tutorial shows that for :math:`\lambda \geq \lambda_{\text{max}} = || \nabla f(0) ||_{\infty}`, the solution to diff --git a/doc/tutorials/cox_datafit.rst b/doc/tutorials/cox_datafit.rst index e5b1418b6..40afa9c0f 100644 --- a/doc/tutorials/cox_datafit.rst +++ b/doc/tutorials/cox_datafit.rst @@ -1,10 +1,13 @@ .. _maths_cox_datafit: +.. meta:: + :description: Detailed mathematical guide on Cox datafit implementation in skglm, covering Breslow and Efron estimates. Useful for survival analysis. + ============================= -Mathematic behind Cox datafit +Mathematic behind Cox Datafit ============================= -This tutorial presents the mathematics behind Cox datafit using both Breslow and Efron estimate. +This tutorial presents the mathematics behind Cox datafit using both Breslow and Efron estimate. Problem setup @@ -95,7 +98,7 @@ where the division and the square operations are performed element-wise. The Hessian, as it is, is costly to evaluate because of the right hand-side term. In particular, the latter involves a :math:`\mathcal{O}(n^3)` operations. We overcome this limitation by using a diagonal upper bound on the Hessian. -We construct such an upper bound by noticing that +We construct such an upper bound by noticing that #. the function :math:`F` is convex and hence :math:`\nabla^2 F(u)` is positive semi-definite #. the second term is positive semi-definite @@ -127,10 +130,10 @@ We can define :math:`y_{i_1}, \ldots, y_{i_m}` the unique times, assumed to be i .. math:: :label: def-H - + H_{y_{i_l}} = \{ i \ | \ s_i = 1 \ ;\ y_i = y_{i_l} \} , - + the set of uncensored observations with the same time :math:`y_{i_l}`. Again, we refer to the expression of the negative log-likelihood according to Efron estimate [`2`_, Section 6, equation (6.7)] to get the datafit formula @@ -139,7 +142,7 @@ Again, we refer to the expression of the negative log-likelihood according to Ef :label: efron-estimate l(\beta) = \frac{1}{n} \sum_{l=1}^{m} ( - \sum_{i \in H_{i_l}} - \langle x_i, \beta \rangle + \sum_{i \in H_{i_l}} - \langle x_i, \beta \rangle + \sum_{i \in H_{i_l}} \log(\sum_{y_j \geq y_{i_l}} e^{\langle x_j, \beta \rangle} - \frac{\#(i) - 1}{ |H_{i_l} |}\sum_{j \in H_{i_l}} e^{\langle x_j, \beta \rangle})) , @@ -158,7 +161,7 @@ On the other hand, the minus term within :math:`\log` can be rewritten as a line .. math:: - - \frac{\#(i) - 1}{| H_{i_l} |}\sum_{j \in H_{i_l}} e^{\langle x_j, \beta \rangle} + - \frac{\#(i) - 1}{| H_{i_l} |}\sum_{j \in H_{i_l}} e^{\langle x_j, \beta \rangle} = \sum_{j=1}^{n} -\frac{\#(i) - 1}{| H_{i_l} |} \ \mathbb{1}_{j \in H_{i_l}} \ e^{\langle x_j, \beta \rangle} = \sum_{j=1}^n a_{i,j} e^{\langle x_j, \beta \rangle} = \langle a_i, e^{\mathbf{X}\beta} \rangle diff --git a/doc/tutorials/intercept.rst b/doc/tutorials/intercept.rst index 5807abe1d..9317ae0b6 100644 --- a/doc/tutorials/intercept.rst +++ b/doc/tutorials/intercept.rst @@ -1,9 +1,12 @@ .. _maths_unpenalized_intercept: -Computation of the intercept +.. meta:: + :description: In-depth guide on intercept handling in skglm solvers. Covers mathematical derivations, gradient updates, Lipschitz constants, and examples for quadratic, logistic, and Huber datafits. + +Computation of the Intercept ============================ .. currentmodule:: skglm -.. include:: intercept.md +.. include:: intercept2.md :parser: myst_parser.sphinx_ diff --git a/doc/tutorials/intercept.md b/doc/tutorials/intercept2.md similarity index 100% rename from doc/tutorials/intercept.md rename to doc/tutorials/intercept2.md diff --git a/doc/tutorials/prox_nn_group_lasso.rst b/doc/tutorials/prox_nn_group_lasso.rst index af0a6c18e..0611ac821 100644 --- a/doc/tutorials/prox_nn_group_lasso.rst +++ b/doc/tutorials/prox_nn_group_lasso.rst @@ -1,4 +1,6 @@ .. _prox_nn_group_lasso: +.. meta:: + :description: Detailed tutorial on deriving the proximity operator and subdifferential for the positive group Lasso penalty in skglm. Includes mathematical proofs and examples. =================================== Details on the Positive Group Lasso diff --git a/doc/tutorials/tutorials.rst b/doc/tutorials/tutorials.rst index d86b58840..187e4a7e5 100644 --- a/doc/tutorials/tutorials.rst +++ b/doc/tutorials/tutorials.rst @@ -1,40 +1,57 @@ .. _tutorials: +.. meta:: + :description: Step-by-step skglm tutorials covering custom datafits, penalties, intercept computations, Cox datafit mathematics, group Lasso details, and regularization strategies. + ========= Tutorials ========= ----------------- - -:ref:`How to add a custom datafit ` --------------------------------------------------------------- +.. grid:: 1 1 2 2 + :gutter: 2 -Learn to add a custom datafit through a hands-on examples: Implementing a Poisson datafit. + .. grid-item-card:: How to Add a Custom Datafit + :link: add_datafit.html + :text-align: left + Learn to add a custom datafit through a hands-on examples: Implementing a Poisson datafit. -:ref:`How to add a custom penalty ` --------------------------------------------------------------- + .. grid-item-card:: How to Add a Custom Penalty + :link: add_penalty.html + :text-align: left -Learn to add a custom penalty by implementing the :math:`\ell_1` penalty. + Learn to add a custom penalty by implementing the :math:`\ell_1` penalty. + .. grid-item-card:: Computation of the Intercept + :link: intercept.html + :text-align: left -:ref:`Computation of the intercept ` ------------------------------------------------------------------ + Explore how ``skglm`` fits an unpenalized intercept. -Explore how ``skglm`` fits an unpenalized intercept. + .. grid-item-card:: Mathematics behind Cox Datafit + :link: cox_datafit.html + :text-align: left + Understand the mathematical foundation of Cox datafit and its applications in survival analysis. -:ref:`Mathematics behind Cox datafit ` ---------------------------------------------------------- + .. grid-item-card:: Details on the Group Lasso + :link: prox_nn_group_lasso.html + :text-align: left -Get details about Cox datafit equations. + Mathematical details about the group Lasso, in particular with nonnegativity constraints. -:ref:`Details on the group Lasso ` -------------------------------------------------------- + .. grid-item-card:: Understanding `alpha_max` + :link: alpha_max.html + :text-align: left -Mathematical details about the group Lasso, in particular with nonnegativity constraints. + Learn how to choose the regularization strength in :math:`\ell_1`-regularization? -:ref:`Critical regularization strength above which solution is 0 ` ------------------------------------------------------------------------------ +.. toctree:: + :hidden: -How to choose the regularization strength in L1-regularization? + add_datafit + add_penalty + intercept + cox_datafit + prox_nn_group_lasso + alpha_max diff --git a/examples/README.txt b/examples/README.txt index aab3104b1..3d6cb247b 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -1,8 +1,11 @@ .. _general_examples: -Examples Gallery -================ +.. title:: Examples -.. contents:: Contents - :local: - :depth: 3 +Examples +======== + +.. toctree:: + :maxdepth: 1 + + auto_examples/index diff --git a/pyproject.toml b/pyproject.toml index 7484b29d7..b96d5e692 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,6 +65,9 @@ doc = [ "pytest", "furo", "lifelines", + "pydata_sphinx_theme", + "sphinx-sitemap", + "sphinxext-opengraph", ]