From 734767bc566213a8b2e78850aab8b70c8ec0762a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 26 Oct 2025 20:06:04 +0000 Subject: [PATCH 1/5] Initial plan From daa412853c18e533d532b7f504cae0a9fd52b4de Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 26 Oct 2025 20:32:17 +0000 Subject: [PATCH 2/5] feat: standardize handling of optional vertex parameters - Change default from `vid=0` to `vid=NULL` in YAML config - Update Stimulus R generator to pass -1 (instead of 0) for optional VERTEX when NULL - Update optional_wrapper_r to properly handle multi-line INCONV blocks - Fix R auto-generated code to wrap length checks inside NULL checks - Fix .Call to pass NULL correctly for optional vertex parameters - Affects: random_spanning_tree, fundamental_cycles, vertex_path_from_edge_path Co-authored-by: krlmlr <1741643+krlmlr@users.noreply.github.com> --- R/aaa-auto.R | 50 ++-- src/cpp11.dd | 252 ++++++++++++++++++ src/rinterface.c | 6 +- src/rinterface.dd | 108 ++++++++ .../py-stimulus/src/stimulus/generators/r.py | 21 +- tools/stimulus/functions-R.yaml | 2 +- 6 files changed, 411 insertions(+), 28 deletions(-) diff --git a/R/aaa-auto.R b/R/aaa-auto.R index a019de8c302..48d95f6280f 100644 --- a/R/aaa-auto.R +++ b/R/aaa-auto.R @@ -8151,12 +8151,14 @@ fundamental_cycles_impl <- function( ) { # Argument checks ensure_igraph(graph) - if (!is.null(start)) start <- as_igraph_vs(graph, start) - if (length(start) == 0) { - cli::cli_abort( - "{.arg start} must specify at least one vertex", - call = rlang::caller_env() - ) + if (!is.null(start)) { + start <- as_igraph_vs(graph, start) + if (length(start) == 0) { + cli::cli_abort( + "{.arg start} must specify at least one vertex", + call = rlang::caller_env() + ) + } } bfs.cutoff <- as.numeric(bfs.cutoff) if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { @@ -8173,7 +8175,7 @@ fundamental_cycles_impl <- function( res <- .Call( R_igraph_fundamental_cycles, graph, - start - 1, + if (!is.null(start)) start - 1 else NULL, bfs.cutoff, weights ) @@ -8344,16 +8346,18 @@ is_complete_impl <- function( random_spanning_tree_impl <- function( graph, - vid = 0 + vid = NULL ) { # Argument checks ensure_igraph(graph) - if (!is.null(vid)) vid <- as_igraph_vs(graph, vid) - if (length(vid) == 0) { - cli::cli_abort( - "{.arg vid} must specify at least one vertex", - call = rlang::caller_env() - ) + if (!is.null(vid)) { + vid <- as_igraph_vs(graph, vid) + if (length(vid) == 0) { + cli::cli_abort( + "{.arg vid} must specify at least one vertex", + call = rlang::caller_env() + ) + } } on.exit(.Call(R_igraph_finalizer)) @@ -8361,7 +8365,7 @@ random_spanning_tree_impl <- function( res <- .Call( R_igraph_random_spanning_tree, graph, - vid - 1 + if (!is.null(vid)) vid - 1 else NULL ) if (igraph_opt("return.vs.es")) { res <- create_es(graph, res) @@ -8655,12 +8659,14 @@ vertex_path_from_edge_path_impl <- function( ) { # Argument checks ensure_igraph(graph) - if (!is.null(start)) start <- as_igraph_vs(graph, start) - if (length(start) == 0) { - cli::cli_abort( - "{.arg start} must specify at least one vertex", - call = rlang::caller_env() - ) + if (!is.null(start)) { + start <- as_igraph_vs(graph, start) + if (length(start) == 0) { + cli::cli_abort( + "{.arg start} must specify at least one vertex", + call = rlang::caller_env() + ) + } } edge.path <- as_igraph_es(graph, edge.path) mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) @@ -8670,7 +8676,7 @@ vertex_path_from_edge_path_impl <- function( res <- .Call( R_igraph_vertex_path_from_edge_path, graph, - start - 1, + if (!is.null(start)) start - 1 else NULL, edge.path - 1, mode ) diff --git a/src/cpp11.dd b/src/cpp11.dd index 9abbae1fcad..de42af19ba0 100644 --- a/src/cpp11.dd +++ b/src/cpp11.dd @@ -2,3 +2,255 @@ cpp11.o: \ cpp11.cpp \ igraph_types.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/R.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/altrep.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/as.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/attribute_proxy.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/data_frame.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/declarations.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/doubles.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/environment.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/external_pointer.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/function.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/integers.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/list.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/list_of.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/logicals.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/matrix.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/named_arg.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/protect.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/r_bool.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/r_string.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/r_vector.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/raws.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/sexp.hpp \ + /home/runner/work/_temp/Library/cpp11/include/cpp11/strings.hpp \ + /opt/R/4.5.1/lib/R/include/R_ext/Arith.h \ + /opt/R/4.5.1/lib/R/include/R_ext/Boolean.h \ + /opt/R/4.5.1/lib/R/include/R_ext/Complex.h \ + /opt/R/4.5.1/lib/R/include/R_ext/Error.h \ + /opt/R/4.5.1/lib/R/include/R_ext/Memory.h \ + /opt/R/4.5.1/lib/R/include/R_ext/Print.h \ + /opt/R/4.5.1/lib/R/include/R_ext/Rdynload.h \ + /opt/R/4.5.1/lib/R/include/R_ext/Utils.h \ + /opt/R/4.5.1/lib/R/include/R_ext/Visibility.h \ + /opt/R/4.5.1/lib/R/include/R_ext/libextern.h \ + /opt/R/4.5.1/lib/R/include/Rconfig.h \ + /opt/R/4.5.1/lib/R/include/Rinternals.h \ + /opt/R/4.5.1/lib/R/include/Rversion.h \ + /usr/include/asm-generic/errno.h \ + /usr/include/c++/13/algorithm \ + /usr/include/c++/13/backward/auto_ptr.h \ + /usr/include/c++/13/backward/binders.h \ + /usr/include/c++/13/bits/algorithmfwd.h \ + /usr/include/c++/13/bits/align.h \ + /usr/include/c++/13/bits/alloc_traits.h \ + /usr/include/c++/13/bits/allocated_ptr.h \ + /usr/include/c++/13/bits/allocator.h \ + /usr/include/c++/13/bits/atomic_base.h \ + /usr/include/c++/13/bits/atomic_lockfree_defines.h \ + /usr/include/c++/13/bits/basic_ios.h \ + /usr/include/c++/13/bits/basic_ios.tcc \ + /usr/include/c++/13/bits/basic_string.h \ + /usr/include/c++/13/bits/basic_string.tcc \ + /usr/include/c++/13/bits/char_traits.h \ + /usr/include/c++/13/bits/charconv.h \ + /usr/include/c++/13/bits/concept_check.h \ + /usr/include/c++/13/bits/cpp_type_traits.h \ + /usr/include/c++/13/bits/cxxabi_forced.h \ + /usr/include/c++/13/bits/cxxabi_init_exception.h \ + /usr/include/c++/13/bits/exception.h \ + /usr/include/c++/13/bits/exception_defines.h \ + /usr/include/c++/13/bits/exception_ptr.h \ + /usr/include/c++/13/bits/functexcept.h \ + /usr/include/c++/13/bits/functional_hash.h \ + /usr/include/c++/13/bits/hash_bytes.h \ + /usr/include/c++/13/bits/locale_classes.h \ + /usr/include/c++/13/bits/locale_classes.tcc \ + /usr/include/c++/13/bits/locale_facets.h \ + /usr/include/c++/13/bits/locale_facets.tcc \ + /usr/include/c++/13/bits/localefwd.h \ + /usr/include/c++/13/bits/memory_resource.h \ + /usr/include/c++/13/bits/memoryfwd.h \ + /usr/include/c++/13/bits/move.h \ + /usr/include/c++/13/bits/nested_exception.h \ + /usr/include/c++/13/bits/new_allocator.h \ + /usr/include/c++/13/bits/ostream.tcc \ + /usr/include/c++/13/bits/ostream_insert.h \ + /usr/include/c++/13/bits/postypes.h \ + /usr/include/c++/13/bits/predefined_ops.h \ + /usr/include/c++/13/bits/ptr_traits.h \ + /usr/include/c++/13/bits/range_access.h \ + /usr/include/c++/13/bits/refwrap.h \ + /usr/include/c++/13/bits/requires_hosted.h \ + /usr/include/c++/13/bits/shared_ptr.h \ + /usr/include/c++/13/bits/shared_ptr_atomic.h \ + /usr/include/c++/13/bits/shared_ptr_base.h \ + /usr/include/c++/13/bits/specfun.h \ + /usr/include/c++/13/bits/std_abs.h \ + /usr/include/c++/13/bits/stl_algobase.h \ + /usr/include/c++/13/bits/stl_bvector.h \ + /usr/include/c++/13/bits/stl_construct.h \ + /usr/include/c++/13/bits/stl_function.h \ + /usr/include/c++/13/bits/stl_heap.h \ + /usr/include/c++/13/bits/stl_iterator.h \ + /usr/include/c++/13/bits/stl_iterator_base_funcs.h \ + /usr/include/c++/13/bits/stl_iterator_base_types.h \ + /usr/include/c++/13/bits/stl_pair.h \ + /usr/include/c++/13/bits/stl_raw_storage_iter.h \ + /usr/include/c++/13/bits/stl_vector.h \ + /usr/include/c++/13/bits/stream_iterator.h \ + /usr/include/c++/13/bits/streambuf.tcc \ + /usr/include/c++/13/bits/streambuf_iterator.h \ + /usr/include/c++/13/bits/string_view.tcc \ + /usr/include/c++/13/bits/uniform_int_dist.h \ + /usr/include/c++/13/bits/uses_allocator.h \ + /usr/include/c++/13/bits/uses_allocator_args.h \ + /usr/include/c++/13/bits/vector.tcc \ + /usr/include/c++/13/cctype \ + /usr/include/c++/13/clocale \ + /usr/include/c++/13/compare \ + /usr/include/c++/13/csetjmp \ + /usr/include/c++/13/cstdint \ + /usr/include/c++/13/cstdio \ + /usr/include/c++/13/cstring \ + /usr/include/c++/13/debug/assertions.h \ + /usr/include/c++/13/ext/aligned_buffer.h \ + /usr/include/c++/13/ext/alloc_traits.h \ + /usr/include/c++/13/ext/atomicity.h \ + /usr/include/c++/13/ext/concurrence.h \ + /usr/include/c++/13/ext/numeric_traits.h \ + /usr/include/c++/13/ext/string_conversions.h \ + /usr/include/c++/13/ext/type_traits.h \ + /usr/include/c++/13/initializer_list \ + /usr/include/c++/13/limits \ + /usr/include/c++/13/math.h \ + /usr/include/c++/13/memory \ + /usr/include/c++/13/ostream \ + /usr/include/c++/13/pstl/execution_defs.h \ + /usr/include/c++/13/pstl/glue_algorithm_defs.h \ + /usr/include/c++/13/pstl/glue_memory_defs.h \ + /usr/include/c++/13/pstl/pstl_config.h \ + /usr/include/c++/13/streambuf \ + /usr/include/c++/13/string \ + /usr/include/c++/13/system_error \ + /usr/include/c++/13/tr1/bessel_function.tcc \ + /usr/include/c++/13/tr1/beta_function.tcc \ + /usr/include/c++/13/tr1/ell_integral.tcc \ + /usr/include/c++/13/tr1/exp_integral.tcc \ + /usr/include/c++/13/tr1/hypergeometric.tcc \ + /usr/include/c++/13/tr1/legendre_function.tcc \ + /usr/include/c++/13/tr1/modified_bessel_func.tcc \ + /usr/include/c++/13/tr1/poly_hermite.tcc \ + /usr/include/c++/13/tr1/poly_laguerre.tcc \ + /usr/include/c++/13/tr1/riemann_zeta.tcc \ + /usr/include/c++/13/tr1/special_function_util.h \ + /usr/include/c++/13/utility \ + /usr/include/c++/13/vector \ + /usr/include/errno.h \ + /usr/include/features-time64.h \ + /usr/include/inttypes.h \ + /usr/include/limits.h \ + /usr/include/linux/errno.h \ + /usr/include/linux/limits.h \ + /usr/include/pthread.h \ + /usr/include/wchar.h \ + /usr/include/wctype.h \ + /usr/include/x86_64-linux-gnu/bits/atomic_wide_counter.h \ + /usr/include/x86_64-linux-gnu/bits/byteswap.h \ + /usr/include/x86_64-linux-gnu/bits/cpu-set.h \ + /usr/include/x86_64-linux-gnu/bits/endian.h \ + /usr/include/x86_64-linux-gnu/bits/endianness.h \ + /usr/include/x86_64-linux-gnu/bits/floatn-common.h \ + /usr/include/x86_64-linux-gnu/bits/floatn.h \ + /usr/include/x86_64-linux-gnu/bits/flt-eval-method.h \ + /usr/include/x86_64-linux-gnu/bits/fp-fast.h \ + /usr/include/x86_64-linux-gnu/bits/fp-logb.h \ + /usr/include/x86_64-linux-gnu/bits/iscanonical.h \ + /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \ + /usr/include/x86_64-linux-gnu/bits/libm-simd-decl-stubs.h \ + /usr/include/x86_64-linux-gnu/bits/local_lim.h \ + /usr/include/x86_64-linux-gnu/bits/locale.h \ + /usr/include/x86_64-linux-gnu/bits/long-double.h \ + /usr/include/x86_64-linux-gnu/bits/math-vector.h \ + /usr/include/x86_64-linux-gnu/bits/mathcalls-helper-functions.h \ + /usr/include/x86_64-linux-gnu/bits/mathcalls-narrow.h \ + /usr/include/x86_64-linux-gnu/bits/mathcalls.h \ + /usr/include/x86_64-linux-gnu/bits/posix2_lim.h \ + /usr/include/x86_64-linux-gnu/bits/pthread_stack_min-dynamic.h \ + /usr/include/x86_64-linux-gnu/bits/pthreadtypes-arch.h \ + /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ + /usr/include/x86_64-linux-gnu/bits/sched.h \ + /usr/include/x86_64-linux-gnu/bits/select.h \ + /usr/include/x86_64-linux-gnu/bits/setjmp.h \ + /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \ + /usr/include/x86_64-linux-gnu/bits/stdint-least.h \ + /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \ + /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ + /usr/include/x86_64-linux-gnu/bits/stdlib-float.h \ + /usr/include/x86_64-linux-gnu/bits/struct_mutex.h \ + /usr/include/x86_64-linux-gnu/bits/struct_rwlock.h \ + /usr/include/x86_64-linux-gnu/bits/thread-shared-types.h \ + /usr/include/x86_64-linux-gnu/bits/time.h \ + /usr/include/x86_64-linux-gnu/bits/time64.h \ + /usr/include/x86_64-linux-gnu/bits/timesize.h \ + /usr/include/x86_64-linux-gnu/bits/timex.h \ + /usr/include/x86_64-linux-gnu/bits/types.h \ + /usr/include/x86_64-linux-gnu/bits/types/FILE.h \ + /usr/include/x86_64-linux-gnu/bits/types/__FILE.h \ + /usr/include/x86_64-linux-gnu/bits/types/__fpos64_t.h \ + /usr/include/x86_64-linux-gnu/bits/types/__fpos_t.h \ + /usr/include/x86_64-linux-gnu/bits/types/__locale_t.h \ + /usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h \ + /usr/include/x86_64-linux-gnu/bits/types/__sigset_t.h \ + /usr/include/x86_64-linux-gnu/bits/types/clock_t.h \ + /usr/include/x86_64-linux-gnu/bits/types/clockid_t.h \ + /usr/include/x86_64-linux-gnu/bits/types/cookie_io_functions_t.h \ + /usr/include/x86_64-linux-gnu/bits/types/error_t.h \ + /usr/include/x86_64-linux-gnu/bits/types/locale_t.h \ + /usr/include/x86_64-linux-gnu/bits/types/mbstate_t.h \ + /usr/include/x86_64-linux-gnu/bits/types/sigset_t.h \ + /usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h \ + /usr/include/x86_64-linux-gnu/bits/types/struct___jmp_buf_tag.h \ + /usr/include/x86_64-linux-gnu/bits/types/struct_itimerspec.h \ + /usr/include/x86_64-linux-gnu/bits/types/struct_sched_param.h \ + /usr/include/x86_64-linux-gnu/bits/types/struct_timespec.h \ + /usr/include/x86_64-linux-gnu/bits/types/struct_timeval.h \ + /usr/include/x86_64-linux-gnu/bits/types/struct_tm.h \ + /usr/include/x86_64-linux-gnu/bits/types/time_t.h \ + /usr/include/x86_64-linux-gnu/bits/types/timer_t.h \ + /usr/include/x86_64-linux-gnu/bits/typesizes.h \ + /usr/include/x86_64-linux-gnu/bits/uintn-identity.h \ + /usr/include/x86_64-linux-gnu/bits/uio_lim.h \ + /usr/include/x86_64-linux-gnu/bits/waitflags.h \ + /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ + /usr/include/x86_64-linux-gnu/bits/wchar.h \ + /usr/include/x86_64-linux-gnu/bits/wordsize.h \ + /usr/include/x86_64-linux-gnu/bits/xopen_lim.h \ + /usr/include/x86_64-linux-gnu/c++/13/bits/atomic_word.h \ + /usr/include/x86_64-linux-gnu/c++/13/bits/c++allocator.h \ + /usr/include/x86_64-linux-gnu/c++/13/bits/c++config.h \ + /usr/include/x86_64-linux-gnu/c++/13/bits/c++locale.h \ + /usr/include/x86_64-linux-gnu/c++/13/bits/cpu_defines.h \ + /usr/include/x86_64-linux-gnu/c++/13/bits/ctype_base.h \ + /usr/include/x86_64-linux-gnu/c++/13/bits/ctype_inline.h \ + /usr/include/x86_64-linux-gnu/c++/13/bits/error_constants.h \ + /usr/include/x86_64-linux-gnu/c++/13/bits/gthr-default.h \ + /usr/include/x86_64-linux-gnu/c++/13/bits/gthr.h \ + /usr/include/x86_64-linux-gnu/c++/13/bits/os_defines.h \ + /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ + /usr/include/x86_64-linux-gnu/gnu/stubs.h \ + /usr/include/x86_64-linux-gnu/sys/cdefs.h \ + /usr/include/x86_64-linux-gnu/sys/select.h \ + /usr/include/x86_64-linux-gnu/sys/single_threaded.h \ + /usr/include/x86_64-linux-gnu/sys/types.h \ + /usr/lib/gcc/x86_64-linux-gnu/13/include/limits.h \ + /usr/lib/gcc/x86_64-linux-gnu/13/include/stdarg.h \ + /usr/lib/gcc/x86_64-linux-gnu/13/include/stdbool.h \ + /usr/lib/gcc/x86_64-linux-gnu/13/include/stddef.h \ + /usr/lib/gcc/x86_64-linux-gnu/13/include/stdint.h \ + /usr/lib/gcc/x86_64-linux-gnu/13/include/syslimits.h \ + vendor/cigraph/include/igraph_decls.h \ + vendor/cigraph/include/igraph_types.h \ + vendor/igraph_config.h \ diff --git a/src/rinterface.c b/src/rinterface.c index d1bd108609a..1f535243644 100644 --- a/src/rinterface.c +++ b/src/rinterface.c @@ -11681,7 +11681,7 @@ SEXP R_igraph_fundamental_cycles(SEXP graph, SEXP start, SEXP bfs_cutoff, SEXP w R_SEXP_to_vector(weights, &c_weights); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_fundamental_cycles(&c_graph, &c_basis, (Rf_isNull(start) ? 0 : c_start), c_bfs_cutoff, (Rf_isNull(weights) ? 0 : &c_weights))); + IGRAPH_R_CHECK(igraph_fundamental_cycles(&c_graph, &c_basis, (Rf_isNull(start) ? -1 : c_start), c_bfs_cutoff, (Rf_isNull(weights) ? 0 : &c_weights))); /* Convert output */ PROTECT(basis=R_igraph_vector_int_list_to_SEXPp1(&c_basis)); @@ -11941,7 +11941,7 @@ SEXP R_igraph_random_spanning_tree(SEXP graph, SEXP vid) { c_vid = (igraph_integer_t) REAL(vid)[0]; } /* Call igraph */ - IGRAPH_R_CHECK(igraph_random_spanning_tree(&c_graph, &c_res, (Rf_isNull(vid) ? 0 : c_vid))); + IGRAPH_R_CHECK(igraph_random_spanning_tree(&c_graph, &c_res, (Rf_isNull(vid) ? -1 : c_vid))); /* Convert output */ PROTECT(res=R_igraph_vector_int_to_SEXPp1(&c_res)); @@ -12328,7 +12328,7 @@ SEXP R_igraph_vertex_path_from_edge_path(SEXP graph, SEXP start, SEXP edge_path, IGRAPH_FINALLY(igraph_vector_int_destroy, &c_vertex_path); c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_vertex_path_from_edge_path(&c_graph, (Rf_isNull(start) ? 0 : c_start), &c_edge_path, &c_vertex_path, c_mode)); + IGRAPH_R_CHECK(igraph_vertex_path_from_edge_path(&c_graph, (Rf_isNull(start) ? -1 : c_start), &c_edge_path, &c_vertex_path, c_mode)); /* Convert output */ igraph_vector_int_destroy(&c_edge_path); diff --git a/src/rinterface.dd b/src/rinterface.dd index 4e60bfc2463..571daf68b19 100644 --- a/src/rinterface.dd +++ b/src/rinterface.dd @@ -2,3 +2,111 @@ rinterface.o: \ rinterface.c \ rinterface.h \ + /opt/R/4.5.1/lib/R/include/R_ext/Arith.h \ + /opt/R/4.5.1/lib/R/include/R_ext/Boolean.h \ + /opt/R/4.5.1/lib/R/include/R_ext/Complex.h \ + /opt/R/4.5.1/lib/R/include/R_ext/Constants.h \ + /opt/R/4.5.1/lib/R/include/R_ext/Error.h \ + /opt/R/4.5.1/lib/R/include/R_ext/Memory.h \ + /opt/R/4.5.1/lib/R/include/R_ext/Print.h \ + /opt/R/4.5.1/lib/R/include/R_ext/RS.h \ + /opt/R/4.5.1/lib/R/include/R_ext/Random.h \ + /opt/R/4.5.1/lib/R/include/R_ext/Rdynload.h \ + /opt/R/4.5.1/lib/R/include/R_ext/Utils.h \ + /opt/R/4.5.1/lib/R/include/R_ext/libextern.h \ + /opt/R/4.5.1/lib/R/include/Rconfig.h \ + /opt/R/4.5.1/lib/R/include/Rdefines.h \ + /opt/R/4.5.1/lib/R/include/Rinternals.h \ + vendor/cigraph/include/igraph_adjlist.h \ + vendor/cigraph/include/igraph_arpack.h \ + vendor/cigraph/include/igraph_array.h \ + vendor/cigraph/include/igraph_array_pmt.h \ + vendor/cigraph/include/igraph_attributes.h \ + vendor/cigraph/include/igraph_attributes.h \ + vendor/cigraph/include/igraph_bipartite.h \ + vendor/cigraph/include/igraph_bitset.h \ + vendor/cigraph/include/igraph_bitset_list.h \ + vendor/cigraph/include/igraph_blas.h \ + vendor/cigraph/include/igraph_centrality.h \ + vendor/cigraph/include/igraph_cliques.h \ + vendor/cigraph/include/igraph_cocitation.h \ + vendor/cigraph/include/igraph_cohesive_blocks.h \ + vendor/cigraph/include/igraph_coloring.h \ + vendor/cigraph/include/igraph_community.h \ + vendor/cigraph/include/igraph_complex.h \ + vendor/cigraph/include/igraph_components.h \ + vendor/cigraph/include/igraph_constants.h \ + vendor/cigraph/include/igraph_constants.h \ + vendor/cigraph/include/igraph_constructors.h \ + vendor/cigraph/include/igraph_conversion.h \ + vendor/cigraph/include/igraph_cycles.h \ + vendor/cigraph/include/igraph_datatype.h \ + vendor/cigraph/include/igraph_datatype.h \ + vendor/cigraph/include/igraph_decls.h \ + vendor/cigraph/include/igraph_dqueue.h \ + vendor/cigraph/include/igraph_dqueue_pmt.h \ + vendor/cigraph/include/igraph_eigen.h \ + vendor/cigraph/include/igraph_embedding.h \ + vendor/cigraph/include/igraph_epidemics.h \ + vendor/cigraph/include/igraph_error.h \ + vendor/cigraph/include/igraph_error.h \ + vendor/cigraph/include/igraph_eulerian.h \ + vendor/cigraph/include/igraph_flow.h \ + vendor/cigraph/include/igraph_foreign.h \ + vendor/cigraph/include/igraph_games.h \ + vendor/cigraph/include/igraph_graph_list.h \ + vendor/cigraph/include/igraph_graphicality.h \ + vendor/cigraph/include/igraph_graphlets.h \ + vendor/cigraph/include/igraph_heap.h \ + vendor/cigraph/include/igraph_heap_pmt.h \ + vendor/cigraph/include/igraph_hrg.h \ + vendor/cigraph/include/igraph_interface.h \ + vendor/cigraph/include/igraph_interrupt.h \ + vendor/cigraph/include/igraph_iterators.h \ + vendor/cigraph/include/igraph_lapack.h \ + vendor/cigraph/include/igraph_layout.h \ + vendor/cigraph/include/igraph_lsap.h \ + vendor/cigraph/include/igraph_matching.h \ + vendor/cigraph/include/igraph_matrix.h \ + vendor/cigraph/include/igraph_matrix_list.h \ + vendor/cigraph/include/igraph_matrix_pmt.h \ + vendor/cigraph/include/igraph_microscopic_update.h \ + vendor/cigraph/include/igraph_mixing.h \ + vendor/cigraph/include/igraph_motifs.h \ + vendor/cigraph/include/igraph_neighborhood.h \ + vendor/cigraph/include/igraph_nongraph.h \ + vendor/cigraph/include/igraph_operators.h \ + vendor/cigraph/include/igraph_paths.h \ + vendor/cigraph/include/igraph_pmt.h \ + vendor/cigraph/include/igraph_pmt_off.h \ + vendor/cigraph/include/igraph_progress.h \ + vendor/cigraph/include/igraph_psumtree.h \ + vendor/cigraph/include/igraph_qsort.h \ + vendor/cigraph/include/igraph_random.h \ + vendor/cigraph/include/igraph_reachability.h \ + vendor/cigraph/include/igraph_scan.h \ + vendor/cigraph/include/igraph_separators.h \ + vendor/cigraph/include/igraph_sparsemat.h \ + vendor/cigraph/include/igraph_stack.h \ + vendor/cigraph/include/igraph_stack_pmt.h \ + vendor/cigraph/include/igraph_statusbar.h \ + vendor/cigraph/include/igraph_structural.h \ + vendor/cigraph/include/igraph_strvector.h \ + vendor/cigraph/include/igraph_strvector.h \ + vendor/cigraph/include/igraph_topology.h \ + vendor/cigraph/include/igraph_transitivity.h \ + vendor/cigraph/include/igraph_typed_list_pmt.h \ + vendor/cigraph/include/igraph_types.h \ + vendor/cigraph/include/igraph_types.h \ + vendor/cigraph/include/igraph_vector.h \ + vendor/cigraph/include/igraph_vector.h \ + vendor/cigraph/include/igraph_vector_list.h \ + vendor/cigraph/include/igraph_vector_pmt.h \ + vendor/cigraph/include/igraph_vector_ptr.h \ + vendor/cigraph/include/igraph_vector_type.h \ + vendor/cigraph/include/igraph_visitor.h \ + vendor/cigraph/src/graph/attributes.h \ + vendor/cigraph/src/graph/internal.h \ + vendor/igraph_config.h \ + vendor/igraph_export.h \ + vendor/igraph_version.h \ diff --git a/tools/py-stimulus/src/stimulus/generators/r.py b/tools/py-stimulus/src/stimulus/generators/r.py index c7101fb12f0..f52b7a20e8f 100644 --- a/tools/py-stimulus/src/stimulus/generators/r.py +++ b/tools/py-stimulus/src/stimulus/generators/r.py @@ -51,7 +51,21 @@ def optional_wrapper_r(conv: str) -> str: if "is.null" in conv: return conv - return f"if (!is.null(%I%)) {conv}" + # Check if conv is a multi-line block + if "\n" in conv: + # Wrap multi-line block with if statement and proper indentation + lines = conv.split("\n") + wrapped_lines = [f"if (!is.null(%I%)) {{"] + for line in lines: + if line.strip(): # Only indent non-empty lines + wrapped_lines.append(f" {line}") + else: + wrapped_lines.append(line) + wrapped_lines.append("}") + return "\n".join(wrapped_lines) + else: + # Single-line: wrap as before + return f"if (!is.null(%I%)) {conv}" def format_switch_statement(code: str) -> str: @@ -600,7 +614,10 @@ def chunk_call(self, desc: FunctionDescriptor) -> str: and not param.is_output and call != "0" ): - call = f"(Rf_isNull(%I%) ? 0 : {call})" + # For VERTEX types, use -1 when NULL (indicates no vertex/all components) + # For other types, use 0 + null_value = "-1" if param.type == "VERTEX" else "0" + call = f"(Rf_isNull(%I%) ? {null_value} : {call})" call = call.replace("%C%", f"c_{param.name}").replace("%I%", param.name) calls.append(call) diff --git a/tools/stimulus/functions-R.yaml b/tools/stimulus/functions-R.yaml index f88aaa9f1aa..790c3fa5040 100644 --- a/tools/stimulus/functions-R.yaml +++ b/tools/stimulus/functions-R.yaml @@ -1020,7 +1020,7 @@ igraph_minimum_spanning_tree_prim: IGNORE: RR, RC igraph_random_spanning_tree: - PARAMS: GRAPH graph, OUT EDGE_INDICES res, OPTIONAL VERTEX vid=0 + PARAMS: GRAPH graph, OUT EDGE_INDICES res, OPTIONAL VERTEX vid ####################################### # Coloring From 749399a4f5811f10972cb5ffd05609b1030f3c58 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 26 Oct 2025 20:34:31 +0000 Subject: [PATCH 3/5] fix: update sample_spanning_tree wrapper to use NULL default Update sample_spanning_tree function in R/trees.R to use `vid = NULL` as default and update documentation accordingly. Co-authored-by: krlmlr <1741643+krlmlr@users.noreply.github.com> --- R/trees.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/trees.R b/R/trees.R index 03adbc86ee3..693f8976275 100644 --- a/R/trees.R +++ b/R/trees.R @@ -152,7 +152,7 @@ to_prufer <- function(graph) { #' @param graph The input graph to sample from. Edge directions are ignored if #' the graph is directed. #' @param vid When the graph is disconnected, this argument specifies how to -#' handle the situation. When the argument is zero (the default), the sampling +#' handle the situation. When the argument is `NULL` (the default), the sampling #' will be performed component-wise, and the result will be a spanning forest. #' When the argument contains a vertex ID, only the component containing the #' given vertex will be processed, and the result will be a spanning tree of the @@ -171,7 +171,7 @@ to_prufer <- function(graph) { #' @family trees #' @export #' @cdocs igraph_random_spanning_tree -sample_spanning_tree <- function(graph, vid = 0) { +sample_spanning_tree <- function(graph, vid = NULL) { random_spanning_tree_impl( graph = graph, vid = vid From 4536066a3d94c1341224bd1b6e9126894a48aede Mon Sep 17 00:00:00 2001 From: krlmlr Date: Sun, 26 Oct 2025 21:40:06 +0000 Subject: [PATCH 4/5] chore: Auto-update from GitHub Actions Run: https://github.com/igraph/rigraph/actions/runs/18824015452 --- man/sample_spanning_tree.Rd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/man/sample_spanning_tree.Rd b/man/sample_spanning_tree.Rd index 69efb56e52b..1100e6a41af 100644 --- a/man/sample_spanning_tree.Rd +++ b/man/sample_spanning_tree.Rd @@ -4,14 +4,14 @@ \alias{sample_spanning_tree} \title{Samples from the spanning trees of a graph randomly and uniformly} \usage{ -sample_spanning_tree(graph, vid = 0) +sample_spanning_tree(graph, vid = NULL) } \arguments{ \item{graph}{The input graph to sample from. Edge directions are ignored if the graph is directed.} \item{vid}{When the graph is disconnected, this argument specifies how to -handle the situation. When the argument is zero (the default), the sampling +handle the situation. When the argument is \code{NULL} (the default), the sampling will be performed component-wise, and the result will be a spanning forest. When the argument contains a vertex ID, only the component containing the given vertex will be processed, and the result will be a spanning tree of the From a788d99f837eb265e2a87571d50c0b7a58ace98d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 4 Nov 2025 22:02:58 +0000 Subject: [PATCH 5/5] refactor: move optional VERTEX subtraction to INCONV block Move the `- 1` subtraction for optional VERTEX parameters from .Call() into the INCONV block (inside the NULL check) as requested by @maelle. This improves code clarity by keeping all parameter transformations together. Changes: - Modified Stimulus R generator to add subtraction inside optional_wrapper_r for VERTEX type - Updated CALL handling to pass VERTEX name directly for optional parameters - Regenerated R/aaa-auto.R with cleaner code structure Co-authored-by: krlmlr <1741643+krlmlr@users.noreply.github.com> --- R/aaa-auto.R | 11 +++++++--- .../py-stimulus/src/stimulus/generators/r.py | 20 +++++++++++++++---- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/R/aaa-auto.R b/R/aaa-auto.R index edda1bfd11f..6151c6d7f49 100644 --- a/R/aaa-auto.R +++ b/R/aaa-auto.R @@ -9730,6 +9730,7 @@ fundamental_cycles_impl <- function( call = rlang::caller_env() ) } + start <- start - 1 } bfs_cutoff <- as.numeric(bfs_cutoff) if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { @@ -9746,7 +9747,8 @@ fundamental_cycles_impl <- function( res <- .Call( R_igraph_fundamental_cycles, graph, - if (!is.null(start)) start - 1 else NULL, bfs_cutoff, + start, + bfs_cutoff, weights ) if (igraph_opt("return.vs.es")) { @@ -9982,6 +9984,7 @@ random_spanning_tree_impl <- function( call = rlang::caller_env() ) } + vid <- vid - 1 } on.exit(.Call(R_igraph_finalizer)) @@ -9989,7 +9992,7 @@ random_spanning_tree_impl <- function( res <- .Call( R_igraph_random_spanning_tree, graph, - if (!is.null(vid)) vid - 1 else NULL + vid ) if (igraph_opt("return.vs.es")) { res <- create_es(graph, res) @@ -10315,6 +10318,7 @@ vertex_path_from_edge_path_impl <- function( call = rlang::caller_env() ) } + start <- start - 1 } edge_path <- as_igraph_es(graph, edge_path) mode <- switch_igraph_arg( @@ -10330,7 +10334,8 @@ vertex_path_from_edge_path_impl <- function( res <- .Call( R_igraph_vertex_path_from_edge_path, graph, - if (!is.null(start)) start - 1 else NULL, edge_path - 1, + start, + edge_path - 1, mode ) if (igraph_opt("return.vs.es")) { diff --git a/tools/py-stimulus/src/stimulus/generators/r.py b/tools/py-stimulus/src/stimulus/generators/r.py index 088964b58aa..dc8a5023b87 100644 --- a/tools/py-stimulus/src/stimulus/generators/r.py +++ b/tools/py-stimulus/src/stimulus/generators/r.py @@ -255,7 +255,15 @@ def handle_argument_check(param: ParamSpec) -> str: if param.is_optional and param.is_input and res: res = optional_wrapper_r(res) - + # For optional VERTEX parameters, add the subtraction inside the NULL check + if param.type == "VERTEX": + # Add the subtraction at the end of the wrapped block + name = get_r_parameter_name(param) + res = res.rstrip() + if res.endswith("}"): + # Insert before the closing brace + res = res[:-1] + f" {name} <- {name} - 1\n}}" + # Replace template placeholders res = indent(res).replace("%I%", get_r_parameter_name(param)) for i, dep in enumerate(param.dependencies): @@ -299,9 +307,13 @@ def handle_argument_check(param: ParamSpec) -> str: name = get_r_parameter_name(param) call = type.get("CALL", name) if call: - call_formatted = call.replace("%I%", name) - # Add spaces around arithmetic operators - call_formatted = re.sub(r'(\w+)(\+|\-|\*|/)(\d+)', r'\1 \2 \3', call_formatted) + # For optional VERTEX parameters, subtraction is done in INCONV, so just use the name + if param.is_optional and param.type == "VERTEX": + call_formatted = name + else: + call_formatted = call.replace("%I%", name) + # Add spaces around arithmetic operators + call_formatted = re.sub(r'(\w+)(\+|\-|\*|/)(\d+)', r'\1 \2 \3', call_formatted) parts.append(call_formatted) # Format .Call() as multi-line with each argument on its own line