Skip to content

Commit 1cab7b5

Browse files
author
Daniel García
committed
Merge branch 'feature/integrate-bb-algorithm' into develop
2 parents ae21578 + 08e1043 commit 1cab7b5

File tree

11 files changed

+130
-40
lines changed

11 files changed

+130
-40
lines changed

app/src/main/java/com/tripletres/platformscience/data/repo/DriverRepository.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class DriverRepository @Inject constructor(
1212
) {
1313

1414
suspend fun saveDrivers(drivers: List<DriverEntity>) = driverDao.insertAll(drivers)
15-
suspend fun getDriversFromDB(): List<DriverEntity> = driverDao.getAll()
15+
suspend fun getDriversFromDB(): List<DriverEntity> = driverDao.getAll() ?: emptyList()
1616
suspend fun clearDriversFromDB() = driverDao.deleteAll()
1717
suspend fun getDriverByIdFromDB(id: Long): DriverEntity = driverDao.getById(id)
1818

app/src/main/java/com/tripletres/platformscience/domain/AssignDriversToShipmentsUseCase.kt

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ package com.tripletres.platformscience.domain
22

33
import com.tripletres.platformscience.data.repo.DriverRepository
44
import com.tripletres.platformscience.data.repo.ShipmentRepository
5+
import com.tripletres.platformscience.domain.algorithm.AssignationAlgorithmType
6+
import com.tripletres.platformscience.domain.algorithm.BranchAndBoundAlgorithm
57
import com.tripletres.platformscience.domain.algorithm.GreedyAssignationAlgorithm
6-
import com.tripletres.platformscience.domain.model.Driver
7-
import com.tripletres.platformscience.domain.model.Shipment
8-
import com.tripletres.platformscience.domain.model.asDriverList
9-
import com.tripletres.platformscience.domain.model.asShipmentList
8+
import com.tripletres.platformscience.domain.algorithm.IAssignationAlgorithm
9+
import com.tripletres.platformscience.domain.model.*
1010
import javax.inject.Inject
1111

1212
/**
@@ -18,11 +18,14 @@ class AssignDriversToShipmentsUseCase @Inject constructor(
1818
private val saveDriversAssigned: SaveDriversAssignedToShipmentsUseCase,
1919
) {
2020

21-
suspend operator fun invoke(): List<Driver> {
21+
// Can be changed for your favorite algorithm
22+
private val defaultAlgorithm = AssignationAlgorithmType.GREEDY.name
23+
24+
suspend operator fun invoke(algorithm: String?): List<Driver> {
2225
val drivers = driverRepository.getDriversFromDB().asDriverList()
2326
val shipments = shipmentRepository.getShipmentsFromDB().asShipmentList()
2427

25-
val driverAssigned = assignDriversToShipment(drivers, shipments)
28+
val driverAssigned = assignDriversToShipment(drivers, shipments, algorithm)
2629
//Save in assigned drivers
2730
saveDriversAssigned(driverAssigned)
2831
return driverAssigned
@@ -31,8 +34,23 @@ class AssignDriversToShipmentsUseCase @Inject constructor(
3134
/**
3235
* Perform assignation of shipments to drivers
3336
*/
34-
private fun assignDriversToShipment(drivers: List<Driver>, shipments: List<Shipment>): List<Driver> {
35-
return ShipmentDriverAssignation(GreedyAssignationAlgorithm()).execute(drivers, shipments)
37+
private fun assignDriversToShipment(
38+
drivers: List<Driver>,
39+
shipments: List<Shipment>,
40+
algorithm: String?,
41+
): List<Driver> {
42+
return ShipmentDriverAssignation(defineAlgorithm(algorithm)).execute(drivers, shipments)
43+
}
44+
45+
/**
46+
* Gets assignation algorithm from type or default
47+
*/
48+
private fun defineAlgorithm(algorithm: String?): IAssignationAlgorithm {
49+
val type = algorithm ?: defaultAlgorithm
50+
return when (type.toAssignationAlgorithmType()) {
51+
AssignationAlgorithmType.GREEDY -> GreedyAssignationAlgorithm()
52+
AssignationAlgorithmType.BRANCH -> BranchAndBoundAlgorithm()
53+
}
3654
}
3755

3856
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.tripletres.platformscience.domain.algorithm
2+
3+
/**
4+
* To identify what type of algorithm to use
5+
*/
6+
enum class AssignationAlgorithmType {
7+
GREEDY,
8+
BRANCH,
9+
}

app/src/main/java/com/tripletres/platformscience/domain/algorithm/BranchAndBoundAlgorithm.kt

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,15 @@ class BranchAndBoundAlgorithm : IAssignationAlgorithm {
3737
private var n = 0
3838

3939
override fun getBestMatching(input: MutableList<MutableList<SuitabilityScore>>): List<Driver> {
40-
n = input.size
41-
return execute(matrix = input)
40+
return execute(matrix = prepareInput(input))
4241
}
4342

4443
private fun execute(matrix: MutableList<MutableList<SuitabilityScore>>): List<Driver> {
4544
//Priority queue for nodes that are "live"
4645
val priorityQueue = mutableListOf<Node>()
4746

4847
// Initialize nodes with root of search (dummy)
49-
val assigned = HashMap<Shipment, Boolean>()
48+
val assigned = mutableListOf<Shipment>()
5049
val root = Node.dummy()
5150
var minOut = root
5251
priorityQueue.add(root)
@@ -70,12 +69,12 @@ class BranchAndBoundAlgorithm : IAssignationAlgorithm {
7069
//For each shipment find unassigned shipments
7170
matrix[i].forEachIndexed { j, it ->
7271
//If unassigned
73-
if (!min.assigned.containsKey(it.shipment)) {
72+
if (!min.assigned.contains(it.shipment)) {
7473
val child = Node.newNode(
7574
driver = matrix[i][j].driver,
7675
driverIndex = i, // should have here?
7776
shipment = matrix[i][j].shipment,
78-
assigned = HashMap(assigned),
77+
assigned = assigned.toMutableList(),
7978
parent = min
8079
)
8180
//Cost for ancestor nodes including current node
@@ -99,7 +98,7 @@ class BranchAndBoundAlgorithm : IAssignationAlgorithm {
9998
private fun getLowestSSAfterDriverAssignedShipment(
10099
matrix: MutableList<MutableList<SuitabilityScore>>,
101100
driver: Int,
102-
assigned: HashMap<Shipment, Boolean>,
101+
assigned: MutableList<Shipment>
103102
): Float {
104103
var cost = 0f;
105104

@@ -116,8 +115,8 @@ class BranchAndBoundAlgorithm : IAssignationAlgorithm {
116115
matrix[i].forEachIndexed { j, it ->
117116

118117
//If shipment is unassigned
119-
if (!assigned.containsKey(it.shipment) &&
120-
available.containsKey(it.shipment) &&
118+
if (!assigned.contains(it.shipment) &&
119+
available.contains(it.shipment) &&
121120
it.ss < min
122121
) {
123122
//Store shipment number
@@ -172,14 +171,14 @@ class BranchAndBoundAlgorithm : IAssignationAlgorithm {
172171
var driver: Driver,
173172
var driverIndex: Int = 0,
174173
var shipment: Shipment,
175-
var assigned: HashMap<Shipment, Boolean> = HashMap(),
174+
var assigned: MutableList<Shipment> = mutableListOf(),
176175
) {
177176
companion object {
178177
fun newNode(
179178
driver: Driver,
180179
driverIndex: Int,
181180
shipment: Shipment,
182-
assigned: HashMap<Shipment, Boolean> = HashMap(),
181+
assigned: MutableList<Shipment> = mutableListOf(),
183182
parent: Node? = null,
184183
): Node {
185184
val node = Node(
@@ -189,7 +188,7 @@ class BranchAndBoundAlgorithm : IAssignationAlgorithm {
189188
parent = parent,
190189
driverIndex = driverIndex
191190
)
192-
node.assigned[shipment] = true
191+
node.assigned.add(shipment)
193192

194193
return node
195194
}
@@ -200,4 +199,32 @@ class BranchAndBoundAlgorithm : IAssignationAlgorithm {
200199
}
201200
}
202201

202+
/**
203+
* Simple preparation driver x, shipment y
204+
*/
205+
private fun prepareInput(input: MutableList<MutableList<SuitabilityScore>>): MutableList<MutableList<SuitabilityScore>> {
206+
//Drivers must be x, shipments must be y
207+
//must be squared nxn
208+
n = input.size
209+
210+
return if (n > 1 && input[0][0].driver != input[1][0].driver) {
211+
input // drivers in x
212+
} else {
213+
//Need to traspose :/
214+
val dummy = input[0][0].copy()
215+
val transpose = MutableList(n) { MutableList(n) { dummy } }
216+
217+
println("-------INPUT--------")
218+
for (i in 0 until n) {
219+
for (j in 0 until n) {
220+
transpose[j][i] = input[i][j]
221+
print(transpose[i][j].ss)
222+
print("f,")
223+
}
224+
println()
225+
}
226+
transpose
227+
}
228+
}
229+
203230
}

app/src/main/java/com/tripletres/platformscience/domain/model/Converter.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.tripletres.platformscience.domain.model
33
import com.tripletres.platformscience.data.db.driver.DriverAssignationEntity
44
import com.tripletres.platformscience.data.db.driver.DriverEntity
55
import com.tripletres.platformscience.data.db.shipment.ShipmentEntity
6+
import com.tripletres.platformscience.domain.algorithm.AssignationAlgorithmType
67
import com.tripletres.platformscience.ui.model.DriverItem
78
import com.tripletres.platformscience.ui.model.ShipmentItem
89

@@ -57,3 +58,14 @@ fun Driver.asDriverEntity(): DriverEntity {
5758
}
5859

5960
private fun Shipment.asShipmentEntity(): ShipmentEntity = ShipmentEntity(this.id, this.address)
61+
62+
/**
63+
* Algorithm type converter
64+
*/
65+
fun String.toAssignationAlgorithmType(): AssignationAlgorithmType {
66+
return when (this) {
67+
"GREEDY" -> AssignationAlgorithmType.GREEDY
68+
"BRANCH_BOUND" -> AssignationAlgorithmType.BRANCH
69+
else -> TODO("No available")
70+
}
71+
}

app/src/main/java/com/tripletres/platformscience/ui/view/settings/SimpleSettingsView.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ import com.tripletres.platformscience.R
2121
@Composable
2222
fun SimpleSettingsView(modifier: Modifier? = Modifier) {
2323
val viewModel: SimpleSettingsViewModel = hiltViewModel()
24-
val uiState by viewModel.uiState.collectAsState()
24+
val uiState = viewModel.uiState.collectAsState()
2525
Column(modifier = modifier ?: Modifier.fillMaxWidth()) {
2626
Row(verticalAlignment = Alignment.CenterVertically) {
2727
Switch(
28-
checked = uiState.dbOrApi,
29-
onCheckedChange = { viewModel.updateDbOrApi(!uiState.dbOrApi) })
28+
checked = uiState.value.dbOrApi,
29+
onCheckedChange = { viewModel.updateDbOrApi(!uiState.value.dbOrApi) })
3030

3131
Text(text =
32-
"${stringResource(id = R.string.setting_db_or_api)}: ${uiState.dbOrApiLabel}")
32+
"${stringResource(id = R.string.setting_db_or_api)}: ${uiState.value.dbOrApiLabel}")
3333
}
3434
Divider()
3535
Text(
@@ -38,8 +38,8 @@ fun SimpleSettingsView(modifier: Modifier? = Modifier) {
3838
modifier = Modifier.padding(top = 8.dp)
3939
)
4040
Row(verticalAlignment = Alignment.CenterVertically) {
41-
uiState.algorithms.forEach { algorithm ->
42-
RadioButton(selected = algorithm == uiState.algorithmSelected, onClick = {
41+
uiState.value.algorithms.forEach { algorithm ->
42+
RadioButton(selected = algorithm == uiState.value.algorithmSelected, onClick = {
4343
viewModel.updateAlgorithmSelected(algorithm)
4444
})
4545
Text(

app/src/main/java/com/tripletres/platformscience/ui/view/settings/SimpleSettingsViewModel.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class SimpleSettingsViewModel @Inject constructor(
2121
fun updateDbOrApi(state: Boolean) {
2222
val dbOrApi = if (state) SimpleSettingsUtil.DB_OR_API_DEF else SimpleSettingsUtil.DB_OR_API_API
2323
settings.setPreference(SimpleSettingsUtil.DB_OR_API, dbOrApi)
24-
24+
updateState()
2525
}
2626

2727
fun updateAlgorithmSelected(algorithm: String) {
@@ -44,6 +44,6 @@ class SimpleSettingsViewModel @Inject constructor(
4444
/**
4545
* Call update state when saved to shared preferences
4646
*/
47-
private fun updateState(newState: SimpleSettingsUtil) =_uiState.update { fromSettings() }
47+
private fun updateState() =_uiState.update { fromSettings() }
4848

4949
}

app/src/main/java/com/tripletres/platformscience/ui/view/splash/SplashViewModel.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ import com.tripletres.platformscience.domain.AssignDriversToShipmentsUseCase
66
import com.tripletres.platformscience.domain.LoadDriversShipmentsUseCase
77
import com.tripletres.platformscience.ui.model.DriverItem
88
import com.tripletres.platformscience.util.LogUtils
9+
import com.tripletres.platformscience.util.SimpleSettingsUtil
10+
import com.tripletres.platformscience.util.SimpleSettingsUtil.Companion.ALGORITHM
11+
import com.tripletres.platformscience.util.SimpleSettingsUtil.Companion.DB_OR_API
12+
import com.tripletres.platformscience.util.SimpleSettingsUtil.Companion.DB_OR_API_DEF
913
import dagger.hilt.android.lifecycle.HiltViewModel
1014
import kotlinx.coroutines.Dispatchers
1115
import kotlinx.coroutines.flow.MutableStateFlow
@@ -21,6 +25,7 @@ import javax.inject.Inject
2125
class SplashViewModel @Inject constructor(
2226
private val loadDriversShipmentsUseCase: LoadDriversShipmentsUseCase,
2327
private val assignDriversToShipmentsUseCase: AssignDriversToShipmentsUseCase,
28+
private val settings: SimpleSettingsUtil,
2429
) : ViewModel() {
2530

2631
private val _uiState = MutableStateFlow(SplashUiState())
@@ -34,17 +39,16 @@ class SplashViewModel @Inject constructor(
3439
viewModelScope.launch(Dispatchers.IO) {
3540
loadDriversShipmentsUseCase(getCachedSetting())
3641
updateStatus(SplashUiStatus.ASSIGNING)
37-
assignDriversToShipmentsUseCase()
42+
assignDriversToShipmentsUseCase(getAlgorithmSetting())
3843
updateStatus(SplashUiStatus.DONE)
39-
val drivers: List<DriverItem> = emptyList()
40-
LogUtils.d("Drivers: ${drivers.toString()}")
4144
}
4245
}
4346

4447
private fun updateStatus(newStatus: SplashUiStatus) {
4548
_uiState.update { state -> state.copy(status = newStatus) }
4649
}
4750

48-
private fun getCachedSetting() = true //TODO: settings from user
51+
private fun getCachedSetting() = settings.getPreference(DB_OR_API) == DB_OR_API_DEF
52+
private fun getAlgorithmSetting() = settings.getPreference(ALGORITHM)
4953

5054
}

app/src/main/java/com/tripletres/platformscience/util/SimpleSettingsUtil.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,15 @@ class SimpleSettingsUtil @Inject constructor(@ApplicationContext val context: Co
2020
const val DB_OR_API_API = "API" //API option
2121
const val ALGORITHM: String = "ALGORITHM"
2222
const val ALGORITHM_GREEDY: String = "GREEDY"
23-
const val ALGORITHM_DEF: String = ALGORITHM_GREEDY //TODO: change for constant
23+
const val ALGORITHM_BRANCH_BOUND: String = "BRANCH_BOUND"
24+
const val ALGORITHM_DEF: String = ALGORITHM_GREEDY
2425

2526
//TODO: Add more algorithms
2627
fun allAlgorithms(): List<String> {
27-
return listOf(ALGORITHM_GREEDY)
28+
return listOf(
29+
ALGORITHM_GREEDY,
30+
ALGORITHM_BRANCH_BOUND
31+
)
2832
}
2933

3034
}

app/src/test/java/com/tripletres/platformscience/domain/AssignDriversToShipmentsUseCaseUnitTest.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ class AssignDriversToShipmentsUseCaseUnitTest {
2424
@RelaxedMockK
2525
lateinit var saveDriversAssigned: SaveDriversAssignedToShipmentsUseCase
2626

27+
private var algorithmString = "GREEDY"
28+
2729
@Before
2830
fun setUp() {
2931
MockKAnnotations.init(this)
@@ -38,7 +40,7 @@ class AssignDriversToShipmentsUseCaseUnitTest {
3840
driverRepository,
3941
shipmentRepository,
4042
saveDriversAssigned
41-
).invoke()
43+
).invoke(algorithmString)
4244

4345
//Then get db data
4446
assertNotNull(res)
@@ -55,7 +57,7 @@ class AssignDriversToShipmentsUseCaseUnitTest {
5557
driverRepository,
5658
shipmentRepository,
5759
saveDriversAssigned
58-
).invoke()
60+
).invoke(algorithmString)
5961

6062
//Then save drivers assigned
6163
assertNotNull(res)

app/src/test/java/com/tripletres/platformscience/domain/algorithm/DriverShipmentMockData.kt

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import com.tripletres.platformscience.domain.model.Driver
55
import com.tripletres.platformscience.domain.model.Shipment
66

77

8-
fun ssMockList(): MutableList<MutableList<ShipmentDriverAssignation.SuitabilityScore>> {
8+
fun ssMockList(major: Boolean = false): MutableList<MutableList<ShipmentDriverAssignation.SuitabilityScore>> {
99
val matrix = mutableListOf<MutableList<ShipmentDriverAssignation.SuitabilityScore>>()
1010
val singleSS = arrayListOf(
1111
arrayListOf(9f, 2f, 7f, 8f),
@@ -14,10 +14,24 @@ fun ssMockList(): MutableList<MutableList<ShipmentDriverAssignation.SuitabilityS
1414
arrayListOf(7f, 6f, 9f, 4f)
1515
)
1616

17-
for (i in (0..3)) {
17+
val mayorSS = arrayListOf(
18+
arrayListOf(11.25f, 11.25f, 11.25f, 11.25f, 11.25f, 11.25f, 11.25f, 11.25f, 11.25f, 11.25f),
19+
arrayListOf(9.0f, 10.5f, 11.25f, 11.25f, 11.25f, 11.25f, 11.25f, 11.25f, 11.25f, 11.25f),
20+
arrayListOf(11.25f, 13.5f, 11.25f, 11.25f, 11.25f, 11.25f, 11.25f, 11.25f, 11.25f, 11.25f),
21+
arrayListOf(13.5f, 6.0f, 13.5f, 6.0f, 11.25f, 11.25f, 11.25f, 11.25f, 11.25f, 11.25f),
22+
arrayListOf(11.25f, 12.0f, 11.25f, 12.0f, 11.25f, 11.25f, 11.25f, 11.25f, 11.25f, 11.25f),
23+
arrayListOf(9.0f, 10.5f, 9.0f, 10.5f, 9.0f, 10.5f, 11.25f, 11.25f, 11.25f, 11.25f),
24+
arrayListOf(11.25f, 10.5f, 11.25f, 10.5f, 11.25f, 10.5f, 11.25f, 11.25f, 11.25f, 11.25f),
25+
arrayListOf(9.0f, 10.5f, 9.0f, 10.5f, 9.0f, 10.5f, 9.0f, 10.5f, 11.25f, 11.25f),
26+
arrayListOf(9.0f, 15.0f, 9.0f, 15.0f, 9.0f, 15.0f, 9.0f, 15.0f, 9.0f, 11.25f),
27+
arrayListOf(11.25f, 7.5f, 11.25f, 7.5f, 11.25f, 7.5f, 11.25f, 7.5f, 11.25f, 7.5f)
28+
)
29+
val n = if(major) mayorSS.size else singleSS.size
30+
31+
for (i in (0..n.minus(1))) {
1832
val mj = mutableListOf<ShipmentDriverAssignation.SuitabilityScore>()
19-
for (j in (0..3)) {
20-
val mock = ssMock(i, j, singleSS[i][j])
33+
for (j in (0..n.minus(1))) {
34+
val mock = ssMock(i, j, if(major)mayorSS[i][j] else singleSS[i][j])
2135
mj.add(mock)
2236
}
2337
matrix.add(mj)

0 commit comments

Comments
 (0)