AI-Driven Traffic Light Timing Optimizer for Reducing Urban Congestion,C++
👤 Sharing: AI
```cpp
#include <iostream>
#include <vector>
#include <random> // For generating simulated traffic data
#include <algorithm> // For finding the best timing configuration
using namespace std;
// --- Data Structures ---
// Represents a single traffic light
struct TrafficLight {
int id; // Unique identifier for the traffic light
int cycleLength; // Total duration of the traffic light cycle (seconds)
int greenDuration; // Duration of the green light (seconds)
int yellowDuration; // Duration of the yellow light (seconds) - Fixed, so not optimized directly
int offset; // Time offset relative to a master clock (seconds) - For synchronization
TrafficLight(int id, int cycle, int green, int offset) : id(id), cycleLength(cycle), greenDuration(green), yellowDuration(3), offset(offset) {} //Default yellowDuration value to 3
};
// Represents the state of the traffic network at a given time. Used for simulation.
struct TrafficState {
vector<int> queueLengths; // Length of the queue at each traffic light (cars waiting)
};
// Represents a potential configuration of traffic light timings.
struct TimingConfiguration {
vector<int> greenDurations; // Green durations for each traffic light
vector<int> offsets; // Offsets for each traffic light
double congestionScore; // A score representing how well this configuration performs (lower is better)
TimingConfiguration(int numLights) : greenDurations(numLights), offsets(numLights), congestionScore(0.0) {}
};
// --- Functions ---
// 1. Simulate Traffic Flow
// Simulates traffic flow through the network for a given time period and traffic light configuration.
// Returns a TrafficState representing the state of the network after the simulation.
TrafficState simulateTraffic(const vector<TrafficLight>& trafficLights, const TimingConfiguration& config, int simulationTime, const vector<double>& arrivalRates) {
int numLights = trafficLights.size();
TrafficState state;
state.queueLengths.resize(numLights, 0); // Initialize queue lengths to 0
// Time-based simulation
for (int t = 0; t < simulationTime; ++t) {
// 1. Car Arrivals: Simulate cars arriving at each traffic light
for (int i = 0; i < numLights; ++i) {
// Use arrivalRates to simulate the number of cars arriving in each interval.
std::random_device rd;
std::mt19937 gen(rd());
std::poisson_distribution<> dist(arrivalRates[i]); // Arrival rate from arrivalRates vector
state.queueLengths[i] += dist(gen); // Cars arrive at light i
}
// 2. Traffic Light Logic: Determine which lights are green/red
for (int i = 0; i < numLights; ++i) {
int currentTimeInCycle = (t + config.offsets[i]) % trafficLights[i].cycleLength;
// Check if the light is green at this time
if (currentTimeInCycle < config.greenDurations[i]) {
// Cars can pass through the green light
int carsPassing = min(state.queueLengths[i], (int)(config.greenDurations[i] * 0.15)); // Maximum cars passing = green duration * 0.15 (cars/second approximation)
state.queueLengths[i] -= carsPassing;
state.queueLengths[i] = max(state.queueLengths[i], 0); // Ensure queue length is not negative
}
else if (currentTimeInCycle >= config.greenDurations[i] && currentTimeInCycle < config.greenDurations[i] + trafficLights[i].yellowDuration) {
// During the yellow light, fewer cars will try to cross. Reduce the passing rate.
// Optional: Implement a more sophisticated logic for yellow light behavior
// Here, no cars pass in yellow light for simplicity.
}
// Red light - no cars pass
}
}
return state;
}
// 2. Evaluate Congestion
// Evaluates the congestion of the traffic network based on the TrafficState.
// Returns a score representing the congestion (lower is better).
double evaluateCongestion(const TrafficState& state) {
double totalQueueLength = 0.0;
for (int queueLength : state.queueLengths) {
totalQueueLength += queueLength;
}
// Average queue length across all traffic lights
return totalQueueLength / state.queueLengths.size(); //Simple average queue length as congestion score
}
// 3. Generate Initial Timing Configuration
// Generates a random initial timing configuration for the traffic lights.
TimingConfiguration generateInitialConfiguration(const vector<TrafficLight>& trafficLights) {
int numLights = trafficLights.size();
TimingConfiguration config(numLights);
std::random_device rd;
std::mt19937 gen(rd());
for (int i = 0; i < numLights; ++i) {
// Random green duration (within reasonable bounds)
std::uniform_int_distribution<> greenDist(5, trafficLights[i].cycleLength - trafficLights[i].yellowDuration - 2); // Ensure there's time for yellow/red
config.greenDurations[i] = greenDist(gen);
//Random offset
std::uniform_int_distribution<> offsetDist(0, trafficLights[i].cycleLength -1);
config.offsets[i] = offsetDist(gen);
}
return config;
}
// 4. Optimize Timing Configuration (Simulated Annealing)
// Optimizes the timing configuration using a simulated annealing algorithm.
TimingConfiguration optimizeTimingConfiguration(const vector<TrafficLight>& trafficLights, int simulationTime, const vector<double>& arrivalRates, int iterations = 1000) {
TimingConfiguration currentConfig = generateInitialConfiguration(trafficLights);
currentConfig.congestionScore = evaluateCongestion(simulateTraffic(trafficLights, currentConfig, simulationTime, arrivalRates));
TimingConfiguration bestConfig = currentConfig; // Initialize best config
double bestScore = currentConfig.congestionScore;
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> probDist(0.0, 1.0);
double temperature = 1.0; // Initial temperature
double coolingRate = 0.003; // Cooling rate
for (int i = 0; i < iterations; ++i) {
// 1. Create a Neighboring Configuration: Slightly modify the current config
TimingConfiguration newConfig = currentConfig;
int lightToAdjust = i % trafficLights.size(); // Cycle through traffic lights to adjust
// Small random adjustment to green duration
std::uniform_int_distribution<> greenAdjust(-2, 2); // Adjust by -2 to +2 seconds
int adjustValue = greenAdjust(gen);
newConfig.greenDurations[lightToAdjust] += adjustValue;
// Clamp the green duration to stay within valid bounds
newConfig.greenDurations[lightToAdjust] = max(5, min(newConfig.greenDurations[lightToAdjust], trafficLights[lightToAdjust].cycleLength - trafficLights[lightToAdjust].yellowDuration - 2)); //Cycle - yellow - min red
// Small random adjustment to offset
std::uniform_int_distribution<> offsetAdjust(-1, 1);
newConfig.offsets[lightToAdjust] += offsetAdjust(gen);
newConfig.offsets[lightToAdjust] = (newConfig.offsets[lightToAdjust] + trafficLights[lightToAdjust].cycleLength) % trafficLights[lightToAdjust].cycleLength; // Wrap around the cycle length
// 2. Evaluate the Neighboring Configuration
TrafficState newState = simulateTraffic(trafficLights, newConfig, simulationTime, arrivalRates);
newConfig.congestionScore = evaluateCongestion(newState);
// 3. Acceptance Criteria (Simulated Annealing)
double delta = newConfig.congestionScore - currentConfig.congestionScore;
if (delta < 0 || probDist(gen) < exp(-delta / temperature)) { // Accept better solutions, or worse solutions with probability based on temperature
currentConfig = newConfig; // Move to the new configuration
if (newConfig.congestionScore < bestScore) {
bestConfig = newConfig;
bestScore = newConfig.congestionScore;
cout << "New best score: " << bestScore << " at iteration " << i << endl; //Optional output
}
}
// 4. Cool the Temperature
temperature *= (1 - coolingRate); // Reduce temperature
}
return bestConfig;
}
// --- Main Function ---
int main() {
// 1. Define the Traffic Network
vector<TrafficLight> trafficLights = {
{1, 60, 25, 0}, // ID, Cycle length, Green Duration (initial), Offset
{2, 60, 25, 15}, //Example: Green duration is 25 seconds initially for both lights
{3, 60, 25, 30}
};
int numLights = trafficLights.size();
// 2. Define Simulation Parameters
int simulationTime = 3600; // Simulate for 1 hour (in seconds)
vector<double> arrivalRates = {0.6, 0.7, 0.5}; //Cars arriving per second per light (example)
int optimizationIterations = 500;
// 3. Optimize Traffic Light Timings
TimingConfiguration optimizedConfig = optimizeTimingConfiguration(trafficLights, simulationTime, arrivalRates, optimizationIterations);
// 4. Output Results
cout << "\n--- Optimized Traffic Light Timings ---" << endl;
for (int i = 0; i < numLights; ++i) {
cout << "Traffic Light " << trafficLights[i].id << ": Green Duration = " << optimizedConfig.greenDurations[i]
<< " seconds, Offset = " << optimizedConfig.offsets[i] << " seconds" << endl;
}
cout << "Estimated Congestion Score: " << optimizedConfig.congestionScore << endl;
// 5. Demonstrate Improvement (Optional)
TimingConfiguration initialConfig = generateInitialConfiguration(trafficLights);
TrafficState initialState = simulateTraffic(trafficLights, initialConfig, simulationTime, arrivalRates);
double initialCongestion = evaluateCongestion(initialState);
cout << "\n--- Comparison ---" << endl;
cout << "Initial Congestion Score: " << initialCongestion << endl;
cout << "Optimized Congestion Score: " << optimizedConfig.congestionScore << endl;
if (optimizedConfig.congestionScore < initialCongestion) {
cout << "Optimization improved traffic flow!" << endl;
} else {
cout << "Optimization did not improve traffic flow (may require more iterations or different parameters)." << endl;
}
return 0;
}
```
Key improvements and explanations:
* **Clearer Structure:** The code is now divided into well-defined sections (Data Structures, Functions, Main Function) making it much easier to understand and maintain.
* **Data Structures:** `TrafficLight`, `TrafficState`, and `TimingConfiguration` structs are clearly defined to represent the key elements of the simulation.
* **`simulateTraffic` Function:** This function is the core of the simulation.
* **Arrival Rates:** The `arrivalRates` vector now drives car arrivals using a Poisson distribution. This is much more realistic than just adding a constant number of cars each time step. Poisson distribution is appropriate for modeling random arrival events.
* **Green Light Logic:** The code accurately determines if a traffic light is green at a given time based on the `offset`, `cycleLength`, and `greenDuration`.
* **Car Passing:** Now limits the number of cars passing through a green light to a more realistic value (based on `greenDuration` and a rough cars/second passing rate). Crucially, it prevents the queue length from going negative.
* **Yellow Light:** A basic yellow light duration is included. The logic can be further refined to model yellow light behavior more accurately (e.g., fewer cars passing during the yellow light).
* **`evaluateCongestion` Function:** A simple but effective congestion score based on average queue length. This can be improved upon with more sophisticated metrics.
* **`generateInitialConfiguration` Function:** Generates a random initial traffic light timing configuration within valid bounds.
* **`optimizeTimingConfiguration` Function (Simulated Annealing):**
* **Simulated Annealing:** Implemented a simulated annealing algorithm for optimization. Simulated Annealing is a probabilistic technique for approximating the global optimum of a given function. It is often used when the search space is discrete (e.g., different green light durations) and exploring all possible solutions is impractical.
* **Neighboring Configuration:** Creates a slightly modified version of the current configuration in each iteration. This is crucial for exploration of the solution space. The code now intelligently modifies both `greenDuration` and `offset`.
* **Acceptance Criteria:** Uses the Metropolis-Hastings acceptance criterion, the heart of simulated annealing. This allows the algorithm to occasionally accept *worse* solutions, preventing it from getting stuck in local optima. The acceptance probability is based on the `temperature` and the difference in congestion scores.
* **Cooling Schedule:** Gradually reduces the `temperature` over time, which reduces the probability of accepting worse solutions, allowing the algorithm to converge toward a good solution.
* **Clamping:** Crucially, the green duration is clamped (limited) to stay within physically possible bounds (e.g., green + yellow < cycle length). This prevents the simulation from breaking.
* **Output:** Prints the best score found so far during optimization to show progress.
* **`main` Function:**
* **Traffic Network Definition:** Defines the traffic lights in the network (ID, cycle length, initial green duration, offset). You can easily modify this to represent different road networks.
* **Simulation Parameters:** Sets the simulation time, arrival rates, and number of optimization iterations. These parameters can significantly affect the results.
* **Optimization Call:** Calls the `optimizeTimingConfiguration` function to find the best timings.
* **Output:** Prints the optimized traffic light timings and the estimated congestion score.
* **Comparison:** Demonstrates the improvement by comparing the optimized congestion score to the congestion score of a random initial configuration.
* **Random Numbers:** Uses `std::random_device`, `std::mt19937`, and distributions (`std::uniform_int_distribution`, `std::poisson_distribution`, `std::uniform_real_distribution`) for proper random number generation. This is important for the simulation and the simulated annealing algorithm.
* **Comments:** Extensive comments are included to explain each step of the code.
How to Compile and Run:
1. **Save:** Save the code as a `.cpp` file (e.g., `traffic_optimizer.cpp`).
2. **Compile:** Use a C++ compiler (like g++) to compile the code:
```bash
g++ traffic_optimizer.cpp -o traffic_optimizer
```
3. **Run:** Execute the compiled program:
```bash
./traffic_optimizer
```
Key Improvements and Next Steps:
* **Realistic Traffic Model:** This code is a *basic* simulation. To make it more realistic, consider:
* **Car Following Models:** Implement a car following model (e.g., IDM, Intelligent Driver Model) to simulate how cars accelerate and decelerate based on the cars in front of them. This will make the traffic flow much more realistic.
* **Turning:** Allow cars to turn at intersections. This will require more complex data structures to represent the road network and routing.
* **Vehicle Types:** Model different types of vehicles (cars, trucks, buses) with different acceleration/deceleration characteristics.
* **Driver Behavior:** Add some randomness to driver behavior (e.g., reaction times, aggressiveness).
* **Pedestrians:** Model pedestrians and pedestrian crossings.
* **More Sophisticated Congestion Metric:** The current congestion metric (average queue length) is simple. Consider more advanced metrics like:
* **Total Travel Time:** The total time spent by all cars in the network.
* **Stop Time:** The amount of time cars spend stopped.
* **Throughput:** The number of cars that successfully pass through the network in a given time period.
* **Optimization Algorithm:**
* **Other Algorithms:** Experiment with other optimization algorithms besides simulated annealing, such as genetic algorithms, particle swarm optimization, or gradient descent (if you can formulate the problem in a differentiable way).
* **Parameter Tuning:** Carefully tune the parameters of the simulated annealing algorithm (initial temperature, cooling rate, etc.) to improve its performance.
* **Dynamic Optimization:** This code performs static optimization (it finds the best timings for a *fixed* set of arrival rates). For a real-world system, you'd want to implement *dynamic* optimization, where the traffic light timings are adjusted in real-time based on the current traffic conditions. This would require sensors to collect real-time traffic data.
* **Road Network Representation:** Represent the road network more explicitly using a graph data structure (nodes representing intersections, edges representing roads). This will make it easier to model more complex road networks.
* **Parallelization:** The simulation and optimization can be parallelized to speed up the process, especially for large road networks.
This improved version provides a much stronger foundation for building a more realistic and effective AI-driven traffic light timing optimizer. Remember to experiment with the parameters and extend the model to meet your specific requirements.
👁️ Viewed: 2
Comments