Добавить в корзинуПозвонить
Найти в Дзене
Один Rust не п...Rust

Генетический алгоритм на Rust

Реализация системы управления автопарком (Fleet Management System) включает управление транспортными средствами, водителями и маршрутами, с использованием имитации отслеживания в реальном времени. Создайте новый проект Rust с помощью cargo new fleet_management --bin и добавьте зависимости в Cargo.toml: [dependencies] actix-web = "4" diesel = { version = "2.1", features = ["postgres"] } dotenv = "0.15" jsonwebtoken = "8" linfa = "0.6" linfa-linear = "0.6" log = "0.4" env_logger = "0.10" metrics = "0.20" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" tokio = { version = "1", features = ["full"] } Создайте файл .env для хранения конфигурации: DATABASE_URL=postgres://user:password@localhost/fleet_db JWT_SECRET=your-secret-key Настройка базы данных (db.rs) use diesel::pg::PgConnection; use diesel::prelude::*; use dotenv::dotenv; use std::env; pub fn establish_connection() -> PgConnection { dotenv().ok(); let database_url = env::var("DATABASE_URL").expect("DATABASE_U
Оглавление
ML на RUST без заморочек
Один Rust не п...Rust

Реализация системы управления автопарком (Fleet Management System) включает управление транспортными средствами, водителями и маршрутами, с использованием имитации отслеживания в реальном времени.

1. Настройка проекта

Создайте новый проект Rust с помощью cargo new fleet_management --bin и добавьте зависимости в Cargo.toml:

[dependencies]

actix-web = "4"

diesel = { version = "2.1", features = ["postgres"] }

dotenv = "0.15"

jsonwebtoken = "8"

linfa = "0.6"

linfa-linear = "0.6"

log = "0.4"

env_logger = "0.10"

metrics = "0.20"

serde = { version = "1.0", features = ["derive"] }

serde_json = "1.0"

tokio = { version = "1", features = ["full"] }

Создайте файл .env для хранения конфигурации:

DATABASE_URL=postgres://user:password@localhost/fleet_db

JWT_SECRET=your-secret-key

Настройка базы данных (db.rs)

use diesel::pg::PgConnection;

use diesel::prelude::*;

use dotenv::dotenv;

use std::env;

pub fn establish_connection() -> PgConnection {

dotenv().ok();

let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");

PgConnection::establish(&database_url)

.expect(&format!("Error connecting to {}", database_url))

}

Определение моделей и схемы (models.rs и schema.rs)

models.rs:

use diesel::prelude::*;

use serde::{Deserialize, Serialize};

#[derive(Queryable, Serialize, Deserialize)]

pub struct User {

pub id: i32,

pub username: String,

pub password_hash: String,

pub role: String,

}

#[derive(Queryable, Serialize, Deserialize)]

pub struct Vehicle {

pub id: i32,

pub name: String,

pub driver_id: i32,

}

#[derive(Queryable, Serialize, Deserialize)]

pub struct Route {

pub id: i32,

pub vehicle_id: i32,

pub distance: f64,

pub duration: f64,

}

schema.rs (генерируется Diesel после настройки миграций):

table! {

users (id) {

id -> Int4,

username -> Text,

password_hash -> Text,

role -> Text,

}

}

table! {

vehicles (id) {

id -> Int4,

name -> Text,

driver_id -> Int4,

}

}

table! {

routes (id) {

id -> Int4,

vehicle_id -> Int4,

distance -> Float8,

duration -> Float8,

}

}

Для настройки Diesel выполните:

diesel setup

diesel migration generate create_tables

Аутентификация (auth.rs)

use actix_web::{dev::ServiceRequest, Error};

use jsonwebtoken::{decode, DecodingKey, Validation};

use serde::{Deserialize, Serialize};

use std::env;

#[derive(Debug, Serialize, Deserialize)]

struct Claims {

sub: String,

role: String,

exp: usize,

}

pub fn validate_token(token: &str) -> Result<Claims, String> {

let secret = env::var("JWT_SECRET").expect("JWT_SECRET must be set");

let token_data = decode::<Claims>(

token,

&DecodingKey::from_secret(secret.as_ref()),

&Validation::default(),

)

.map_err(|_| "Invalid token".to_string())?;

Ok(token_data.claims)

}

pub async fn auth_middleware(req: ServiceRequest) -> Result<ServiceRequest, Error> {

let token = req

.headers()

.get("Authorization")

.and_then(|header| header.to_str().ok())

.and_then(|header| header.strip_prefix("Bearer "))

.ok_or_else(|| actix_web::error::ErrorUnauthorized("Missing or invalid token"))?;

validate_token(token)

.map_err(|_| actix_web::error::ErrorUnauthorized("Invalid token"))?;

Ok(req)

}

REST API (routes.rs)

use actix_web::{get, web, HttpResponse};

use diesel::prelude::*;

use crate::{db::establish_connection, models::Vehicle, schema::vehicles};

#[get("/vehicles")]

async fn get_vehicles() -> HttpResponse {

let conn = establish_connection();

let results = vehicles::table

.load::<Vehicle>(&conn)

.expect("Error loading vehicles");

HttpResponse::Ok().json(results)

}

Машинное обучение (ml.rs)

use linfa::prelude::*;

use linfa_linear::LinearRegression;

pub fn train_model() -> LinearRegression<f64> {

// Пример данных: расстояние -> время

let dataset = Dataset::new(vec![vec![10.0], vec![20.0]], vec![15.0, 30.0]);

LinearRegression::new()

.fit(&dataset)

.expect("Failed to train model")

}

pub fn predict_duration(model: &LinearRegression<f64>, distance: f64) -> f64 {

model.predict(&vec![distance])[0]

}

Генетический алгоритм (optimization.rs)

use crate::models::Route;

pub fn optimize_routes(routes: Vec<Route>) -> Vec<Route> {

// Простая заглушка: возвращаем исходные маршруты

// В реальной системе здесь будет генетический алгоритм

routes

}

Главный файл (main.rs)

use actix_web::{middleware, App, HttpServer};

use dotenv::dotenv;

use std::env;

use env_logger;

use crate::auth::auth_middleware;

use crate::ml::train_model;

use crate::routes::get_vehicles;

mod auth;

mod db;

mod ml;

mod models;

mod optimization;

mod routes;

mod schema;

#[actix_web::main]

async fn main() -> std::io::Result<()> {

dotenv().ok();

env_logger::init();

let ml_model = train_model();

println!("ML model trained");

HttpServer::new(move || {

App::new()

.wrap(middleware::Logger::default())

.wrap_fn(auth_middleware)

.service(get_vehicles)

})

.bind("127.0.0.1:8080")?

.run()

.await

}

Генетический алгоритм (ГА) — это метод, который имитирует естественный отбор для поиска оптимальных решений. В данном случае мы будем оптимизировать маршруты автопарка, минимизируя общее расстояние.

Основные шаги алгоритма:

  • Инициализация: Создаем начальную популяцию случайных маршрутов.
  • Оценка приспособленности: Вычисляем, насколько хорош каждый маршрут (меньше расстояние — лучше).
  • Селекция: Выбираем лучшие маршруты для дальнейшего скрещивания.
  • Кроссовер: Комбинируем части маршрутов для создания новых.
  • Мутация: Вносим случайные изменения для разнообразия.
  • Итерации: Повторяем процесс заданное число раз.

Ниже приведен код для файла optimization.rs:

use rand::seq::SliceRandom;

use rand::Rng;

// Структура для маршрута

#[derive(Clone)]

pub struct Route {

pub waypoints: Vec<(f64, f64)>, // Координаты точек (широта, долгота)

pub distance: f64, // Общее расстояние маршрута

}

// Расчет расстояния между двумя точками (упрощенная формула)

fn distance(p1: (f64, f64), p2: (f64, f64)) -> f64 {

((p2.0 - p1.0).powi(2) + (p2.1 - p1.1).powi(2)).sqrt()

}

// Расчет общего расстояния маршрута

fn calculate_distance(route: &Route) -> f64 {

route

.waypoints

.windows(2)

.map(|w| distance(w[0], w[1]))

.sum()

}

// Функция приспособленности (меньше расстояние — выше значение)

fn fitness(route: &Route) -> f64 {

1.0 / calculate_distance(route)

}

// Основной генетический алгоритм

pub fn genetic_algorithm(

population_size: usize, // Размер популяции

generations: usize, // Количество поколений

mutation_rate: f64, // Вероятность мутации

waypoints: Vec<(f64, f64)>, // Точки маршрута

) -> Route {

let mut rng = rand::thread_rng();

let mut population: Vec<Route> = (0..population_size)

.map(|_| {

let mut wp = waypoints.clone();

wp.shuffle(&mut rng);

let dist = calculate_distance(&Route {

waypoints: wp.clone(),

distance: 0.0,

});

Route {

waypoints: wp,

distance: dist,

}

})

.collect();

for _ in 0..generations {

// Сортировка по приспособленности

population.sort_by(|a, b| fitness(b).partial_cmp(&fitness(a)).unwrap());

// Селекция: берем лучшие 50%

let selected = population[..population_size / 2].to_vec();

// Кроссовер: создаем новую популяцию

let mut new_population = selected.clone();

while new_population.len() < population_size {

let parent1 = selected[rng.gen_range(0..selected.len())].clone();

let parent2 = selected[rng.gen_range(0..selected.len())].clone();

let crossover_point = rng.gen_range(1..waypoints.len() - 1);

let mut child_waypoints = parent1.waypoints[..crossover_point].to_vec();

for wp in parent2.waypoints.iter() {

if !child_waypoints.contains(wp) {

child_waypoints.push(*wp);

}

}

let child = Route {

waypoints: child_waypoints,

distance: calculate_distance(&Route {

waypoints: child_waypoints.clone(),

distance: 0.0,

}),

};

new_population.push(child);

}

// Мутация

for route in new_population.iter_mut() {

if rng.gen::<f64>() < mutation_rate {

let i = rng.gen_range(0..waypoints.len());

let j = rng.gen_range(0..waypoints.len());

route.waypoints.swap(i, j);

route.distance = calculate_distance(route);

}

}

population = new_population;

}

// Возвращаем лучший маршрут

population.sort_by(|a, b| fitness(b).partial_cmp(&fitness(a)).unwrap());

population[0].clone()

}

Файл routes.rs:

use actix_web::{get, post, web, HttpResponse, Responder};

use diesel::prelude::*;

use crate::optimization::genetic_algorithm;

// Предполагаемые функции и структуры (реализуются отдельно)

mod db {

pub fn establish_connection() -> diesel::PgConnection { unimplemented!() }

}

mod auth {

pub fn validate_token(_req: &actix_web::HttpRequest) -> Result<Claims, ()> { unimplemented!() }

pub struct Claims { pub role: String }

}

mod models {

pub struct User { pub id: i32, pub name: String, pub role: String }

pub struct Vehicle { pub id: i32, pub name: String }

pub struct Route { pub id: i32, pub waypoints: String }

pub struct NewUser { pub name: String, pub role: String }

pub struct NewVehicle { pub name: String }

pub struct NewRoute { pub waypoints: String }

}

mod schema {

diesel::table! { users (id) { id -> Integer, name -> Text, role -> Text } }

diesel::table! { vehicles (id) { id -> Integer, name -> Text } }

diesel::table! { routes (id) { id -> Integer, waypoints -> Text } }

}

use crate::{db, auth, models::*, schema::*};

// Список пользователей (только для админов)

#[get("/users")]

async fn get_users(req: web::HttpRequest) -> impl Responder {

if let Ok(claims) = auth::validate_token(&req) {

if claims.role != "admin" {

return HttpResponse::Forbidden().finish();

}

let conn = db::establish_connection();

let results = users::table.load::<User>(&conn).expect("Ошибка загрузки пользователей");

HttpResponse::Ok().json(results)

} else {

HttpResponse::Unauthorized().finish()

}

}

// Создание пользователя (только для админов)

#[post("/users")]

async fn create_user(req: web::HttpRequest, new_user: web::Json<NewUser>) -> impl Responder {

if let Ok(claims) = auth::validate_token(&req) {

if claims.role != "admin" {

return HttpResponse::Forbidden().finish();

}

let conn = db::establish_connection();

diesel::insert_into(users::table)

.values(&new_user.into_inner())

.execute(&conn)

.expect("Ошибка создания пользователя");

HttpResponse::Created().finish()

} else {

HttpResponse::Unauthorized().finish()

}

}

// Список транспортных средств

#[get("/vehicles")]

async fn get_vehicles() -> impl Responder {

let conn = db::establish_connection();

let results = vehicles::table.load::<Vehicle>(&conn).expect("Ошибка загрузки транспорта");

HttpResponse::Ok().json(results)

}

// Добавление транспортного средства

#[post("/vehicles")]

async fn create_vehicle(new_vehicle: web::Json<NewVehicle>) -> impl Responder {

let conn = db::establish_connection();

diesel::insert_into(vehicles::table)

.values(&new_vehicle.into_inner())

.execute(&conn)

.expect("Ошибка создания транспорта");

HttpResponse::Created().finish()

}

// Список маршрутов

#[get("/routes")]

async fn get_routes() -> impl Responder {

let conn = db::establish_connection();

let results = routes::table.load::<Route>(&conn).expect("Ошибка загрузки маршрутов");

HttpResponse::Ok().json(results)

}

// Создание маршрута

#[post("/routes")]

async fn create_route(new_route: web::Json<NewRoute>) -> impl Responder {

let conn = db::establish_connection();

diesel::insert_into(routes::table)

.values(&new_route.into_inner())

.execute(&conn)

.expect("Ошибка создания маршрута");

HttpResponse::Created().finish()

}

// Оптимизация маршрутов

#[post("/optimize_routes")]

async fn optimize_routes() -> impl Responder {

let waypoints = vec![(0.0, 0.0), (1.0, 1.0), (2.0, 2.0), (3.0, 3.0)];

let optimized_route = genetic_algorithm(100, 50, 0.01, waypoints);

HttpResponse::Ok().json(optimized_route)

}

Для запуска всех endpoints нужно зарегистрировать их в main.rs:

use actix_web::{App, HttpServer};

use crate::routes::{

get_users, create_user, get_vehicles, create_vehicle, get_routes, create_route, optimize_routes,

};

mod auth;

mod db;

mod models;

mod optimization;

mod routes;

mod schema;

#[actix_web::main]

async fn main() -> std::io::Result<()> {

HttpServer::new(|| {

App::new()

.service(get_users)

.service(create_user)

.service(get_vehicles)

.service(create_vehicle)

.service(get_routes)

.service(create_route)

.service(optimize_routes)

})

.bind("127.0.0.1:8080")?

.run()

.await

}