Using BarChart[ ] tooltips to illustrate where data is coming from - wolfram-mathematica

I am currently visualizing word and phrase frequency across a large database of textual information (approximately 108MB spread across 307 text files). My goal is to have a way to quickly see what files are the most relevant and in a visually attractive format (although this project will probably also demonstrate that just having textual representation is always clearer).
Right now I have the following:
SetDirectory["/MYMATHEMATICADIRECTORY/"];
filelist = FileNames[];
viewerCount1 = {0};
viewerCount2 = {0};
word1 = "freedom";
word2 = "liberty";
Do[
searchDB = StringSplit[Import[filename]];
AppendTo[viewerCount1, Count[searchDB, word1]];
AppendTo[viewerCount2, Count[searchDB, word2]];
, {filename, filelist}]
list3 = Take[viewerCount1, {2, -1}]
list4 = Take[viewerCount2, {2, -1}]
The FileNames[ ] generates a list such as: {"001ABbenevolat.txt-cleaned.txt", "002abnature.txt-cleaned.txt", "003aboriginaldocs.txt-cleaned.txt", "004ABpresse.txt-cleaned.txt", "005acadian.txt-cleaned.txt", "006acadiedelile.txt-cleaned.txt","007acfa.txt-cleaned.txt"} [except with 307 entries, all numbered].
list3 generates a list such as: {0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 100, 2, 0, 0, 0, 10, 1, 7, 0, 0, 0, 0, 23, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 9, 0, 1, 0, 1, 0, 5, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 4, 0, 0, 0, 1, 11, 0, 2, 0, 0, 2, 7, 1, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 13,...} and so on.
The command:
BarChart3D[{list3, list4}, BarSpacing -> {0.5, 0}, ChartLayout -> "Grid"]
Generates something close to what I want (imagining them as file folders sticking up). However, I want to add meaningful tool-tips. By default, it comes up with frequency. Would there be a quick way to also include the filename the frequency is attached to, as well as the frequency? i.e. a tool-tip that brings up '007acfa.txt-cleaned.txt -- 32' where 32 occurrences appear in file 7?

