This tutorial teaches you how to use the Minto library’s logging functionality and various logging control methods.
1. Basic Log Output¶
Let’s start by trying the basic logging functionality.
import time
import jijmodeling as jm
import ommx_openjij_adapter as oj_ad
import minto
# Create an Experiment with logging enabled
exp = minto.Experiment(
name="tutorial_experiment",
auto_saving=False, # Disable saving for tutorial
)
def create_problem():
n = jm.Placeholder("n")
rows = jm.Placeholder("rows", ndim=1)
cols = jm.Placeholder("cols", ndim=1)
value = jm.Placeholder("value", ndim=1)
nnz = value.len_at(0)
problem = jm.Problem("qubo")
i = jm.Element("i", nnz)
x = jm.BinaryVar("x", shape=(n,))
problem += jm.sum(i, value[i] * x[rows[i]] * x[cols[i]])
return problem
def qubo_instance_data():
n = 5
rows = [0, 1, 2, 3, 4]
cols = [1, 2, 3, 4, 0]
value = [1.0, -1.0, 2.0, -2.0, 3.0]
return {"n": n, "rows": rows, "cols": cols, "value": value}
interpreter = jm.Interpreter(qubo_instance_data())
instance = interpreter.eval_problem(create_problem())
# Create and execute a run
run = exp.run()
with run:
num_sweeps = 1000
run.log_parameter("solver_type", "SimulatedAnnealing")
run.log_parameter("temperature", 1.0)
run.log_parameter("num_sweeps", num_sweeps)
solution = oj_ad.OMMXOpenJijSAAdapter.solve(instance, num_sweeps=num_sweeps)
run.log_solution(solution)
# Finish the experiment
exp.finish_experiment()2. Custom Log Configuration¶
Let’s customize how logs are displayed.
from minto.logging_config import LogConfig, LogFormat, LogLevel
# Simple log configuration
simple_config = LogConfig(
format=LogFormat.SIMPLE, show_timestamps=False, show_icons=False, show_colors=False
)
print("=== Simple Log Configuration ===")
exp_simple = minto.Experiment(
name="simple_experiment",
verbose_logging=True,
log_config=simple_config,
auto_saving=False,
collect_environment=False,
)
run = exp_simple.run()
with run:
run.log_parameter("method", "QAOA")
run.log_parameter("layers", 3)
exp_simple.finish_experiment()# Detailed log configuration
detailed_config = LogConfig(
level=LogLevel.DEBUG,
format=LogFormat.DETAILED,
show_timestamps=True,
show_icons=True,
show_colors=False, # Colors are often disabled in Jupyter environments
max_parameter_length=200, # Increase maximum parameter display length
)
print("\n=== Detailed Log Configuration ===")
exp_detailed = minto.Experiment(
name="detailed_experiment",
verbose_logging=True,
log_config=detailed_config,
auto_saving=False,
collect_environment=False,
)
run = exp_detailed.run()
with run:
run.log_parameter("algorithm", "Quantum Annealing")
run.log_parameter("annealing_time", 20.0)
# Log objects
problem_data = {"variables": 100, "constraints": 50, "objective": "minimize"}
run.log_object("problem_instance", problem_data)
exp_detailed.finish_experiment()3. Solver Execution Logging¶
Let’s learn how to automatically log solver execution time and parameters.
# Define QUBO problem using jijmodeling (same as in basic example)
def create_problem():
n = jm.Placeholder("n")
rows = jm.Placeholder("rows", ndim=1)
cols = jm.Placeholder("cols", ndim=1)
value = jm.Placeholder("value", ndim=1)
nnz = value.len_at(0)
problem = jm.Problem("qubo")
i = jm.Element("i", nnz)
x = jm.BinaryVar("x", shape=(n,))
problem += jm.sum(i, value[i] * x[rows[i]] * x[cols[i]])
return problem
def qubo_instance_data():
n = 5
rows = [0, 1, 2, 3, 4]
cols = [1, 2, 3, 4, 0]
value = [1.0, -1.0, 2.0, -2.0, 3.0]
return {"n": n, "rows": rows, "cols": cols, "value": value}
# Prepare the problem instance
interpreter = jm.Interpreter(qubo_instance_data())
instance = interpreter.eval_problem(create_problem())
# Execute solver logging with real OpenJij solver
exp = minto.Experiment(
name="solver_logging_experiment",
verbose_logging=True,
auto_saving=False,
collect_environment=False,
)
run = exp.run()
with run:
# Method 1: Manual parameter logging and solver execution
run.log_parameter("solver_type", "SimulatedAnnealing")
run.log_parameter("num_sweeps", 2000)
run.log_parameter("temperature", 1.0)
# Execute solver directly
solution = oj_ad.OMMXOpenJijSAAdapter.solve(instance, num_sweeps=2000)
run.log_solution(solution)
print("\n--- Using log_solver wrapper ---")
# Method 2: Using log_solver wrapper for automatic parameter logging
def solve_with_openjij(instance, num_sweeps=1000, seed=None):
"""Wrapper function for OpenJij solver"""
return oj_ad.OMMXOpenJijSAAdapter.solve(
instance, num_sweeps=num_sweeps, seed=seed
)
# Wrap the solver function to automatically log parameters and execution time
wrapped_solver = run.log_solver(
"OpenJij_SA",
solve_with_openjij,
exclude_params=["seed"], # Exclude seed from logging if desired
)
# Execute solver with automatic parameter and timing logging
solution2 = wrapped_solver(instance=instance, num_sweeps=1500, seed=42)
run.log_solution(solution2)
exp.finish_experiment()4. Multiple Run Execution¶
Let’s execute multiple runs and verify the hierarchical log display.
# Parameter sweep experiment
exp = minto.Experiment(
name="parameter_sweep",
verbose_logging=True,
auto_saving=False,
collect_environment=False,
)
# Execute with different temperature parameters
temperatures = [0.1, 0.5, 1.0, 2.0]
for i, temp in enumerate(temperatures):
run = exp.run()
with run:
run.log_parameter("temperature", temp)
run.log_parameter("algorithm", "Simulated Annealing")
run.log_parameter("max_iterations", 1000)
# Execute dummy optimization
time.sleep(0.05) # Simulate computation time
# Simulate results based on temperature
import random
energy = random.uniform(-100, -50) * (1 + temp)
run.log_parameter("final_energy", energy)
exp.finish_experiment()5. Using Global Configuration¶
Let’s learn how to set global log configuration and share it across multiple experiments.
from minto.logger import configure_logging, get_logger
# Global log configuration
configure_logging(
enabled=True,
level=LogLevel.INFO,
show_timestamps=True,
show_icons=True,
show_colors=False, # For Jupyter environments
)
print("=== Experiment 1 using Global Configuration ===")
exp1 = minto.Experiment(
name="global_config_exp1",
verbose_logging=True, # Global configuration is automatically applied
auto_saving=False,
collect_environment=False,
)
run = exp1.run()
with run:
run.log_parameter("method", "Genetic Algorithm")
run.log_parameter("population_size", 100)
exp1.finish_experiment()
print("\n=== Experiment 2 using Global Configuration ===")
exp2 = minto.Experiment(
name="global_config_exp2",
verbose_logging=True, # Same global configuration is applied
auto_saving=False,
collect_environment=False,
)
run = exp2.run()
with run:
run.log_parameter("method", "Particle Swarm Optimization")
run.log_parameter("swarm_size", 50)
exp2.finish_experiment()6. Direct Logger Usage¶
Let’s also check how to use the logger directly without the Experiment/Run classes.
# Get the global logger
logger = get_logger()
print("=== Direct Logger Usage ===")
# Manual experiment logging
logger.log_experiment_start("manual_experiment")
# Manual run logging
logger.log_run_start(0)
logger.log_parameter("manual_param", "direct_logging")
logger.log_object("custom_object", {"type": "manual", "value": 42})
# Log solver execution
logger.log_solver("manual_solver", execution_time=1.5)
# End run and experiment
logger.log_run_end(0, 2.0)
logger.log_experiment_end("manual_experiment", 2.0, 1)7. Environment-Specific Configuration Examples¶
Let’s check recommended configurations for different environments (development, production, CI).
# Development environment configuration
dev_config = LogConfig(
level=LogLevel.DEBUG,
format=LogFormat.DETAILED,
show_timestamps=True,
show_icons=True,
show_colors=False, # For Jupyter
max_parameter_length=300, # Allow longer parameter values in development
)
print("=== Development Environment Configuration ===")
exp_dev = minto.Experiment(
name="development_test",
verbose_logging=True,
log_config=dev_config,
auto_saving=False,
collect_environment=False,
)
run = exp_dev.run()
with run:
run.log_parameter("debug_mode", True)
run.log_parameter("verbose_output", True)
exp_dev.finish_experiment()
# Production environment configuration
prod_config = LogConfig(
level=LogLevel.WARNING,
format=LogFormat.MINIMAL, # Use MINIMAL instead of COMPACT
show_timestamps=True,
show_icons=False,
show_colors=False,
max_parameter_length=50, # Limit parameter length in production
)
print("\n=== Production Environment Configuration ===")
exp_prod = minto.Experiment(
name="production_test",
verbose_logging=True,
log_config=prod_config,
auto_saving=False,
collect_environment=False,
)
run = exp_prod.run()
with run:
run.log_parameter("production_mode", True)
# Only WARNING level and above are displayed, so normal parameter logs won't be shown
exp_prod.finish_experiment()8. Disabling Logging¶
Set just the verbose_logging parameter to False to disable logging for an individual experiment.
# Method 1: Disable logging for individual experiments
print("=== Method 1: Disable logging for individual experiments ===")
exp_no_log = minto.Experiment(
name="no_logging_experiment",
verbose_logging=False, # Disable logging for this experiment
auto_saving=False,
collect_environment=False,
)
run = exp_no_log.run()
with run:
# These log calls will not produce any output
run.log_parameter("param1", "value1")
run.log_parameter("param2", 42)
print("Parameters logged, but no log output shown")
exp_no_log.finish_experiment()Summary¶
In this tutorial, we learned about the Minto library’s logging functionality:
Basic Log Output: Easy logging activation with
verbose_logging=TrueCustom Configuration: Detailed control of log display using
LogConfigSolver Logging: Automatic logging of solver execution with
log_solverHierarchical Display: Clear hierarchical structure for multiple runs
Global Configuration: Batch configuration with
configure_loggingDirect Logger: Flexible control with low-level APIs
Environment Adaptation: Optimization for development and production environments
By utilizing these features, you can efficiently monitor experiment progress and significantly improve debugging and optimization work.