Построение решения при использовании пользовательской матрицы расстояния/времени

Я работаю над проектом, который использует этот пример кода по своей сути; использование пользовательской матрицы расстояния/времени для решения проблемы маршрутизации. Алгоритм работает отлично, но я не могу найти способ просмотреть результаты на графике. Запуск только примера кода без каких-либо изменений приводит к:

2015-07-07 11:56:33,354 [main] ПРЕДУПРЕЖДЕНИЕ jsprit.analysis.toolbox.Plotter - не удается построить vrp, так как отсутствует координата

Эта ошибка имеет смысл. Ничто не может быть нанесено на график, потому что на самом деле не указаны местоположения; мы указали только относительное расстояние/время между местоположениями. Я должен использовать пользовательскую матрицу, потому что я работаю в широте/долготе и мне нужно реальное расстояние между точками. Однако по мере того, как моя проблема увеличивается, мне было бы очень полезно просто присвоить каждому местоположению его широту/долготу и построить график, рассматривающий эти точки, как если бы они были декартовыми координатами. Зона охвата невелика, поэтому она все равно должна позволить мне быстро увидеть, имеет ли решение смысл, без необходимости делать более сложные графики. Итак, мой вопрос заключается в том, есть ли простой способ заставить jsprit решить проблему, используя пользовательскую матрицу расстояния/времени, но присваивая координаты местоположениям для построения графика? Не могу понять, заранее спасибо.

РЕДАКТИРОВАТЬ: я потратил много времени, работая над этим безрезультатно, даже с предложенными изменениями от Стефана. Я не могу найти способ сделать это без изменения базового кода, и я не хочу, чтобы это вызывало проблемы с тем, что у меня уже работает.

Создание местоположения — это хорошо, хотя оно немного отличается от предлагаемого кода:

Location.Builder.newInstance().setId("0").setCoordinate(Coordinate.newInstance(10.0, 10.0)).build();

Затем возникает проблема: когда я хочу создать Службу, текущий код вынуждает меня определить новое местоположение (Местоположение принимает только новый экземпляр):

Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(Location.newInstance(6.0, 1.0)).build();

Я не могу найти существующий способ просто сказать, что Служба находится в заранее определенном месте.

