10.1. The Vehicle Routing Problem (VRP) — or-tools User’s Manual

twitter Новости

.1.1. The Problem

Given a graph G=(V,E)

This “definition” remains vague enough to encompass the most known variants of the VRP. Indeed, not only does the VRP
exist in different flavors (capacitated, multi-depots, with time-windows, with pick-up and delivery, …) but several
slightly different definitions exist in the literature.

In this manual, we will use the definition given by Gilbert Laporte in [Laporte1992]. In this article, a VRP
is designed in such a way that

The last point is important. Indeed, without side constraints and if the graph obeys the triangle inequality
(i.e. d(x,z) leqslant d(x,y)   d(y,z)../../_images/mtsp_metric_graph.pngd(x,z) leqslant d(x,y)   d(y,z)xzy

The most common side constraints include:

And the list goes on.

For our basic version of the VRP, all vehicles must be used. This version of the VRP
is better known as the mTSP[2]. Some problems can be coined as mTSP and we refer again the reader to [Bektas2006]
to find some examples.

Below you’ll find a picture of a solution of a VRP with 32 cities and 5 vehicles (A-n32-k5) in the
sub-section Visualization with ePix.

.1.5. To hold and check a (C)VRP solution: the CVRPSolution class

To represent a (C)VRP solution, we have defined the CVRPSolution class. Two constructors are available:

Two methods verify the feasibility of the solution:

The CVRPSolution class provides iterators to run through the solution. For instance, the
ComputeObjectiveValue() method – that computes the objective value of the solution – is written as follows:

Because this method is constant and doesn’t change the solution, it uses constant iterators. The CVRPSolution
class also provides the following non constant iterators:

About vrp-rep

What exactly is VRP-REP?VRP-REP is an open data platform for sharing benchmark instances and solutions to vehicle routing problem.

How do I cite VRP-REP on my researchYou can give credit to the people running the platform by citing the following reference in your research:

J.E. Mendoza, C. Guéret, M. Hoskins, H. Lobit, V. Pillac, T. Vidal, D. Vigo. VRP-REP: the vehicle routing community repository. Third meeting of the EURO Working Group on Vehicle Routing and Logistics Optimization (VeRoLog). Oslo, Norway. 2022.

Asynchronous hell

As you can see, this new version of vRP rely on asynchronous MySQL queries, so many API functions are now asynchronous. The current way of handling async calls is to pass a callback which will act as the trigger to get the return values when done.

If you need to create your own API function in an async way, a little helper exists in lib/utils.lua.

local MySQL =module("vrp_mysql", "MySQL")
local rsc = {}

-- async api call, following the previous example-- list banned (or not) users-- cbreturns list of usersfunctionrsc.getBannedUsers(banned, cbr)
  -- this case is simple, but sometimes you would want to have conditional returns, and a default return value-- create the task--- callback, default return values as a table (default nil), timeout in milliseconds (optional, default 5000)local task =Task(cbr, {{}}, 5000)

  -- this ensure that if the mysql query fails, the task will return the empty list of users "{}" after 5 seconds

  MySQL.query("vRP/myrsc_getbans", {banned = banned}, function(rows, affected)
    local list = {}

    for k,v inpairs(rows) dotable.insert(list, v.id)
    endtask({list}) -- trigger end of the task, return list of valuesend)
end

Audio

-- TUNNEL CLIENT API-- play audio source (once)--- url: valid audio HTML url (ex: .ogg/.wav/direct ogg-stream url)--- volume: 0-1--- x,y,z: position (omit for unspatialized)--- max_dist  (omit for unspatialized)
vRP.playAudioSource(url, volume, x, y, z, max_dist)

-- set named audio source (looping)--- name: source name--- url: valid audio HTML url (ex: .ogg/.wav/direct ogg-stream url)--- volume: 0-1--- x,y,z: position (omit for unspatialized)--- max_dist  (omit for unspatialized)
vRP.setAudioSource(name, url, volume, x, y, z, max_dist)

-- remove named audio source
vRP.removeAudioSource(name)

Chest

chest
A home chest.

Configuration

Only the files in the cfg/ directory should be modified. Modifying the vRP core files is highly discouraged (don’t open an issue if it’s about modified core files).

There is only one required file to configure before launching the server, cfg/base.lua, to setup the MySQL database credentials.

There is a lot to configure in vRP, nothing comes preconfigured so everyone can make his unique server.
Everything you need to know is in the configuration files, but if you have troubles configuring, look at the configuration of the vRP LaTest servers above.

Game table

gametable

Group/permission

Group and permissions are a way to limit features to specific players.
Each group have a set of permissions defined in cfg/groups.lua.
Permissions can be used with most of the vRP modules, giving the ability to create specific garages, item transformers, etc.

Api
-- PROXY API-- return group title
vRP.getGroupTitle(group)

-- add a group to a connected user
vRP.addUserGroup(user_id,group)

-- remove a group from a connected user
vRP.removeUserGroup(user_id,group)

-- check if the user has a specific group
vRP.hasGroup(user_id,group)

-- register a special permission function-- name: name of the permission -> "!name.[...]"-- callback(user_id, parts)--- parts: parts (strings) of the permissions, ex "!name.param1.param2" -> ["name", "param1", "param2"]--- should return true or false/nil
vRP.registerPermissionFunction(name, callback)

-- check if the user has a specific permission
vRP.hasPermission(user_id, perm)

-- check if the user has a specific list of permissions (all of them)
vRP.hasPermissions(user_id, perms)

-- get user group by group type-- return group name or an empty string
vRP.getUserGroupByType(user_id,gtype)

-- return list of connected users by group
vRP.getUsersByGroup(group)

-- return list of connected users by permission
vRP.getUsersByPermission(perm)

Homes

The home system is experimental, don’t expect too much from it at this point. But it’s a good basis for some RP interactions, and further developments.

Identity

The identity module add identity cards with a car registration number (one per identity, all vehicles will have the same registration number).

Instances

What is a dataset?A dataset is simply a set of instances. A dataset contains: one file for each instance of the dataset, and one readme.txt file explaining the format of the instance files.

What is the dataset alias?The alias of a dataset is the quick reference name of the dataset in the VRP-REP platform. By default, the alias is built using the information of the reference in which the dataset was proposed (see bellow What is a reference?). The default alias is built as follows:

  • author year if the reference was single authored
  • first_author_last_name and second_author_last_name year if the reference was coauthored by two authors
  • first_author_last_name et al. year if the reference was coauthored by more than two authors

Inventory

The inventory is autosaved and, as the wallet, gets empty upon death.

Items

Items are simple identifiers associated with a quantity in an inventory. But they can also be parametrics.

Parametrics items are identified like other items in the inventory but also have arguments as: weapon|pistol instead of just an ID. Parametric items don’t contain any data, they are generic item definitions that will be specialized by the arguments.

-- PROXY API-- define an inventory item (call this at server start) (parametric or plain text data)-- idname: unique item name-- name: display name or genfunction-- description: item description (html) or genfunction-- choices: menudata choices (see gui api) only as genfunction or nil-- weight: weight or genfunction---- genfunction are functions returning a correct value as: function(args) return value end-- where args is a list of {base_idname,arg,arg,arg,...}

vRP.defInventoryItem(idname,name,description,choices,weight)

-- return name, description, weight
vRP.getItemDefinition(idname)

vRP.getItemName(idname)

vRP.getItemDescription(idname)

vRP.getItemChoices(idname)

vRP.getItemWeight(idname)

-- add item to a connected user inventory
vRP.giveInventoryItem(user_id,idname,amount,notify)

-- try to get item from a connected user inventory-- return true if the item has been found and the quantity removed
vRP.tryGetInventoryItem(user_id,idname,amount,notify)

-- get item amount from a connected user inventory
vRP.getInventoryItemAmount(user_id,idname)

-- get connected user inventory-- return map of full idname => amount or nil
vRP.getInventory(user_id)

-- clear connected user inventory
vRP.clearInventory(user_id)

-- compute weight of a list of items (in inventory/chest format)
vRP.computeItemsWeight(items)

-- return user inventory total weight
vRP.getInventoryWeight(user_id)

-- return user inventory max weight
vRP.getInventoryMaxWeight(user_id)

-- open a chest by name-- cb_close(): called when the chest is closed
vRP.openChest(source, name, max_weight, cb_close)

-- TUNNEL SERVER API-- TUNNEL CLIENT API

Example 1. Full example of a resource defining a water bottle item.

Once defined, items can be used by any resources (ex: they can be added to shops).

local Proxy =module("vrp", "lib/Proxy")
local Tunnel =require("vrp", "lib/Tunnel")

vRP = Proxy.getInterface("vRP")
vRPclient = Tunnel.getInterface("vRP","vrp_waterbottle")

-- create Water bottle itemlocal wb_choices = {}  -- (see gui API for menudata choices structure)

wb_choices["Drink"] = {function(player,choice) -- add drink actionlocal user_id = vRP.getUserId(player) -- get user_idif user_id thenif vRP.tryGetInventoryItem(user_id,"water_bottle",1) then-- try to remove one bottle
      vRP.varyThirst(user_id,-35) -- decrease thirst
      vRPclient.notify(player,"~b~ Drinking.") -- notify
      vRP.closeMenu(player) -- the water bottle is consumed by the action, close the menuendendend,"Do it."}

-- add item definition
vRP.defInventoryItem("water_bottle","Water bottle","Drink this my friend.",function() return wb_choices end,0.5)

-- (at any time later) give 2 water bottles to a connected user
vRP.giveInventoryItem(user_id,"water_bottle",2)

Item transformer

The item transformer is a very generic way to create harvest and processing areas.

The concept:

  • you can use the action of the item transformer when entering the area

  • the item transformer has a number of work units, regenerated at a specific rate

  • the item transformer takes reagents (money, items or none) to produce products (money or items) and it consumes a work unit

This way, processing and harvesting are limited by the work units.

-- add an item transformer-- name: transformer id name-- itemtr: item transformer definition table--- name--- permissions (optional)--- max_units--- units_per_minute--- x,y,z,radius,height (area properties)--- r,g,b (color)--- recipes, map of action =>---- description---- in_money---- out_money---- reagents: items as idname => amount---- products: items as idname => amount---- aptitudes: list as "group.aptitude" => exp amount generated--- onstart(player,recipe): optional callback--- onstep(player,recipe): optional callback--- onstop(player,recipe): optional callback
vRP.setItemTransformer(name,itemtr)

-- remove an item transformer
vRP.removeItemTransformer(name)

Example 2. Example from another resource using proxy

local itemtr = {
  name="Water bottles tree", -- menu name
  r=0,g=125,b=255, -- color
  max_units=10,
  units_per_minute=5,
  x=1858,y=3687.5,z=34.26, -- pos
  radius=5, height=1.5, -- area
  recipes = {
    ["Harvest"] = { -- action name
      description="Harvest some water bottles.", -- action description
      in_money=0, -- money taken per unit
      out_money=0, -- money earned per unit
      reagents={}, -- items taken per unit
      products={ -- items given per unit
        ["water_bottle"] =1
      }
    }
  }
}

vRP.setItemTransformer("my_unique_transformer",itemtr)

Items

Items are simple identifiers associated with a quantity in an inventory. But they can also be parametrics.

Parametrics items are identified like other items in the inventory but also have arguments as: weapon|pistol instead of just an ID. Parametric items don’t contain any data, they are generic item definitions that will be specialized by the arguments.

-- PROXY API-- define an inventory item (call this at server start) (parametric or plain text data)-- idname: unique item name-- name: display name or genfunction-- description: item description (html) or genfunction-- choices: menudata choices (see gui api) only as genfunction or nil-- weight: weight or genfunction---- genfunction are functions returning a correct value as: function(args) return value end-- where args is a list of {base_idname,arg,arg,arg,...}

vRP.defInventoryItem(idname,name,description,choices,weight)

-- return name, description, weight
vRP.getItemDefinition(idname)

vRP.getItemName(idname)

vRP.getItemDescription(idname)

vRP.getItemChoices(idname)

vRP.getItemWeight(idname)

-- add item to a connected user inventory
vRP.giveInventoryItem(user_id,idname,amount,notify)

-- try to get item from a connected user inventory-- return true if the item has been found and the quantity removed
vRP.tryGetInventoryItem(user_id,idname,amount,notify)

-- get item amount from a connected user inventory
vRP.getInventoryItemAmount(user_id,idname)

-- get connected user inventory-- return map of full idname => amount or nil
vRP.getInventory(user_id)

-- clear connected user inventory
vRP.clearInventory(user_id)

-- compute weight of a list of items (in inventory/chest format)
vRP.computeItemsWeight(items)

-- return user inventory total weight
vRP.getInventoryWeight(user_id)

-- return user inventory max weight
vRP.getInventoryMaxWeight(user_id)

-- open a chest by name-- cb_close(): called when the chest is closed
vRP.openChest(source, name, max_weight, cb_close)

-- TUNNEL SERVER API-- TUNNEL CLIENT API

Example 1. Full example of a resource defining a water bottle item.

Once defined, items can be used by any resources (ex: they can be added to shops).

local Proxy =module("vrp", "lib/Proxy")
local Tunnel =require("vrp", "lib/Tunnel")

vRP = Proxy.getInterface("vRP")
vRPclient = Tunnel.getInterface("vRP","vrp_waterbottle")

-- create Water bottle itemlocal wb_choices = {}  -- (see gui API for menudata choices structure)

wb_choices["Drink"] = {function(player,choice) -- add drink actionlocal user_id = vRP.getUserId(player) -- get user_idif user_id thenif vRP.tryGetInventoryItem(user_id,"water_bottle",1) then-- try to remove one bottle
      vRP.varyThirst(user_id,-35) -- decrease thirst
      vRPclient.notify(player,"~b~ Drinking.") -- notify
      vRP.closeMenu(player) -- the water bottle is consumed by the action, close the menuendendend,"Do it."}

-- add item definition
vRP.defInventoryItem("water_bottle","Water bottle","Drink this my friend.",function() return wb_choices end,0.5)

-- (at any time later) give 2 water bottles to a connected user
vRP.giveInventoryItem(user_id,"water_bottle",2)

Miscellanea

I do not find an answer to my question in this FAQ page. What can I do?Post your question in the forum. The VRP-REP team will make their best attempt to answer it ASAP.

How do I change my personal data?Go to your profile page (click on the little guy in the top right of any page).

  • to change your name or affiliation, click on the corresponding values and do your editing
  • to change your password, click on the “Change password” button
  • to change your email and/or country, contact the steering committee

How do I get credit for my contributionsThe contributors page is automatically generated from the contents of the database. If you have contributed either a dataset or a solution report to the platform, your name should appear in the list of contributors. If that is not the case, contact technical support.

Money

The money is managed with direct SQL queries to prevent most potential value corruptions.
The wallet empties itself when respawning (after death).

Mysql

MySQL queries are managed by the resource vrp_mysql, acting like a server for all other resources using it. So connections, commands and queries are globals and should use namespaces if you want to create your own queries to prevent collisions.

By default, the vRP connection is created, using credentials in cfg/base.lua, so you can add new commands to it if you are creating a vRP extension.

-- API-- create a connection-- host can also be written "host:port"
MySQL.createConnection(name, host, user, password, database)

-- create a command for a specific connection--- path: "conname/cmdname"
MySQL.createCommand(path, sql)

-- do query--- path: "conname/cmdname"--- (optional) params: associative table of SQL params ("@something" => something)--- (optional) callback(rows, affected): rows as list, with associative table for columns
MySQL.query(path, params, callback)

-- do a scalar query (one row, one column)--- (optional) callback(scalar)
MySQL.scalar(path, params, callback)

-- do a execute query (no results)--- (optional) callback(affected)
MySQL.execute(path, params, callback)

Here is an example of how to use the MySQL module in other resources :

  • add the dependencies vrp and vrp_mysql to your resource
  • load @vrp/lib/utils.lua in your resource (first)
  • then load/use the MySQL module:
-- load the MySQL modulelocal MySQL =module("vrp_mysql", "MySQL")

-- create a new connection
MySQL.createConnection("con_name", host, user, password, database)

-- create a command for this connection
MySQL.createCommand("con_name/command_name", [[CREATE TABLE things(  id INTEGER PRIMARY AUTO_INCREMENT,  thing TEXT);]])

-- execute the command to init tables
MySQL.execute("con_name/command_name")

-- you can also add commands to a created connection-- adding a command to the vRP connection to get all banned or not banned users
MySQL.createCommand("vRP/myrsc_getbans", "SELECT id FROM vrp_users WHERE banned = @banned")

-- execute the command after a while, get all banned users
MySQL.query("vRP/myrsc_getbans", {banned =true}, function(rows, affected)
  -- rows: rows as a list-- affected: number of rows affected (when updating things, etc)-- display banned usersend)

-- execute the command after a while, get all non banned users
MySQL.query("vRP/myrsc_getbans", {banned =false}, function(rows, affected)
  -- rows: rows as a list-- affected: number of rows affected (when updating things, etc)-- display banned usersend)

Player state

-- PROXY API-- TUNNEL SERVER API-- TUNNEL CLIENT API-- get player weapons data-- return table with weapons data, use print(json.encode(result)) to understand the structure
vRP.getWeapons()

-- give weapons-- weapons: same structure as returned by getWeapons()-- (optional) clear_before: if true, will remove all the weapons before adding the new ones
vRP.giveWeapons(weapons,clear_before)

-- get player apparence customization data-- return table with customization data, use print(json.encode(result)) to understand the structure-- .model or .modelhash define the player model, the indexes define each component as [drawable_id,texture_id,palette_id] array-- props are referenced using the prefix "p" for the key (p0,p1,p2,p...), -1 = no prop
vRP.getCustomization()

-- set player apparence-- customization_data: same structure as returned by getCustomization()
vRP.setCustomization(customization_data)

-- set player armour (0-100)
vRP.setArmour(amount)

Proxy

The proxy lib is used to call other resources functions through a proxy event.

Ex:

resource1.lua

resource2.lua

The notation is Interface.function(…).

Good practice is to get the interface once and set it as a global, but if you want to get multiple times the same interface from the same resource, you need to specify a unique identifier (the name of the resource a unique id for each one).

Radio

radio

Regular permissions

Regular permissions are plain text permissions, they can be added to groups. You can add a – before the permission to negate (even if other groups add the permission, they will be ignored).

Rpki-vrp-checker

The rpki-vrp-checker utility takes a set of VRPs (in JSON format)
and applies a number of tests to the VRP set to assess whether
the set conforms to the Network Operator’s expectations.

Special aptitude permission

You can use a special permission to check for aptitudes.
Form: @group.aptitude.operator, operators to check the level are greater >, less <, equal . Ex:

  • @physical.strength.3 -> strength level equal to 3
  • @science.chemicals.>4 -> chemicals science level greater or equal to 5

Special function permission

Permissions can also be custom functions, registered by vRP.registerPermissionFunction.
Form: !name.param1.param2…

Here is a list of permission functions defined by vRP:

  • !not. ...: negation of another permission function (ex !not.is.inside)
  • !is.inside: check if the player is inside a building (approximation)
  • !is.invehicle: check if the player is inside a vehicle

Special item permission

You can use a special permission to check for items.
Form: #idname.operator, operators to check the amount are greater >, less <, equal . Ex:

  • #tacos.>0 -> one or more tacos
  • #weed.1 -> exactly one weed

Survival

Running, walking, being hurt/injured, and just living add hunger and thirst. When the hunger and the thirst are at their maximum level (100%), next hunger/thirst overflow will damage the character by the same amount (ex: when thirsty, don’t run, take a car).
This module disable the basic health regen.

The survival module implement also a coma system, if the health of the player is below the coma threshold, the player is in coma for a specific duration before dying. The health (thus coma) is recorded in the player state.
If a player disconnect and reconnect while in coma, he will fall in coma again and die in a few seconds.

Tutorials

(gh-md-toc)

Update

vRP will warn you at server launch if a new version is available. You can also update while I commit things, but do that only if you like to beta test, because you will need to update a lot.

A good way to update (bleeding-edge):

  • use git to clone vRP to create your own version of it, checkout the branch you want, create a branch from it
  • create a symbolic link (or an update script) to vrp/ in your fxserver resources directory
  • (repeat) configure, commit your changes, stay updated with the vRP repository, solve conflicts

This way, you will know when config files should be updated and what exactly has been updated.

A more primitive way to update:

  • save your cfg/ folder somewhere
  • copy all new files in vrp/
  • compare your old cfg/ folder with the new one, fill the gaps (one mistake will break everything, take your time)
  • replace the new cfg/ folder with the old modified cfg/ folder

Utils

lib/utils define global tools required by vRP and vRP extensions.

Any function making usage of async() require a Citizen thread if not already in one. Citizen will throw an error if you’re not in one.

Wardrobe

wardrobe
Save your character customization in the wardrobe, so you don’t need to customize/pay clothes in skinshop again.

Extending menus

Some menus can be built/extended by any resources with menu builders.

List of known menu names you can extend, each line is name: description (data properties):

Оцените статью
Huawei Devices
Добавить комментарий