R/igraph

repository·main·Indexed 20 days ago

https://github.com/igraph/rigraph

The R interface to the igraph network analysis library, providing tools for graph and network analysis within the R environment. The repository includes documentation for installation via CRAN or GitHub, system dependencies for compilation, and developer guides for managing the stimulus code generator, argument-signature migrations, and reverse dependency tracking.

Tokens
17K
Snippets
60
Records
90
Agent score
70%

What's inside rigraph

  1. Overview of stimulus

    main
    stimulus is an experimental code generator designed to create high-level interfaces for igraph. It is currently used to generate a significant portion of the igraph R interface. The project's goal is to provide a refactored, flexible framework that can be used to generate other high-level interfaces, such as the Python bindings, which currently rely on hand-written code.
  2. How argument-migration blocks work

    main

    When a public function's signature is migrated (e.g., by inserting ... and renaming arguments), Stimulus uses argument-migration blocks to prevent breaking existing calls. These blocks recover legacy calls by position or by (partial) name and emit a soft-deprecation.

    Implementation Details

    • Source of Truth: Migration definitions are stored in tools/migrations/<topic>.R registry files. Each entry declares the old and new signatures.
    • Generation: The tool tools/generate-migrations.R reads these registries and rewrites the code between # BEGIN GENERATED ARG_HANDLE: <fn> and # END GENERATED ARG_HANDLE markers inside the R functions.
    • Usage: The generated block uses lifecycle::deprecate_soft() to warn users without silencing internal igraph callers.

    Warning: Do not edit the code between the # BEGIN and # END markers by hand. They are regenerated automatically.

    Regenerating migrations

    After editing a registry file in tools/migrations/, run:

    Rscript tools/generate-migrations.R

    Migration Best Practices

    To reorder an argument or drop a positional slot without breaking old calls, place the affected argument after ... in the new signature. Arguments following the ellipsis are treated as keyword-only and are recovered by name rather than position.

  3. Understand the rigraph package structure

    main

    The rigraph R package is a monorepo that combines the C core library with the R interface. It uses a vendoring strategy to include the igraph C library directly in the repository to ensure CRAN compliance and ease of building.

    Key directories:

    • R/: Native R code.
    • tests/testthat/: R unit tests.
    • src/: Contains glue code (C++ bridge between R and C) and the vendor/ directory.
    • src/vendor/cigraph/: The vendored igraph C core. Never modify this directory directly.
    • patch/: Contains R-specific patches applied to the vendored C code.
    • DESCRIPTION: Package metadata.
  4. How the dependency tracking system works

    main

    The build system uses an automated mechanism to enable efficient incremental compilation by tracking header dependencies.

    The Workflow:

    1. Generation: The compiler uses -MMD -MP flags to create raw .d files during compilation.
    2. Filtering: A deps.mk pipeline processes these .d files into .dd files. This process filters out system headers (keeping only local project headers), formats them for Makefile compatibility, and adds an auto-generated header comment.
    3. Integration: The main Makefile includes these .dd files, allowing make to automatically recompile source files whenever a local header dependency changes.

    File Types:

    • .d files: Raw compiler-generated dependency files. These are machine-specific and must never be committed to git.
    • .dd files: Processed, local-only dependency files. These are committed to the repository.
  5. Implement a custom CodeGenerator in Stimulus

    main

    To support a new language in Stimulus, you must implement a custom CodeGenerator class.

    Requirements:

    1. Inheritance: The class must derive from the base CodeGenerator class provided by Stimulus.
    2. Naming Convention: The class name must be prepended with the language identifier. For example, a generator for the C code of the R interface is named RCCodeGenerator.
    3. Implementation: You must implement the generate_function abstract method. This method contains the logic for how functions are translated into the target language.

    When running the CLI, the -l flag must match the identifier used in your class name (e.g., -l RC selects RCCodeGenerator).

  6. How argument recovery works during migration

    main

    When a user calls a migrated function using an old signature, the system maps those arguments to the new signature using these rules:

    1. Head Arguments: Arguments defined before ... in the new signature bind positionally. They must maintain their relative order and names.
    2. Trailing Arguments: Old positional slots located beyond the 'head' arguments are recovered from ....
      • Unnamed values are mapped by position.
      • Named values (including abbreviated names) are mapped by partial match.
      • Renamed arguments are also recovered via partial name matching.
    3. Reordering or Dropping Arguments: To reorder an argument or drop it from positional matching, place it after ... in the new signature. This makes the argument keyword-only, meaning it is recovered by (partial) name rather than by position, avoiding positional math errors.
  7. Define parameter dependencies with DEPS

    main

    The DEPS property in a function definition allows you to specify that a parameter depends on the result of other code. This is useful for automated type conversion (e.g., converting vertex names to indices).

    Syntax:

    DEPS: parameter_name ON dependency1 dependency2

    Usage in Templates:

    Inside type definitions, you can reference these dependencies using the %I[number]% placeholder, where [number] is the 1-based index of the dependency in the DEPS list.

    Example: If you define DEPS: res ON graph vids, then:

    • %I1% refers to graph
    • %I2% refers to vids
  8. How the patch stack works for C core adjustments

    main

    Because the igraph C core is vendored directly, any R-specific adjustments required for the C code must be maintained in the patch/ directory.

    Workflow:

    1. Every vendoring run (automated or manual) takes the raw C sources from src/vendor/cigraph/.
    2. It then applies an ordered series of git-format patches from the patch/ directory.
    3. The resulting "R-ready" C sources are what get committed to the repository.

    Patch Management Rules:

    • Patches are numbered (e.g., 0001-...patch) to define application order.
    • If a patch is no longer needed (e.g., the fix was accepted upstream), delete the file.
    • Do not renumber the remaining patches. Gaps in numbering are expected.
    • When adding a new patch, use the next available number and attempt to submit the change to the upstream igraph/igraph repository to retire the patch.
  9. Migrate from deprecated igraph graph construction functions

    main

    To prevent future hard errors, update long-deprecated graph construction and analysis functions to their current names.

    Mapping for FrF2 and similar packages:

    • graph.empty() $\rightarrow$ make_empty_graph()
    • add.edges() $\rightarrow$ add_edges()
    • independence.number() $\rightarrow$ ivs_size()
    • clique.number() $\rightarrow$ clique_num()
    # Example migration for FrF2
    # Old:
    g <- graph.empty(n = 10)
    add.edges(g, edges)
    
    # New:
    g <- make_empty_graph(n = 10)
    add_edges(g, edges)
  10. Run the Maintainer Notification Script

    main

    Execute the notify-maintainers.sh script to automate notifying package maintainers about reverse dependency issues.

    The script follows this logic for each affected package:

    1. GitHub Integration: If a GitHub repository is accessible, it creates a GitHub issue using gh issue create and logs the URL.
    2. Email Fallback: If GitHub is not accessible, it generates an email draft in the notifications/ directory with the To: field pre-filled using the maintainer's CRAN email.

    Note: The script performs either a GitHub issue creation OR an email draft creation per package, not both.

    ./notify-maintainers.sh
  11. Customize package lists and issue templates

    main

    To add new packages or modify the content of notifications, edit the notify-maintainers.sh script directly. Each package entry must follow this specific pattern:

    PACKAGE="PackageName"
    GITHUB_URL="https://github.com/owner/repo"
    MAINTAINER_EMAIL="maintainer@example.com"  # from CRAN DESCRIPTION
    
    ISSUE_TITLE="Short description of the issue"
    ISSUE_BODY="..."
    EMAIL_SUBJECT="..."
    
    notify_package "$PACKAGE" "$GITHUB_URL" "$MAINTAINER_EMAIL" "$ISSUE_TITLE" "$ISSUE_BODY" "$EMAIL_SUBJECT"
    PACKAGE="PackageName"
    GITHUB_URL="https://github.com/owner/repo"
    MAINTAINER_EMAIL="maintainer@example.com"
    
    ISSUE_TITLE="Short description of the issue"
    ISSUE_BODY="..."
    EMAIL_SUBJECT="..."
    
    notify_package "$PACKAGE" "$GITHUB_URL" "$MAINTAINER_EMAIL" "$ISSUE_TITLE" "$ISSUE_BODY" "$EMAIL_SUBJECT"
  12. Fix matrix orientation for `get_edge_ids()`

    main

    The vp argument in get_edge_ids() (formerly get.edge.ids()) expects a matrix of vertex pairs in an $n imes 2$ orientation (where $n$ is the number of pairs). Previously, $2 imes n$ was accepted, but this is now defunct.

    Task:

    • Ensure the matrix passed to vp is $n imes 2$.
    • You can fix this by transposing the matrix using t(), converting it to a 2-column data frame, or passing a flat vertex-pair vector.
    • Rename the deprecated alias get.edge.ids() to the current get_edge_ids().
    # If 'pairs' is currently 2 x n, transpose it:
    igraph::get_edge_ids(g, t(pairs))