Двигаясь дальше, я подумал о добавлении местоположений непосредственно в VehicleRoutingProblem.Builder. Обратите внимание, что добавление местоположения в построитель требует, чтобы оно было определено как «addLocation(String LocationID, координата координаты), поэтому оно не будет принимать заранее определенные местоположения явно; они должны быть определены в построителе. Это выглядит следующим образом:

    VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 5).setCostPerDistance(1).setCostPerTime(2).build();
    VehicleImpl vehicle = VehicleImpl.Builder.newInstance("vehicle")
            .setStartLocation(Location.newInstance("0")).setType(type).build();

    Service s1 = Service.Builder.newInstance("1").addSizeDimension(0, 1).setLocation(Location.newInstance("1")).build();
    Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(Location.newInstance("2")).build();
    Service s3 = Service.Builder.newInstance("3").addSizeDimension(0, 1).setLocation(Location.newInstance("3")).build();        

    //define a matrix-builder building an asymmetric matrix
    VehicleRoutingTransportCostsMatrix.Builder costMatrixBuilder = VehicleRoutingTransportCostsMatrix.Builder.newInstance(true);
    costMatrixBuilder.addTransportDistance("0", "1", 19.13);
    costMatrixBuilder.addTransportDistance("0", "2", 18.56);
    costMatrixBuilder.addTransportDistance("0", "3", 21.68);
    costMatrixBuilder.addTransportDistance("1", "0", 15.91);
    costMatrixBuilder.addTransportDistance("1", "2", 15.01);
    costMatrixBuilder.addTransportDistance("1", "3", 11.45);
    costMatrixBuilder.addTransportDistance("2", "0", 19.42);
    costMatrixBuilder.addTransportDistance("2", "1", 12.54);
    costMatrixBuilder.addTransportDistance("2", "3", 11.13);
    costMatrixBuilder.addTransportDistance("3", "0", 25.75);
    costMatrixBuilder.addTransportDistance("3", "1", 9.94);
    costMatrixBuilder.addTransportDistance("3", "2", 11.24);

    costMatrixBuilder.addTransportTime("0", "1", 12);
    costMatrixBuilder.addTransportTime("0", "2", 11);
    costMatrixBuilder.addTransportTime("0", "3", 15);
    costMatrixBuilder.addTransportTime("1", "0", 10);
    costMatrixBuilder.addTransportTime("1", "2", 10);
    costMatrixBuilder.addTransportTime("1", "3", 10);
    costMatrixBuilder.addTransportTime("2", "0", 15);
    costMatrixBuilder.addTransportTime("2", "1", 9);
    costMatrixBuilder.addTransportTime("2", "3", 10);
    costMatrixBuilder.addTransportTime("3", "0", 17);
    costMatrixBuilder.addTransportTime("3", "1", 13);
    costMatrixBuilder.addTransportTime("3", "2", 10);

    VehicleRoutingTransportCosts costMatrix = costMatrixBuilder.build();

    VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().setFleetSize(FleetSize.FINITE).setRoutingCost(costMatrix)
            .addVehicle(vehicle).addJob(s1).addJob(s2).addJob(s3)
            .addLocation("0", Coordinate.newInstance(1.0, 1.0)).addLocation("1", Coordinate.newInstance(9.0, 2.0))
            .addLocation("2", Coordinate.newInstance(5.0, 4.0)).addLocation("3", Coordinate.newInstance(4.0, 8.0))
            .addLocation("4", Coordinate.newInstance(3.0, 7.0)).build();`

Это работает нормально. Но он все равно не будет отображаться, потому что он не устанавливает связь между индексами местоположения и возможностью их построения. Однако я могу подтвердить (как и было запрошено), что решатель использует только предопределенную матрицу затрат, поэтому напечатанный ответ по-прежнему верен.


person roganjosh    schedule 07.07.2015    source источник


Ответы (1)


Вы можете просто назначить долготу/широту своим местоположениям. Если вы задаете собственную матрицу стоимости, алгоритм должен учитывать только матрицу стоимости, т.е. координаты не должны влиять на алгоритм (если повлияли, сообщите мне). Однако тогда вы должны иметь возможность построить его, т. е. рассматривать координаты так, как если бы они были декартовыми.

Редактировать: местоположения могут быть определены с помощью фабрики местоположений и строителя. Один из трех заводов работает следующим образом:

Location location = Location.newInstance(10,12);

Конструктор более гибкий, но не такой удобный, как фабрика, и работает следующим образом:

Location location = Location.Builder.newInstance().setId("1").setIndex(1).setCoordinate(Coordinate.newInstance(10,12).build();

Этими способами вы создаете местоположения, и вы всегда можете назначить эти местоположения транспортным средствам и услугам следующим образом:

Service service = Service.Builder.newInstance("s1").setLocation(location).build();

и аналогичные для транспортных средств. Если вам требуется идентификатор местоположения для вашей матрицы затрат и координаты для построения графика, укажите местоположение, у которого есть идентификатор и координата (см. выше) ... и не добавляйте местоположения вручную в построитель задач. Обратите внимание, что вам нужно сделать это для ваших транспортных средств И ваших услуг.

Что вы также можете сделать, так это расширить плоттер, чтобы он мог проецировать долготу/широту на любую предпочтительную проекцию и вносить ваше расширение в jsprit :). Это подводит меня к другому решению: вы всегда можете спроецировать долготу/широту на проекцию по вашему выбору, а затем назначить эти спроецированные координаты вашим местоположениям jsprit, что может сделать ваш сюжет намного более привлекательным.

Редактировать: Кстати: на вашем месте я бы использовал FastVehicleRoutingCostMatrix, который основан на индексах, а не на идентификаторах. Как следует из названия, он просто быстрее, поскольку использует массивы вместо карт.

person Stefan Schröder    schedule 07.07.2015
comment
Спасибо за ваш быстрый ответ (и такой фантастический инструмент!). Позже я проведу некоторое тестирование, чтобы подтвердить, что матрица затрат переопределяет указанное местоположение, и дам вам знать в любом случае. Из-за того, что он был опущен в примере кода, я не был уверен в приоритете. Я серьезно новичок в Java, поэтому не уверен, какого прогресса я добьюсь в более приятных сюжетах, но если я что-нибудь добьюсь, я отправлю его вам. Тот факт, что я уже запущен и работаю, связан только с отличными примерами кода, которые вы предоставили :) - person roganjosh; 07.07.2015
comment
Я просто хочу проверить, правильно ли я понимаю ваш ответ, поскольку я не добился успеха. Вы предлагаете, чтобы для одного определения службы я мог сделать .setLocation(Location.newInstance(1,1)).setLocation(Location.newInstance("1"))? Я вижу три метода определения местоположения (координата, строка, индекс). Хотя он автоматически определяет то, что я ввел в качестве местоположения, определение его во второй раз с другим типом удостоверения удаляет первое определение. - person roganjosh; 07.07.2015
comment
Кроме того, costMatrixBuilder.addTransportDistance принимает только (string, string, double). Строки поступают из экземпляра местоположения, а не экземпляра построителя, поэтому кажется, что вы вынуждены определять местоположения строкой, если хотите использовать пользовательскую матрицу затрат. Определение парой координат вызывает jsprit.core.util.EuclideanDistanceCalculator.calculateDistance. Извините, если неправильно истолковал ваш ответ. - person roganjosh; 07.07.2015
comment
На вашем месте я бы использовал FastVehicleRoutingTransportCostsMatrix. Чтобы это работало, вам нужно присвоить индекс вашему сервису/месту доставки. Например, вы указываете время в пути от местоположения с индексом 1 до местоположения с индексом 2 следующим образом: - person Stefan Schröder; 08.07.2015
comment
fastVehicleRoutingTransportCostsMatrix.addTransportTime(locationIndexA, locationIndexB, offsetTime(A)) - person Stefan Schröder; 08.07.2015
comment
Вы можете определить соответствующее местоположение следующим образом: Location.Builder().newInstance().setIndex(locationIndexA).setCoordinate(x,y).build(). - person Stefan Schröder; 08.07.2015
comment
Это имеет больше смысла, спасибо. Я попробую это позже сегодня, надеюсь, и отчитаюсь. Если я заработаю, вы хотите, чтобы я отправил вам исправленный пример CostMatrixExample.Java? Как лучше всего это сделать? - person roganjosh; 08.07.2015
comment
Привет, извиняюсь за задержку, мне нужно было поработать над чем-то другим. Сегодня я провел много времени, работая над вашими предложениями, и он не дает того результата, на который мы надеялись, - он все еще не будет строиться. Я обновил свой ответ, указав всего несколько вещей, которые я пробовал (я сделал МНОГО). Я включил редактирование просто для справки, я не ожидаю, что вам придется продолжать работать над этой нишевой проблемой. Спасибо за ваши предложения и время. - person roganjosh; 13.07.2015
comment
Я очень благодарен, что вы обновили свой ответ, я попробую еще раз. Я попробовал быстрый построитель матриц, который дал тот же эффект. Меня смутило поле отправленияTime, и, похоже, оно не имело никакого значения. От всего сердца могу сказать вам, что единственная причина, по которой я перешел с Python на Java (с нуля), заключалась в том, что я не знаю ничего, что могло бы конкурировать по скорости с GraphHopper+jsprit. Эквивалент Python занимает 18 секунд, чтобы проложить маршрут, который GraphHopper делает за 2 мс, и вы решаете мою проблему менее чем за 1/10 времени Python. Скорость даже не в моем периферийном зрении атм :) - person roganjosh; 14.07.2015
comment
Большой! Кстати: здесь (graphhopper.com/api/1/examples/#optimization) вы можете увидеть, как Graphhopper и jsprit работают вместе вживую :). - person Stefan Schröder; 14.07.2015