Skip to content

chore: introduce structural component to score - #2583

Open
Christopher-Chianelli wants to merge 6 commits into
TimefoldAI:no-loopsfrom
Christopher-Chianelli:chore/structural-score
Open

chore: introduce structural component to score#2583
Christopher-Chianelli wants to merge 6 commits into
TimefoldAI:no-loopsfrom
Christopher-Chianelli:chore/structural-score

Conversation

@Christopher-Chianelli

Copy link
Copy Markdown
Contributor

No description provided.

@triceo triceo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Leaving comments. Comments on any score type should be considered to apply to every other score type as well - I didn't want to duplicate every comment 10 times.

Score documentation needs updating; we need to explain what is a structural score, what it's for, and how it's handled. (If you prefer, can wait for a later PR.)

Consider adding migration recipes as much as you can. Going forward, we will try to make every change to happen automatically. However, automated or not, please update the recipes in the docs to mention all the changes.

Also, I would like to see tests added; structural score is an important part of the score types, we should test for it. The existing coverage should be easily extendable.

public record BendableBigDecimalScore(long structuralScore, BigDecimal[] hardScores,
BigDecimal[] softScores) implements IBendableScore<BendableBigDecimalScore> {

public BendableBigDecimalScore(BigDecimal[] hardScores,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Let's deprecate these convenience constructors to make it clear that the canonical constructor is still the way to go.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not sure about that; the solver sets the structural score, not score calculation, so for the vast majority, if not all, cases, users will do Score(0L, ...).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Does the user need to create a score? Should they? IMO no.
I'd even go as far as to write in the Javadoc that the constructor is not considered public API, as the user has no need to create Score instances.

Comment thread core/src/main/java/ai/timefold/solver/core/api/score/BendableBigDecimalScore.java Outdated
Comment thread core/src/main/java/ai/timefold/solver/core/api/score/BendableBigDecimalScore.java Outdated
Comment thread core/src/main/java/ai/timefold/solver/core/api/score/BendableScore.java Outdated
SimpleBigDecimalScore, SimpleScore {
/**
* The structural component of a Score. 0 if the solution is structurally sound
* (i.e. no inconsistent variables), -1 otherwise.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I would specifically mention that this is effectively a superhard score - it is the most important component of any score.

Comment thread core/src/main/java/ai/timefold/solver/core/impl/score/ScoreUtil.java Outdated

@triceo triceo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, with comments.
If you want to leave docs for later, that's your call, but in that case I recommend keeping a list of things to document; it's growing long.

public String toString() {
return hardScore + HARD_LABEL + "/" + mediumScore + MEDIUM_LABEL + "/" + softScore + SOFT_LABEL;
return (structuralScore < 0)
? "%dstructural/%s%s/%s%s/%s%s".formatted(structuralScore, hardScore, HARD_LABEL, mediumScore, MEDIUM_LABEL,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We have String constants for hard/medium/soft, let's introduce a constant for "structural" as well.

@Override
public String toString() {
return Long.toString(score);
return (structuralScore < 0) ? "%dstructural/%d".formatted(structuralScore, score) : Long.toString(score);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Similarly here.

var scoreTokens = new String[2][];
var scoreTokens = new String[3][];
var startIndex = 0;
var structuralSlashIndex = scoreString.indexOf("structural/");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

And here.

var structuralSlashIndex = scoreString.indexOf("structural/");
if (structuralSlashIndex >= 0) {
scoreTokens[0] = new String[] { scoreString.substring(0, structuralSlashIndex) };
startIndex = structuralSlashIndex + "structural/".length();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

And here.

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