Please select time limit in seconds, algorithm for calculation and click on the Open file button.
44 | After that, you can select example of vrp problem to solve.
45 | ]]>
46 |
47 | Author: Tomas David\n\nYear: 2015\n\nThe application demonstrates
48 | OptaPlanner functionality on the Android platform. Demonstration is exemplified by Vehicle
49 | routing problem example.
50 |
51 |
52 |
53 | FFD with LA
54 | Branch and bound
55 | Brute force
56 |
57 |
58 | vrpFirstFitDecreasingSolverConfig.xml
59 | vrpBranchAndBoundSolverConfig.xml
60 | vrpBruteForceSolverConfig.xml
61 |
62 |
63 |
--------------------------------------------------------------------------------
/app/src/main/java/org/tomasdavid/vehicleroutingproblem/components/StopSolverDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Tomas David
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.tomasdavid.vehicleroutingproblem.components;
18 |
19 | import android.app.AlertDialog;
20 | import android.app.Dialog;
21 | import android.content.DialogInterface;
22 | import android.content.DialogInterface.OnClickListener;
23 | import android.os.Bundle;
24 | import android.support.annotation.NonNull;
25 | import android.support.v4.app.DialogFragment;
26 | import android.support.v4.app.Fragment;
27 | import android.support.v7.widget.Toolbar;
28 |
29 | import org.tomasdavid.vehicleroutingproblem.MainActivity;
30 | import org.tomasdavid.vehicleroutingproblem.R;
31 | import org.tomasdavid.vehicleroutingproblem.fragments.VrpFragment;
32 |
33 | /**
34 | * Stop solver dialog. Displays when solver running and user clicks on the back button.
35 | *
36 | * @author Tomas David
37 | */
38 | public class StopSolverDialog extends DialogFragment implements OnClickListener {
39 |
40 | /**
41 | * {@inheritDoc}
42 | */
43 | @NonNull
44 | @Override
45 | public Dialog onCreateDialog(Bundle savedInstanceState) {
46 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
47 | builder.setMessage(R.string.solver_running_message)
48 | .setPositiveButton(R.string.button_ok, this)
49 | .setNegativeButton(R.string.button_cancel, this);
50 | return builder.create();
51 | }
52 |
53 | /**
54 | * {@inheritDoc}
55 | */
56 | @Override
57 | public void onClick(DialogInterface dialog, int which) {
58 | if (which == DialogInterface.BUTTON_POSITIVE) {
59 |
60 | // solver is stopped, nav. drawer is hidden and list fragment is displayed
61 | Fragment fragment = getActivity().getSupportFragmentManager().findFragmentById(R.id.activity_main);
62 | if (fragment instanceof VrpFragment) {
63 | ((Toolbar) getActivity().findViewById(R.id.toolbar)).setNavigationIcon(null);
64 | (((VrpFragment) fragment).getVrpSolverTask()).stopTask();
65 | ((MainActivity) getActivity()).lockDrawer();
66 | getActivity().onBackPressed();
67 | }
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/app/src/main/java/org/tomasdavid/vehicleroutingproblem/adapters/StatisticsListAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Tomas David
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.tomasdavid.vehicleroutingproblem.adapters;
18 |
19 | import android.app.Activity;
20 | import android.content.Context;
21 | import android.view.LayoutInflater;
22 | import android.view.View;
23 | import android.view.ViewGroup;
24 | import android.widget.ArrayAdapter;
25 | import android.widget.ImageView;
26 | import android.widget.TextView;
27 |
28 | import org.tomasdavid.vehicleroutingproblem.R;
29 |
30 | import java.util.List;
31 |
32 | /**
33 | * Adapter for statistic items of navigation drawer.
34 | *
35 | * @author Tomas David
36 | */
37 | public class StatisticsListAdapter extends ArrayAdapter {
38 |
39 | /**
40 | * Adapter context.
41 | */
42 | private Context context;
43 |
44 | /**
45 | * List of statistic items.
46 | */
47 | private List statisticItems;
48 |
49 | /**
50 | * Constructor for statistics list adapter.
51 | * @param context Adapter context.
52 | * @param statisticItems List of statistic items.
53 | */
54 | public StatisticsListAdapter(Context context, List statisticItems) {
55 | super(context, R.layout.item_statistic, statisticItems);
56 | this.context = context;
57 | this.statisticItems = statisticItems;
58 | }
59 |
60 | /**
61 | * {@inheritDoc}
62 | */
63 | @Override
64 | public View getView(int position, View convertView, ViewGroup parent) {
65 | LayoutInflater inflater = ((Activity)context).getLayoutInflater();
66 |
67 | // sets parameters of row
68 | View rowView = inflater.inflate(R.layout.item_statistic, null, true);
69 | ImageView image = (ImageView) rowView.findViewById(R.id.item_statistic_image);
70 | TextView name = (TextView) rowView.findViewById(R.id.item_statistic_name);
71 | TextView value = (TextView) rowView.findViewById(R.id.item_statistic_value);
72 | image.setImageResource(statisticItems.get(position).getImageResId());
73 | name.setText(statisticItems.get(position).getName());
74 | value.setText(statisticItems.get(position).getValue());
75 |
76 | return rowView;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/main/java/org/optaplanner/examples/vehiclerouting/domain/solver/DepotAngleCustomerDifficultyWeightFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 JBoss Inc
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.optaplanner.examples.vehiclerouting.domain.solver;
18 |
19 | import org.apache.commons.lang3.builder.CompareToBuilder;
20 | import org.optaplanner.core.impl.heuristic.selector.common.decorator.SelectionSorterWeightFactory;
21 | import org.optaplanner.examples.vehiclerouting.domain.Customer;
22 | import org.optaplanner.examples.vehiclerouting.domain.Depot;
23 | import org.optaplanner.examples.vehiclerouting.domain.VehicleRoutingSolution;
24 |
25 | /**
26 | * On large datasets, the constructed solution looks like pizza slices.
27 | */
28 | public class DepotAngleCustomerDifficultyWeightFactory
29 | implements SelectionSorterWeightFactory {
30 |
31 | public Comparable createSorterWeight(VehicleRoutingSolution vehicleRoutingSolution, Customer customer) {
32 | Depot depot = vehicleRoutingSolution.getDepotList().get(0);
33 | return new DepotAngleCustomerDifficultyWeight(customer,
34 | customer.getLocation().getAngle(depot.getLocation()),
35 | customer.getLocation().getDistance(depot.getLocation())
36 | + depot.getLocation().getDistance(customer.getLocation()));
37 | }
38 |
39 | public static class DepotAngleCustomerDifficultyWeight
40 | implements Comparable {
41 |
42 | private final Customer customer;
43 | private final double depotAngle;
44 | private final int depotRoundTripDistance;
45 |
46 | public DepotAngleCustomerDifficultyWeight(Customer customer,
47 | double depotAngle, int depotRoundTripDistance) {
48 | this.customer = customer;
49 | this.depotAngle = depotAngle;
50 | this.depotRoundTripDistance = depotRoundTripDistance;
51 | }
52 |
53 | public int compareTo(DepotAngleCustomerDifficultyWeight other) {
54 | return new CompareToBuilder()
55 | .append(depotAngle, other.depotAngle)
56 | .append(depotRoundTripDistance, other.depotRoundTripDistance) // Ascending (further from the depot are more difficult)
57 | .append(customer.getId(), other.customer.getId())
58 | .toComparison();
59 | }
60 |
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/java/org/tomasdavid/vehicleroutingproblem/adapters/VrpFileItemViewHolder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Tomas David
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.tomasdavid.vehicleroutingproblem.adapters;
18 |
19 | import android.os.Bundle;
20 | import android.support.v4.app.FragmentActivity;
21 | import android.support.v7.widget.RecyclerView;
22 | import android.view.View;
23 | import android.widget.TextView;
24 |
25 | import org.tomasdavid.vehicleroutingproblem.R;
26 | import org.tomasdavid.vehicleroutingproblem.VrpKeys;
27 | import org.tomasdavid.vehicleroutingproblem.fragments.VrpFragment;
28 |
29 | /**
30 | * Vrp file item view holder for vrp list of files.
31 | *
32 | * @author Tomas David
33 | */
34 | public class VrpFileItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
35 |
36 | /**
37 | * File text view.
38 | */
39 | private TextView fileTextView;
40 |
41 | /**
42 | * Vrp file list adapter.
43 | */
44 | private VrpFileListAdapter adapter;
45 |
46 | /**
47 | * Constructor of file item holder.
48 | * @param itemView File text view.
49 | * @param adapter Vrp file list adapter.
50 | */
51 | public VrpFileItemViewHolder(View itemView, VrpFileListAdapter adapter) {
52 | super(itemView);
53 | this.fileTextView = (TextView) itemView.findViewById(R.id.vrp_file_item);
54 | this.adapter = adapter;
55 | itemView.setOnClickListener(this);
56 | }
57 |
58 | /**
59 | * Returns file text view.
60 | * @return File text view
61 | */
62 | public TextView getFileTextView() {
63 | return fileTextView;
64 | }
65 |
66 | /**
67 | * {@inheritDoc}
68 | */
69 | @Override
70 | public void onClick(View v) {
71 |
72 | // add values to bundle
73 | Bundle bundle = new Bundle();
74 | bundle.putInt(VrpKeys.VRP_TIME_LIMIT.name(), adapter.getTimeLimit());
75 | bundle.putString(VrpKeys.VRP_ALGORITHM.name(), adapter.getAlgorithm());
76 | bundle.putString(VrpKeys.VRP_FILE_NAME.name(), adapter.getVrpFileNames()[getLayoutPosition()]);
77 |
78 | // start vrp fragment
79 | VrpFragment fragment = new VrpFragment();
80 | fragment.setArguments(bundle);
81 | ((FragmentActivity) v.getContext()).getSupportFragmentManager()
82 | .beginTransaction().replace(R.id.activity_main, fragment).addToBackStack(null).commit();
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/app/src/main/java/org/tomasdavid/vehicleroutingproblem/components/OpenFileButton.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Tomas David
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.tomasdavid.vehicleroutingproblem.components;
18 |
19 | import android.content.Context;
20 | import android.os.Bundle;
21 | import android.support.v4.app.FragmentActivity;
22 | import android.util.AttributeSet;
23 | import android.view.View;
24 | import android.widget.Button;
25 | import android.widget.NumberPicker;
26 | import android.widget.Spinner;
27 |
28 | import org.tomasdavid.vehicleroutingproblem.R;
29 | import org.tomasdavid.vehicleroutingproblem.VrpKeys;
30 | import org.tomasdavid.vehicleroutingproblem.fragments.VrpFileListFragment;
31 |
32 | /**
33 | * Button for continue to vrp list fragment.
34 | *
35 | * @author Tomas David
36 | */
37 | public class OpenFileButton extends Button implements View.OnClickListener {
38 |
39 | public OpenFileButton(Context context) {
40 | super(context);
41 | init();
42 | }
43 |
44 | public OpenFileButton(Context context, AttributeSet attrs) {
45 | super(context, attrs);
46 | init();
47 | }
48 |
49 | public OpenFileButton(Context context, AttributeSet attrs, int defStyleAttr) {
50 | super(context, attrs, defStyleAttr);
51 | init();
52 | }
53 |
54 | /**
55 | * Sets onClick listener.
56 | */
57 | private void init() {
58 | this.setOnClickListener(this);
59 | }
60 |
61 | /**
62 | * {@inheritDoc}
63 | */
64 | @Override
65 | public void onClick(View v) {
66 | FragmentActivity activity = (FragmentActivity) v.getContext();
67 | NumberPicker numberPicker = (NumberPicker) activity.findViewById(R.id.timeLimitPicker);
68 | Spinner algSpinner = (Spinner) activity.findViewById(R.id.algorithm_spinner);
69 |
70 | // add setting values to bundle and starts new fragment
71 | Bundle bundle = new Bundle();
72 | bundle.putInt(VrpKeys.VRP_TIME_LIMIT.name(), numberPicker.getValue());
73 | bundle.putString(VrpKeys.VRP_ALGORITHM.name(), activity.getResources().obtainTypedArray(R.array.algorithm_files)
74 | .getString(algSpinner.getSelectedItemPosition()));
75 | VrpFileListFragment fragment = new VrpFileListFragment();
76 | fragment.setArguments(bundle);
77 | activity.getSupportFragmentManager().beginTransaction().replace(R.id.activity_main, fragment)
78 | .addToBackStack(null).commit();
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/app/src/main/java/org/tomasdavid/vehicleroutingproblem/fragments/VrpFileListFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Tomas David
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.tomasdavid.vehicleroutingproblem.fragments;
18 |
19 | import android.os.Bundle;
20 | import android.support.v4.app.Fragment;
21 | import android.support.v7.widget.LinearLayoutManager;
22 | import android.support.v7.widget.RecyclerView;
23 | import android.view.LayoutInflater;
24 | import android.view.View;
25 | import android.view.ViewGroup;
26 |
27 | import org.tomasdavid.vehicleroutingproblem.R;
28 | import org.tomasdavid.vehicleroutingproblem.VrpKeys;
29 | import org.tomasdavid.vehicleroutingproblem.adapters.VrpFileListAdapter;
30 |
31 | import java.io.IOException;
32 | import java.util.ArrayList;
33 |
34 | /**
35 | * Fragment for displaying list of vrp files.
36 | *
37 | * @author Tomas David
38 | */
39 | public class VrpFileListFragment extends Fragment {
40 |
41 | /**
42 | * Extension of vrp file.
43 | */
44 | private static final String VRP_EXTENSION = ".vrp";
45 |
46 | /**
47 | * {@inheritDoc}
48 | */
49 | @Override
50 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
51 | View view = inflater.inflate(R.layout.fragment_vrp_file_list, container, false);
52 |
53 | // initialize recycler view
54 | RecyclerView mRecyclerView = (RecyclerView) view.findViewById(R.id.vrp_file_list);
55 | mRecyclerView.setHasFixedSize(true);
56 | mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
57 |
58 | ArrayList vrpAssets = new ArrayList<>();
59 | String[] assetsRoot;
60 |
61 | // get all assets
62 | try {
63 | assetsRoot = getActivity().getAssets().list(getActivity().getString(R.string.vrps_dir));
64 | } catch (IOException e) {
65 | assetsRoot = new String[0];
66 | }
67 |
68 | // remove files without vrp file extension
69 | for (String asset : assetsRoot) {
70 | if (asset.endsWith(VRP_EXTENSION)) {
71 | vrpAssets.add(asset);
72 | }
73 | }
74 |
75 | // initialize adapter
76 | VrpFileListAdapter mAdapter = new VrpFileListAdapter(
77 | vrpAssets.toArray(new String[vrpAssets.size()]),
78 | getArguments().getInt(VrpKeys.VRP_TIME_LIMIT.name()),
79 | getArguments().getString(VrpKeys.VRP_ALGORITHM.name())
80 | );
81 | mRecyclerView.setAdapter(mAdapter);
82 |
83 | return view;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/app/src/main/java/org/tomasdavid/vehicleroutingproblem/tasks/ProgressBarTask.java:
--------------------------------------------------------------------------------
1 | package org.tomasdavid.vehicleroutingproblem.tasks;
2 |
3 | import android.os.AsyncTask;
4 | import android.support.v4.app.FragmentActivity;
5 | import android.util.Log;
6 | import android.widget.ProgressBar;
7 |
8 | import org.tomasdavid.vehicleroutingproblem.R;
9 | import org.tomasdavid.vehicleroutingproblem.fragments.VrpFragment;
10 |
11 | /**
12 | * Progress bar task for change time progress of progress bar when solver is solving.
13 | *
14 | * @author Tomas David
15 | */
16 | /*
17 | * Copyright 2015 Tomas David
18 | *
19 | * Licensed under the Apache License, Version 2.0 (the "License");
20 | * you may not use this file except in compliance with the License.
21 | * You may obtain a copy of the License at
22 | *
23 | * http://www.apache.org/licenses/LICENSE-2.0
24 | *
25 | * Unless required by applicable law or agreed to in writing, software
26 | * distributed under the License is distributed on an "AS IS" BASIS,
27 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28 | * See the License for the specific language governing permissions and
29 | * limitations under the License.
30 | */
31 |
32 | public class ProgressBarTask extends AsyncTask {
33 |
34 | /**
35 | * Class tag.
36 | */
37 | private static final String TAG = "ProgressBarTask";
38 |
39 | /**
40 | * One second = 1000 milliseconds
41 | */
42 | private static final int SECOND = 1000;
43 |
44 | /**
45 | * Actual progress of progress bar.
46 | */
47 | private int progress;
48 |
49 | /**
50 | * Vrp fragment where progress bar is placed.
51 | */
52 | private VrpFragment fragment;
53 |
54 | /**
55 | * Constructor of progress bar task.
56 | * @param fragment Vrp fragment where progress bar is placed.
57 | */
58 | public ProgressBarTask(VrpFragment fragment) {
59 | this.fragment = fragment;
60 | this.progress = 0;
61 | }
62 |
63 | /**
64 | * {@inheritDoc}
65 | */
66 | @Override
67 | protected Void doInBackground(Integer... params) {
68 |
69 | // initialize progress bar
70 | progress = 0;
71 | ProgressBar progressBar = (ProgressBar) fragment.getActivity().findViewById(R.id.progress_bar);
72 | progressBar.setProgress(progress);
73 |
74 | // while solver task is running change progress every 1 second
75 | while (fragment.getVrpSolverTask().isRunning() && progress < progressBar.getMax()) {
76 | try {
77 | Thread.sleep(SECOND);
78 | } catch (InterruptedException e) {
79 | Log.e(TAG, "Thread sleep error.", e);
80 | }
81 |
82 | if (fragment != null) {
83 | FragmentActivity activity = fragment.getActivity();
84 | if (activity != null) {
85 | progressBar = (ProgressBar) activity.findViewById(R.id.progress_bar);
86 | if (progressBar != null) {
87 | progressBar.incrementProgressBy(1);
88 | }
89 | }
90 | }
91 | progress++;
92 | }
93 |
94 | return null;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/app/src/main/java/org/tomasdavid/vehicleroutingproblem/adapters/VrpFileListAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Tomas David
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.tomasdavid.vehicleroutingproblem.adapters;
18 |
19 | import android.support.v7.widget.RecyclerView;
20 | import android.view.LayoutInflater;
21 | import android.view.ViewGroup;
22 |
23 | import org.tomasdavid.vehicleroutingproblem.R;
24 |
25 | /**
26 | * Adapter of vrp file list.
27 | *
28 | * @author Tomas David
29 | */
30 | public class VrpFileListAdapter extends RecyclerView.Adapter {
31 |
32 | /**
33 | * Time limit for calculation.
34 | */
35 | private int timeLimit;
36 |
37 | /**
38 | * Algorithm for calculation.
39 | */
40 | private String algorithm;
41 |
42 | /**
43 | * Array of vrp files names.
44 | */
45 | private String[] vrpFileNames;
46 |
47 | /**
48 | * Adapter constructor.
49 | * @param vrpFileNames Array of vrp files names.
50 | * @param timeLimit Time limit for calculation.
51 | * @param algorithm Algorithm for calculation.
52 | */
53 | public VrpFileListAdapter(String[] vrpFileNames, int timeLimit, String algorithm) {
54 | this.vrpFileNames = vrpFileNames;
55 | this.timeLimit = timeLimit;
56 | this.algorithm = algorithm;
57 | }
58 |
59 | /**
60 | * Returns time limit for calculation.
61 | * @return Time limit for calculation.
62 | */
63 | public int getTimeLimit() {
64 | return timeLimit;
65 | }
66 |
67 | /**
68 | * Returns algorithm for calculation.
69 | * @return Algorithm for calculation.
70 | */
71 | public String getAlgorithm() {
72 | return algorithm;
73 | }
74 |
75 | /**
76 | * Returns array of vrp files names.
77 | * @return Array of vrp files names.
78 | */
79 | public String[] getVrpFileNames() {
80 | return vrpFileNames;
81 | }
82 |
83 | /**
84 | * {@inheritDoc}
85 | */
86 | @Override
87 | public VrpFileItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
88 | return new VrpFileItemViewHolder(LayoutInflater.from(parent.getContext()).inflate(
89 | R.layout.item_vrp_file, parent, false), this);
90 | }
91 |
92 | /**
93 | * {@inheritDoc}
94 | */
95 | @Override
96 | public void onBindViewHolder(VrpFileItemViewHolder holder, int position) {
97 | holder.getFileTextView().setText(vrpFileNames[position]);
98 | }
99 |
100 | /**
101 | * {@inheritDoc}
102 | */
103 | @Override
104 | public int getItemCount() {
105 | return vrpFileNames.length;
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/app/src/main/java/org/tomasdavid/vehicleroutingproblem/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Tomas David
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.tomasdavid.vehicleroutingproblem;
18 |
19 | import android.os.Bundle;
20 | import android.support.v4.app.Fragment;
21 | import android.support.v4.widget.DrawerLayout;
22 | import android.support.v7.app.ActionBarActivity;
23 | import android.support.v7.widget.Toolbar;
24 | import android.view.Gravity;
25 |
26 | import org.tomasdavid.vehicleroutingproblem.components.StopSolverDialog;
27 | import org.tomasdavid.vehicleroutingproblem.fragments.MainFragment;
28 | import org.tomasdavid.vehicleroutingproblem.fragments.VrpFragment;
29 | import org.tomasdavid.vehicleroutingproblem.tasks.VrpSolverTask;
30 |
31 | /**
32 | * Main and only activity of application.
33 | *
34 | * @author Tomas David
35 | */
36 | public class MainActivity extends ActionBarActivity {
37 |
38 | /**
39 | * Navigation drawer for displaying statistics.
40 | */
41 | private DrawerLayout statsDrawer;
42 |
43 | /**
44 | * Unlock navigation drawer.
45 | */
46 | public void unlockDrawer() {
47 | statsDrawer.setDrawerLockMode(DrawerLayout.VISIBLE);
48 | }
49 |
50 | /**
51 | * Hide and lock navigation drawer.
52 | */
53 | public void lockDrawer() {
54 | statsDrawer.closeDrawer(Gravity.START);
55 | statsDrawer.setDrawerLockMode(DrawerLayout.INVISIBLE);
56 | }
57 |
58 | /**
59 | * {@inheritDoc}
60 | */
61 | @Override
62 | public void onCreate(Bundle savedInstanceState) {
63 | super.onCreate(savedInstanceState);
64 | setContentView(R.layout.activity_main);
65 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
66 | toolbar.setTitle(R.string.app_name);
67 | setSupportActionBar(toolbar);
68 | statsDrawer = (DrawerLayout) findViewById(R.id.drawer_layout);
69 | lockDrawer();
70 | if (savedInstanceState == null) {
71 | MainFragment fragment = new MainFragment();
72 | getSupportFragmentManager().beginTransaction().add(R.id.activity_main, fragment).commit();
73 | }
74 | }
75 |
76 | /**
77 | * {@inheritDoc}
78 | */
79 | @Override
80 | public void onBackPressed() {
81 | Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.activity_main);
82 | if (fragment instanceof VrpFragment) {
83 | VrpSolverTask vrpSolverTask = ((VrpFragment) fragment).getVrpSolverTask();
84 | if (vrpSolverTask.isRunning()) {
85 | new StopSolverDialog().show(getSupportFragmentManager(), null);
86 | return;
87 | } else {
88 | lockDrawer();
89 | ((Toolbar) findViewById(R.id.toolbar)).setNavigationIcon(null);
90 | }
91 | }
92 | super.onBackPressed();
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/app/src/main/java/org/optaplanner/examples/vehiclerouting/domain/timewindowed/solver/ArrivalTimeUpdatingVariableListener.java:
--------------------------------------------------------------------------------
1 | package org.optaplanner.examples.vehiclerouting.domain.timewindowed.solver;
2 |
3 | import org.apache.commons.lang3.ObjectUtils;
4 | import org.optaplanner.core.impl.domain.variable.listener.VariableListener;
5 | import org.optaplanner.core.impl.score.director.ScoreDirector;
6 | import org.optaplanner.examples.vehiclerouting.domain.Customer;
7 | import org.optaplanner.examples.vehiclerouting.domain.Standstill;
8 | import org.optaplanner.examples.vehiclerouting.domain.timewindowed.TimeWindowedCustomer;
9 |
10 | // TODO When this class is added only for TimeWindowedCustomer, use TimeWindowedCustomer instead of Customer
11 | public class ArrivalTimeUpdatingVariableListener implements VariableListener {
12 |
13 | public void beforeEntityAdded(ScoreDirector scoreDirector, Customer customer) {
14 | // Do nothing
15 | }
16 |
17 | public void afterEntityAdded(ScoreDirector scoreDirector, Customer customer) {
18 | if (customer instanceof TimeWindowedCustomer) {
19 | updateVehicle(scoreDirector, (TimeWindowedCustomer) customer);
20 | }
21 | }
22 |
23 | public void beforeVariableChanged(ScoreDirector scoreDirector, Customer customer) {
24 | // Do nothing
25 | }
26 |
27 | public void afterVariableChanged(ScoreDirector scoreDirector, Customer customer) {
28 | if (customer instanceof TimeWindowedCustomer) {
29 | updateVehicle(scoreDirector, (TimeWindowedCustomer) customer);
30 | }
31 | }
32 |
33 | public void beforeEntityRemoved(ScoreDirector scoreDirector, Customer customer) {
34 | // Do nothing
35 | }
36 |
37 | public void afterEntityRemoved(ScoreDirector scoreDirector, Customer customer) {
38 | // Do nothing
39 | }
40 |
41 | protected void updateVehicle(ScoreDirector scoreDirector, TimeWindowedCustomer sourceCustomer) {
42 | Standstill previousStandstill = sourceCustomer.getPreviousStandstill();
43 | Integer departureTime = (previousStandstill instanceof TimeWindowedCustomer)
44 | ? ((TimeWindowedCustomer) previousStandstill).getDepartureTime() : null;
45 | TimeWindowedCustomer shadowCustomer = sourceCustomer;
46 | Integer arrivalTime = calculateArrivalTime(shadowCustomer, departureTime);
47 | while (shadowCustomer != null && ObjectUtils.notEqual(shadowCustomer.getArrivalTime(), arrivalTime)) {
48 | scoreDirector.beforeVariableChanged(shadowCustomer, "arrivalTime");
49 | shadowCustomer.setArrivalTime(arrivalTime);
50 | scoreDirector.afterVariableChanged(shadowCustomer, "arrivalTime");
51 | departureTime = shadowCustomer.getDepartureTime();
52 | shadowCustomer = shadowCustomer.getNextCustomer();
53 | arrivalTime = calculateArrivalTime(shadowCustomer, departureTime);
54 | }
55 | }
56 |
57 | private Integer calculateArrivalTime(TimeWindowedCustomer customer, Integer previousDepartureTime) {
58 | if (customer == null) {
59 | return null;
60 | }
61 | if (previousDepartureTime == null) {
62 | // PreviousStandstill is the Vehicle, so we leave from the Depot at the best suitable time
63 | return Math.max(customer.getReadyTime(), customer.getDistanceFromPreviousStandstill());
64 | }
65 | return previousDepartureTime + customer.getDistanceFromPreviousStandstill();
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/java/org/optaplanner/persistence/xstream/impl/score/XStreamScoreConverter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 JBoss Inc
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.optaplanner.persistence.xstream.impl.score;
18 |
19 | import com.thoughtworks.xstream.converters.Converter;
20 | import com.thoughtworks.xstream.converters.MarshallingContext;
21 | import com.thoughtworks.xstream.converters.UnmarshallingContext;
22 | import com.thoughtworks.xstream.io.HierarchicalStreamReader;
23 | import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
24 | import org.optaplanner.core.api.score.Score;
25 | import org.optaplanner.core.api.score.buildin.bendable.BendableScore;
26 | import org.optaplanner.core.impl.score.definition.ScoreDefinition;
27 |
28 | /**
29 | * Some {@link Score} implementations require specific subclasses:
30 | * For {@link BendableScore}, use {@link XStreamBendableScoreConverter}.
31 | */
32 | public class XStreamScoreConverter implements Converter {
33 |
34 | private final ScoreDefinition scoreDefinition;
35 |
36 | public XStreamScoreConverter(ScoreDefinition scoreDefinition) {
37 | this.scoreDefinition = scoreDefinition;
38 | }
39 |
40 | public XStreamScoreConverter(Class extends Score> scoreClass,
41 | Class extends ScoreDefinition> scoreDefinitionClass) {
42 | if (BendableScore.class.equals(scoreClass)) {
43 | throw new IllegalArgumentException(XStreamScoreConverter.class + " is not compatible with scoreClass ("
44 | + scoreClass + "), use " + XStreamBendableScoreConverter.class.getSimpleName() + " instead.");
45 | }
46 | try {
47 | scoreDefinition = scoreDefinitionClass.newInstance();
48 | } catch (InstantiationException e) {
49 | throw new IllegalArgumentException("The scoreDefinitionClass (" + scoreDefinitionClass
50 | + ") does not have a public no-arg constructor", e);
51 | } catch (IllegalAccessException e) {
52 | throw new IllegalArgumentException("The scoreDefinitionClass (" + scoreDefinitionClass
53 | + ") does not have a public no-arg constructor", e);
54 | }
55 | if (scoreClass != scoreDefinition.getScoreClass()) {
56 | throw new IllegalStateException("The scoreClass (" + scoreClass + ") of the Score field to serialize to XML"
57 | + " does not match the scoreDefinition's scoreClass (" + scoreDefinition.getScoreClass() + ").");
58 | }
59 | }
60 |
61 | public boolean canConvert(Class type) {
62 | return scoreDefinition.getScoreClass().isAssignableFrom(type);
63 | }
64 |
65 | public void marshal(Object scoreObject, HierarchicalStreamWriter writer, MarshallingContext context) {
66 | String scoreString = scoreDefinition.formatScore((Score) scoreObject);
67 | writer.setValue(scoreString);
68 | }
69 |
70 | public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
71 | String scoreString = reader.getValue();
72 | return scoreDefinition.parseScore(scoreString);
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/app/src/main/java/org/optaplanner/examples/vehiclerouting/domain/location/segmented/RoadSegmentLocation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 JBoss Inc
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.optaplanner.examples.vehiclerouting.domain.location.segmented;
18 |
19 | import java.util.Map;
20 |
21 | import com.thoughtworks.xstream.annotations.XStreamAlias;
22 | import org.optaplanner.examples.vehiclerouting.domain.location.DistanceType;
23 | import org.optaplanner.examples.vehiclerouting.domain.location.Location;
24 | import org.optaplanner.examples.vehiclerouting.domain.location.RoadLocation;
25 |
26 | /**
27 | * Like {@link RoadLocation},
28 | * but for high scale problems to avoid the memory issue of keeping the entire cost matrix in memory.
29 | * Used with {@link DistanceType#SEGMENTED_ROAD_DISTANCE}.
30 | */
31 | @XStreamAlias("VrpRoadSegmentLocation")
32 | public class RoadSegmentLocation extends Location {
33 |
34 | // Prefer Map over array or List because customers might be added and removed in real-time planning.
35 | protected Map nearbyTravelDistanceMap;
36 | protected Map hubTravelDistanceMap;
37 |
38 | public RoadSegmentLocation() {
39 | }
40 |
41 | public RoadSegmentLocation(long id, double latitude, double longitude) {
42 | super(id, latitude, longitude);
43 | }
44 |
45 | public Map getNearbyTravelDistanceMap() {
46 | return nearbyTravelDistanceMap;
47 | }
48 |
49 | public void setNearbyTravelDistanceMap(Map nearbyTravelDistanceMap) {
50 | this.nearbyTravelDistanceMap = nearbyTravelDistanceMap;
51 | }
52 |
53 | public Map getHubTravelDistanceMap() {
54 | return hubTravelDistanceMap;
55 | }
56 |
57 | public void setHubTravelDistanceMap(Map hubTravelDistanceMap) {
58 | this.hubTravelDistanceMap = hubTravelDistanceMap;
59 | }
60 |
61 | @Override
62 | public int getDistance(Location location) {
63 | Double distance = getDistanceDouble((RoadSegmentLocation) location);
64 | // Multiplied by 1000 to avoid floating point arithmetic rounding errors
65 | return (int) (distance * 1000.0 + 0.5);
66 | }
67 |
68 | public Double getDistanceDouble(RoadSegmentLocation location) {
69 | Double distance = nearbyTravelDistanceMap.get((RoadSegmentLocation) location);
70 | if (distance == null) {
71 | // location isn't nearby
72 | distance = getShortestDistanceDoubleThroughHubs((RoadSegmentLocation) location);
73 | }
74 | return distance;
75 | }
76 |
77 | protected double getShortestDistanceDoubleThroughHubs(RoadSegmentLocation location) {
78 | double shortestDistance = Double.MAX_VALUE;
79 | for (Map.Entry entry : hubTravelDistanceMap.entrySet()) {
80 | double distance = entry.getValue();
81 | distance += entry.getKey().getDistanceDouble(location);
82 | if (distance < shortestDistance) {
83 | shortestDistance = distance;
84 | }
85 | }
86 | return shortestDistance;
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
22 |
23 |
28 |
29 |
35 |
36 |
41 |
42 |
43 |
44 |
49 |
50 |
54 |
55 |
61 |
62 |
67 |
68 |
69 |
70 |
75 |
76 |
81 |
82 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/app/src/main/java/org/optaplanner/examples/vehiclerouting/solver/score/VehicleRoutingEasyScoreCalculator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 JBoss Inc
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.optaplanner.examples.vehiclerouting.solver.score;
18 |
19 | import java.util.HashMap;
20 | import java.util.List;
21 | import java.util.Map;
22 |
23 | import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;
24 | import org.optaplanner.core.impl.score.director.easy.EasyScoreCalculator;
25 | import org.optaplanner.examples.vehiclerouting.domain.Customer;
26 | import org.optaplanner.examples.vehiclerouting.domain.Standstill;
27 | import org.optaplanner.examples.vehiclerouting.domain.Vehicle;
28 | import org.optaplanner.examples.vehiclerouting.domain.VehicleRoutingSolution;
29 | import org.optaplanner.examples.vehiclerouting.domain.timewindowed.TimeWindowedCustomer;
30 | import org.optaplanner.examples.vehiclerouting.domain.timewindowed.TimeWindowedVehicleRoutingSolution;
31 |
32 | public class VehicleRoutingEasyScoreCalculator implements EasyScoreCalculator {
33 |
34 | public HardSoftScore calculateScore(VehicleRoutingSolution solution) {
35 | boolean timeWindowed = solution instanceof TimeWindowedVehicleRoutingSolution;
36 | List customerList = solution.getCustomerList();
37 | List vehicleList = solution.getVehicleList();
38 | Map vehicleDemandMap = new HashMap(vehicleList.size());
39 | for (Vehicle vehicle : vehicleList) {
40 | vehicleDemandMap.put(vehicle, 0);
41 | }
42 | int hardScore = 0;
43 | int softScore = 0;
44 | for (Customer customer : customerList) {
45 | Standstill previousStandstill = customer.getPreviousStandstill();
46 | if (previousStandstill != null) {
47 | Vehicle vehicle = customer.getVehicle();
48 | vehicleDemandMap.put(vehicle, vehicleDemandMap.get(vehicle) + customer.getDemand());
49 | // Score constraint distanceToPreviousStandstill
50 | softScore -= customer.getDistanceFromPreviousStandstill();
51 | if (customer.getNextCustomer() == null) {
52 | // Score constraint distanceFromLastCustomerToDepot
53 | softScore -= customer.getLocation().getDistance(vehicle.getLocation());
54 | }
55 | if (timeWindowed) {
56 | TimeWindowedCustomer timeWindowedCustomer = (TimeWindowedCustomer) customer;
57 | int dueTime = timeWindowedCustomer.getDueTime();
58 | Integer arrivalTime = timeWindowedCustomer.getArrivalTime();
59 | if (dueTime < arrivalTime) {
60 | // Score constraint arrivalAfterDueTime
61 | hardScore -= (arrivalTime - dueTime);
62 | }
63 | }
64 | }
65 | }
66 | for (Map.Entry entry : vehicleDemandMap.entrySet()) {
67 | int capacity = entry.getKey().getCapacity();
68 | int demand = entry.getValue();
69 | if (demand > capacity) {
70 | // Score constraint vehicleCapacity
71 | hardScore -= (demand - capacity);
72 | }
73 | }
74 | // Score constraint arrivalAfterDueTimeAtDepot is a build-in hard constraint in VehicleRoutingImporter
75 | return HardSoftScore.valueOf(hardScore, softScore);
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/main/java/org/optaplanner/examples/vehiclerouting/domain/location/segmented/HubSegmentLocation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 JBoss Inc
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.optaplanner.examples.vehiclerouting.domain.location.segmented;
18 |
19 | import java.util.Map;
20 |
21 | import com.thoughtworks.xstream.annotations.XStreamAlias;
22 | import org.optaplanner.examples.vehiclerouting.domain.location.DistanceType;
23 | import org.optaplanner.examples.vehiclerouting.domain.location.Location;
24 |
25 | /**
26 | * Assistant for {@link RoadSegmentLocation}.
27 | * Used with {@link DistanceType#SEGMENTED_ROAD_DISTANCE}.
28 | */
29 | @XStreamAlias("VrpHubSegmentLocation")
30 | public class HubSegmentLocation extends Location {
31 |
32 | // Prefer Map over array or List because customers might be added and removed in real-time planning.
33 | protected Map nearbyTravelDistanceMap;
34 | protected Map hubTravelDistanceMap;
35 |
36 | public HubSegmentLocation() {
37 | }
38 |
39 | public HubSegmentLocation(long id, double latitude, double longitude) {
40 | super(id, latitude, longitude);
41 | }
42 |
43 | public Map getNearbyTravelDistanceMap() {
44 | return nearbyTravelDistanceMap;
45 | }
46 |
47 | public void setNearbyTravelDistanceMap(Map nearbyTravelDistanceMap) {
48 | this.nearbyTravelDistanceMap = nearbyTravelDistanceMap;
49 | }
50 |
51 | public Map getHubTravelDistanceMap() {
52 | return hubTravelDistanceMap;
53 | }
54 |
55 | public void setHubTravelDistanceMap(Map hubTravelDistanceMap) {
56 | this.hubTravelDistanceMap = hubTravelDistanceMap;
57 | }
58 |
59 | @Override
60 | public int getDistance(Location location) {
61 | double distance;
62 | if (location instanceof RoadSegmentLocation) {
63 | distance = getDistanceDouble((RoadSegmentLocation) location);
64 | } else {
65 | distance = hubTravelDistanceMap.get((HubSegmentLocation) location);
66 | }
67 | // Multiplied by 1000 to avoid floating point arithmetic rounding errors
68 | return (int) (distance * 1000.0 + 0.5);
69 | }
70 |
71 | public double getDistanceDouble(RoadSegmentLocation location) {
72 | Double distance = nearbyTravelDistanceMap.get(location);
73 | if (distance == null) {
74 | // location isn't nearby
75 | distance = getShortestDistanceDoubleThroughOtherHub(location);
76 | }
77 | return distance;
78 | }
79 |
80 | protected double getShortestDistanceDoubleThroughOtherHub(RoadSegmentLocation location) {
81 | double shortestDistance = Double.MAX_VALUE;
82 | // Don't use location.getHubTravelDistanceMap().keySet() instead because distances aren't always paired
83 | for (Map.Entry otherHubEntry : hubTravelDistanceMap.entrySet()) {
84 | HubSegmentLocation otherHub = otherHubEntry.getKey();
85 | Double otherHubNearbyDistance = otherHub.nearbyTravelDistanceMap.get(location);
86 | if (otherHubNearbyDistance != null) {
87 | double distance = otherHubEntry.getValue() + otherHubNearbyDistance;
88 | if (distance < shortestDistance) {
89 | shortestDistance = distance;
90 | }
91 | }
92 | }
93 | return shortestDistance;
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/app/src/main/java/org/optaplanner/examples/vehiclerouting/domain/location/Location.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012 JBoss Inc
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.optaplanner.examples.vehiclerouting.domain.location;
18 |
19 | import com.thoughtworks.xstream.annotations.XStreamAlias;
20 | import com.thoughtworks.xstream.annotations.XStreamInclude;
21 | import org.optaplanner.examples.common.domain.AbstractPersistable;
22 | import org.optaplanner.examples.vehiclerouting.domain.VehicleRoutingSolution;
23 |
24 | @XStreamAlias("VrpLocation")
25 | @XStreamInclude({
26 | AirLocation.class,
27 | RoadLocation.class
28 | })
29 | public abstract class Location extends AbstractPersistable {
30 |
31 | protected String name = null;
32 | protected double latitude;
33 | protected double longitude;
34 |
35 | public Location() {
36 | }
37 |
38 | public Location(long id, double latitude, double longitude) {
39 | super(id);
40 | this.latitude = latitude;
41 | this.longitude = longitude;
42 | }
43 |
44 | public String getName() {
45 | return name;
46 | }
47 |
48 | public void setName(String name) {
49 | this.name = name;
50 | }
51 |
52 | public double getLatitude() {
53 | return latitude;
54 | }
55 |
56 | public void setLatitude(double latitude) {
57 | this.latitude = latitude;
58 | }
59 |
60 | public double getLongitude() {
61 | return longitude;
62 | }
63 |
64 | public void setLongitude(double longitude) {
65 | this.longitude = longitude;
66 | }
67 |
68 | // ************************************************************************
69 | // Complex methods
70 | // ************************************************************************
71 |
72 | /**
73 | * The distance's unit of measurement depends on the {@link VehicleRoutingSolution}'s {@link DistanceType}.
74 | * It can be in miles or km, but for most cases it's in the TSPLIB's unit of measurement.
75 | * @param location never null
76 | * @return a positive number, the distance multiplied by 1000 to avoid floating point arithmetic rounding errors
77 | */
78 | public abstract int getDistance(Location location);
79 |
80 | public double getAirDistanceDouble(Location location) {
81 | // Implementation specified by TSPLIB http://www2.iwr.uni-heidelberg.de/groups/comopt/software/TSPLIB95/
82 | // Euclidean distance (Pythagorean theorem) - not correct when the surface is a sphere
83 | double latitudeDifference = location.latitude - latitude;
84 | double longitudeDifference = location.longitude - longitude;
85 | return Math.sqrt(
86 | (latitudeDifference * latitudeDifference) + (longitudeDifference * longitudeDifference));
87 | }
88 |
89 | /**
90 | * The angle relative to the direction EAST.
91 | * @param location never null
92 | * @return in Cartesian coordinates
93 | */
94 | public double getAngle(Location location) {
95 | // Euclidean distance (Pythagorean theorem) - not correct when the surface is a sphere
96 | double latitudeDifference = location.latitude - latitude;
97 | double longitudeDifference = location.longitude - longitude;
98 | return Math.atan2(latitudeDifference, longitudeDifference);
99 | }
100 |
101 |
102 | @Override
103 | public String toString() {
104 | if (name == null) {
105 | return id.toString();
106 | }
107 | return id.toString() + "-" + name;
108 | }
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_legend.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
16 |
17 |
21 |
22 |
28 |
29 |
30 |
32 |
33 |
37 |
38 |
44 |
45 |
46 |
48 |
49 |
57 |
58 |
64 |
65 |
66 |
68 |
69 |
75 |
76 |
82 |
83 |
84 |
86 |
87 |
93 |
94 |
100 |
101 |
102 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/app/src/main/java/org/tomasdavid/vehicleroutingproblem/fragments/MainFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Tomas David
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.tomasdavid.vehicleroutingproblem.fragments;
18 |
19 | import android.os.Bundle;
20 | import android.support.v4.app.Fragment;
21 | import android.text.Html;
22 | import android.view.LayoutInflater;
23 | import android.view.Menu;
24 | import android.view.MenuInflater;
25 | import android.view.MenuItem;
26 | import android.view.View;
27 | import android.view.ViewGroup;
28 | import android.widget.ArrayAdapter;
29 | import android.widget.NumberPicker;
30 | import android.widget.Spinner;
31 | import android.widget.TextView;
32 |
33 | import org.tomasdavid.vehicleroutingproblem.components.AboutAppDialog;
34 | import org.tomasdavid.vehicleroutingproblem.components.LegendDialog;
35 | import org.tomasdavid.vehicleroutingproblem.R;
36 |
37 | /**
38 | * Main fragment with settings.
39 | *
40 | * @author Tomas David
41 | */
42 | public class MainFragment extends Fragment {
43 |
44 | /**
45 | * Default time limit in number picker.
46 | */
47 | private static final int DEFAULT_TIME_LIMIT = 10;
48 |
49 | /**
50 | * Minimum time limit in number picker.
51 | */
52 | private static final int MIN_TIME_LIMIT = 1;
53 |
54 | /**
55 | * Maximum time limit in number picker.
56 | */
57 | private static final int MAX_TIME_LIMIT = 1000;
58 |
59 | /**
60 | * {@inheritDoc}
61 | */
62 | @Override
63 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
64 | View view = inflater.inflate(R.layout.fragment_main, container, false);
65 |
66 | // time limit number picker initialization
67 | NumberPicker numberPicker = (NumberPicker) view.findViewById(R.id.timeLimitPicker);
68 | numberPicker.setMinValue(MIN_TIME_LIMIT);
69 | numberPicker.setMaxValue(MAX_TIME_LIMIT);
70 | numberPicker.setValue(DEFAULT_TIME_LIMIT);
71 | numberPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);
72 |
73 | // welcome text
74 | TextView welcomeText = (TextView) view.findViewById(R.id.welcome_text);
75 | welcomeText.setText(Html.fromHtml(getString(R.string.welcome_text)));
76 |
77 | // spinner for choosing algorithm initialization
78 | Spinner algSpinner = (Spinner) view.findViewById(R.id.algorithm_spinner);
79 | ArrayAdapter spinnerAdapter = ArrayAdapter.createFromResource(getActivity(), R.array.algorithms,
80 | android.R.layout.simple_spinner_item);
81 | spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
82 | algSpinner.setAdapter(spinnerAdapter);
83 |
84 | setHasOptionsMenu(true);
85 | return view;
86 | }
87 |
88 | /**
89 | * {@inheritDoc}
90 | */
91 | @Override
92 | public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
93 | inflater.inflate(R.menu.menu_vrp, menu);
94 |
95 | // disable play button
96 | menu.findItem(R.id.action_run).setVisible(false);
97 |
98 | super.onCreateOptionsMenu(menu, inflater);
99 | }
100 |
101 | /**
102 | * {@inheritDoc}
103 | */
104 | @Override
105 | public boolean onOptionsItemSelected(MenuItem item) {
106 | int id = item.getItemId();
107 | if (id == R.id.action_about) {
108 | AboutAppDialog aad = new AboutAppDialog();
109 | aad.show(getActivity().getSupportFragmentManager(), null);
110 | return true;
111 | } else if (id == R.id.action_legend) {
112 | LegendDialog ld = new LegendDialog();
113 | ld.show(getActivity().getSupportFragmentManager(), null);
114 | return true;
115 | }
116 | return super.onOptionsItemSelected(item);
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/app/src/main/java/org/tomasdavid/vehicleroutingproblem/painter/VrpTranslator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Tomas David
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.tomasdavid.vehicleroutingproblem.painter;
18 |
19 | import android.content.res.Resources;
20 |
21 | import org.optaplanner.examples.vehiclerouting.domain.VehicleRoutingSolution;
22 | import org.optaplanner.examples.vehiclerouting.domain.location.Location;
23 | import org.tomasdavid.vehicleroutingproblem.R;
24 |
25 | /**
26 | * Class for translation between longitude/latitude and screen coordinate system.
27 | * This file was modified from original file LatitudeLongitudeTranslator.java from OptaPlanner project.
28 | *
29 | * @author Tomas David
30 | * @author Geoffrey De Smet
31 | */
32 | public class VrpTranslator {
33 |
34 | private double minLatitude = Double.MAX_VALUE;
35 | private double maxLatitude = -Double.MAX_VALUE;
36 | private double minLongitude = Double.MAX_VALUE;
37 | private double maxLongitude = -Double.MAX_VALUE;
38 |
39 | private double latitudeLength = 0.0;
40 | private double longitudeLength = 0.0;
41 |
42 | private double width = 0.0;
43 | private double height = 0.0;
44 |
45 | private double widthMargin = 0.0;
46 | private double heightMargin = 0.0;
47 |
48 | private double scale;
49 |
50 | /**
51 | * Constructor prepares vehicle routing solution for specified screen size.
52 | * @param vrs Vehicle routing solution.
53 | * @param width Width of screen.
54 | * @param height Height of screen.
55 | * @param resources Application resources.
56 | */
57 | public VrpTranslator(VehicleRoutingSolution vrs, double width, double height,
58 | Resources resources) {
59 | for (Location location : vrs.getLocationList()) {
60 | addCoordinates(location.getLatitude(), location.getLongitude());
61 | }
62 |
63 | this.widthMargin = resources.getDimension(R.dimen.margin_width);
64 | this.heightMargin = resources.getDimension(R.dimen.margin_height);
65 |
66 | this.width = width - 2.0 * widthMargin;
67 | this.height = height - 2.0 * heightMargin;
68 |
69 | latitudeLength = maxLatitude - minLatitude;
70 | longitudeLength = maxLongitude - minLongitude;
71 |
72 | if (this.width / longitudeLength > this.height / latitudeLength) {
73 | scale = this.height / latitudeLength;
74 | } else {
75 | scale = this.width / longitudeLength;
76 | }
77 | }
78 |
79 | /**
80 | * Add coordinates to find out min/max longitude/latitude.
81 | * @param latitude Point latitude.
82 | * @param longitude Point longitude.
83 | */
84 | public void addCoordinates(double latitude, double longitude) {
85 | if (latitude < minLatitude) {
86 | minLatitude = latitude;
87 | }
88 | if (latitude > maxLatitude) {
89 | maxLatitude = latitude;
90 | }
91 | if (longitude < minLongitude) {
92 | minLongitude = longitude;
93 | }
94 | if (longitude > maxLongitude) {
95 | maxLongitude = longitude;
96 | }
97 | }
98 |
99 | /**
100 | * Converts point longitude to x coordinate.
101 | * @param longitude Point longitude.
102 | * @return X coordinate on screen.
103 | */
104 | public float translateLongitudeToX(double longitude) {
105 | return (float) Math.floor(((longitude - minLongitude) * scale) + widthMargin + (width-longitudeLength * scale) / 2.0);
106 | }
107 |
108 | /**
109 | * Converts point latitude to y coordinate.
110 | * @param latitude Point latitude.
111 | * @return Y coordinate on screen.
112 | */
113 | public float translateLatitudeToY(double latitude) {
114 | return (float) Math.floor(((maxLatitude - latitude) * scale) + heightMargin + (height-latitudeLength * scale) / 2.0);
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/app/src/main/assets/vrps/F-n135-k7.vrp:
--------------------------------------------------------------------------------
1 | NAME : F-n135-k7
2 | COMMENT : (Fisher: problem 12, Min no of trucks: 7, Best value: 1165)
3 | TYPE : CVRP
4 | DIMENSION : 135
5 | EDGE_WEIGHT_TYPE : EUC_2D
6 | CAPACITY : 2210
7 | NODE_COORD_SECTION
8 | 1 -6.0 15.0
9 | 2 3.2 5.1
10 | 3 24.6 8.3
11 | 4 23.3 1.3
12 | 5 27.8 8.3
13 | 6 29.0 8.0
14 | 7 31.0 8.0
15 | 8 33.5 10.5
16 | 9 30.0 10.5
17 | 10 29.0 10.0
18 | 11 26.5 11.7
19 | 12 28.3 14.3
20 | 13 27.0 14.3
21 | 14 23.5 19.0
22 | 15 26.0 20.0
23 | 16 25.0 20.0
24 | 17 20.5 19.0
25 | 18 -20.0 13.0
26 | 19 -21.0 14.0
27 | 20 -30.0 30.0
28 | 21 -5.0 30.0
29 | 22 1.3 17.8
30 | 23 1.8 13.8
31 | 24 1.8 13.1
32 | 25 2.0 13.6
33 | 26 4.8 17.0
34 | 27 7.0 15.0
35 | 28 9.8 16.6
36 | 29 11.4 14.5
37 | 30 14.4 11.3
38 | 31 11.0 12.0
39 | 32 9.3 10.7
40 | 33 0.6 2.8
41 | 34 -30.0 -10.0
42 | 35 2.0 0.0
43 | 36 14.5 1.0
44 | 37 15.0 1.8
45 | 38 17.2 2.4
46 | 39 17.2 4.2
47 | 40 18.2 4.4
48 | 41 20.3 2.1
49 | 42 22.8 3.1
50 | 43 23.0 4.0
51 | 44 20.8 4.0
52 | 45 20.8 4.0
53 | 46 18.5 6.4
54 | 47 -14.0 16.0
55 | 48 -0.5 6.9
56 | 49 3.2 2.8
57 | 50 5.6 1.8
58 | 51 8.7 2.8
59 | 52 9.0 3.3
60 | 53 9.0 3.5
61 | 54 11.2 3.3
62 | 55 10.8 4.7
63 | 56 11.5 4.6
64 | 57 12.3 4.7
65 | 58 12.3 5.5
66 | 59 11.2 6.9
67 | 60 6.5 9.7
68 | 61 5.8 8.5
69 | 62 7.2 6.0
70 | 63 7.2 4.0
71 | 64 -4.0 -4.0
72 | 65 -3.0 1.2
73 | 66 -40.0 49.0
74 | 67 -15.0 10.0
75 | 68 -11.0 -10.0
76 | 69 -25.0 -20.0
77 | 70 -25.0 -35.0
78 | 71 -24.0 -35.0
79 | 72 -18.0 10.0
80 | 73 -2.0 10.0
81 | 74 -4.0 8.0
82 | 75 -3.0 5.0
83 | 76 2.1 6.2
84 | 77 -1.7 3.0
85 | 78 -3.0 2.0
86 | 79 -7.0 0.0
87 | 80 -3.0 -6.0
88 | 81 -30.0 -11.0
89 | 82 -62.0 -10.0
90 | 83 -8.0 30.0
91 | 84 1.0 60.0
92 | 85 10.0 52.0
93 | 86 10.0 52.0
94 | 87 10.0 51.0
95 | 88 16.0 29.0
96 | 89 26.0 21.0
97 | 90 16.0 21.0
98 | 91 15.5 19.2
99 | 92 0.0 16.5
100 | 93 17.2 14.3
101 | 94 16.5 7.8
102 | 95 16.9 7.7
103 | 96 18.0 2.0
104 | 97 16.2 4.0
105 | 98 15.0 4.0
106 | 99 15.0 3.0
107 | 100 14.8 2.4
108 | 101 14.5 3.0
109 | 102 13.0 2.6
110 | 103 11.8 3.0
111 | 104 12.0 4.0
112 | 105 12.8 3.6
113 | 106 13.4 5.5
114 | 107 -150.0 8.0
115 | 108 -152.0 1.0
116 | 109 -152.0 0.0
117 | 110 -142.0 -31.0
118 | 111 -78.0 -19.0
119 | 112 -78.0 -18.0
120 | 113 -78.0 -17.0
121 | 114 -80.0 -14.0
122 | 115 -118.0 22.0
123 | 116 -107.0 30.0
124 | 117 -85.0 14.0
125 | 118 -78.0 15.0
126 | 119 -15.0 16.0
127 | 120 -62.0 32.0
128 | 121 -120.0 -20.0
129 | 122 -90.0 -22.0
130 | 123 -79.0 -19.0
131 | 124 -79.0 -18.5
132 | 125 -79.0 -18.0
133 | 126 -78.0 -17.5
134 | 127 -79.0 -17.0
135 | 128 -80.0 -17.0
136 | 129 -80.0 -16.0
137 | 130 -80.0 -15.0
138 | 131 -48.0 37.0
139 | 132 -85.0 15.0
140 | 133 -62.0 -9.0
141 | 134 -15.0 -4.0
142 | 135 -1.0 3.2
143 | DEMAND_SECTION
144 | 1 0
145 | 2 30
146 | 3 226
147 | 4 37
148 | 5 24
149 | 6 36
150 | 7 1
151 | 8 31
152 | 9 24
153 | 10 30
154 | 11 24
155 | 12 24
156 | 13 32
157 | 14 24
158 | 15 24
159 | 16 19
160 | 17 24
161 | 18 18
162 | 19 36
163 | 20 115
164 | 21 24
165 | 22 24
166 | 23 61
167 | 24 71
168 | 25 36
169 | 26 18
170 | 27 30
171 | 28 31
172 | 29 36
173 | 30 18
174 | 31 1004
175 | 32 18
176 | 33 34
177 | 34 504
178 | 35 18
179 | 36 39
180 | 37 24
181 | 38 37
182 | 39 24
183 | 40 99
184 | 41 24
185 | 42 24
186 | 43 36
187 | 44 30
188 | 45 25
189 | 46 24
190 | 47 122
191 | 48 196
192 | 49 229
193 | 50 83
194 | 51 18
195 | 52 24
196 | 53 306
197 | 54 18
198 | 55 20
199 | 56 18
200 | 57 24
201 | 58 22
202 | 59 24
203 | 60 18
204 | 61 18
205 | 62 24
206 | 63 24
207 | 64 30
208 | 65 24
209 | 66 40
210 | 67 166
211 | 68 254
212 | 69 187
213 | 70 94
214 | 71 17
215 | 72 285
216 | 73 24
217 | 74 24
218 | 75 205
219 | 76 23
220 | 77 28
221 | 78 51
222 | 79 49
223 | 80 19
224 | 81 262
225 | 82 120
226 | 83 266
227 | 84 704
228 | 85 38
229 | 86 18
230 | 87 30
231 | 88 25
232 | 89 12
233 | 90 18
234 | 91 25
235 | 92 35
236 | 93 18
237 | 94 12
238 | 95 20
239 | 96 1126
240 | 97 9
241 | 98 36
242 | 99 12
243 | 100 31
244 | 101 96
245 | 102 27
246 | 103 54
247 | 104 137
248 | 105 12
249 | 106 58
250 | 107 206
251 | 108 178
252 | 109 486
253 | 110 36
254 | 111 261
255 | 112 135
256 | 113 135
257 | 114 373
258 | 115 535
259 | 116 42
260 | 117 9
261 | 118 110
262 | 119 36
263 | 120 18
264 | 121 726
265 | 122 187
266 | 123 23
267 | 124 134
268 | 125 47
269 | 126 51
270 | 127 43
271 | 128 79
272 | 129 112
273 | 130 91
274 | 131 232
275 | 132 483
276 | 133 828
277 | 134 11
278 | 135 12
279 | DEPOT_SECTION
280 | 1
281 | -1
282 | EOF
283 |
284 |
--------------------------------------------------------------------------------
/app/src/main/java/org/optaplanner/examples/vehiclerouting/domain/Customer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012 JBoss Inc
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.optaplanner.examples.vehiclerouting.domain;
18 |
19 | import com.thoughtworks.xstream.annotations.XStreamAlias;
20 | import com.thoughtworks.xstream.annotations.XStreamInclude;
21 | import org.optaplanner.core.api.domain.entity.PlanningEntity;
22 | import org.optaplanner.core.api.domain.variable.AnchorShadowVariable;
23 | import org.optaplanner.core.api.domain.variable.PlanningVariable;
24 | import org.optaplanner.core.api.domain.variable.PlanningVariableGraphType;
25 | import org.optaplanner.examples.common.domain.AbstractPersistable;
26 | import org.optaplanner.examples.vehiclerouting.domain.location.Location;
27 | import org.optaplanner.examples.vehiclerouting.domain.solver.DepotAngleCustomerDifficultyWeightFactory;
28 | import org.optaplanner.examples.vehiclerouting.domain.timewindowed.TimeWindowedCustomer;
29 |
30 | @PlanningEntity(difficultyWeightFactoryClass = DepotAngleCustomerDifficultyWeightFactory.class)
31 | @XStreamAlias("VrpCustomer")
32 | @XStreamInclude({
33 | TimeWindowedCustomer.class
34 | })
35 | public class Customer extends AbstractPersistable implements Standstill {
36 |
37 | protected Location location;
38 | protected int demand;
39 |
40 | // Planning variables: changes during planning, between score calculations.
41 | protected Standstill previousStandstill;
42 |
43 | // Shadow variables
44 | protected Customer nextCustomer;
45 | protected Vehicle vehicle;
46 |
47 | public Location getLocation() {
48 | return location;
49 | }
50 |
51 | public void setLocation(Location location) {
52 | this.location = location;
53 | }
54 |
55 | public int getDemand() {
56 | return demand;
57 | }
58 |
59 | public void setDemand(int demand) {
60 | this.demand = demand;
61 | }
62 |
63 | @PlanningVariable(valueRangeProviderRefs = {"vehicleRange", "customerRange"},
64 | graphType = PlanningVariableGraphType.CHAINED)
65 | public Standstill getPreviousStandstill() {
66 | return previousStandstill;
67 | }
68 |
69 | public void setPreviousStandstill(Standstill previousStandstill) {
70 | this.previousStandstill = previousStandstill;
71 | }
72 |
73 | public Customer getNextCustomer() {
74 | return nextCustomer;
75 | }
76 |
77 | public void setNextCustomer(Customer nextCustomer) {
78 | this.nextCustomer = nextCustomer;
79 | }
80 |
81 | @AnchorShadowVariable(sourceVariableName = "previousStandstill")
82 | public Vehicle getVehicle() {
83 | return vehicle;
84 | }
85 |
86 | public void setVehicle(Vehicle vehicle) {
87 | this.vehicle = vehicle;
88 | }
89 |
90 | // ************************************************************************
91 | // Complex methods
92 | // ************************************************************************
93 |
94 | /**
95 | * @return a positive number, the distance multiplied by 1000 to avoid floating point arithmetic rounding errors
96 | */
97 | public int getDistanceFromPreviousStandstill() {
98 | if (previousStandstill == null) {
99 | return 0;
100 | }
101 | return getDistanceFrom(previousStandstill);
102 | }
103 |
104 | /**
105 | * @param standstill never null
106 | * @return a positive number, the distance multiplied by 1000 to avoid floating point arithmetic rounding errors
107 | */
108 | public int getDistanceFrom(Standstill standstill) {
109 | return standstill.getLocation().getDistance(location);
110 | }
111 |
112 | /**
113 | * @param standstill never null
114 | * @return a positive number, the distance multiplied by 1000 to avoid floating point arithmetic rounding errors
115 | */
116 | public int getDistanceTo(Standstill standstill) {
117 | return location.getDistance(standstill.getLocation());
118 | }
119 |
120 | @Override
121 | public String toString() {
122 | return location + "(after " + (previousStandstill == null ? "null" : previousStandstill.getLocation()) + ")";
123 | }
124 |
125 | }
126 |
--------------------------------------------------------------------------------
/app/src/main/java/org/optaplanner/examples/vehiclerouting/domain/timewindowed/TimeWindowedCustomer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012 JBoss Inc
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.optaplanner.examples.vehiclerouting.domain.timewindowed;
18 |
19 | import com.thoughtworks.xstream.annotations.XStreamAlias;
20 | import org.optaplanner.core.api.domain.entity.PlanningEntity;
21 | import org.optaplanner.core.api.domain.variable.CustomShadowVariable;
22 | import org.optaplanner.examples.vehiclerouting.domain.Customer;
23 | import org.optaplanner.examples.vehiclerouting.domain.Standstill;
24 | import org.optaplanner.examples.vehiclerouting.domain.timewindowed.solver.ArrivalTimeUpdatingVariableListener;
25 |
26 | @PlanningEntity
27 | @XStreamAlias("VrpTimeWindowedCustomer")
28 | public class TimeWindowedCustomer extends Customer {
29 |
30 | // Times are multiplied by 1000 to avoid floating point arithmetic rounding errors
31 | private int readyTime;
32 | private int dueTime;
33 | private int serviceDuration;
34 |
35 | // Shadow variable
36 | private Integer arrivalTime;
37 |
38 | /**
39 | * @return a positive number, the time multiplied by 1000 to avoid floating point arithmetic rounding errors
40 | */
41 | public int getReadyTime() {
42 | return readyTime;
43 | }
44 |
45 | public void setReadyTime(int readyTime) {
46 | this.readyTime = readyTime;
47 | }
48 |
49 | /**
50 | * @return a positive number, the time multiplied by 1000 to avoid floating point arithmetic rounding errors
51 | */
52 | public int getDueTime() {
53 | return dueTime;
54 | }
55 |
56 | public void setDueTime(int dueTime) {
57 | this.dueTime = dueTime;
58 | }
59 |
60 | /**
61 | * @return a positive number, the time multiplied by 1000 to avoid floating point arithmetic rounding errors
62 | */
63 | public int getServiceDuration() {
64 | return serviceDuration;
65 | }
66 |
67 | public void setServiceDuration(int serviceDuration) {
68 | this.serviceDuration = serviceDuration;
69 | }
70 |
71 | /**
72 | * @return a positive number, the time multiplied by 1000 to avoid floating point arithmetic rounding errors
73 | */
74 | @CustomShadowVariable(variableListenerClass = ArrivalTimeUpdatingVariableListener.class,
75 | sources = {@CustomShadowVariable.Source(variableName = "previousStandstill")})
76 | public Integer getArrivalTime() {
77 | return arrivalTime;
78 | }
79 |
80 | public void setArrivalTime(Integer arrivalTime) {
81 | this.arrivalTime = arrivalTime;
82 | }
83 |
84 | // ************************************************************************
85 | // Complex methods
86 | // ************************************************************************
87 |
88 | /**
89 | * @return a positive number, the time multiplied by 1000 to avoid floating point arithmetic rounding errors
90 | */
91 | public Integer getDepartureTime() {
92 | if (arrivalTime == null) {
93 | return null;
94 | }
95 | return Math.max(arrivalTime, readyTime) + serviceDuration;
96 | }
97 |
98 | public boolean isArrivalBeforeReadyTime() {
99 | return arrivalTime != null
100 | && arrivalTime < readyTime;
101 | }
102 |
103 | public boolean isArrivalAfterDueTime() {
104 | return arrivalTime != null
105 | && dueTime < arrivalTime;
106 | }
107 |
108 | @Override
109 | public TimeWindowedCustomer getNextCustomer() {
110 | return (TimeWindowedCustomer) super.getNextCustomer();
111 | }
112 |
113 | /**
114 | * @return a positive number, the time multiplied by 1000 to avoid floating point arithmetic rounding errors
115 | */
116 | public int getTimeWindowGapTo(TimeWindowedCustomer other) {
117 | // dueTime doesn't account for serviceDuration
118 | int latestDepartureTime = dueTime + serviceDuration;
119 | int otherLatestDepartureTime = other.getDueTime() + other.getServiceDuration();
120 | if (latestDepartureTime < other.getReadyTime()) {
121 | return other.getReadyTime() - latestDepartureTime;
122 | }
123 | if (otherLatestDepartureTime < readyTime) {
124 | return readyTime - otherLatestDepartureTime;
125 | }
126 | return 0;
127 | }
128 |
129 | }
130 |
--------------------------------------------------------------------------------
/app/src/main/java/org/optaplanner/examples/vehiclerouting/domain/VehicleRoutingSolution.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012 JBoss Inc
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.optaplanner.examples.vehiclerouting.domain;
18 |
19 | import java.util.ArrayList;
20 | import java.util.Collection;
21 | import java.util.List;
22 |
23 | import com.thoughtworks.xstream.annotations.XStreamAlias;
24 | import com.thoughtworks.xstream.annotations.XStreamConverter;
25 | import com.thoughtworks.xstream.annotations.XStreamInclude;
26 | import org.optaplanner.core.api.domain.solution.PlanningEntityCollectionProperty;
27 | import org.optaplanner.core.api.domain.solution.PlanningSolution;
28 | import org.optaplanner.core.api.domain.solution.Solution;
29 | import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider;
30 | import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;
31 | import org.optaplanner.core.impl.score.buildin.hardsoft.HardSoftScoreDefinition;
32 | import org.optaplanner.examples.common.domain.AbstractPersistable;
33 | import org.optaplanner.examples.vehiclerouting.domain.location.DistanceType;
34 | import org.optaplanner.examples.vehiclerouting.domain.location.Location;
35 | import org.optaplanner.examples.vehiclerouting.domain.timewindowed.TimeWindowedVehicleRoutingSolution;
36 | import org.optaplanner.persistence.xstream.impl.score.XStreamScoreConverter;
37 |
38 | @PlanningSolution
39 | @XStreamAlias("VrpVehicleRoutingSolution")
40 | @XStreamInclude({
41 | TimeWindowedVehicleRoutingSolution.class
42 | })
43 | public class VehicleRoutingSolution extends AbstractPersistable implements Solution {
44 |
45 | protected String name;
46 | protected DistanceType distanceType;
47 | protected String distanceUnitOfMeasurement;
48 | protected List locationList;
49 | protected List depotList;
50 | protected List vehicleList;
51 |
52 | protected List customerList;
53 |
54 | @XStreamConverter(value = XStreamScoreConverter.class, types = {HardSoftScoreDefinition.class})
55 | protected HardSoftScore score;
56 |
57 | public String getName() {
58 | return name;
59 | }
60 |
61 | public void setName(String name) {
62 | this.name = name;
63 | }
64 |
65 | public DistanceType getDistanceType() {
66 | return distanceType;
67 | }
68 |
69 | public void setDistanceType(DistanceType distanceType) {
70 | this.distanceType = distanceType;
71 | }
72 |
73 | public String getDistanceUnitOfMeasurement() {
74 | return distanceUnitOfMeasurement;
75 | }
76 |
77 | public void setDistanceUnitOfMeasurement(String distanceUnitOfMeasurement) {
78 | this.distanceUnitOfMeasurement = distanceUnitOfMeasurement;
79 | }
80 |
81 | public List getLocationList() {
82 | return locationList;
83 | }
84 |
85 | public void setLocationList(List locationList) {
86 | this.locationList = locationList;
87 | }
88 |
89 | public List getDepotList() {
90 | return depotList;
91 | }
92 |
93 | public void setDepotList(List depotList) {
94 | this.depotList = depotList;
95 | }
96 |
97 | @PlanningEntityCollectionProperty
98 | @ValueRangeProvider(id = "vehicleRange")
99 | public List getVehicleList() {
100 | return vehicleList;
101 | }
102 |
103 | public void setVehicleList(List vehicleList) {
104 | this.vehicleList = vehicleList;
105 | }
106 |
107 | @PlanningEntityCollectionProperty
108 | @ValueRangeProvider(id = "customerRange")
109 | public List getCustomerList() {
110 | return customerList;
111 | }
112 |
113 | public void setCustomerList(List customerList) {
114 | this.customerList = customerList;
115 | }
116 |
117 | public HardSoftScore getScore() {
118 | return score;
119 | }
120 |
121 | public void setScore(HardSoftScore score) {
122 | this.score = score;
123 | }
124 |
125 | // ************************************************************************
126 | // Complex methods
127 | // ************************************************************************
128 |
129 | public Collection extends Object> getProblemFacts() {
130 | List