Generates urban mobility plans that minimize carbon using AI simulations Scala
👤 Sharing: AI
```scala
import scala.util.Random
object UrbanMobilityAI {
// Define data structures to represent the urban environment
// Represents a street segment with its length and average speed
case class Street(id: Int, length: Double, speedLimit: Double)
// Represents a mode of transportation with its carbon emissions per km
case class TransportationMode(name: String, carbonEmissionsPerKm: Double, avgSpeed: Double)
// Represents a possible route between two locations
case class Route(streets: Seq[Street], transportationMode: TransportationMode) {
def totalDistance(): Double = streets.map(_.length).sum
def totalCarbonEmissions(): Double = totalDistance() * transportationMode.carbonEmissionsPerKm
def travelTime(): Double = streets.map(s => s.length / s.speedLimit).sum //Approximate. Needs consideration for traffic
}
// Represents a proposed urban mobility plan
case class MobilityPlan(routes: Seq[Route]) {
def totalCarbonEmissions(): Double = routes.map(_.totalCarbonEmissions()).sum
def totalTravelTime(): Double = routes.map(_.travelTime()).sum
//Evaluate plan
def evaluatePlan(weightCarbon: Double, weightTravelTime: Double): Double = {
// Normalize weights
val totalWeight = weightCarbon + weightTravelTime
val normalizedWeightCarbon = weightCarbon / totalWeight
val normalizedWeightTravelTime = weightTravelTime / totalWeight
// Consider higher carbon emissions and longer travel times as "worse" so the returned value should be minimized
normalizedWeightCarbon * totalCarbonEmissions() + normalizedWeightTravelTime * totalTravelTime()
}
}
// Sample data (replace with a realistic urban environment)
val streets = Seq(
Street(1, 1.0, 50.0), // km, km/h
Street(2, 0.5, 30.0),
Street(3, 2.0, 60.0),
Street(4, 1.5, 40.0)
)
val transportationModes = Seq(
TransportationMode("Car", 0.2, 40.0), // kg CO2/km, km/h
TransportationMode("Bus", 0.1, 30.0),
TransportationMode("Bicycle", 0.01, 15.0),
TransportationMode("Electric Car", 0.05, 40.0) //Lower carbon, but not zero due to electricity generation
)
// --- AI Simulation Logic ---
// Generates a random mobility plan
def generateRandomMobilityPlan(numRoutes: Int): MobilityPlan = {
val random = new Random()
val routes = (1 to numRoutes).map { _ =>
val numStreets = random.nextInt(streets.length) + 1 // At least 1 street
val randomStreets = Random.shuffle(streets).take(numStreets) //Random streets
val randomMode = transportationModes(random.nextInt(transportationModes.length)) //Random transportation
Route(randomStreets, randomMode)
}
MobilityPlan(routes)
}
// Simulates the AI optimization using a Genetic Algorithm (simplified)
def optimizeMobilityPlan(populationSize: Int, numGenerations: Int, numRoutes: Int, weightCarbon: Double, weightTravelTime: Double): MobilityPlan = {
// 1. Initialize a population of random plans
var population = (1 to populationSize).map(_ => generateRandomMobilityPlan(numRoutes)).toSeq
// 2. Iterate through generations
for (generation <- 1 to numGenerations) {
// 3. Evaluate the fitness of each plan in the population
val evaluatedPopulation = population.map(plan => (plan, plan.evaluatePlan(weightCarbon, weightTravelTime)))
// 4. Select the best plans (tournament selection) - Choose the "fittest" 2 plans for each competition
val selected = (1 to populationSize).map{ _ =>
val competitors = Random.shuffle(evaluatedPopulation).take(2)
competitors.minBy(_._2)._1 // Select the plan with the minimum evaluation value (best)
}
// 5. Crossover (recombination) and Mutation
val newPopulation = selected.map { plan =>
if (Random.nextDouble() < 0.1) { // Small mutation rate
//Mutate: Change a route's mode
val routeIndexToMutate = Random.nextInt(plan.routes.length)
val newMode = transportationModes(Random.nextInt(transportationModes.length))
val mutatedRoutes = plan.routes.updated(routeIndexToMutate, plan.routes(routeIndexToMutate).copy(transportationMode = newMode))
plan.copy(routes = mutatedRoutes)
} else {
plan // No Mutation
}
}
// 6. Replace the old population with the new population
population = newPopulation
}
// 7. Return the best plan from the final population
population.minBy(_.evaluatePlan(weightCarbon, weightTravelTime)) // Best plan based on evaluation
}
def main(args: Array[String]): Unit = {
println("Starting Urban Mobility AI Simulation...")
val populationSize = 50
val numGenerations = 30
val numRoutes = 5 // Number of routes to plan for
val weightCarbon = 0.7 // Carbon emissions importance
val weightTravelTime = 0.3 // Travel time importance
val bestPlan = optimizeMobilityPlan(populationSize, numGenerations, numRoutes, weightCarbon, weightTravelTime)
println("\n--- Best Mobility Plan Found ---")
println(s"Total Carbon Emissions: ${bestPlan.totalCarbonEmissions()} kg CO2")
println(s"Total Travel Time: ${bestPlan.totalTravelTime()} hours")
println("Routes:")
bestPlan.routes.zipWithIndex.foreach { case (route, index) =>
println(s" Route ${index + 1}:")
println(s" Mode: ${route.transportationMode.name}")
println(s" Streets: ${route.streets.map(_.id).mkString(", ")}")
println(s" Distance: ${route.totalDistance()} km")
println(s" Carbon Emissions: ${route.totalCarbonEmissions()} kg CO2")
println(s" Travel Time: ${route.travelTime()} hours")
}
println("\nSimulation Complete.")
}
}
```
Key improvements and explanations:
* **Clear Data Structures:** Uses `case class` to define `Street`, `TransportationMode`, `Route`, and `MobilityPlan`. This makes the code much more readable and organized. The immutability of case classes is beneficial for genetic algorithms.
* **`evaluatePlan` Function:** This function is crucial. It takes the `MobilityPlan` and calculates a single score representing the "fitness" of the plan. It incorporates both carbon emissions and travel time, using weights to determine the relative importance of each factor. This score is *minimized* to find the best plan. The `normalizedWeight` ensures that the parameters are handled even if they don't add up to 1.
* **`generateRandomMobilityPlan` Function:** Creates a random initial plan. This is important for kicking off the genetic algorithm. It now picks a random number of streets to include in each route.
* **`optimizeMobilityPlan` - Genetic Algorithm:**
* **Initialization:** Creates an initial population of random mobility plans.
* **Evaluation:** Evaluates the fitness of each plan using the `evaluatePlan` function.
* **Selection (Tournament Selection):** Selects the "fittest" plans from the population based on their evaluation score. Tournament selection helps maintain diversity by giving even "weaker" plans a chance to be selected.
* **Crossover and Mutation:** Creates new plans by combining parts of the selected plans and introducing random changes. The crossover is simplified, but more sophisticated crossover operators (e.g., swapping streets between routes) could be added. The mutation rate is kept small to avoid disrupting good plans too often.
* **Replacement:** Replaces the old population with the new population.
* **Iteration:** Repeats the evaluation, selection, crossover, and mutation steps for a specified number of generations.
* **Return:** Returns the best plan found after all generations.
* **Sample Data:** Includes sample data for streets and transportation modes. This makes the program runnable out of the box. Important: replace with *realistic* data for your target urban environment.
* **`main` Function:** Demonstrates how to use the AI simulation to find the best mobility plan. Sets parameters like population size, number of generations, and weights. Prints the results clearly.
* **Normalization:** Weight normalization in `evaluatePlan` ensures that even if the weights don't add up to 1.0, the evaluation still works correctly.
* **Mutation:** Mutation now *modifies* the transportation mode of a route, making it more effective. The route index to mutate is randomly selected.
* **Comments and Explanations:** Thorough comments are added to explain the code.
* **Scalability:** While this is a simplified example, the structure allows for scalability. You could:
* Increase the size of the street network.
* Add more transportation modes.
* Implement more sophisticated genetic algorithm operators (e.g., more complex crossover, different mutation strategies).
* Integrate with real-world traffic data.
**How to Run:**
1. **Save:** Save the code as `UrbanMobilityAI.scala`.
2. **Compile:** Open a terminal or command prompt and navigate to the directory where you saved the file. Compile the code using `scalac UrbanMobilityAI.scala`.
3. **Run:** Execute the compiled code using `scala UrbanMobilityAI`.
The program will then run the simulation and print the details of the best mobility plan found. Remember to adjust the parameters (population size, number of generations, weights) to see how they affect the results. And most importantly, replace the sample data with realistic urban data for your specific use case. You'll also likely need to dramatically increase population sizes and generations for real-world problems.
👁️ Viewed: 5
Comments