Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to use groupBy? #148

Open
SeifFeidi opened this issue Feb 6, 2023 · 3 comments
Open

How to use groupBy? #148

SeifFeidi opened this issue Feb 6, 2023 · 3 comments

Comments

@SeifFeidi
Copy link

I have a list of users with this structure: User (id, date, week_num, user_name),
I want to group all users by week_num and count number of appointments for each user_name to have at least 2 appointments by week for the same user_name.
I tried with countBi (), but I have this error (name 'countBi' is not defined)

@Christopher-Chianelli
Copy link
Contributor

Christopher-Chianelli commented Feb 6, 2023

You need to import ConstraintCollectors from optapy.constraint and use ConstraintCollectors to get the collector. For instance:

from optapy.constraint import ConstraintCollectors

def each_user_name_must_have_at_least_two_appointments(constraint_factory: ConstraintFactory):
    return (
        constraint_factory.for_each(User)
                                        .group_by(lambda user: user.week_num,
                                                           lambda user: user.user_name,
                                                           ConstraintCollectors.count())
                                        .filter(lambda week, user_name, count: count < 2)
                                        .penalize('User have less than two appointments in a given week',
                                                         HardSoftScore.ONE_HARD)
    ) 

(as for what count method to use, that depends on the cardinality of the stream; see https://www.optapy.org/docs/latest/constraint-streams/constraint-streams.html#collectorsCount for details)

@SeifFeidi
Copy link
Author

SeifFeidi commented Feb 7, 2023

thank you for your help
With this example I have one appointment by week, I want to have one appointment for each user. name by week!!

def nbr_rdv_resp(constraint_factory: ConstraintFactory):
return (
constraint_factory.for_each(User)
.group_by(lambda user: user.dateslot.num_week,
lambda user: user.name,
ConstraintCollectors.count())
.filter(lambda week, name, count: count >= 2)
.penalize('User have less than two appointments in a given week',
HardMediumSoftScore.ONE_HARD)
)

@Christopher-Chianelli
Copy link
Contributor

That look like it should work (translating into english, the constraint you written should be equivalent to "penalize having more than one appointment per (user.week_num, user.name) pair by 1 hard"). If you want exactly one (i.e. not 0 or 1), you need to use if_not_exists to penalize the 0 case:

from optapy.constraint import Joiners

def each_user_name_must_have_at_least_one_appointment_per_week(constraint_factory: ConstraintFactory):
    return (
        constraint_factory.for_each(Week)
                                        .join(UserName)
                                        .if_not_exists(User,
                                                                 Joiners.equal(lambda week, user_name: week.week_num,
                                                                                          lambda user: user.week_num),
                                                                 Joiners.equal(lambda week, user_name: user_name.user_name,
                                                                                          lambda user: user.user_name),
                                        )
                                        .penalize('User name does not have an appointment for the given week',
                                                         HardSoftScore.ONE_HARD)
    ) 

(Where Week and UserName are problem fact classes that store information about possible week numbers and user names respectively that have a corresponding @problem_fact_collection_property fields in the @planning_solution)

Have you tested it using constraint_verifier (see https://github.com/optapy/optapy-quickstarts/blob/stable/school-timetabling/tests.py and https://www.optapy.org/docs/latest/constraint-streams/constraint-streams.html#constraintStreamsTesting)

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

No branches or pull requests

2 participants