Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
2e386c7
Record native search branch split and preserve research
zayenz Oct 13, 2026
a6baf8e
Add tasks to open-search
zayenz Oct 13, 2026
31970a1
Extract standalone heuristic search onto open-cp
zayenz Oct 13, 2026
258233f
Add tasks to open-search
zayenz Oct 13, 2026
da0189d
Gate heuristic search as experimental and separate preview changelog …
zayenz Oct 13, 2026
55454f6
Record validated open-search rebase onto current open-cp
zayenz Oct 13, 2026
c546ebd
Add tasks to open-search
zayenz Oct 13, 2026
05eeba0
Repair search completion and keep the preview compatible with Gecode 6.5
zayenz Oct 13, 2026
b526e12
Use concrete wording in source comments and search documentation
zayenz Oct 13, 2026
6a6688d
Simplify heuristic search examples around the public interfaces
zayenz Oct 13, 2026
6e889f7
Keep brancher preparation policy in the search layer
zayenz Oct 13, 2026
c4d287c
Invalidate completion witnesses at constraint posting
zayenz Oct 13, 2026
82a6b6b
Check every validated tour against benchmark optimality claims
zayenz Oct 13, 2026
ef00bdc
Plan fifteen-puzzle heuristic search integration
zayenz Oct 14, 2026
e3c3617
Add tasks to open-search
zayenz Oct 14, 2026
9f31627
Add A* and CABS to the fifteen-puzzle example
zayenz Oct 14, 2026
5d78467
Add tasks to open-search
zayenz Oct 14, 2026
3e70e55
Carry deferred puzzle goal checks into the heuristic branch
zayenz Oct 14, 2026
bd2c4d2
Add tasks to open-search
zayenz Oct 14, 2026
f575912
Restore puzzle pruning without eager board construction
zayenz Oct 14, 2026
f867b6a
Add tasks to open-search
zayenz Oct 14, 2026
c4185d2
Record NoGPI stack integration and verification
zayenz Oct 14, 2026
f4b3d31
Add tasks to open-search
zayenz Oct 14, 2026
9c5a02e
Record NoGPI method documentation review
zayenz Oct 14, 2026
7ab8111
Refresh open-search base after NoGPI rebase
zayenz Oct 15, 2026
6bef238
Refresh open-search base after NoGPI pointer updates
zayenz Oct 15, 2026
604ecee
Add tasks to open-search
zayenz Oct 15, 2026
42d5aa1
Align puzzle simplification task with the fixed formulation
zayenz Oct 15, 2026
afdb45a
Record verified fixed-style puzzle simplification
zayenz Oct 15, 2026
f47d44d
Add tasks to open-search
zayenz Oct 15, 2026
5442378
Use the requested IntArgs neighbor representation
zayenz Oct 15, 2026
df70496
Record verified IntArgs puzzle neighbors
zayenz Oct 15, 2026
5b994cd
Add tasks to open-search
zayenz Oct 15, 2026
8d340a2
Record verified shared puzzle goal implications
zayenz Oct 15, 2026
19d41c8
Add tasks to open-search
zayenz Oct 15, 2026
ceca668
Record verified Manhattan puzzle value selection
zayenz Oct 15, 2026
6f85479
Allow pending parallel stops in completion test
zayenz Oct 18, 2026
d94b705
Tighten heuristic search documentation
zayenz Oct 18, 2026
7f015ef
Remove saved heuristic-search results and work records
zayenz Oct 18, 2026
9986205
Simplify experimental heuristic search
zayenz Oct 18, 2026
02e50d1
Simplify heuristic search API and examples
zayenz Oct 18, 2026
034bb3b
Fix heuristic search integration and trim evaluation tools
zayenz Oct 18, 2026
f4dde4c
Add optional candidate dominance to CABS
zayenz Oct 18, 2026
4a5a076
Add native parallel A* and CABS search
zayenz Oct 18, 2026
db1c8ad
Index live CABS candidates for dominance
zayenz Oct 18, 2026
978f7ce
Retain heuristic-search parents on parallel workers
zayenz Oct 18, 2026
01b0d70
Dispose of rejected heuristic-search spaces on workers
zayenz Oct 18, 2026
efe4cec
Repair CABS heaps after single-candidate dominance replacement
zayenz Oct 18, 2026
456991a
Consolidate heuristic search usage and avoid chunk-cache contention
zayenz Oct 19, 2026
5085dc1
Keep heuristic search examples focused and refresh build dependencies
zayenz Oct 20, 2026
c9a85b7
Model idle puzzle steps after reaching the goal
zayenz Oct 21, 2026
54d48a1
Describe heuristic search using ordinary optimization terminology
zayenz Oct 21, 2026
03b4a48
Remove changelog entry for reverted chunk cache change
zayenz Oct 21, 2026
d9c29c6
Document worker control for heuristic search engines
zayenz Oct 21, 2026
b8ebc84
Index CABS beam entries for direct dominance replacement
zayenz Oct 21, 2026
c50c768
Batch sibling admission in parallel CABS
zayenz Oct 21, 2026
010a938
Simplify the TSPTW example and its validation
zayenz Oct 21, 2026
3e447b4
Explain heuristic search contracts and example invariants
zayenz Oct 21, 2026
baee3e6
Trim dependency churn and remove TSPTW validation tooling
zayenz Oct 21, 2026
6d927de
Keep search documentation in the changelog and API reference
zayenz Oct 21, 2026
1c390cd
Remove ancillary search tooling and redundant explanations
zayenz Oct 21, 2026
0bdd246
Restore experimental changelog grouping and validation
zayenz Oct 21, 2026
5c83ea5
Clarify heuristic search documentation
zayenz Oct 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:

- name: Configure
shell: bash
run: ./configure
run: ./configure --enable-experimental

- name: Build
shell: bash
Expand Down Expand Up @@ -220,6 +220,7 @@ jobs:
shell: bash
run: >
cmake -S "$GITHUB_WORKSPACE" -B "$GITHUB_WORKSPACE/build-ninja"
-DGECODE_ENABLE_EXPERIMENTAL=ON
-G Ninja
-DCMAKE_BUILD_TYPE=$BUILD_TYPE
-DGECODE_ENABLE_QT=OFF
Expand Down Expand Up @@ -483,6 +484,7 @@ jobs:
-DGECODE_ENABLE_MPFR=OFF
-DGECODE_BUILD_SHARED=${{ matrix.build_shared }}
-DGECODE_BUILD_STATIC=${{ matrix.build_static }}
-DGECODE_ENABLE_EXPERIMENTAL=${{ matrix.build_shared }}

- name: Build
shell: pwsh
Expand Down Expand Up @@ -594,6 +596,7 @@ jobs:
-DGECODE_ENABLE_MPFR=OFF \
-DGECODE_BUILD_SHARED=OFF \
-DGECODE_BUILD_STATIC=ON \
-DGECODE_ENABLE_EXPERIMENTAL=ON \
-DGECODE_ENABLE_EXAMPLES=OFF \
-DGECODE_ENABLE_FLATZINC=OFF

Expand Down Expand Up @@ -662,7 +665,7 @@ jobs:
shell: msys2 {0}
run: |
export PATH="$UV_DIR:$PATH"
CC=gcc CXX=g++ ./configure --with-host-os=Windows --disable-qt --disable-gist --disable-mpfr
CC=gcc CXX=g++ ./configure --with-host-os=Windows --disable-qt --disable-gist --disable-mpfr --enable-experimental

- name: Build
shell: msys2 {0}
Expand Down
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ endif()
set(GECODE_ENABLE_GIST "${GECODE_ENABLE_GIST_DEFAULT}" CACHE STRING "Enable Gist (AUTO, ON, or OFF)")
set_property(CACHE GECODE_ENABLE_GIST PROPERTY STRINGS AUTO ON OFF)
option(GECODE_ENABLE_CPPROFILER "Enable CPProfiler support" ON)
option(GECODE_ENABLE_EXPERIMENTAL "Enable experimental preview APIs" OFF)
option(GECODE_ENABLE_CBS "Enable counting-based search support" OFF)
set(GECODE_ENABLE_EXAMPLES_DEFAULT ${PROJECT_IS_TOP_LEVEL})
option(GECODE_ENABLE_EXAMPLES "Build examples" ${GECODE_ENABLE_EXAMPLES_DEFAULT})
Expand Down Expand Up @@ -692,6 +693,9 @@ endif()
if(GECODE_ENABLE_CPPROFILER)
set(GECODE_HAS_CPPROFILER "/**/")
endif()
if(GECODE_ENABLE_EXPERIMENTAL)
set(GECODE_HAS_EXPERIMENTAL "/**/")
endif()
if(GECODE_ENABLE_CBS)
set(GECODE_HAS_CBS "/**/")
endif()
Expand Down Expand Up @@ -1815,6 +1819,7 @@ include(FeatureSummary)
foreach(gecode_option IN ITEMS
GECODE_BUILD_SHARED GECODE_BUILD_STATIC
GECODE_ENABLE_THREAD GECODE_ENABLE_CPPROFILER GECODE_ENABLE_CBS
GECODE_ENABLE_EXPERIMENTAL
GECODE_ENABLE_EXAMPLES GECODE_INSTALL
GECODE_ENABLE_SEARCH GECODE_ENABLE_INT_VARS GECODE_ENABLE_SET_VARS
GECODE_ENABLE_FLOAT_VARS GECODE_ENABLE_MINIMODEL GECODE_ENABLE_DRIVER
Expand Down
21 changes: 15 additions & 6 deletions Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -269,19 +269,23 @@ SEARCHSRC0 = \
cpprofiler/tracer worker-control
SEARCHHDR0 = \
statistics.hpp stop.hpp options.hpp cutoff.hpp \
support.hh worker.hh worker-control.hh exception.hpp engine.hpp base.hpp \
support.hh beam-heap.hh worker.hh worker-control.hh exception.hpp engine.hpp base.hpp \
nogoods.hh nogoods.hpp build.hpp traits.hpp sebs.hpp \
seq/path.hh seq/path.hpp seq/dfs.hh seq/dfs.hpp \
seq/bab.hh seq/bab.hpp seq/lds.hh seq/lds.hpp \
seq/rbs.hh seq/rbs.hpp seq/dead.hh \
seq/bab.hh seq/bab.hpp seq/astar.hh seq/cabs.hh seq/lds.hh seq/lds.hpp \
seq/rbs.hh seq/rbs.hpp seq/dead.hh seq/choice-expansion.hh \
seq/pbs.hh seq/pbs.hpp \
par/path.hh par/path.hpp par/engine.hh par/engine.hpp \
par/dfs.hh par/dfs.hpp par/bab.hh par/bab.hpp \
par/pbs.hh par/pbs.hpp \
dfs.hpp bab.hpp lds.hpp rbs.hpp pbs.hpp \
par/pbs.hh par/pbs.hpp par/frontier.hh \
dfs.hpp bab.hpp astar.hpp cabs.hpp lds.hpp rbs.hpp pbs.hpp \
relax.hh tracer.hpp trace-recorder.hpp \
cpprofiler/message.hpp cpprofiler/connector.hpp

ifeq "@enable_experimental@" "yes"
SEARCHSRC0 += astar cabs par/frontier
endif

SEARCHSRC = $(SEARCHSRC0:%=gecode/search/%.cpp)
SEARCHHDR = gecode/search.hh $(SEARCHHDR0:%=gecode/search/%)
SEARCHOBJ = $(SEARCHSRC:%.cpp=%$(OBJSUFFIX))
Expand Down Expand Up @@ -912,8 +916,13 @@ INTEXAMPLESRC0 = \
qcp job-shop open-route common-pattern fifteen-puzzle


ifeq "@enable_experimental@" "yes"
INTEXAMPLESRC0 += tsptw
endif

INTEXAMPLEHDR = $(INTEXAMPLEHDR0:%=examples/%.hpp) \
examples/common-pattern.hh
examples/common-pattern.hh \
examples/tsptw-data.hh examples/tsptw-transition.hh
INTEXAMPLESRC = $(INTEXAMPLESRC0:%=examples/%.cpp)
ifeq "@enable_examples@" "yes"
INSTALLEXAMPLEHDR = $(INTEXAMPLEHDR)
Expand Down
19 changes: 19 additions & 0 deletions changelog.in
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@
# driver|iter|support|example|test|gist|flatzinc|other
# What: bug|documentation|performance|new|removed|change
# Rank: minor|major
# Experimental: true|false <optional, defaults to false>
# True entries appear under Experimental changes within each release.
# Bug: <optional, for number from bugzilla>
# Issue: <optional, for number from github>
# Thanks: <optional, who reported etc>
Expand Down Expand Up @@ -92,6 +94,23 @@ Prefix embedded mimalloc symbols with gecode_ to avoid allocator conflicts.
Mimalloc can substantially improve parallel search performance on some workloads.
The system allocator is the default.

[ENTRY]
Module: search
What: new
Rank: major
Experimental: true
[DESCRIPTION]
Add experimental A* (AStar) and complete anytime beam search (CABS).
[MORE]
Both engines use objective bounds for pruning and optional ranks to guide
exploration. They support parallel search, dynamic worker control, and
portfolios with BAB. CABS also supports model-defined dominance.
Enable with --enable-experimental or GECODE_ENABLE_EXPERIMENTAL=ON;
the preview is disabled by default. APIs may change or be removed in future
feature releases. The fifteen-puzzle and TSPTW examples demonstrate both
engines. TSPTW compares a closed CP model with a transition model that
constructs the route one city at a time.

[ENTRY]
Module: int
What: new
Expand Down
8 changes: 8 additions & 0 deletions cmake/GecodeSources.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ set(GECODE_SEARCH_SOURCES
gecode/search/worker-control.cpp
)

if(GECODE_ENABLE_EXPERIMENTAL)
list(APPEND GECODE_SEARCH_SOURCES
gecode/search/astar.cpp
gecode/search/cabs.cpp
gecode/search/par/frontier.cpp
)
endif()

set(GECODE_INT_SOURCES
gecode/int/arithmetic.cpp
gecode/int/arithmetic/mult.cpp
Expand Down
31 changes: 31 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,7 @@ HAVEFLEX
enable_cpprofiler
LINKCPPROFILER
enable_cbs
enable_experimental
enable_gist
enable_qt
QTLIBS
Expand Down Expand Up @@ -859,6 +860,7 @@ with_mpfr_include
with_mpfr_lib
enable_qt
enable_gist
enable_experimental
enable_cbs
enable_cpprofiler
enable_driver
Expand Down Expand Up @@ -1531,6 +1533,7 @@ Optional Features:
--enable-qt build with Qt support, requires Qt 5.15 or newer
[default=yes]
--enable-gist build Gecode Interactive Search Tool [default=yes]
--enable-experimental build experimental preview APIs [default=no]
--enable-cbs build with support for counting-based search
[default=no]
--enable-cpprofiler build with support for CPProfiler [default=yes]
Expand Down Expand Up @@ -3407,6 +3410,8 @@ GECODE_SOVERSION=${ac_gecode_soversion}








Expand Down Expand Up @@ -13888,6 +13893,32 @@ printf "%s\n" "no" >&6; }
fi


# Check whether --enable-experimental was given.
if test ${enable_experimental+y}
then :
enableval=$enable_experimental;
else case e in #(
e) enable_experimental=no ;;
esac
fi

{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build experimental preview APIs" >&5
printf %s "checking whether to build experimental preview APIs... " >&6; }
case $enable_experimental in #(
yes) :

printf "%s\n" "#define GECODE_HAS_EXPERIMENTAL /**/" >>confdefs.h
;; #(
no) :
;; #(
*) :
as_fn_error $? "--enable-experimental accepts only yes or no" "$LINENO" 5 ;;
esac
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_experimental" >&5
printf "%s\n" "$enable_experimental" >&6; }



# Check whether --enable-cbs was given.
if test ${enable_cbs+y}
then :
Expand Down
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ dnl ------------------------------------------------------------------
AC_GECODE_MPFR
AC_GECODE_QT
AC_GECODE_GIST
AC_GECODE_EXPERIMENTAL
AC_GECODE_CBS
AC_GECODE_CPPROFILER
AC_GECODE_FLEXBISON
Expand Down
12 changes: 7 additions & 5 deletions docs/worker-control.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
## Purpose

`Search::WorkerControl` lets an external scheduler change how many workers a
running DFS or BAB engine may use. A portfolio with a fixed thread budget can
running DFS or BAB engine may use. Experimental AStar and CABS engines also
support worker control. A portfolio with a fixed thread budget can
move workers among its engines at runtime.

The engine still starts with a fixed maximum:
Expand All @@ -26,8 +27,8 @@ control.request(1); // Resume
Gecode resolves the `threads` option when it constructs the engine. The result
is the fixed worker capacity. A request must be between zero and that capacity,
inclusive. Zero pauses the engine without discarding its search state.
This also applies when the resolved capacity is one: sequential DFS and BAB
wait at search boundaries until the control resumes them.
This also applies when the resolved capacity is one: sequential DFS, BAB,
AStar, and CABS wait at search boundaries until the control resumes them.
Pausing requires a build with thread support. Without thread support, attaching
an initially paused control or calling `request(0)` raises
`Search::InvalidWorkerRequest`; controls must be used from one thread.
Expand Down Expand Up @@ -80,8 +81,9 @@ An empty default-constructed handle means that worker adjustment is disabled.
Calling `request` on an empty handle raises
`Search::UninitializedWorkerControl`.

A shared identity can be bound to only one leaf engine at a time. It cannot be
shared by two DFS/BAB engines or attached directly to an enclosing meta-engine.
A shared identity can be bound to only one leaf engine at a time (DFS, BAB,
AStar, or CABS). It cannot be shared by two engines or attached directly to an
enclosing meta-engine.
Ordinary reuse for a replacement engine after destruction is also rejected.
These uses raise `Search::WorkerControlInUse`.

Expand Down
1 change: 1 addition & 0 deletions doxygen/doxygen.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -1007,6 +1007,7 @@ PREDEFINED = "GECODE_SET_EXPORT=" \
"GECODE_HAS_FLOAT_VARS=1" \
"GECODE_HAS_GIST=1" \
"GECODE_HAS_CPPROFILER=1" \
"GECODE_HAS_EXPERIMENTAL=1" \
"GECODE_THREADS_PTHREADS=1" \
"GECODE_HAS_THREADS=1" \
"GECODE_HAS_MPFR=1" \
Expand Down
6 changes: 6 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,9 @@ endfunction()
foreach(example_source IN LISTS GECODE_EXAMPLE_SOURCES)
gecode_add_example("${example_source}")
endforeach()

if(GECODE_ENABLE_EXPERIMENTAL)
add_executable(tsptw tsptw.cpp)
target_link_libraries(tsptw PRIVATE gecodesearch gecodeint)
set_property(TARGET tsptw PROPERTY FOLDER "Examples")
endif()
79 changes: 79 additions & 0 deletions examples/data/tsptw/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# TSPTW example

