1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#[cfg(test)]
#[path = "../../../tests/unit/extensions/analyze/clusters_test.rs"]
mod clusters_test;

use std::io::{BufReader, BufWriter, Read};
use std::sync::Arc;
use vrp_core::construction::clustering::dbscan::create_job_clusters;
use vrp_core::models::common::IdDimension;
use vrp_core::models::problem::get_job_locations;
use vrp_core::models::Problem;
use vrp_core::utils::Environment;
use vrp_pragmatic::format::get_coord_index;
use vrp_pragmatic::format::problem::{deserialize_matrix, deserialize_problem, PragmaticProblem};
use vrp_pragmatic::format::solution::serialize_named_locations_as_geojson;
use vrp_pragmatic::format::FormatError;

/// Gets job clusters.
pub fn get_clusters<F: Read>(
    problem_reader: BufReader<F>,
    matrices_readers: Option<Vec<BufReader<F>>>,
    min_points: Option<usize>,
    epsilon: Option<f64>,
) -> Result<String, String> {
    let problem = Arc::new(
        get_core_problem(problem_reader, matrices_readers).map_err(|errs| FormatError::format_many(&errs, ","))?,
    );

    let coord_index = get_coord_index(&problem);
    let environment = Arc::new(Environment::default());

    let clusters = create_job_clusters(problem.as_ref(), environment.random.as_ref(), min_points, epsilon);

    let locations = clusters
        .iter()
        .enumerate()
        .flat_map(|(cluster_idx, jobs)| {
            jobs.iter()
                .filter_map(move |job| {
                    job.dimens().get_id().cloned().map(|job_id| {
                        get_job_locations(job)
                            .flatten()
                            .filter_map(move |l_idx| coord_index.get_by_idx(l_idx))
                            .map(move |location| (job_id.clone(), location, cluster_idx))
                    })
                })
                .flatten()
        })
        .collect::<Vec<_>>();

    let mut buffer = String::new();
    let writer = unsafe { BufWriter::new(buffer.as_mut_vec()) };

    serialize_named_locations_as_geojson(writer, locations.as_slice())
        .map_err(|err| format!("cannot write named locations as geojson: '{}'", err))?;

    Ok(buffer)
}

fn get_core_problem<F: Read>(
    problem_reader: BufReader<F>,
    matrices_readers: Option<Vec<BufReader<F>>>,
) -> Result<Problem, Vec<FormatError>> {
    let problem = deserialize_problem(problem_reader)?;

    let matrices = matrices_readers.map(|matrices| {
        matrices.into_iter().map(|file| deserialize_matrix(BufReader::new(file))).collect::<Result<Vec<_>, _>>()
    });

    let matrices = if let Some(matrices) = matrices { Some(matrices?) } else { None };

    (problem, matrices).read_pragmatic()
}