All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.chocosolver.solver.trace.frames.StatisticsPanel Maven / Gradle / Ivy

There is a newer version: 4.10.17
Show newest version
/*
 * This file is part of choco-solver, http://choco-solver.org/
 *
 * Copyright (c) 2023, IMT Atlantique. All rights reserved.
 *
 * Licensed under the BSD 4-clause license.
 *
 * See LICENSE file in the project root for full license information.
 */
package org.chocosolver.solver.trace.frames;

import org.chocosolver.solver.Solver;
import org.chocosolver.solver.search.SearchState;
import org.knowm.xchart.QuickChart;
import org.knowm.xchart.XChartPanel;
import org.knowm.xchart.XYChart;

import javax.swing.*;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryType;
import java.lang.management.MemoryUsage;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * A simple dashboard to show resolution statistics on a frame during resolution.
 *
 * 

* Project: choco-solver. * * @author Charles Prud'homme * @since 21/11/2017. */ public class StatisticsPanel extends JPanel { private static final String[] fieldnames = { "Variables", "Constraints", "Objective", "Solutions", "Nodes", "Fails", "Backtracks", "Backjumps", "Restarts", "Fixpoints", "Depth", "Time (sec.)", // time in second "Nodes/sec.", // node per second "Fails/sec.", // node per second "Fixpoints/sec.", // node per second "Mem. usage (MB)", }; @SuppressWarnings("unchecked") private static final Function[] fieldvalues = (Function[]) new Function[]{ (Function) solver -> Long.toString(solver.getModel().getNbVars()), (Function) solver -> Long.toString(solver.getModel().getNbCstrs()), (Function) solver -> (solver.hasObjective() ? solver.getBestSolutionValue().toString() : "--"), (Function) solver -> Long.toString(solver.getSolutionCount()), (Function) solver -> Long.toString(solver.getNodeCount()), (Function) solver -> Long.toString(solver.getFailCount()), (Function) solver -> Long.toString(solver.getBackTrackCount()), (Function) solver -> Long.toString(solver.getBackjumpCount()), (Function) solver -> Long.toString(solver.getRestartCount()), (Function) solver -> Long.toString(solver.getFixpointCount()), (Function) solver -> Long.toString(solver.getCurrentDepth()), (Function) solver -> toHHmmss((long) (solver.getTimeCount() * 1000)), (Function) solver -> String.format("%.2f", (solver.getNodeCount() / solver.getTimeCount())), (Function) solver -> String.format("%.2f", (solver.getFailCount() / solver.getTimeCount())), (Function) solver -> String.format("%.2f", (solver.getFixpointCount() / solver.getTimeCount())), (Function) solver -> String.format("%d", getUsedMemInBytes()), }; /** * A boolean to kill the printer when the resolution ends. */ private volatile boolean alive; /** * Solver to extract statistics from */ private final Solver solver; /** * Fields to update */ private final JTextField[] textFields; /** * Chart for objective function */ private XYChart chart; /** * Panel that hosts {@link #chart} */ private XChartPanel chartpanel; /** * List required by {@link #chart}, for X coordinate */ private final List time; /** * List required by {@link #chart}, for Y coordinate */ private final List obj; /** * Chart menu */ private JMenu menuChart; /** * Chart option, modified thanks to {@link #menuChart} */ private byte chartOptions; /** * Create a simple dashboard that show statistics from 'solver' every 'duration' milliseconds * * @param solver to extract statistics from * @param duration frequency rate, in milliseconds */ public StatisticsPanel(Solver solver, long duration, JFrame mainFrame) { this.solver = solver; setLayout(new BorderLayout()); int length = fieldnames.length; textFields = new JTextField[length]; JLabel[] labels = new JLabel[length]; for (int i = 0; i < length; i++) { textFields[i] = new JTextField(8); textFields[i].setEnabled(false); textFields[i].setHorizontalAlignment(SwingConstants.RIGHT); labels[i] = new JLabel(fieldnames[i] + ": "); labels[i].setLabelFor(textFields[i]); } //Lay out the text controls and the labels. JPanel textControlsPane = new JPanel(); GridBagLayout gridbag = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints(); textControlsPane.setLayout(gridbag); addLabelTextRows(labels, textFields, textControlsPane); c.gridwidth = GridBagConstraints.REMAINDER; //last c.anchor = GridBagConstraints.WEST; c.weightx = 1.0; textControlsPane.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createTitledBorder("Resolution statistics"), BorderFactory .createEmptyBorder(5, 5, 5, 5))); //Put everything together. JPanel leftPane = new JPanel(new BorderLayout()); leftPane.add(textControlsPane, BorderLayout.PAGE_START); add(leftPane, BorderLayout.LINE_START); // Create Chart time = new ArrayList<>(); obj = new ArrayList<>(); chartOptions = 0b11; makeMenu(mainFrame); printStatistics(); //noinspection InfiniteLoopStatement // Create Chart /** * Thread that updates data */ Thread printer = new Thread(() -> { alive = true; try { Thread.sleep(5); //noinspection InfiniteLoopStatement do { if (solver.getSearchState().equals(SearchState.RUNNING)) { printStatistics(); if (solver.hasObjective()) { if ((chartOptions & 0b10) != 0) { time.add(solver.getTimeCount()); obj.add(solver.getBestSolutionValue()); } if (chart == null) { // Create Chart chart = QuickChart .getChart("Objective", "Time (sec)", "Objective value", solver.getObjectiveManager().getObjective().getName(), time, obj); chart.getStyler().setChartBackgroundColor(leftPane.getBackground()); chartpanel = new XChartPanel<>(chart); add(chartpanel); mainFrame.pack(); } if ((chartOptions & 0b01) != 0) { chart.updateXYSeries( solver.getObjectiveManager().getObjective().getName(), time, obj, null); chartpanel.revalidate(); chartpanel.repaint(); } } else { menuChart.setEnabled(false); } } Thread.sleep(duration); } while (alive); } catch (InterruptedException ignored) { } }); printer.setDaemon(true); printer.start(); } private void makeMenu(JFrame mainFrame) { //Create the menu bar. JMenuBar menuBar = new JMenuBar(); JMenu mainMenu = new JMenu("Menu"); mainMenu.setMnemonic(KeyEvent.VK_M); menuBar.add(mainMenu); mainFrame.setJMenuBar(menuBar); menuChart = new JMenu("Chart"); menuChart.setMnemonic(KeyEvent.VK_C); menuChart.add(makeShowHideItem(mainFrame)); menuChart.add(makeDisconnectConnectItem(mainFrame)); mainMenu.add(menuChart); } private JMenuItem makeDisconnectConnectItem(JFrame mainFrame) { JMenuItem item = new JMenuItem("Disconnect", KeyEvent.VK_D); item.setAccelerator(KeyStroke.getKeyStroke( KeyEvent.VK_D, InputEvent.ALT_DOWN_MASK)); item.addActionListener(e -> { if ((chartOptions & 0b10) != 0) { this.remove(chartpanel); } chartOptions = 0b00; time.clear(); obj.clear(); mainFrame.pack(); }); return item; } private JMenuItem makeShowHideItem(JFrame mainFrame) { JMenuItem item = new JMenuItem("Hide/Show", KeyEvent.VK_H); item.setAccelerator(KeyStroke.getKeyStroke( KeyEvent.VK_H, InputEvent.ALT_DOWN_MASK)); item.addActionListener(e -> { if ((chartOptions & 0b10) != 0) { this.remove(chartpanel); chartOptions ^= 0b10; } else { this.add(chartpanel); chartOptions = 0b11; } mainFrame.pack(); }); return item; } private void addLabelTextRows(JLabel[] labels, JTextField[] textFields, Container container) { GridBagConstraints c = new GridBagConstraints(); c.anchor = GridBagConstraints.EAST; int numLabels = labels.length; for (int i = 0; i < numLabels; i++) { c.gridwidth = GridBagConstraints.RELATIVE; //next-to-last c.fill = GridBagConstraints.NONE; //reset to default c.weightx = 0.0; //reset to default container.add(labels[i], c); c.gridwidth = GridBagConstraints.REMAINDER; //end row c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 1.0; container.add(textFields[i], c); } } private void printStatistics() { for (int i = 0; i < textFields.length; i++) { textFields[i].setText(fieldvalues[i].apply(solver)); } } private static String toHHmmss(long etime) { return String.format("%02d:%02d:%02d", TimeUnit.MILLISECONDS.toHours(etime), TimeUnit.MILLISECONDS.toMinutes(etime) % TimeUnit.HOURS.toMinutes(1), TimeUnit.MILLISECONDS.toSeconds(etime) % TimeUnit.MINUTES.toSeconds(1)); } private static long getUsedMemInBytes(){ long usedHeapMemoryAfterLastGC = 0; List memoryPools = new ArrayList<>(ManagementFactory.getMemoryPoolMXBeans()); for (MemoryPoolMXBean memoryPool : memoryPools) { if (memoryPool.getType().equals(MemoryType.HEAP)) { MemoryUsage poolCollectionMemoryUsage = memoryPool.getUsage(); usedHeapMemoryAfterLastGC += poolCollectionMemoryUsage.getUsed(); } } return(long)(usedHeapMemoryAfterLastGC / 1e6); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy