Skip to content

Commit

Permalink
Clarify SimpleTestModel
Browse files Browse the repository at this point in the history
  • Loading branch information
gaelrenoux committed Sep 22, 2024
1 parent ff97b2f commit c85bb24
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 52 deletions.
1 change: 1 addition & 0 deletions src/test/scala/fr/renoux/gaston/MinimalTestModel.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import fr.renoux.gaston.util.Count
import java.util.concurrent.atomic.AtomicInteger


/** This test model problem is trivial to solve. It is used for simple tests on constraints, preferences, etc. */
object MinimalTestModel {

object Persons {
Expand Down
68 changes: 46 additions & 22 deletions src/test/scala/fr/renoux/gaston/SimpleTestModel.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import fr.renoux.gaston.input.{InputLoader, InputSettings}
import fr.renoux.gaston.model.constraints._
import fr.renoux.gaston.model.preferences.{PersonGroupAntiPreference, PersonTopicPreference}
import fr.renoux.gaston.model.{Problem, _}
import fr.renoux.gaston.util.Context
import fr.renoux.gaston.util.{BitMap, Context}

import java.util.concurrent.atomic.AtomicInteger

Expand Down Expand Up @@ -124,7 +124,8 @@ class SimpleTestModel(implicit settings: InputSettings) {

import ProblemCounts.CompleteCounts

val Complete = new Problem(Slots.All, Topics.All, Topics.Unassigned.toBitMap, Persons.All, Constraints.All, Preferences.All)
val WithUnassignedTopics = new Problem(Slots.All, Topics.All, Topics.Unassigned.toBitMap, Persons.All, Constraints.All, Preferences.All)
val NoUnassignedTopics = new Problem(Slots.All, Topics.Concrete, BitMap.empty[Slot, Topic], Persons.All, Constraints.All, Preferences.All)
}

object Solutions {
Expand All @@ -133,29 +134,52 @@ class SimpleTestModel(implicit settings: InputSettings) {
import Slots._
import Topics._

private implicit val problem: Problem = Problems.Complete
private implicit val context: Context = Context.Default

val Best = Schedule.from(
Morning(
Acting(Arthur, Iago, Hercule),
Dancing(Daniela, Corwin, Bianca),
Grinding(Garion, Fiona),
UnassignedMorning()
),
AfterNoon(
Bathing(Bianca, Arthur),
Eating(Eric, Daniela, Corwin),
Helping(Hercule, Garion, Fiona),
UnassignedAfternoon()
),
Evening(
Cooking(Corwin, Bianca),
Fighting(Fiona, Eric, Daniela),
Inking(Iago, Hercule, Garion),
UnassignedEvening()
val BestWithUnassignedTopics: Schedule = {
implicit val problem: Problem = Problems.WithUnassignedTopics
Schedule.from(
Morning(
Acting(Arthur, Iago, Hercule),
Dancing(Daniela, Corwin, Bianca),
Grinding(Garion, Fiona),
UnassignedMorning()
),
AfterNoon(
Bathing(Bianca, Arthur),
Eating(Eric, Daniela, Corwin),
Helping(Hercule, Garion, Fiona),
UnassignedAfternoon()
),
Evening(
Cooking(Corwin, Bianca),
Fighting(Fiona, Eric, Daniela),
Inking(Iago, Hercule, Garion),
UnassignedEvening()
)
)
)
}

val BestNoUnassignedTopics: Schedule = {
implicit val problem: Problem = Problems.NoUnassignedTopics
Schedule.from(
Morning(
Acting(Arthur, Iago, Hercule),
Dancing(Daniela, Corwin, Bianca),
Grinding(Garion, Fiona)
),
AfterNoon(
Bathing(Bianca, Arthur),
Eating(Eric, Daniela, Corwin),
Helping(Hercule, Garion, Fiona)
),
Evening(
Cooking(Corwin, Bianca),
Fighting(Fiona, Eric, Daniela),
Inking(Iago, Hercule, Garion)
)
)
}

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ class ScoreCalculatorSpec extends AnyFlatSpec with Matchers {


"score" should "give the correct result for a simple problem" in {
SimpleTestModel.Solutions.Best.score.value should be(10.2265625)
SimpleTestModel.Solutions.BestWithUnassignedTopics.score.value should be(10.2265625)
}

it should "give a correct unweightedScoresByPerson" in {
SimpleTestModel.Solutions.Best.scoreCalculator.unweightedScoresByPerson should be(Map(
SimpleTestModel.Solutions.BestWithUnassignedTopics.scoreCalculator.unweightedScoresByPerson should be(Map(
SimpleTestModel.Persons.Arthur -> Score(5.0),
SimpleTestModel.Persons.Bianca -> Score(6.0),
SimpleTestModel.Persons.Corwin -> Score(6.0),
Expand All @@ -27,7 +27,7 @@ class ScoreCalculatorSpec extends AnyFlatSpec with Matchers {
}

it should "give a correct weightedScoresByPerson" in {
SimpleTestModel.Solutions.Best.scoreCalculator.weightedScoresByPerson should be(Map(
SimpleTestModel.Solutions.BestWithUnassignedTopics.scoreCalculator.weightedScoresByPerson should be(Map(
SimpleTestModel.Persons.Arthur -> Score(5.0),
SimpleTestModel.Persons.Bianca -> Score(6.0),
SimpleTestModel.Persons.Corwin -> Score(6.0),
Expand Down
8 changes: 4 additions & 4 deletions src/test/scala/fr/renoux/gaston/engine/SyncRunnerSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class SyncRunnerSpec extends AnyFlatSpec with Matchers with PrivateMethodTester
"Given a fixed seed, the runner" should "always return the same result after 10 iterations" in {
val results =
for {_ <- 0 until 10} yield {
run(SimpleTestModel.Problems.Complete, iterations = 10, seed = 42)
run(SimpleTestModel.Problems.WithUnassignedTopics, iterations = 10, seed = 42)
}

results.map(_._2).foreach {
Expand All @@ -38,7 +38,7 @@ class SyncRunnerSpec extends AnyFlatSpec with Matchers with PrivateMethodTester
println(results.head._1.toFormattedString)
// TODO Check out why it still has a very incomplete schedule in 10 iterations

val otherResult = run(SimpleTestModel.Problems.Complete, iterations = 10, seed = 43)
val otherResult = run(SimpleTestModel.Problems.WithUnassignedTopics, iterations = 10, seed = 43)
otherResult._2 should be(10)
otherResult._1 shouldNot be(results.head._1)
otherResult._1.score shouldNot be(results.head._1.score)
Expand All @@ -51,7 +51,7 @@ class SyncRunnerSpec extends AnyFlatSpec with Matchers with PrivateMethodTester
"Given a fixed seed, the runner" should "always return the same result after 100 iterations" in {
val results =
for {_ <- 0 until 3} yield {
run(SimpleTestModel.Problems.Complete, iterations = 100, seed = 666)
run(SimpleTestModel.Problems.WithUnassignedTopics, iterations = 100, seed = 666)
}

results.map(_._2).foreach {
Expand All @@ -66,7 +66,7 @@ class SyncRunnerSpec extends AnyFlatSpec with Matchers with PrivateMethodTester
println(results.head._2)
println(results.head._1.toFormattedString)

val otherResult = run(SimpleTestModel.Problems.Complete, iterations = 100, seed = 777)
val otherResult = run(SimpleTestModel.Problems.WithUnassignedTopics, iterations = 100, seed = 777)
otherResult._2 should be(100)
// since we'll have the optimial solution, we must compare the seeds only.
otherResult._1.chainSeed shouldNot be(results.head._1.chainSeed)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,34 +38,34 @@ class RandomAssignerSpec extends AnyFlatSpec with Matchers {

it should "fill in a schedule where one person is unscheduled" in {
implicit val rand: Random = new Random(0)
implicit val problem: Problem = SimpleTestModel.Problems.Complete
implicit val problem: Problem = SimpleTestModel.Problems.WithUnassignedTopics
import fr.renoux.gaston.SimpleTestModel.Slots
import fr.renoux.gaston.SimpleTestModel.Slots._
import fr.renoux.gaston.SimpleTestModel.Topics._
import fr.renoux.gaston.SimpleTestModel.Persons._

val randomAssigner = new RandomAssigner

val baseSchedule = SimpleTestModel.Solutions.Best.updateSlotSchedule(Morning) { ss =>
val baseSchedule = SimpleTestModel.Solutions.BestWithUnassignedTopics.updateSlotSchedule(Morning) { ss =>
ss.updateTopicRecord(Grinding)(_.removePerson(Fiona))
}
val testFilled = randomAssigner.fill(baseSchedule)
println(testFilled.map(_.toFormattedString))
testFilled.nonEmpty should be(true)
testFilled.get should be(SimpleTestModel.Solutions.Best)
testFilled.get should be(SimpleTestModel.Solutions.BestWithUnassignedTopics)
}

it should "fill in an empty schedule" in {
implicit val rand: Random = new Random(0)
implicit val problem: Problem = SimpleTestModel.Problems.Complete
implicit val problem: Problem = SimpleTestModel.Problems.WithUnassignedTopics
import fr.renoux.gaston.SimpleTestModel.Slots
import fr.renoux.gaston.SimpleTestModel.Slots._
import fr.renoux.gaston.SimpleTestModel.Topics._
import fr.renoux.gaston.SimpleTestModel.Persons._

val randomAssigner = new RandomAssigner

val partialSchedule = SimpleTestModel.Solutions.Best.clearSlots(Slots.All.flatten: _*)
val partialSchedule = SimpleTestModel.Solutions.BestWithUnassignedTopics.clearSlots(Slots.All.flatten: _*)
val filledSchedule = randomAssigner.fill(partialSchedule)

filledSchedule.nonEmpty should be(true)
Expand Down
12 changes: 6 additions & 6 deletions src/test/scala/fr/renoux/gaston/model/ScheduleSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class ScheduleSpec extends AnyFlatSpec with Matchers {
import fr.renoux.gaston.SimpleTestModel.Topics._
import fr.renoux.gaston.SimpleTestModel.strongPreference

private implicit val problem: Problem = Complete
private implicit val problem: Problem = WithUnassignedTopics
private implicit val context: Context = Context.Default

private val Simple = Schedule.from(
Expand All @@ -30,15 +30,15 @@ class ScheduleSpec extends AnyFlatSpec with Matchers {
)

"planning" should "work" in {
Best.planning should be(Map(
BestWithUnassignedTopics.planning should be(Map(
Morning -> Set(Acting, Dancing, Grinding, UnassignedMorning),
AfterNoon -> Set(Bathing, Eating, Helping, UnassignedAfternoon),
Evening -> Set(Cooking, Fighting, Inking, UnassignedEvening)
))
}

"topicToSlot" should "work" in {
Best.topicToSlot should be(Map(
BestWithUnassignedTopics.topicToSlot should be(Map(
Acting -> Morning,
Dancing -> Morning,
Grinding -> Morning,
Expand All @@ -64,7 +64,7 @@ class ScheduleSpec extends AnyFlatSpec with Matchers {
} */

"personsByTopic" should "work" in {
Best.personsByTopic should be(Map(
BestWithUnassignedTopics.personsByTopic should be(Map(
Acting -> Set(Arthur, Iago, Hercule),
Dancing -> Set(Daniela, Corwin, Bianca),
Grinding -> Set(Garion, Fiona),
Expand All @@ -81,7 +81,7 @@ class ScheduleSpec extends AnyFlatSpec with Matchers {
}

"personGroups" should "work" in {
Best.personGroups.toSet should be(Set(
BestWithUnassignedTopics.personGroups.toSet should be(Set(
Set(Arthur, Iago, Hercule),
Set(Daniela, Corwin, Bianca),
Set(Garion, Fiona),
Expand Down Expand Up @@ -245,7 +245,7 @@ class ScheduleSpec extends AnyFlatSpec with Matchers {

"isSound" should "validate a correct schedule" in {
Simple.isSound should be(true)
Best.isSound should be(true)
BestWithUnassignedTopics.isSound should be(true)
}

it should "reject a schedule demanding ubiquity" in {
Expand Down
6 changes: 3 additions & 3 deletions src/test/scala/fr/renoux/gaston/model/SlotScheduleSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ class SlotScheduleSpec extends AnyFlatSpec with Matchers {
import fr.renoux.gaston.SimpleTestModel.Solutions._
import fr.renoux.gaston.SimpleTestModel.Topics._

implicit val problem: Problem = Complete
implicit val problem: Problem = WithUnassignedTopics

private val bestMorning = Best.on(Morning)
private val bestMorning = BestWithUnassignedTopics.on(Morning)

"topics" should "work" in {
bestMorning.topics should be(Set(Acting, Dancing, Grinding, UnassignedMorning))
Expand All @@ -34,7 +34,7 @@ class SlotScheduleSpec extends AnyFlatSpec with Matchers {
}

"unweightedScoresByPerson" should "be correct for a simple case" in {
val slots = SimpleTestModel.Solutions.Best.slotSchedulesList.sortBy(_.slot.id).map(_.unweightedScoresByPerson)
val slots = SimpleTestModel.Solutions.BestWithUnassignedTopics.slotSchedulesList.sortBy(_.slot.id).map(_.unweightedScoresByPerson)
val slot1 = slots.head
val slot2 = slots.tail.head
val slot3 = slots.tail.tail.head
Expand Down
18 changes: 9 additions & 9 deletions src/test/scala/fr/renoux/gaston/tools/ScheduleParserSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ class ScheduleParserSpec extends AnyFlatSpec with Matchers {
import fr.renoux.gaston.SimpleTestModel.Solutions._
import fr.renoux.gaston.SimpleTestModel.Topics._

private implicit val problem: Problem = Complete
private implicit val problem: Problem = WithUnassignedTopics
private implicit val context: Context = Context.Default

val parser = new ScheduleParser()
val formatted: String = Best.toFormattedString
val formatted: String = BestWithUnassignedTopics.toFormattedString
println(formatted)

"parseTopic" should "read a correct topic" in {
Expand All @@ -42,22 +42,22 @@ class ScheduleParserSpec extends AnyFlatSpec with Matchers {
}

"readSlotSchedule" should "parse a slot schedule" in {
val lines = Best.toFormattedString.linesIterator.toList.tail // drop the line 'Schedule:'
val lines = BestWithUnassignedTopics.toFormattedString.linesIterator.toList.tail // drop the line 'Schedule:'
val result: Either[String, (Option[SlotSchedule], List[String])] = parser.readSlotSchedule(0, lines)
result.left.toOption should be(None)
val (slotSchedule, linesLeft) = result.toOption.get
slotSchedule.get.toFormattedString should be(Best.on(AfterNoon).toFormattedString) // AfterNoon is the first slot alphabetically
slotSchedule should be(Some(Best.on(AfterNoon)))
slotSchedule.get.toFormattedString should be(BestWithUnassignedTopics.on(AfterNoon).toFormattedString) // AfterNoon is the first slot alphabetically
slotSchedule should be(Some(BestWithUnassignedTopics.on(AfterNoon)))
linesLeft should be(lines.drop(5))
}

"parseFormattedString" should "parse a schedule" in {
val result = parser.parseFormattedString(Best.toFormattedString)
val result = parser.parseFormattedString(BestWithUnassignedTopics.toFormattedString)
result.left.toOption should be(None)
result.toOption.get.toFormattedString should be(Best.toFormattedString)
result.toOption.get should be(Best)
result.toOption.get.toFormattedString should be(BestWithUnassignedTopics.toFormattedString)
result.toOption.get should be(BestWithUnassignedTopics)

println("result.toOption.get.toFormattedString")
result.toOption.get.toFormattedString should be(Best.toFormattedString)
result.toOption.get.toFormattedString should be(BestWithUnassignedTopics.toFormattedString)
}
}

0 comments on commit c85bb24

Please sign in to comment.