<代码分享> 分支定界算法的 Python 代码框架

news2024/11/17 3:42:57

本文以求解整数规划模型为例,提供分支定界算法的 Python 代码框架,期待完善、指正和交流。


文件结构


文件结构


具体代码


problem.py


定义问题的格式:

from typing import List


class Problem(object):
    """
    problem
    """
    def __init__(self, problem_type: str, 
                 num_var: int, mat_cons: List[List[int or float]], obj_coef: List[int or float]) -> None:
        """
        initialise
        
        :param problem_type:  problem type
        :param num_var:  number of variables
        :param mat_cons:  constraint coefficients matrix
        :param obj_coef:  objective coefficients list
        """

        self.problem_type = problem_type
        
        self.num_var = num_var
        self.mat_cons = mat_cons
        self.obj_coef = obj_coef


solver.py


定义问题求解模块的基类:

from algorithm.problem import Problem


class Solver(object):
    """
    problem solver
    """
    def __init__(self, problem: Problem) -> None:
        """
        initialise
        
        :param problem:  problem to solve
        """
        
        self.num_var = problem.num_var
        self.mat_cons = problem.mat_cons
        self.obj_coef = problem.obj_coef

        # solution status
        self.status = 'empty'  # {'empty', 'invalid', 'optimal', 'feasible', 'infeasible', 'fail'}
        self.obj = None
        self.solution = []

    def _is_valid(self) -> bool:
        return True

    def solve(self):
        pass


solver_lp.py


继承求解模块基类,针对线性规划问题,编写调用 OR-Tools GLOP 求解器的求解模块子类:

from datetime import datetime

import rich
from ortools.linear_solver import pywraplp

from config import ACCURACY
from algorithm.solver import Solver
from algorithm.problem import Problem


class SolverLP(Solver):
    """
    problem solver, LP model
    """
    def __init__(self, problem: Problem) -> None:
        """
        initialise
        
        :param problem:  problem to solve
        """

        super().__init__(problem)

    def _is_valid(self) -> bool:
        """
        check model format

        :return:  if model valid
        """

        # constraint coefficient lists
        for i in range(len(self.mat_cons)):
            cons = self.mat_cons[i]

            # coefficients list length
            if len(cons) != self.num_var + 2:
                rich.print(f"Constraint {i} length {len(cons)} invalid, need to be {self.num_var} + 2")
                return False
            
        # objective coefficients list length
        if len(self.obj_coef) != self.num_var + 1:
            rich.print(
                f"Objective coefficients list length {len(self.obj_coef)} invalid, need to be {self.num_var} + 1")
            return False
        
        return True

    def solve(self):
        """
        solving
        """

        if not self._is_valid():
            self.status = 'invalid'
            return
        
        solver = pywraplp.Solver("lp", problem_type=pywraplp.Solver.GLOP_LINEAR_PROGRAMMING)
        
        x = [solver.NumVar(0, solver.infinity(), 'x_{}'.format(i)) for i in range(self.num_var)]

        # constraints
        for cons in self.mat_cons:
            exp = 0
            for j in range(len(cons[: -2])):
                exp += cons[j] * x[j]
            sign, b = cons[-2], cons[-1]
            
            # index -2 coefficient: negative for <=; 0 for ==; positive for >=
            if sign < 0:
                solver.Add(exp <= b)
            elif sign == 0:
                solver.Add(exp == b)
            else:
                solver.Add(exp >= b)

        # objective
        obj = 0
        for j in range(len(self.obj_coef[: -1])):
            obj += self.obj_coef[j] * x[j]
        # index -1 coefficient: positive for maximise; otherwise minimise
        solver.Minimize(obj) if self.obj_coef[-1] <= 0 else solver.Maximize(obj)

        # solve
        dts = datetime.now()
        status = solver.Solve()
        dte = datetime.now()
        tm = round((dte - dts).seconds + (dte - dts).microseconds / (10 ** 6), 3)
        rich.print(f"LP model solving time:  {tm} s")

        # result
        if status == pywraplp.Solver.OPTIMAL:
            self.status = 'optimal'
            self.obj = solver.Objective().Value()
            self.solution = [x[i].solution_value() for i in range(self.num_var)]
            rich.print(f"objective value:  {self.obj}")
            rich.print(f"solution:  {[round(x, ACCURACY) for x in self.solution]}")
        elif status == pywraplp.Solver.FEASIBLE:
            self.status = 'feasible'
            rich.print(f"Didn't get an optimal solution, but a feasible one.")
        elif status == pywraplp.Solver.INFEASIBLE:
            self.status = 'infeasible'
            rich.print(f"The problem does not have a feasible solution.")
        else:
            self.status = 'fail'
            rich.print(f"Failed to solving problem for an unknown reason.")


node.py


分支定界算法的节点模块:

from typing import List
import copy

from config import PROBLEM_TYPES, INSTANCE, ACCURACY
from algorithm.problem import Problem
from algorithm.solver_lp import SolverLP


class Node(object):
    """
    branch and bound node
    """
    def __init__(self, id: int, father: int or None, new_cons: List[int or float]) -> None:
        """
        initialise
        
        :param id:  node ID
        :param father:  father node ID, None for root
        :param id:  new constraits other than father node's constraints
        """

        self.problem: Problem = copy.deepcopy(INSTANCE)
        self.problem_type = self.problem.problem_type
        self.num_var, self.mat_cons, self.obj_coef = self.problem.num_var, self.problem.mat_cons, self.problem.obj_coef
        
        # check problem type
        if self.problem_type not in PROBLEM_TYPES:
            raise Exception(f"Problem type {self.problem_type} invalid!")
        
        self.id = id

        self.father = father
        self.new_cons = new_cons

        self.depth = None

        # solution
        self.status = 'empty'  # {'empty', 'feasible', 'relax', 'infeasible'}
        self.obj = None
        self.solution = []
        self.infeasible_list = []

    def add_ancestor_cons(self, ancestor_cons: List[List[int or float]]):
        """
        initialise
        
        :param ancestor_cons:  constraints from ancestors
        """

        self.mat_cons += ancestor_cons

    def solve(self):
        """
        solve problem
        """

        # add new constraint
        if self.new_cons:
            self.mat_cons.append(self.new_cons)

        solver = SolverLP(problem=self.problem)
        solver.solve()

        status, self.obj, self.solution = solver.status, solver.obj, solver.solution
        if status in {'optimal', 'feasible'}:
            self._check_solution()
            self.status = 'feasible' if not self.infeasible_list else 'relax'
        else:
            self.status = 'infeasible'

    def _check_solution(self):
        """
        check if solution valid
        """

        if self.problem_type == 'IP':
            self._check_integer()
        else:
            pass

    def _check_integer(self):
        """
        check if all solutions are integers
        """

        for i in range(len(self.solution)):
            x = self.solution[i]
            if round(x, ACCURACY) != round(x):
                self.infeasible_list.append((i, x))


algorithm.py


分支定界算法的算法模块,要点:

  • 每得到一个可行解,更新最优可行解(incumbent)
  • 每完成一次分支(所有子节点求解完毕),更新全局的界(bound)

import datetime
from typing import List, Dict
import math

import rich

from config import PROBLEM_TYPES, INSTANCE, ACCURACY
from algorithm.problem import Problem
from algorithm.node import Node


class BranchAndBound(object):
    """
    branch and bound algorithm
    """
    def __init__(self, time_limit: int or float = 3600, gap_upper: float = 0) -> None:
        """
        initialise
        
        :param time_limit:  time limit of solving
        :param gap_upper:  upper bound of gap of solving
        """

        self.problem: Problem = INSTANCE
        self.problem_type = self.problem.problem_type
        self.num_var, self.mat_cons, self.obj_coef = self.problem.num_var, self.problem.mat_cons, self.problem.obj_coef
        
        # check problem type
        if self.problem_type not in PROBLEM_TYPES:
            raise Exception(f"Problem type {self.problem_type} invalid!")

        # optimising direction
        self.opt_dir = 'min' if self.obj_coef[-1] <= 0 else 'max'

        # solving params
        self.time_limit = time_limit
        self.gap_upper = gap_upper
        self.dt_start, self.dt_end = datetime.datetime.now(), None
        self.final_time_cost = None
        self.final_gap = None

        # nodes
        self.idx_acc = 0
        self.nodes: Dict[int, Node] = {}  # all nodes, key: ID
        self.leaf_nodes: List[int] = []  # node ID

        # solution status
        self.status = 'empty'  # {'empty', 'optimal', 'feasible', 'infeasible', 'fail'}
        self.solution = None
        self.incumbent, self.incumbent_node = None, None  # update once feasible solution found
        self.bound, self.bound_node = None, None  # update once leaf nodes updated

    @property
    def time_cost(self) -> float:
        """
        get time cost
        """

        dt_end = datetime.datetime.now()
        tm_delta: datetime.timedelta = dt_end - self.dt_start
        return round(tm_delta.seconds + tm_delta.microseconds / 1e6, 6)

    @property
    def reach_time_limit(self) -> bool:
        """
        check if reach time limit
        """

        return self.time_cost >= self.time_limit
    
    @property
    def gap(self) -> bool:
        """
        calculate current gap
        """

        # case 1: searched all nodes
        if self.bound_node not in self.leaf_nodes:
            return 0
        
        # case 2: catched both incumbent and bound
        elif self.bound is not None and self.incumbent is not None:
            return abs(self.bound - self.incumbent) / abs(self.incumbent)
        
        else:
            return None
    
    @property
    def reach_accuracy(self) -> bool:
        """
        check if gap reach accuracy
        """

        return True if self.gap is not None and self.gap <= self.gap_upper else False

    def run(self):
        """
        algorithm main process
        """

        self.dt_start = datetime.datetime.now()

        # root node and solve
        node_index = self.idx_acc
        self.idx_acc += 1
        node = Node(id=node_index, father=None, new_cons=[])
        node.depth = 0
        self.nodes[node_index] = node
        rich.print(f"Solving node {node_index}")
        node.solve()

        # special case 1: root node feasible
        if node.status == 'feasible':
            self.solution = node.solution
            self.status = 'optimal'
            return

        # special case 2: root node infeasible
        elif node.status == 'infeasible':
            self.status = 'infeasible'
            return
        
        # update leaf nodes and bound
        self.leaf_nodes.append(node.id)
        self._update_bound()
        rich.print()

        # main circulation
        node_index = self._select_node()
        while node_index is not None:  # attention: don't use "while node_index" because the index can be 0
            # branch and get new leaf nodes
            is_terminated = self._branch(node_index=node_index)

            # check termination
            if is_terminated:
                self.final_time_cost = self.time_cost
                self.final_gap = self.gap
                rich.print(f"final time cost:  {self.final_time_cost}")
                rich.print(f"final gap:  {self.final_gap}")
                return

            # select node to branch
            node_index = self._select_node()
            rich.print()

        # all nodes searched
        self.final_gap = self.gap
        if self.incumbent_node is not None:
            self.solution = self.nodes[self.incumbent_node].solution
            self.status = 'optimal' if self.final_gap == 0 else 'feasible'
        else:
            self.status = 'ineasible'
        self.final_time_cost = self.time_cost
        rich.print(f"final time cost:  {round(self.final_time_cost, 3)} s")
        rich.print(f"final gap:  {self.final_gap}")
        rich.print(f"total nodes:  {len(self.nodes)}")
        rich.print(f"maximal node depth:  {max(self.nodes[i].depth for i in self.nodes)}")
        rich.print()

    def _select_node(self) -> int or None:  # TODO: node selection strategy: bound node
        """
        node selection

        :return:  selected node index
        """

        # have updated bound before
        return self.bound_node if self.bound_node in self.leaf_nodes else None

    def _branch(self, node_index: int) -> bool:
        """
        branching
        
        :param node_index:  father node index

        :return:  if algorithm terminates
        """

        node = self.nodes[node_index]

        list_new_cons = self._get_new_constraints(node_index=node_index)
        for cons in list_new_cons:
            # new node
            node_index_new = self.idx_acc
            self.idx_acc += 1
            node_new = Node(id=node_index_new, father=node.id, new_cons=cons)
            node_new.depth = node.depth + 1
            self.nodes[node_index_new] = node_new

            # inherit constraints from ancestors
            ancestor_cons = []
            node_new_ = node_new
            while node_new_.father:
                ancestor_cons.append(self.nodes[node_new_.father].new_cons)
                node_new_ = self.nodes[node_new_.father]
            node_new.add_ancestor_cons(ancestor_cons=ancestor_cons)

            # solve node and check incumbent
            rich.print(f"Solving node {node_index_new}")
            rich.print(f"new constraint coefficients:  {cons}")
            node_new.solve()
            rich.print(f"node status:  {node_new.status}")
            if node_new.status == 'feasible':
                incumbent_updated = self._update_incumbent(feasible_node=node_index_new)
                
                # update incumbent and check accuracy
                if incumbent_updated:
                    if self.reach_accuracy:
                        rich.print(
                            f"Gap {self.gap} reach accuracy {self.gap_upper}, bound {round(self.bound, ACCURACY)}")

                        self.solution = self.nodes[self.incumbent_node].solution
                        self.status = 'optimal' if self.gap == 0 else 'feasible'
                        return True
                
            # check time limit
            if self.reach_time_limit:
                rich.print(f"Time limit reached!")

                if self.incumbent_node is not None:
                    self.solution = self.nodes[self.incumbent_node].solution
                    self.status = 'optimal' if self.gap == 0 else 'feasible'
                else:
                    rich.print(f"Didn't find a feasible solution within time limit!")
                    self.status = 'fail'

                return True
                
            # add new leaf node
            if node_new.status == 'relax':
                self.leaf_nodes.append(node_index_new)
            rich.print()
                
        # remove old leaf node
        self.leaf_nodes.remove(node_index)
        
        # update bound and check accuracy
        bound_updated = self._update_bound()
        if bound_updated:
            if self.reach_accuracy:
                rich.print(
                    f"Gap {self.gap} reach accuracy {self.gap_upper}, incumbent {round(self.incumbent, ACCURACY)}")
                rich.print()

                self.solution = self.nodes[self.incumbent_node].solution
                self.status = 'optimal' if self.gap == 0 else 'feasible'

                return True

        return False

    def _get_new_constraints(self, node_index: int) -> List[List[float or int]]:  # TODO: branching strategy: index-based
        """
        get new constraints for node branching
        
        :param node_index:  branching node

        :return:  new constraints list
        """

        node = self.nodes[node_index]

        if self.problem_type == 'IP':
            idx_infeasible, infeasible_solution = node.infeasible_list[0]
            new_cons_1 = [1 if i == idx_infeasible else 0 for i in range(self.num_var)] + [
                -1, math.floor(infeasible_solution)]
            new_cons_2 = [1 if i == idx_infeasible else 0 for i in range(self.num_var)] + [
                1, math.ceil(infeasible_solution)]

            return [new_cons_1, new_cons_2]

        else:
            pass

    def _update_incumbent(self, feasible_node: int) -> bool:
        """
        update global feasible solution
        
        :param feasible_node:  index of new feasible node

        :return:  if incumbent updated
        """

        node = self.nodes[feasible_node]

        # get a feasible solution firstly
        if self.incumbent is None:
            self.incumbent, self.incumbent_node = node.obj, feasible_node
            rich.print(f"Get new incumbent {round(self.incumbent, ACCURACY)} from node {self.incumbent_node}")
            return True
        
        # get a better feasible solution
        elif (self.opt_dir == 'min' and node.obj < self.incumbent) or (
            self.opt_dir == 'max' and node.obj > self.incumbent):
            self.incumbent, self.incumbent_node = node.obj, feasible_node
            rich.print(f"Get new incumbent {round(self.incumbent, ACCURACY)} from node {self.incumbent_node}")
            return True
        
        return False
    
    def _update_bound(self) -> bool:
        """
        update global bound

        :return:  if bound updated
        """

        bound, bound_node = None, None
        for node_idx in self.leaf_nodes:
            node = self.nodes[node_idx]
            if node.status == 'relax':
                if bound is None:
                    bound, bound_node = node.obj, node_idx
                elif (self.opt_dir == 'min' and node.obj < bound) or (
                    self.opt_dir == 'max' and node.obj > bound):
                    bound, bound_node = node.obj, node_idx

        if bound is not None:
            self.bound, self.bound_node = bound, bound_node
            rich.print(f"Get new bound {round(self.bound, ACCURACY)} from node {self.bound_node}")
            return True
        
        return False


cases.py


基于前面定义的问题格式,提供两个整数规划算例:

一个简单算例:
简单算例

一个 NP 算例:
分支定界算法的 NP 算例

from algorithm.problem import Problem


CASES = {}


"""
IP: simple
"""

num_var = 2
mat_cons = [
    [1, 1, -1, 5], 
    [10, 6, -1, 45]
]
var_range = [
    [1, 0, 1, 0], 
    [0, 1, 1, 0]
]
mat_cons += var_range
obj_coef = [5, 4, 1]

CASES['IP-simple'] = Problem(problem_type='IP', num_var=num_var, mat_cons=mat_cons, obj_coef=obj_coef)


"""
IP: NP-hard
"""

num_var = 16
mat_cons = [[2 for _ in range(num_var - 1)] + [1] + [0] + [15]]
var_range = [
    [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [1] + [0], 
    [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [1] + [0], 
    [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [1] + [0], 
    [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [1] + [0], 
    [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [1] + [0], 
    [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [1] + [0], 
    [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [1] + [0], 
    [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0] + [1] + [0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0] + [1] + [0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0] + [1] + [0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0] + [1] + [0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0] + [1] + [0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0] + [1] + [0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0] + [1] + [0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0] + [1] + [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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [-1] + [1], 
    [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [-1] + [1], 
    [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [-1] + [1], 
    [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [-1] + [1], 
    [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [-1] + [1], 
    [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [-1] + [1], 
    [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [-1] + [1], 
    [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0] + [-1] + [1], 
    [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0] + [-1] + [1], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0] + [-1] + [1], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0] + [-1] + [1], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0] + [-1] + [1], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0] + [-1] + [1], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0] + [-1] + [1], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0] + [-1] + [1], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] + [-1] + [1],
]
mat_cons += var_range
obj_coef = [0 for _ in range(num_var - 1)] + [1] + [-1]

CASES['IP-NP-hard'] = Problem(problem_type='IP', num_var=num_var, mat_cons=mat_cons, obj_coef=obj_coef)


config.py


根目录下的配置文件,含算例选取、算法精确度等全局变量:

from algorithm.cases import CASES


PROBLEM_TYPES = {'IP'}  # TODO: only support IP model so far

# INSTANCE = CASES['IP-simple']
INSTANCE = CASES['IP-NP-hard']

ACCURACY = 3  # 0.001


main.py


主程序:

import rich

from config import ACCURACY
from algorithm.algorithm import BranchAndBound


rich.print()
branch_and_bound = BranchAndBound(time_limit=300, gap_upper=0)
branch_and_bound.run()

status = branch_and_bound.status
solution = [round(x, ACCURACY) for x in branch_and_bound.solution]
optimal_obj = branch_and_bound.incumbent
rich.print(f"algorithm final status:  {status}")
rich.print(f"algorithm final solution:  {solution}")
rich.print(f"algorithm final objective value:  {optimal_obj}")
rich.print()



算例运行效果


简单算例


简单算例效果

简单算例的流程图

NP 算例


NP 算例效果


展望


本文原本致力于写一个朴素的适用于各类问题的分支定界算法框架,其实也就是玩玩,但由于精力有限,只完成了求解整数规划问题的部分,并且算法内部的具体策略较为简单,因此对更多的功能实现做出一点展望,期望完善、指正和交流:

  • 更丰富的分支策略:本文代码选用所有不可行约束中序号最小的进行分支
  • 更丰富的节点选择策略:本文代码选择了叶子节点中的界(bound)节点进行下一深度的搜索
  • 更夫妇的问题类型:如使用分支定界算法求解 TSP、CBS(conflict-based search)、branch-and-price 等问题,当然,当前框架不一定可行或合理,期待更好的实现方法
  • 引入有效割:提升算法性能

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/503570.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OneAPI 编译cp2k 9.1和cp2k 2023.1

环境信息&#xff1a; Rocky Linux 8.6 Linux server 4.18.0-425.19.2.el8_7.x86_64 gcc version 8.5.0 20210514 (Red Hat 8.5.0-16) (GCC) OneAPI 2023 Intel(R) oneAPI DPC/C Compiler 2023.0.0 (2023.0.0.20221201) ifort version 2021.8.0 一、编译cp2k 9.1 这里用的…

linux系统下常用软件的安装与操作实现

本文来介绍下如何在 Linux 上安装 Windows 上常用的软件&#xff0c;桌面更多的用的是 Ubuntu &#xff0c;下面就以 Ubuntu 为例。 目录 一、安装环境 二、安装步骤 三、总结 一、安装环境 本文使用的安装环境&#xff0c;如下所示&#xff1a; linuxylinuxy:~$ cat /proc…

【Python】【进阶篇】25、Django for标签详解

目录 25、Django for标签详解1. for标签的使用2. for标签嵌套使用3. forloop变量详解 25、Django for标签详解 通过上一节的《Django if标签详解》的讲解&#xff0c;我相信大家对于模板标签已经不再陌生&#xff0c;在本节我们再给大家隆重介绍一位最熟悉的陌生人&#xff0c…

如何熟练的使用trtexec

目录 如何熟练的使用trtexec前言1. 参数解释1.1 Model Options1.2 Build Options1.3 Inference Options1.4 Reporting Options1.5 System Options1.6 完整的参数 如何熟练的使用trtexec 前言 杜老师推出的 trtexec 工具的使用课程&#xff0c;链接。记录下个人学习笔记&#x…

禁止Windows更新自动安装驱动程序

禁止Windows更新自动安装驱动程序 问题解决方案方案1&#xff1a;修改系统设置方案2&#xff1a;修改组策略方案3&#xff1a;修改注册表方案4&#xff1a;回退驱动 问题 Windows更新时&#xff0c;会自动更新驱动程序&#xff0c;甚至有时会将驱动程序反向更新&#xff0c;替…

使用 webdriver API 编写自动化脚本的基本语法

文章目录 1. 打开和关闭浏览器1&#xff09;打开浏览器并访问 URL2&#xff09;关闭浏览器窗口 2. 元素的定位1&#xff09;以 id 定位元素2&#xff09;以 name 定位元素3&#xff09;以 tag name 定位元素4&#xff09;以 class name 定位元素5&#xff09;以 xpath 定位元素…

第九章 控制单元的功能课后习题

指令周期有四个阶段&#xff1a;取值 间址 执行 中断 &#xff0c;控制单元为了完成不同指令会发出不同的操作命令&#xff0c;这些操作信号控制着计算机所有部件有次序的完成不同的操作&#xff0c;以达到执行程序的目的。 控制单元的外特性 9.2控制单元的功能是什么?其输入…

【Java+GS】GeoServer——使用Java发布图层(SHP文件和DB数据库),附自用工具类

文章目录 SHP文件发布逻辑 1、获取到geoserver的manager对象2、调用createWorkArea方法&#xff0c;参入manager&#xff0c;创建空间空间 workArea3、调用createShpDataPool方法&#xff0c;创建数据存储4、发布样式Style.5、发布图层 调用业务层库发布shp文件图层业务逻辑如下…

【致敬未来的攻城狮计划】— 连续打卡第二十五天:RA2E1的 DTC传输模式

系列文章目录 由于一些特殊原因&#xff1a; 系列文章链接&#xff1a;&#xff08;其他系列文章&#xff0c;请点击链接&#xff0c;可以跳转到其他系列文章&#xff09; 24.RA2E1的 DMAC——数据传输 文章目录 系列文章目录 前言 一、DTC是什么&#xff1f; 二、DTC内部寄存…

Springboot——集成Elastic Job实现任务调度

目录 1.任务调度 2.Elastic Job 3.springboot集成Elastic Job 1.任务调度 什么是任务调度&#xff1f; 任务调度就是指系统为了自动地完成特定任务&#xff0c;在指定的时刻去执行任务的过程&#xff0c;其目的是为了让系统自动且精确地完成任务从而解放人力资源。 如&am…

WX小程序 - 1

视图层&#xff1a;WXML&#xff0c;WXSS 逻辑层&#xff1a;JS 响应数据绑定&#xff0c;事件绑定 勾选这个其实就是解决跨域问题&#xff08;仅限本地开发阶段&#xff09;。 上线需要去合法域名添加。 app.json 文件创建和删除&#xff0c;保持一致&#xff0c;否则报错…

二叉树的层序遍历思想模板

分为两种&#xff1a; 1.第一种是直接将遍历的数据保存到列表里&#xff1b; 2.第二种是将每一层的数据以列表形式保存在列表&#xff1b;&#xff08;今天要讲述的内容&#xff09; 代码如下&#xff0c;思想在后 class Solution {public List<List<Integer>> …

全新 – Amazon EC2 R6a 实例由第三代 AMD EPYC 处理器提供支持,适用于内存密集型工作负载

我们在 Amazon re:Invent 2021 上推出了通用型 Amazon EC2 M6a 实例&#xff0c;并于今年 2 月推出了计算密集型 C6a 实例。这些实例由运行频率高达 3.6 GHz 的第三代 AMD EPYC 处理器提供支持&#xff0c;与上一代实例相比&#xff0c;性价比提高多达 35%。 如今&#xff0c;…

不断联的从Google Drive下载超大文件

不断联的从Google Drive下载超大文件 最近在研究OWOD代码&#xff0c;需要从google drive 下载超大文件&#xff0c;普通方式下载&#xff0c;首先得有个上外网的工具&#xff0c;其次下载过程中总是会断开&#xff0c;所以看了一些博客&#xff0c;总结如下&#xff1a; 安…

基于TINY4412的Andorid开发-------简单的LED灯控制【转】

基于TINY4412的Andorid开发-------简单的LED灯控制 阅读目录(Content) 一、编写驱动程序二、编写代码测试驱动程序三、编写HAL代码四、编写Framework代码五、编写JNI代码六、编写App 参考资料&#xff1a; 《Andriod系统源代码情景分析》 《嵌入式Linux系统开发完全手册_基…

实时语义分割PIDNet算法TensorRT转换

[PIDNet](GitHub - XuJiacong/PIDNet: This is the official repository for our recent work: PIDNet) 是22年新开源的实时语义分割算法&#xff0c;和DDRNet一样具有不错的性能 网络结构如下&#xff1a; 网络分为三个分支&#xff0c;如上图&#xff0c;整体结构和DDRNet比…

shell 脚本中的函数

目录 一. shell 函数作用&#xff1a;二. shell 函数的定义格式&#xff1a;三.函数返回值&#xff1a;四.函数传参&#xff1a;扩展&#xff1a; 六. 函数变量的作用范围:七 . 递归7.1阶乘 八. 函数库 一. shell 函数作用&#xff1a; 使用函数可以避免代码的重复 使用函数可以…

OJ刷题 第十五篇(递推较多,奥赛篇)

31005 - 昆虫繁殖&#xff08;难度非常大&#xff0c;信息奥赛题&#xff09; 时间限制 : 1 秒 内存限制 : 128 MB 科学家在热带森林中发现了一种特殊的昆虫&#xff0c;这种昆虫的繁殖能力很强。每对成虫过x个月产y对卵&#xff0c;每对卵要过两个月长成成虫。假设每个成虫…

从零开始 Spring Boot 27:IoC

从零开始 Spring Boot 27&#xff1a;IoC 自从开始学习和从事Spring Boot开发以来&#xff0c;一个一直让我很迷惑的问题是IoC和Bean到底是什么东西。这个问题一直到我翻阅完Spring开发文档Core Technologies (spring.io)后才真正得到解惑。 虽然中文互联网上关于IoC的文章很多…

基于AT89C51单片机的电子琴设计与仿真

点击链接获取Keil源码与Project Backups仿真图&#xff1a; https://download.csdn.net/download/qq_64505944/87765092?spm1001.2014.3001.5503 源码获取 运用单片机&#xff0c;将音乐的大部分音符与相应按键相匹配&#xff0c;让音乐爱好者利用单片机也可以进行演奏。 基…