As an example, suppose you data is something like
list3 = RandomInteger[30, 30];
list4 = RandomInteger[30, 30];
filelist = Table["file " <> ToString[i], {i, 30}];
Then you could do something like
BarChart3D[{
MapThread[Tooltip[#2, Row[{#, " -- ", #2}]] &, {filelist, list3}],
MapThread[Tooltip[#2, Row[{#, " -- ", #2}]] &, {filelist, list4}]},
BarSpacing -> {0.5, 0}, ChartLayout -> "Grid"]
Edit
Another way is to use LabelingFunction:
BarChart3D[{list3, list4},
LabelingFunction ->
(Placed[Row[{filelist[[Last[#2]]], " -- ", #1}], Tooltip] &),
ChartLayout -> "Grid", BarSpacing -> {0.5, 0}]

This should work:
BarChart3D[{list3, list4},
ChartLabels -> Placed[filelist, Tooltip],
ChartLayout -> "Grid",
BarSpacing -> {0.5, 0}]
Edit
Forgot you wanted the height in the tooltip also, for which you do want to use LabelingFunction. Let's go ahead and include the word itself also:
BarChart3D[{list3, list4},
ChartLabels -> {Placed[{word1, word2}, None], Placed[filelist, None]},
ChartLayout -> "Grid",
BarSpacing -> {0.5, 0},
LabelingFunction -> (Tooltip[Row[Flatten[{#3, #1}], " - "]] &)
]

Related

Integer Linear Program, Bipartite Matching with Constraints How To?

The following program produces a matching between two sets of vertices, one represents meets between two teams and the other time slots when the meets could happen. The adjacency map represents both teams' availability to meet at any given time slot, days[][] represents which time slots are on the same date, weekDays[][] represents what day of the week is a given date, and teamToGames maps every meet that includes a given team. The decision variables are in a map match[][], with a value of 1 where a meet is matched to a time slot. Constraints are added so that only 1 meet can be matched to a time slot, only 1 time slot can be matched to a meet, only if allowed by the respective adj[][] value, and so that meets involving the same team cannot be matched to a game slot on the same date nor the following or previous date, excluding thursday-sunday.
What I don't know how to do now, is how can I make it prefer assigning two or more meets on the same date rather than one meet on each of two separate dates? So that there is the least possible amount of dates with only one meet. Kind of like constraining the number of meets on a date to either 0 or >=2 but only if possible.
Thank you for reading and for any help you can offer.
// [START program]
// [START import]
import com.google.ortools.linearsolver.MPConstraint;
import com.google.ortools.linearsolver.MPObjective;
import com.google.ortools.linearsolver.MPSolver;
import com.google.ortools.linearsolver.MPVariable;
// [END import]
/** MIP example that solves an assignment problem. */
public class GameMatching {
static {
System.loadLibrary("jniortools");
}
public static void main(String[] args) {
// Data
// [START data_model]
// Adjacency matrix represents which games can happen on which dates
int[][] adj = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
};
int numGames = adj.length;
int numDates = adj[0].length;
//represents which game time slots are on a given day (4 games on sundays, 2 on weekdays)
int[][] days = {
{0, 1, 2, 3},
{4, 5},
{6, 7},
{8, 9, 10, 11},
{12, 13},
{14, 15},
{16, 17},
{18, 19},
{20, 21, 22, 23},
{24, 25},
{26, 27},
{28, 29},
{30, 31},
{32, 33, 34, 35},
{36, 37},
{38, 39},
{40, 41},
{42, 43},
{44, 45, 46, 47},
{48, 49},
{50, 51},
{52, 53, 54, 55},
{56, 57},
{58, 59},
{60, 61},
{62, 63},
{64, 65, 66, 67},
{68, 69},
{70, 71},
{72, 73},
{74, 75},
{76, 77, 78, 79}
};
//represents what day of the week is a day, a team can play thursday and sunday, but not sunday and monday 0 is sunday, 1 is monday...
int[] weekDays = {0, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0};
// teamToGames[i][j] represents a team i's, games j
int[][] teamToGames = {
{1, 3, 9, 16, 18, 26},
{0, 8, 12, 16, 23, 28},
{1, 5, 7, 13, 21, 27},
{2, 5, 14, 17, 22, 26},
{7, 15, 19, 21, 24, 28},
{3, 10, 14, 20, 27, 29},
{2, 6, 9, 13, 23, 29},
{6, 8, 11, 18, 19, 25},
{8, 4, 10, 11, 17, 24},
{4, 12, 15, 20, 22, 25},
};
// [END data_model]
// Solver
// [START solver]
// Create the linear solver with the CBC backend.
MPSolver solver = new MPSolver("AssignmentMip", MPSolver.OptimizationProblemType.CBC_MIXED_INTEGER_PROGRAMMING);
// [END solver]
// Variables
// [START variables]
// x[i][j] is an array of 0-1 variables, which will be 1
// if a game i is assigned to date j.
MPVariable[][] match = new MPVariable[numGames][numDates];
for (int i = 0; i < numGames; ++i) {
for (int j = 0; j < numDates; ++j) {
match[i][j] = solver.makeIntVar(0, 1, "");
}
}
// [END variables]
// Constraints
// [START constraints]
// Each game is assigned to at most one date.
for (int i = 0; i < numGames; ++i) {
MPConstraint constraint = solver.makeConstraint(0, 1, "");
for (int j = 0; j < numDates; ++j) {
constraint.setCoefficient(match[i][j], 1);
}
}
// Each date is assigned to at most one game.
for (int j = 0; j < numDates; ++j) {
MPConstraint constraint = solver.makeConstraint(0, 1, "");
for (int i = 0; i < numGames; ++i) {
constraint.setCoefficient(match[i][j], 1);
}
}
// Can only assign respecting adj matrix
for (int i = 0; i < numGames; ++i) {
for (int j = 0; j < numDates; ++j) {
MPConstraint constraint = solver.makeConstraint(0, adj[i][j], "");
constraint.setCoefficient(match[i][j], 1);
}
}
// Cannot assign team to consecutive dates
for (int i = 0; i < teamToGames.length; ++i) {
for (int j = 0; j < days.length - 1; ++j) {
if (weekDays[j] != 4) {
MPConstraint constraint = solver.makeConstraint(0, 1, "");
for (int k = 0; k < teamToGames[i].length; ++k) {
for (int l = 0; l < days[j].length; ++l) {
constraint.setCoefficient(match[teamToGames[i][k]][l], 1);
}
for (int l = 0; l < days[j+1].length; ++l) {
constraint.setCoefficient(match[teamToGames[i][k]][l], 1);
}
}
}
}
}
// [END constraints]
// Objective
// [START objective]
MPObjective objective = solver.objective();
for (int i = 0; i < numGames; ++i) {
for (int j = 0; j < numDates; ++j) {
objective.setCoefficient(match[i][j], 1);
}
}
objective.setMaximization();
// [END objective]
// Solve
// [START solve]
MPSolver.ResultStatus resultStatus = solver.solve();
// [END solve]
// Print solution.
// [START print_solution]
// Check that the problem has a feasible solution.
if (resultStatus == MPSolver.ResultStatus.OPTIMAL || resultStatus == MPSolver.ResultStatus.FEASIBLE) {
System.out.println("Total matches: " + objective.value() + "\n");
for (int i = 0; i < numGames; ++i) {
for (int j = 0; j < numDates; ++j) {
// Test if x[i][j] is 0 or 1 (with tolerance for floating point
// arithmetic).
if (match[i][j].solutionValue() > 0.5) {
System.out.println("Game " + i + " assigned to date " + j);
}
}
}
} else {
System.err.println("No solution found.");
}
// [END print_solution]
}
// private GameMatching() {
// }
}
// [END program]
Borrowing a page from the facility location playbook, make a new array of 0-1 variables canHaveMatches[j], add constraints match[i][j] <= canHaveMatches[j], minimize sum_j canHaveMatches[j].

Rust performance issue - High complexity code

I bought RUST by its performance so I decided to translate one project where performance matters a lot, from JAVA 11 to Rust.
The thing is the Version written in JAVA performance pretty much better more than 3x in single thread, +10X in multi thread
For context purpose: The most complex code is a function that trys to find an assigment between 2 sets, imagine that you have houses and stores, the stores have a fixed capacity and houses have necesities, you want to find the best assignment to walk less.
With all this in mind, I guess that the problem is how I use the variables, maybe clone() is called too much automatically, maybe reference access cause some unknown behavior.
Any upgrade that reduce while loop time will be great because it iterate over 5000 times. Sorry for the long code but I think everything is relevant in this case. You can't copy and paste this code if you want I can send you the git project link.
PD: I'm running with cargo run --release
pub fn evaluate(elem: &Element) -> EvaluatedElement {
let p1 = properties::get_cast::<f64>("p1");
let p2 = properties::get_cast::<usize>("p2");
let p3 = properties::get_cast::<usize>("p3");
let p4 = properties::get_cast::<f64>("p4");
let p5 = properties::get_array::<usize>("p5");
let mut kinds1 = kind1::get_map(); //almost 300 elements
let kinds2 = = kind2::get_map(); //almost 300 elements
let usables = elem.usables();
for (i, &a) in usables.iter().enumerate() {
if !a {
&kinds1.remove(&(i + 1));
}
}
let mut assignations = HashMap::new();
for k in (1..=p2).rev() {
let mut kinds2_sub = HashMap::with_capacity((&kinds2).len());
for (_, p) in kinds2.iter() {
if p.val1[k - 1] == 0 {
continue;
}
&kinds2_sub.insert(p.id, Kind2Sub {
parent: p.clone(),
val2: p.val1[k - 1],
val3: std::f64::MAX,
kind1_id: std::usize::MAX,
});
}
let mut opt_kind1_id: Option<usize> = Option::None;
while !&kinds2_sub.is_empty() {//arround 5500 times loop
for mut l in kinds2_sub.values_mut() {
match opt_kind1_id {
None => (),
Some(id) => if !l.kind1_id == id { continue; },
}
l.val3 = std::f64::MAX;
l.kind1_id = std::usize::MAX;
for b in kinds1.values_mut() {
let dist_b_l = calc_dist(b.id, l.id);
if dist_b_l > p4
|| (p1 as usize).min(l.val2) > p4 + b.val3
|| b.val2 < k
|| (l.val2 < (2 * p4) && (b.val3 as i16 - l.val2 as i16) < 0)
{ continue; }
let tmp = dist_b_l * p1.min(l.val2 as f64);
if l.val3 > tmp {
l.val3 = tmp;
l.kind1_id = b.id;
}
}
}
let lc = kinds2_sub.values_mut().min_by(|x, y| x.val3.partial_cmp(&y.val3).unwrap()).unwrap();
let obc = kinds1.get_mut(&lc.kind1_id);
let bc = obc.unwrap_or_else(|| {
panic!("No assignation able")
});
let b_c_id = (*bc).id;
let l_c_id = (*lc).id;
let time = if lc.val2 < (2usize * p1 as usize) { lc.val2 } else { p1 as usize };
let val = (*bc).val3 as i16 - time as i16;
let assignation = Assignation { kind1_id: (*bc).id, kind2_id: lc.id, val3: k, val4: 0 };
let assignation_id = assignation.id();//id() = fn concatenate first 3 values
if !assignations.contains_key(&assignation_id) {
assignations.insert(assignation.id(), assignation);
}
let mut assignation = assignations.get_mut(&assignation_id).unwrap_or_else(|| panic!("Assignation not found {}", assignation_id));
if val >= 0 {
assignation.val4 += time;
lc.val2 -= time;
(*bc).val3 -= time;
} else {
assignation.val4 += (*bc).val3;
lc.val2 -= (*bc).val3;
(*bc).val3 = 0;
}
if (*bc).val3 < p4 {
&kinds1.remove(&b_c_id);
}
if lc.val2 == 0 {
&kinds2_sub.remove(&l_c_id);
}
opt_kind1_id = Some(b_c_id);
}
}
let assignations_values = assignations.iter().map(|(_, v)| v.clone()).collect();
EvaluatedElement::evaluation(assignations_values)
}
Now I have a 4X increase.
Step Value Time Used Stores
RUST -> BI 90 2672540 28057 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0]
Java -> BI 90 2672625 4704 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0]
FIX: -> BI 90 2672540 1093 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0]
The "bug"
match opt_kind1_id {
None => (),
Some(id) => if !l.kind1_id == id { continue; },
}
The fix
if let Some(id) = opt_kind1_id {
if l.kind1_id != id {
continue;
}
}
This continue skips 90% of finding a new value

How can I create a random array between a range of two other arrays?

I need to generate an array of random 20 bytes between a given range of arrays. Since arrays are comparable in Rust, this works:
let low = [0u8; 20];
let high = [2u8; 20];
assert_eq!(true, low < high);
assert_eq!(false, low > high);
assert_eq!(true, low == [0u8; 20]);
For these bounds:
let low: [u8; 20] = [98, 0, 1, 0, 2, 6, 99, 3, 0, 5, 23, 3, 5, 6, 11, 8, 0, 2, 0, 17];
let high: [u8; 20] = [99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
These would be a valid result:
[98, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
These are not:
[98, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]
I want to do something like:
use rand::prelude::*;
fn main() {
let low = [0u8; 20];
let high = [2u8; 20];
let value = rand::thread_rng().gen_range(low, high);
println!("{:?}", value);
}
but I get following error:
error[E0277]: the trait bound `[u8; 20]: rand::distributions::uniform::SampleUniform` is not satisfied
--> src\main.rs:6:36
|
6 | let value = rand::thread_rng().gen_range(low, high);
| ^^^^^^^^^ the trait `rand::distributions::uniform::SampleUniform` is not implemented for `[u8; 20]`
I tried implementing SampleUniform and UniformSampler without much success. Is there a simple way to implement this?
If you want to treat the byte arrays as big integers, use the
num-bigint crate with the rand feature enabled:
use bigint::{ToBigInt, RandBigInt};
let low = -10000.to_bigint().unwrap();
let high = 10000.to_bigint().unwrap();
let b = rng.gen_bigint_range(&low, &high);
You could also use unsigned integers instead of signed. There are methods to convert to and from big endian byte arrays:
from_bytes_be
to_bytes_be
See also:
How do I generate a random num::BigUint?

ECLiPSe CLP : slow combined occurrence/3 constraint behaviour

As a subset of a larger problem, I'm trying to write the 2 following constraints for an NxN board (containing N² cells):
Each row/col contains exactly N occurrences of integer K given by pre-defined hints
No 2x2 block (anywhere on the board) contains more than 1 occurrence of integer K
On the board, several cells will already be filled in on beforehand and should be ignored for the constraints in this SO question, therefore we use integer 2 to represent these cells and model the unknown cells to have a finite domain of binary boolean values:
model(Board,N,Hints) :-
dim(Board,[N,N]),
( foreach(Row-Col,Hints), param(Board)
do
2 is Board[Row,Col]
),
( multifor([I,J],1,N), param(Board)
do
Cell is Board[I,J],
( var(Cell) -> Cell :: 0..1 ; true )
).
The constraints in code respectively:
hint_constraints(Board,N,RowHints,ColHints) :-
( for(I,1,N), foreach(RH,RowHints), foreach(CH,ColHints), param(Board,N)
do
Row is Board[I,1..N],
Col is Board[1..N,I],
ic_global:occurrences(1,Row,RH), % Here, K=1 and N=RH
ic_global:occurrences(1,Col,CH) % Here, K=1 and N=CH
).
block_constraints(Board,N) :-
( multifor([I,J],1,(N-1)), param(Board)
do
Block is Board[I..I+1,J..J+1],
flatten(Block,BlockFlat),
Sum #:: [0,1],
ic_global:occurrences(1,BlockFlat,Sum) % Here, K=1
).
For a simple execution of a puzzle:
solve(BT) :-
puzzle(N,_,RowHints,ColHints,Hints),
model(N,RowHints,ColHints,Hints,Board),
hint_constraints(Board,N,RowHints,ColHints),
block_constraints(Board,N),
once search(Board,0,most_constrained,indomain_max,complete,[backtrack(BT)]).
For the 8x8 puzzle, the first solution is found almost instantly:
?- solve(BT).
[](0, 0, 0, 0, 0, 0, 1, 2)
[](2, 1, 0, 2, 1, 0, 0, 2)
[](0, 0, 0, 0, 0, 0, 1, 0)
[](0, 0, 0, 1, 0, 0, 0, 0)
[](1, 0, 0, 0, 2, 0, 0, 0)
[](2, 2, 1, 0, 1, 2, 1, 2)
[](1, 2, 0, 2, 0, 0, 2, 0)
[](0, 0, 0, 0, 1, 0, 0, 1)
BT = 0
Yes (0.01s cpu)
for the 20x20 instance however, I have left it running for around 5 minutes without getting any result.
To investigate whether one constraint would be significantly more costly than the other, I ran both of them separately:
When we use hint_constraints/4, but not block_constraints/2, we get:
?- solve(BT).
[](1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0)
[](1, 1, 2, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 2, 0)
[](2, 1, 1, 1, 2, 1, 1, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0)
[](1, 1, 0, 0, 0, 0, 0, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2)
[](1, 0, 1, 1, 1, 2, 1, 1, 2, 1, 0, 0, 0, 0, 2, 2, 0, 0, 2, 0)
[](2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0)
[](2, 0, 0, 0, 1, 2, 1, 1, 1, 1, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0)
[](1, 0, 0, 0, 2, 1, 1, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0)
[](2, 0, 0, 0, 1, 1, 0, 1, 1, 2, 1, 0, 2, 0, 2, 0, 2, 0, 0, 2)
[](2, 0, 0, 0, 1, 0, 2, 1, 0, 1, 1, 0, 0, 0, 0, 0, 2, 0, 2, 0)
[](0, 0, 0, 0, 2, 0, 2, 0, 0, 1, 2, 1, 2, 1, 1, 0, 0, 1, 0, 2)
[](0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 2, 0, 0)
[](0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 1, 1, 1, 0, 1, 0, 2, 0, 0)
[](2, 0, 0, 0, 2, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1)
[](0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 1, 0, 1, 0, 1)
[](0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 2, 2, 2, 1)
[](0, 2, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 1, 1, 1)
[](0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 0, 2, 0, 1, 0, 0, 1, 2, 1, 1)
[](2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2)
[](0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 2, 0, 1, 2, 1, 1, 1, 2, 1)
BT = 0
Yes (0.04s cpu)
and can verify that all row/col occurrences are satisfied. The other way around, when we use block_constraints/2, but not hint_constraints/2:
?- solve(BT).
[](0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0)
[](0, 1, 2, 1, 0, 2, 1, 2, 1, 0, 1, 0, 1, 2, 1, 0, 1, 2, 2, 0)
[](2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0)
[](0, 1, 0, 1, 0, 1, 0, 2, 2, 1, 2, 1, 0, 1, 0, 1, 0, 0, 2, 2)
[](0, 0, 0, 0, 0, 2, 0, 1, 2, 0, 0, 0, 0, 0, 2, 2, 0, 1, 2, 1)
[](2, 1, 0, 1, 0, 1, 0, 0, 0, 1, 2, 1, 0, 1, 2, 1, 0, 0, 0, 0)
[](2, 0, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 1, 0, 1)
[](0, 1, 0, 1, 2, 1, 0, 0, 0, 2, 1, 0, 1, 0, 2, 1, 0, 2, 0, 0)
[](2, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 2, 0, 2, 0, 2, 1, 0, 2)
[](2, 1, 0, 1, 0, 1, 2, 0, 0, 1, 0, 1, 0, 1, 0, 1, 2, 0, 2, 1)
[](0, 0, 0, 0, 2, 0, 2, 1, 0, 0, 2, 0, 2, 0, 0, 0, 0, 1, 0, 2)
[](0, 1, 0, 1, 2, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 0)
[](0, 0, 0, 0, 0, 2, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 1, 0)
[](2, 1, 0, 1, 2, 2, 0, 0, 0, 2, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0)
[](0, 0, 2, 0, 0, 1, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0)
[](0, 1, 0, 1, 0, 2, 0, 0, 0, 1, 0, 1, 2, 1, 0, 1, 2, 2, 2, 0)
[](0, 2, 0, 0, 2, 1, 2, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 1, 0, 1)
[](0, 1, 2, 1, 0, 0, 0, 0, 2, 2, 1, 2, 1, 0, 1, 0, 0, 2, 0, 0)
[](2, 0, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2)
[](0, 1, 2, 1, 0, 0, 0, 0, 2, 0, 2, 2, 1, 0, 2, 0, 0, 0, 2, 0)
BT = 0
Yes (0.01s cpu)
we can once more verify that the 2x2 block constraint successfully holds. Unfortunately, when using both constraints together the program seems not to finish anywhere within 5 minutes. I'm a bit confused by this behaviour since both constraints separately appear to work very fast. Though I understand that a lot of checks will have to occur internally to make sure the correct occurrences for each row/col are present while still satisfying the block constraint throughout the process, the fact that it takes over 5 minutes made me think something else must be wrong with the way I have written the block constraint.
Does anyone have an idea on how to optimise my implementation of the block occurrence constraint?
Thanks in advance!
Puzzle instances
puzzle(8, easy, [1,2,1,1,1,3,1,2],
[2,1,1,1,3,0,3,1],
[1-8, 2-1, 2-4, 2-8, 5-5, 6-1, 6-2, 6-6, 6-8, 7-2, 7-4, 7-7]).
puzzle(20,medium,[5,2,6,2,7,1,6,3,5,4,5,3,4,2,4,3,5,4,4,5],
[5,4,3,3,6,3,4,5,2,4,4,4,2,7,1,5,3,6,3,6],
[1-6, 1-15, 2-3, 2-6, 2-8, 2-14, 2-18, 2-19, 3-1, 3-5, 3-11, 4-8, 4-9, 4-11, 4-19, 4-20,
5-6, 5-9, 5-15, 5-16, 5-19, 6-1, 6-11, 6-15, 7-1, 7-6, 7-15, 8-5, 8-10, 8-15, 8-18,
9-1, 9-10, 9-13, 9-15, 9-17, 9-20, 10-1, 10-7, 10-17, 10-19, 11-5, 11-7, 11-11, 11-13, 11-20,
12-5, 12-18, 13-6, 13-11, 13-18, 14-1, 14-5, 14-6, 14-10, 15-3, 15-12, 16-6, 16-13, 16-17, 16-18, 16-19,
17-2, 17-5, 17-7, 17-15, 18-3, 18-9, 18-10, 18-12, 18-18, 19-1, 19-6, 19-20, 20-3, 20-9, 20-11, 20-12, 20-15, 20-19]).

Generating a list with elements based conditionals on other lists in Mathematica

I want to calculate an 2D array "tocalc" in which the elements are calculated based on tests on three other lists (z,b1,b2).
(*example data*)
z = Range[0, 100, 10];
x = Range[10];
b1 = ConstantArray[0., Length[x]];
tocalc = ConstantArray[0, {Length[x], Length[z]}];
b2 = {0, 20, 30, 40, 50, 40, 30, 20, 10, 0};
one solution to this would be
(*simple but slow solution*)
Do[
Do[
If[z[[k]] <= b2[[i]] && z[[k]] >= b1[[i]],
tocalc[[i, k]] = (b2[[i + 1]] - b2[[i - 1]])],
{k, 1, Length[z]}];,
{i, 2, Length[x] - 1}]
with the result
{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {30, 30, 30, 0, 0, 0, 0, 0, 0, 0,
0}, {20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0}, {20, 20, 20, 20, 20, 0,
0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0}, {-20, -20, -20, -20, -20, 0, 0, 0, 0, 0,
0}, {-20, -20, -20, -20, 0, 0, 0, 0, 0, 0, 0}, {-20, -20, -20, 0, 0,
0, 0, 0, 0, 0, 0}, {-20, -20, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0}}
The Question: How can this be done efficiently in Mathematica?
If this is evaluated 10000 times then it would take then 3.66 seconds. While in Matlab this takes 0.04sec so Matlab is almost 100 times faster.
I know that the solution with the two Do loops is not perfect for Mathematica, so i tried several other solutions such as with MapIndexed, Table, functions, Conditionals, and so on. but all are not really faster maybe even slower the the two Do loops.
Here is one example with MapIndexed:
tocalc = ConstantArray[0, {Length[x], Length[z]}];
MapIndexed[
If[z[[Part[#2, 2]]] <= b2[[Part[#2, 1]]] &&
z[[Part[#2, 2]]] >= b1[[Part[#2, 1]]] && Part[#2, 1] >= 2 &&
Part[#2, 1] <= Length[x] - 1,
tocalc[[Part[#2, 1], Part[#2, 2]]] = (b2[[Part[#2, 1] + 1]] -
b2[[Part[#2, 1] - 1]]), 0.] &, tocalc, {2}];
The ideal solution should work for larger matrices and real numbers as well and also for more complicated conditionals.
---edit:
Since it looks some solutions to this are even slower in my real problem here is one example of it:
the Real-World Problem
b2 = {0.`, 0.`, 0.`, 990.3440201085594`, 1525.7589030785484`,
1897.6531659202747`, 2191.6073263357594`, 2433.0441988616717`,
2630.6658409463894`, 2799.347578394955`, 2944.656306810331`,
3070.718467691769`, 3179.485627984329`, 3272.3788096129415`,
3346.199103579602`, 3405.384848015466`, 3346.199103579602`,
3272.3788096129415`, 3179.485627984329`, 3070.718467691769`,
2944.656306810331`, 2799.347578394955`, 2630.6658409463894`,
2433.0441988616717`, 2191.6073263357594`, 1897.6531659202747`,
1525.7589030785484`, 990.3440201085594`, 0.`, 0.`, 0.`};
z = {0.`, 250.`, 500.`, 750.`, 1000.`, 1250.`, 1500.`, 1750.`, 2000.`,
2250.`, 2500.`, 2750.`, 3000.`, 3250.`,
3500.`}; (*z(k)*)
imax = 31; (*number of x(i)*)
b1 = ConstantArray[0., imax]; (*lower boundary, can be different form 0*)
deltax = 50000.`;
mmax = 10000.; (*number of calculations*)
A00 = 1.127190283243198`*^-12; (*somefactor*)
n = 3;
one solution:
f2C = Compile[{{b2, _Real, 1}, {z, _Real, 1}, {b1, _Real, 1}},
With[{zeros = {ConstantArray[0., Length[z]]}},
Join[zeros,
Table[If[
b1[[i]] <= z[[k]] <=
b2[[i]], -(A00*(Abs[(b2[[i + 1]] - b2[[i - 1]])/(2.0*
deltax)])^(n -
1.0)*(b2[[i]]^(n + 1.) - (b2[[i]] - z[[k]])^(n +
1.)))*((b2[[i + 1]] - b2[[i - 1]])/(2.0*deltax))
, 0.],
{i, 2, Length[b2] - 1}, {k, Length[z]}
], zeros]]
, CompilationTarget -> "C"];
The Result is
Timing[Do[f2C[b2, z, b1];, {mmax}]]
Out[85]= {81.3544, Null}
Thanks!
You can do something like below. You will need to figure out how you want to handle the boundaries though (where b2[[i+1]] or b2[[i-1]] is not defined).
f[x_, y_] := If[x[[1]] <= y <= x[[2]], x[[4]] - x[[3]], 0]
Here I restrain the level to which Outer goes, so that I do not need to change the head (as I was doing in the original response).
In[1309]:= Outer[f,
Transpose[{b1, b2, RotateRight[b2], RotateLeft[b2]}], z, 1]
Out[1309]= {{20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {30, 30, 30, 0, 0, 0,
0, 0, 0, 0, 0}, {20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0}, {20, 20, 20,
20, 20, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0}, {-20, -20, -20, -20, -20, 0, 0, 0, 0, 0,
0}, {-20, -20, -20, -20, 0, 0, 0, 0, 0, 0, 0}, {-20, -20, -20, 0, 0,
0, 0, 0, 0, 0, 0}, {-20, -20, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {-10, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0}}
Speed check:
In[1298]:= Timing[
Do[Outer[f,
Apply[list,
Transpose[{b1, b2, RotateRight[b2], RotateLeft[b2]}], {1}],
z], {10^4}]]
Out[1298]= {2.68, Null}
We can compile the function to get better speed.
fC = Compile[{{x, _Integer, 1}, {y, _Integer}},
If[x[[1]] <= y <= x[[2]], x[[4]] - x[[3]], 0]];
In[1306]:= Timing[
Do[Outer[fC, Transpose[{b1, b2, RotateRight[b2], RotateLeft[b2]}], z,
1], {10^4}]]
Out[1306]= {0.8, Null}
--- edit ---
Variants include compiling the entire routine. Here is one such.
ff = Compile[{{b1, _Integer, 1}, {b2, _Integer, 1}, {z, _Integer,
1}},
With[{lc =
RotateRight[ListConvolve[{1, 0, -1}, b2, {-1, -1}, 0]]},
Table[
If[b1[[i]] <= z[[k]] <= b2[[i]], lc[[i]], 0], {i,
Length[b2]}, {k, Length[z]}
]]];
In[385]:= Timing[Do[ff[b1, b2, z], {10^4}]]
Out[385]= {0.24, Null}
If I add CompilationTarget -> "C" then it gets around twice as fast.
Another variant, in C code, gets under 0.1 seconds.
In[441]:=
ff2C = Compile[{{b1, _Integer, 1}, {b2, _Integer, 1}, {z, _Integer,
1}},
With[{zeros = {ConstantArray[0, Length[z]]}},
Join[zeros, Table[
If[b1[[i]] <= z[[k]] <= b2[[i]], b2[[i + 1]] - b2[[i - 1]],
0], {i, 2, Length[b2] - 1}, {k, Length[z]}
], zeros]], CompilationTarget -> "C"];
In[442]:= Timing[Do[ff2C[b1, b2, z], {10^4}]]
Out[442]= {0.04, Null}
In[443]:= ff2C[b1, b2, z]
Out[443]= {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {30, 30, 30, 0, 0, 0, 0,
0, 0, 0, 0}, {20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0}, {20, 20, 20,
20, 20, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0}, {-20, -20, -20, -20, -20, 0, 0, 0, 0, 0,
0}, {-20, -20, -20, -20, 0, 0, 0, 0, 0, 0, 0}, {-20, -20, -20, 0, 0,
0, 0, 0, 0, 0, 0}, {-20, -20, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0}}
I would guess there are variants that may be faster still.
--- end edit ---
--- edit 2 ---
Of course, if you have global variables (that is, defined outside of your Compile), then there is a bit more work to do. I am aware of two possibilities. Prior to version 8 one would suck in constants using a With[] around the Compile, as below.
f2C = With[{n = n, deltax = deltax, A00 = A00},
Compile[{{b2, _Real, 1}, {z, _Real, 1}, {b1, _Real, 1}},
With[{zeros = {ConstantArray[0., Length[z]]}},
Join[zeros,
Table[If[
b1[[i]] <= z[[k]] <=
b2[[i]], -(A00*(Abs[(b2[[i + 1]] - b2[[i - 1]])/(2.0*
deltax)])^(n -
1.0)(b2[[i]]^(n + 1.) - (b2[[i]] - z[[k]])^(n +
1.)))((b2[[i + 1]] - b2[[i - 1]])/(2.0*deltax)),
0.], {i, 2, Length[b2] - 1}, {k, Length[z]}], zeros]],
CompilationTarget -> "C"]];
In version 8 the following achieves the same effect.
f2Cb = Compile[{{b2, _Real, 1}, {z, _Real, 1}, {b1, _Real, 1}},
With[{zeros = {ConstantArray[0., Length[z]]}},
Join[zeros,
Table[If[
b1[[i]] <= z[[k]] <=
b2[[i]], -(A00*(Abs[(b2[[i + 1]] - b2[[i - 1]])/(2.0*
deltax)])^(n -
1.0)(b2[[i]]^(n + 1.) - (b2[[i]] - z[[k]])^(n +
1.)))((b2[[i + 1]] - b2[[i - 1]])/(2.0*deltax)),
0.], {i, 2, Length[b2] - 1}, {k, Length[z]}], zeros]],
CompilationTarget -> "C",
CompilationOptions -> {"InlineExternalDefinitions" -> True}];
With either I get a result on the more realistic example in around 0.7 seconds, whereas my machine would take over 100 seconds without those globals being defined inside the Compile.
A more general approach might be to pass them as parameters (if they were likely to change rather than be constants). That would lead to a slightly slower run time though.
Regarding that option approach, you might have a look at ref/CompilationOptions in the Cocumentation Center
--- end edit 2 ---

Resources