`examples/tsptw.cpp` solves the travelling salesperson problem with time windows.
The small `waiting.txt` instance has two customers. Its optimal route is
`0 -> 1 -> 2 -> 0`, with travel cost 5. It reaches customer 1 at time 2,
waits until time 5, and returns to the depot at time 8.

## Running

Enable `GECODE_ENABLE_EXPERIMENTAL=ON` when configuring Gecode. Replace
`build/open-search` below with that build directory.

```sh
cmake --build build/open-search --target tsptw -j 8
build/open-search/bin/tsptw examples/data/tsptw/waiting.txt --engine bab
build/open-search/bin/tsptw examples/data/tsptw/waiting.txt --formulation transition --engine astar
build/open-search/bin/tsptw examples/data/tsptw/waiting.txt --formulation transition --engine cabs
```

Both formulations support depth-first branch and bound (`bab`), A*, and complete
anytime beam search (`cabs`). The executable emits JSON lines: improving
`solution` records followed by a `summary`. Each tour lists every customer once,
omitting the depot at both ends. Costs and return times are exact decimals;
records also include the integer cost and scale used by the model.

Exhausting search reports `optimal` with a solution or `infeasible` without one.
A resource limit reports `stopped`; any reported solution remains feasible, but
the run has not proved optimality or infeasibility.

## Input format

`examples/tsptw-data.hh` reads a node count `n` including depot 0, an `n` by `n`
matrix in row order, then `n` ready/due time pairs in node order. Whitespace
separates values and `#` starts a comment. Exactly `n*n + 2*n` values must follow
the node count.

Each matrix entry supplies both travel time and cost for a directed trip.
The objective includes the return trip to depot 0. Waiting adds no cost.
If the input includes service time, it must already be included in outgoing
matrix entries. Travel times may differ by direction, and travelling through
another node may be cheaper than going directly.

Departure is fixed at time zero. Each visit starts no earlier than its ready
time and no later than its due time; early arrivals wait. Return to depot 0
must meet its window too; the depot ready time must be zero. Values are
nonnegative decimals without signs or exponents. The reader scales them exactly
to integers and rejects inputs whose dimensions, scaled values, or tour
arithmetic exceed Gecode's integer limits.

## Model and search choices

The default `--formulation closed` creates all successor and visit-time variables
before search. A circuit constraint visits every node once and sums travel
costs; choosing a trip activates its timing constraint. Search branches on trip
costs first, then successors. `--formulation transition` creates visit variables
as the route grows, with explicit waiting and depot return checks.

The transition formulation accepts `--bound prefix|min-arcs` and
`--residual-propagation off|cheap|unary`, defaulting to `prefix` and `off`.
The prefix bound uses travel cost so far. `min-arcs` also estimates remaining
cost by summing the cheapest incoming trips and the cheapest outgoing trips,
then taking the larger total. These trips need not form a tour, so the estimate
can be too low.

`cheap` checks whether each remaining customer can still be reached and followed
by a return within the deadlines, using shortest travel times. `unary` adds a
temporary schedule in which visits cannot overlap and each visit occupies its
cheapest outgoing travel time. These checks can reject a partial route or rule
out its next customer. Shortest paths may use visited customers, keeping the
checks valid when indirect travel is cheaper than direct travel.

CABS with `transition` discards a candidate when another live candidate for the
same location and unvisited customers arrives no later and at no greater cost.
Use `--dominance off` to disable this pruning.

`--time-ms N` and `--node-limit N` stop search at engine boundaries; time
includes reading and preprocessing. They cannot interrupt propagation. CABS
also accepts `--max-width N` and `--frontier-limit N`, where zero disables the cap.
Runs default to one search thread; use `--threads N` to change the thread count.
8 changes: 8 additions & 0 deletions examples/data/tsptw/waiting.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
3
0 2 9
4 0 1
2 8 0
0 20
5 10
0 12
# Asymmetric and nonmetric: 0->2 is more costly than 0->1->2.
Loading
Loading