Skip to content

Tutorial for creating propagators#394

Draft
EmirDe wants to merge 4 commits intomainfrom
tutorial/first-propagator
Draft

Tutorial for creating propagators#394
EmirDe wants to merge 4 commits intomainfrom
tutorial/first-propagator

Conversation

@EmirDe
Copy link
Copy Markdown
Contributor

@EmirDe EmirDe commented Mar 23, 2026

I have been reworking our tutorial for creating propagators (relates to issue #300). The tutorial now looks more Rust-like!

Please have a look, and let me know what you think.

How to view the tutorial

There are two options:

Option 1: static

To just view the draft tutorial, you can open it in your browser tutorials/first-propagator/book/01-introduction.html.

Option 2: dynamic

Alternatively, if you also want to change the files, you can:
cargo install mdbook
then navigate to the folder tutorials/first-propagator and type
mdbook serve --open
That should open the tutorial in the browser, and as you modify the files in the src folder, it should immediately apply changes.

TODOs

There is still quite a bit to go...here is a list of TODOs:

  • Add Clippy, IDEs, and Githooks to the getting started page.
  • Add references to our documentation when we refer to our types.
  • Explain who actually creates the constructor.
  • Explain how we set the inference_code in the constructor.
  • Refactor: create in PropagatorConstructor could be renamed into create_propagator, to make it clearer that it creates propagators, and it is not a method for creating constructors. It might be confusing for people, since create sounds like it constructs the PropagatorConstructor, but instead it actually creates the propagator and not the constructor.
  • Refactor: In the propagator logic, use the new function fixed_value.
  • Refactor: This is a bit ugly Conflict::Propagator(PropagatorConflict {...}). We could come up with something to make this look nicer, and change in the tutorial.
  • Write/Polish the propagation checkers section.
  • Write the retention checker section.
  • Adapt the Testing section from our PDF tutorial.
  • Adapt our Running models section from our PDF tutorial. But it needs to be clear why we are doing this, and whether it fits this tutorial or it should be a separate tutorial?
  • Adapt the Pitfalls section from our PDF tutorial. We might even consider removing this section.
  • Write conclusion along with the checklist for implementing propagators.
  • (not sure if possible/practical) Have the code syntax highlighter proper recognise our data types.
  • (Visually?) separate Rust details from Pumpkin details.
  • Update the Github repo link in the tutorial (see below also)
  • Cloning the repository may be too much, think of the alternative
  • Make the code snippets runnable so we can easily test if the tutorial is up-to-date
  • Improve the conflict detection algorithm to check if the intersections are empty (a_lb > b_ub || a_ub < b_lb)

Copy link
Copy Markdown
Contributor

@maartenflippo maartenflippo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is very valuable. A few general comments/questions, aside from the ones related to specific content.

  1. The text is based on our course tutorial. That means we also take time to explain Rust concepts (e.g. traits, generics, etc.). Does that make sense for a tutorial for the main Pumpkin solver? Personally, I lean toward no, but it might make the solver more approachable.
  2. I assume mention of the course is not in the tutorial? E.g. the repository we link is the course repo instead of the main Pumpkin repo.
  3. How do we expect the user to interact with pumpkin? If they are writing their own propagators, I would expect them to pull in pumpkin-solver as a dependency into their own crate. Then they can run models, implement search procedures and propagators, etc. That is a very different story than if they clone the Pumpkin repository. This also impacts if we mention clippy, git hooks, etc.

Finally, I think we should aim to avoid norun on code blocks as much as possible. That way, we can be confident that when we run mdbook test, the code still matches a specific Pumpkin version. Since we still frequently update various APIs, the tutorial will become stale very quickly otherwise.

Comment on lines +71 to +82
## Conflict Check

If both variables are already assigned to different values, the constraint `a = b` is violated. In general, it is common to check for conflicts before performing propagation, because an early check can often simplify the propagation algorithm that follows.

```rust,no_run,noplayground
if a_lb == a_ub && b_lb == b_ub && a_lb != b_lb {
return Err(Conflict::Propagator(PropagatorConflict {
conjunction: conjunction!([self.a == a_lb] & [self.b == b_lb]),
inference_code: self.inference_code.clone(),
}));
}
```
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This conflict check is too specific. We want the conflict to trigger if the intersection of the domains is empty. If we only consider bounds for that, then we should have the following:

a_lb > b_ub || a_ub < b_lb

### TODO
- use the `fixed_value` function and modify this page accordingly.
- could reference the conjunction macro documentation
- this is a bit ugly: `Err(Conflict::Propagator(PropagatorConflict {...}))`. Maybe we could something to make this nicer. No newline at end of file
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. We could make a function like so:

return propagor_conflict(conjunction, inference_code);

```

### TODO
- use the `fixed_value` function and modify this page accordingly.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to use fixed_value

@EmirDe
Copy link
Copy Markdown
Contributor Author

EmirDe commented Mar 26, 2026

The text is based on our course tutorial. That means we also take time to explain Rust concepts (e.g. traits, generics, etc.). Does that make sense for a tutorial for the main Pumpkin solver? Personally, I lean toward no, but it might make the solver more approachable.

I value being approachable as a key priority to make it easier for people to get into Pumpkin, even if they do not know Rust.

That said, now that you mention it, we could visually separate Rust info from other content, either by placing it in a separate section (say, in the getting started section) and/or by using an emoji at the start of an explanation to indicate that this is for people not familiar with Rust.

Question @maartenflippo: Which part of the tutorial do you feel explains too much Rust that it gets in the way? Just trying to see how to approach this issue.

I assume mention of the course is not in the tutorial? E.g. the repository we link is the course repo instead of the main Pumpkin repo.

That needs to be fixed indeed, relates to the point below.

How do we expect the user to interact with pumpkin? If they are writing their own propagators, I would expect them to pull in pumpkin-solver as a dependency into their own crate. Then they can run models, implement search procedures and propagators, etc. That is a very different story than if they clone the Pumpkin repository. This also impacts if we mention clippy, git hooks, etc.

Good point. If they just write propagators, then indeed it does not make sense to clone the repository, but only pull in the propagator part. What is the best way forward here?

Finally, I think we should aim to avoid norun on code blocks as much as possible. That way, we can be confident that when we run mdbook test, the code still matches a specific Pumpkin version. Since we still frequently update various APIs, the tutorial will become stale very quickly otherwise.

This is a good point, I will look into this.

p.s. I updated the todos.

@EmirDe
Copy link
Copy Markdown
Contributor Author

EmirDe commented Mar 26, 2026

@maartenflippo Could you update the tutorial code with:

  • The new conflict detection logic.
  • Refactor the Conflict::Propagator(PropagatorConflict {...}).
  • Add a retention checker (might be good to merge retention checkers first in Pumpkin?)

I could look into the other points for the tutorial.

@maartenflippo
Copy link
Copy Markdown
Contributor

That said, now that you mention it, we could visually separate Rust info from other content, either by placing it in a separate section (say, in the getting started section) and/or by using an emoji at the start of an explanation to indicate that this is for people not familiar with Rust.

I tried out putting it in a <details> tag. See this commit: b9d8afd, which uses this approach on the section explaining propagator constructors.

@maartenflippo
Copy link
Copy Markdown
Contributor

maartenflippo commented Mar 27, 2026

Refactor the Conflict::Propagator(PropagatorConflict {...}).

See #399. Updated the conflict detection logic using this in 2c3c489.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants