shaders – Tree batching problem in Unity

I have some problems with batching trees.
I’m using the default unity terrain system and trees.
My problem is that trees won’t get batched together (I’ve set up static, dynamic, and GPU instancing) and as I’ve inspected the frame debugger I’ve come to these results:

What causes distinct draw call:

1- Wind

2- color and size variations for trees

draw call reason:
non instanced properties set for instanced shader

if I remove Wind or variations the GPU instancing would work (I don’t want to remove wind and variations), Is there any way to batch trees in this case?

Traversing an acyclic binary tree to construct paths from a given starting node, but the paths come out wrong

The tree is an acyclic binary tree. It’s composed of node objects that have a list of connections to link objects (at most 3), and link objects that have a list of connections to node objects (always 2). I am trying to construct a list of possible paths to other nodes that can be reached given a fuel budget and a fuel cost on each link. What it is supposed to do is go through each non-backtracking connection of a node, and spawn a new route and thread to investigate that, leaving the current one to end at that node and thus create a list of routes to every node in the reachable area. When executed, the list of end destinations are valid but many of the paths that are constructed to get to them are wrong, going down other branches in the tree that are extraneous or entirely outside of the reachable area bounded by the fuel budget as well as jumping between nodes that aren’t directly connected. There seems to be some pattern in the errors, when going down from the root of some branches of the tree the path goes down every offshoot in order first instead of going in a straight line, and when going up the tree the path tends to go further out and make triangle shapes, often landing somewhere other than the listed destination. I have already checked the link and node connections themselves to see if they are assigned properly, and they are. What am I getting wrong?

Route class definition

var origin:Node
var destination:Node
var totaldV:float
var totalt:float
var dVBudget:float
var tBudget:float
var tdVRatio:float
var links:Array
var nodes:Array

func duplicate_values(originator:Route):
    origin = originator.origin
    destination = originator.destination
    totaldV = originator.totaldV
    totalt = originator.totalt
    dVBudget = originator.dVBudget
    tBudget = originator.tBudget
    tdVRatio = originator.tdVRatio
    nodes = originator.nodes
    links = originator.links


func _init(originator_route):
    if originator_route != null:
        duplicate_values(originator_route)

Tree traversal algorithm

var routes:Array
onready var root = get_node("..")

func traverse(current_node:Node, previous_route:Route):
    if previous_route == null:                             # Starts off the recursion by providing an initial node
        previous_route = Route.new(null)
        previous_route.origin = current_node
        previous_route.nodes.append(previous_route.origin)
        previous_route.dVBudget = 2000
        previous_route.totaldV = 0
    for link in current_node.connections:
        if (previous_route.totaldV + link.dV < previous_route.dVBudget && 
        !IsBacktracking(previous_route, LinkDestination(link, current_node))):   # If there is enough fuel and the link isn't backtracking, go through it.
            var working_route:Route = Route.new(previous_route)    # Copy the previous route to make the new route
            routes.append(working_route)
            working_route.destination = LinkDestination(link, current_node)
            working_route.totaldV += link.dV
            working_route.totalt += link.t
            working_route.links.append(link)
            working_route.nodes.append(working_route.destination)
            traverse(working_route.destination, working_route)
    DisplayRoutes()
    root.get_parent().pathSelectionFlag = true   # UI control boolean


func IsBacktracking(route:Route, destinationNode:Node) -> bool:
    for nodeI in route.nodes:
        if (destinationNode == nodeI):
            return true
    return false


func LinkDestination(link:Node, originNode:Node) -> Node:    # Finds the node on the other side of a link
    for nodeI in link.connections:
        if (nodeI != originNode):
            return nodeI
    return originNode

algorithms – Translating the in-order index of a node in a complete, balanced binary tree into the level-order index

Consider the topmost part of a complete, balanced binary tree of all 64-bit numbers, exemplified here.
As highlighted by the lack of a 7*2^64/8 term it is not necessarily full, but it is always complete. The nodes are stored in numerical order (in-order) in a list of which I know the size, and I have the index (call it the in-order index) of a node in that sorted list.

I’m trying to get the index (call it level-order index) of that same node if the array was stored according to the breadth-first traversal order (level-order) of the tree instead. In the example, the tree root would have level-order index 0 and in-order index 3.

What I’ve found already is that the level-order index consists of two parts:

  • A base part which is the amount of nodes contained in the full tree above the level in which the node resides.
  • An offset part which is the amount of nodes to the left of this node in the level in which it is contained.

Summed together, they produce the level-order index.

I’ve been able to solve this for the full tree case, as then the level at which a node is contained is the number of times its in-order index + 1 is divisible by 2. However, for the general case in which the tree is not necessarily full, how would that base part be calculated from the in-order index?

Of course, it is possible by iterating the tree programmatically, but since the exact layout and contents of the entire tree are known simply from the amount of nodes that it contains, I was wondering whether a mathematical relation between these two indices holds. Does anyone have an idea?

performance – Monte Carlo Tree Search Optimization and Loss Prevention

I’m working on a implementation of Monte Carlo Tree Search in Swift.

It’s not bad, but it could be better! I’m principally interested in making my algorithm:

  1. faster (more iterations/second)
  2. prioritize moves that prevent instant losses (you’ll see…)

Here is the main driver:

final class MonteCarloTreeSearch {
    var player: Player
    var timeBudget: Double
    var maxDepth: Int
    var explorationConstant: Double
    var root: Node?
    var iterations: Int

    init(for player: Player, timeBudget: Double = 5, maxDepth: Int = 5, explorationConstant: Double = sqrt(2)) {
        self.player = player
        self.timeBudget = timeBudget
        self.maxDepth = maxDepth
        self.explorationConstant = explorationConstant
        self.iterations = 0
    }
    
    func update(with game: Game) {
        if let newRoot = findNode(for: game) {
            newRoot.parent = nil
            newRoot.move = nil
            root = newRoot
        } else {
            root = Node(game: game)
        }
    }

    func findMove(for game: Game? = nil) -> Move? {
        iterations = 0
        let start = CFAbsoluteTimeGetCurrent()
        if let game = game {
            update(with: game)
        }
        while CFAbsoluteTimeGetCurrent() - start < timeBudget {
            refine()
            iterations += 1
        }
        print("Iterations: (iterations)")
        return bestMove
    }
    
    private func refine() {
        let leafNode = root!.select(explorationConstant)
        let value = rollout(leafNode)
        leafNode.backpropogate(value)
    }
    
    private func rollout(_ node: Node) -> Double {
        var depth = 0
        var game = node.game
        while !game.isFinished {
            if depth >= maxDepth { break }
            guard let move = game.randomMove() else { break }
            game = game.update(move)
            depth += 1
        }
        let value = game.evaluate(for: player).value
        return value
    }
    
    private var bestMove: Move? {
        root?.selectChildWithMaxUcb(0)?.move
    }
    
    private func findNode(for game: Game) -> Node? {
        guard let root = root else { return nil }
        var queue = (root)
        while !queue.isEmpty {
            let head = queue.removeFirst()
            if head.game == game {
                return head
            }
            for child in head.children {
                queue.append(child)
            }
        }
        return nil
    }
}

I built this driver with a maxDepth argument because playouts/rollouts in my real game are fairly long and I have a access to a decent static evaluation function. Also, the BFS findNode method is so that I can reuse parts of the tree.

Here’s what a node in the driver looks like:

final class Node {
    weak var parent: Node?
    var move: Move?
    var game: Game
    var untriedMoves: (Move)
    var children: (Node)
    var cumulativeValueFor: Double
    var cumulativeValueAgainst: Double
    var visits: Double

    init(parent: Node? = nil, move: Move? = nil, game: Game) {
        self.parent = parent
        self.move = move
        self.game = game
        self.children = ()
        self.untriedMoves = game.availableMoves()
        self.cumulativeValueFor = 0
        self.cumulativeValueAgainst = 0
        self.visits = 0
    }
    
    var isFullyExpanded: Bool {
        untriedMoves.isEmpty
    }
    
    lazy var isTerminal: Bool = {
        game.isFinished
    }()
    
    func select(_ c: Double) -> Node {
        var leafNode = self
        while !leafNode.isTerminal {
            if !leafNode.isFullyExpanded {
                return leafNode.expand()
            } else {
                leafNode = leafNode.selectChildWithMaxUcb(c)!
            }
        }
        return leafNode
    }
    
    func expand() -> Node {
        let move = untriedMoves.popLast()!
        let nextGame = game.update(move)
        let childNode = Node(parent: self, move: move, game: nextGame)
        children.append(childNode)
        return childNode
    }
    
    func backpropogate(_ value: Double) {
        visits += 1
        cumulativeValueFor += value
        if let parent = parent {
            parent.backpropogate(value)
        }
    }
    
    func selectChildWithMaxUcb(_ c: Double) -> Node? {
        children.max { $0.ucb(c) < $1.ucb(c) }
    }

    func ucb(_ c: Double) -> Double {
        q + c * u
    }
    
    private var q: Double {
        let value = cumulativeValueFor - cumulativeValueAgainst
        return value / visits
    }
    
    private var u: Double {
        sqrt(log(parent!.visits) / visits)
    }
}

extension Node: CustomStringConvertible {
    var description: String {
        guard let move = move else { return "" }
        return "(move) ((cumulativeValueFor)/(visits))"
    }
}

I don’t think there’s anything extraordinary about my node object? (I am hoping, though, that I can do something to/about q so that I might prevent an “instant” loss in my test game…


I’ve been testing this implementation of MCTS on a 1-D variant of “Connect 4”.

Here’s the game and all of it’s primitives:

enum Player: Int {
    case one = 1
    case two = 2
    
    var opposite: Self {
        switch self {
        case .one: return .two
        case .two: return .one
        }
    }
}

extension Player: CustomStringConvertible {
    var description: String {
        "(rawValue)"
    }
}

typealias Move = Int

enum Evaluation {
    case win
    case loss
    case draw
    case ongoing(Double)
    
    var value: Double {
        switch self {
        case .win: return 1
        case .loss: return 0
        case .draw: return 0.5
        case .ongoing(let v): return v
        }
    }
}

struct Game {
    var array: Array<Int>
    var currentPlayer: Player
    
    init(length: Int = 10, currentPlayer: Player = .one) {
        self.array = Array.init(repeating: 0, count: length)
        self.currentPlayer = currentPlayer
    }
    
    var isFinished: Bool {
        switch evaluate() {
        case .ongoing: return false
        default: return true
        }
    }

    func availableMoves() -> (Move) {
        array
            .enumerated()
            .compactMap { $0.element == 0 ? Move($0.offset) : nil}
    }
    
    func update(_ move: Move) -> Self {
        var copy = self
        copy.array(move) = currentPlayer.rawValue
        copy.currentPlayer = currentPlayer.opposite
        return copy
    }
    
    func evaluate(for player: Player) -> Evaluation {
        let player3 = three(for: player)
        let oppo3 = three(for: player.opposite)
        let remaining0 = array.contains(0)
        switch (player3, oppo3, remaining0) {
        case (true, true, _): return .draw
        case (true, false, _): return .win
        case (false, true, _): return .loss
        case (false, false, false): return .draw
        default: return .ongoing(0.5)
        }
    }
    
    private func three(for player: Player) -> Bool {
        var count = 0
        for slot in array {
            if slot == player.rawValue {
                count += 1
            } else {
                count = 0
            }
            if count == 3 {
                return true
            }
        }
        return false
    }
}

extension Game {
    func evaluate() -> Evaluation {
        evaluate(for: currentPlayer)
    }
    
    func randomMove() -> Move? {
        availableMoves().randomElement()
    }
}

extension Game: CustomStringConvertible {
    var description: String {
        return array.reduce(into: "") { result, i in
            result += String(i)
        }
    }
}

extension Game: Equatable {}

While there are definitely efficiencies to be gained in optimizing the evaluate/three(for:) scoring methods, I’m more concerned about improving the performance of the driver and the node as this “1d-connect-3” game isn’t my real game. That said, if there’s a huge mistake here and a simple fix I’ll take it!

Another note: I am actually using ongoing(Double) in my real game (I’ve got a static evaluation function that can reliably score a player as 1-99% likely to win).


A bit of Playground code:


var mcts = MonteCarloTreeSearch(for: .two, timeBudget: 5, maxDepth: 3)
var game = Game(length: 10)
// 0000000000
game = game.update(0) // player 1
// 1000000000
game = game.update(8) // player 2
// 1000000020
game = game.update(1) // player 1
// 1100000020
let move1 = mcts.findMove(for: game)!
// usually 7 or 9... and not 2
print(mcts.root!.children)
game = game.update(move1) // player 2
mcts.update(with: game)
game = game.update(4) // player 1
mcts.update(with: game)
let move2 = mcts.findMove()!

Unfortunately, move1 in this sample “playthru” doesn’t try to prevent the instant win-condition on the next turn for player 1?! (I know that orthodox Monte Carlo Tree Search is in the business of maximizing winning not minimizing losing, but not picking 2 here is unfortunate).

So yeah, any help in making all this faster (perhaps through parallelization), and fixing the “instant-loss” business would be swell!

godot – How to inherit of a scene tree structure in a way that a change in the ancestor is updated in the descendant?

You can make an inherited scene. From the “Scene” menu, select “New Inherited Sceneā€¦” and pick the base scene. Then apply the modifications you need (e.g. change textures).


There is also a composition equivalent:

  • Create a new scene.
  • Add the “base” scene as a node.
  • Make it editable (“Editable Children” on the context menu on the Scene panel).
  • Then add the modifications you need (e.g. change textures).

Either way, you cannot remove from the original, only add or modify. And whatever you didn’t change will be inherited from the base scene.

Displaying and managing tree data of 10 to 100k+ top level nodes

I need to allow users to select products / sub products that are up to 3 levels deep.

We also are only able to display 100 top level products at once due to technical constraints, this is currently achieved by requiring the user to type a certain number of characters and it will fetch nodes based on the search criteria.

Here is an example picture of the input:

enter image description here

The data structure seems to fit this searchable tree select well, but general feedback currently is that it is difficult to use with 1000s of products.

Any thoughts on how this could be improved or if there would be any better UX ideas for handling 1000s of nodes?

Please let me know if I can provide any more information, this is my first time reaching out to the UX stackoverflow :]

graphs – Upper bound on the number of subgraphs in a tree

Is there an upper bound of the number of induced subgraphs in a tree (i.e., connected acyclic undirected graph)? The bound can be expressed in terms of vertices, edges, etc.

For example, consider the following graph $G$ represented as edge list: ${(S,T),(T,G),(T,B),(B,H),(H,Q)}$. The number of connected subgraph (i.e., tree) is (represented by the set of vertices): ${S}$, ${T}$, ${G}$, ${B}$, ${S,T}$, ${T,G}$, ${T,B}$, ${S,T,G}$, ${B,T,G}$,${S,T,B}$, ${S,T,G,B}$,
${T,G,B,H}$,${T,B,H,Q}$, ${S,T,B,H}$,${S,T,B,H,G}$,${T,G,B,H,Q}$,${S,T,B,H,Q}$, and
${S,T,B,H,G,Q}$.

I find two seemingly relevant answer that can directly answer my questions 1 and 2 but I’m not sure.

xiaomi – “FATAL ERROR: Unable to parse input tree” during kernel compilation

I am attempting to compile this kernel for my Redmi Note 9S.

I am using this release of AOSP’s clang and this release of AOSP’s gcc to cross-compile on an x86_64 host for the ARM64 target.

My .config file was obtained from /proc/config.gz on my phone and the kernel accepts it without needing any changes.

Here is my PATH:
/home/conner/xiaomi2/toolchain/clang/bin:/home/conner/xiaomi2/toolchain/gcc/bin:/usr/local/lib/node/nodejs/bin:/home/conner/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

And here is the command used to compile the kernel:
ARCH=arm64 CLANG_TRIPLE=aarch64-linux-gnu- CROSS_COMPILE=aarch64-linux-android- make CC=clang KCFLAGS=-fPIC KCPPFLAGS=-fPIC O=out

Compilation continues without error until:

Error: ../arch/arm64/boot/dts/qcom/dsi-panel-rm69299-visionox-amoled-fhd-plus-video.dtsi:13.1-10 syntax error
FATAL ERROR: Unable to parse input tree

Full error:

  LD      vmlinux
  SORTEX  vmlinux
  SYSMAP  System.map
  DTC     arch/arm64/boot/dts/qcom/apq8016-sbc.dtb
  DTC     arch/arm64/boot/dts/qcom/apq8096-db820c.dtb
  DTC     arch/arm64/boot/dts/qcom/ipq8074-hk01.dtb
  DTC     arch/arm64/boot/dts/qcom/msm8916-mtp.dtb
  DTC     arch/arm64/boot/dts/qcom/msm8992-bullhead-rev-101.dtb
  DTC     arch/arm64/boot/dts/qcom/msm8994-angler-rev-101.dtb
  DTC     arch/arm64/boot/dts/qcom/msm8996-mtp.dtb
  DTC     arch/arm64/boot/dts/qcom/atoll-ab.dtb
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (reg_format): "reg" property in /soc/qcom,spmi@c440000/qcom,pm6150l@5/qcom,amoled/oledb@e000 has invalid length (8 bytes) (#address-cells == 2, #size-cells == 1)
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (reg_format): "reg" property in /soc/qcom,spmi@c440000/qcom,pm6150l@5/qcom,amoled/ab@de00 has invalid length (8 bytes) (#address-cells == 2, #size-cells == 1)
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (reg_format): "reg" property in /soc/qcom,spmi@c440000/qcom,pm6150l@5/qcom,amoled/ibb@dc00 has invalid length (8 bytes) (#address-cells == 2, #size-cells == 1)
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (reg_format): "reg" property in /soc/i2c@a8c000/qcom,pm8008@9/qcom,pm8008-regulator/qcom,pm8008-l1@4000 has invalid length (2 bytes) (#address-cells == 2, #size-cells == 1)
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (reg_format): "reg" property in /soc/i2c@a8c000/qcom,pm8008@9/qcom,pm8008-regulator/qcom,pm8008-l2@4100 has invalid length (2 bytes) (#address-cells == 2, #size-cells == 1)
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (reg_format): "reg" property in /soc/i2c@a8c000/qcom,pm8008@9/qcom,pm8008-regulator/qcom,pm8008-l3@4200 has invalid length (2 bytes) (#address-cells == 2, #size-cells == 1)
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (reg_format): "reg" property in /soc/i2c@a8c000/qcom,pm8008@9/qcom,pm8008-regulator/qcom,pm8008-l4@4300 has invalid length (2 bytes) (#address-cells == 2, #size-cells == 1)
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (reg_format): "reg" property in /soc/i2c@a8c000/qcom,pm8008@9/qcom,pm8008-regulator/qcom,pm8008-l5@4400 has invalid length (2 bytes) (#address-cells == 2, #size-cells == 1)
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (reg_format): "reg" property in /soc/i2c@a8c000/qcom,pm8008@9/qcom,pm8008-regulator/qcom,pm8008-l6@4400 has invalid length (2 bytes) (#address-cells == 2, #size-cells == 1)
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (reg_format): "reg" property in /soc/i2c@a8c000/qcom,pm8008@9/qcom,pm8008-regulator/qcom,pm8008-l7@4400 has invalid length (2 bytes) (#address-cells == 2, #size-cells == 1)
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (avoid_default_addr_size): Relying on default #address-cells value for /soc/qcom,spmi@c440000/qcom,pm6150l@5/qcom,amoled/oledb@e000
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (avoid_default_addr_size): Relying on default #size-cells value for /soc/qcom,spmi@c440000/qcom,pm6150l@5/qcom,amoled/oledb@e000
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (avoid_default_addr_size): Relying on default #address-cells value for /soc/qcom,spmi@c440000/qcom,pm6150l@5/qcom,amoled/ab@de00
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (avoid_default_addr_size): Relying on default #size-cells value for /soc/qcom,spmi@c440000/qcom,pm6150l@5/qcom,amoled/ab@de00
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (avoid_default_addr_size): Relying on default #address-cells value for /soc/qcom,spmi@c440000/qcom,pm6150l@5/qcom,amoled/ibb@dc00
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (avoid_default_addr_size): Relying on default #size-cells value for /soc/qcom,spmi@c440000/qcom,pm6150l@5/qcom,amoled/ibb@dc00
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (avoid_default_addr_size): Relying on default #address-cells value for /soc/i2c@a8c000/qcom,pm8008@9/qcom,pm8008-regulator/qcom,pm8008-l1@4000
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (avoid_default_addr_size): Relying on default #size-cells value for /soc/i2c@a8c000/qcom,pm8008@9/qcom,pm8008-regulator/qcom,pm8008-l1@4000
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (avoid_default_addr_size): Relying on default #address-cells value for /soc/i2c@a8c000/qcom,pm8008@9/qcom,pm8008-regulator/qcom,pm8008-l2@4100
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (avoid_default_addr_size): Relying on default #size-cells value for /soc/i2c@a8c000/qcom,pm8008@9/qcom,pm8008-regulator/qcom,pm8008-l2@4100
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (avoid_default_addr_size): Relying on default #address-cells value for /soc/i2c@a8c000/qcom,pm8008@9/qcom,pm8008-regulator/qcom,pm8008-l3@4200
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (avoid_default_addr_size): Relying on default #size-cells value for /soc/i2c@a8c000/qcom,pm8008@9/qcom,pm8008-regulator/qcom,pm8008-l3@4200
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (avoid_default_addr_size): Relying on default #address-cells value for /soc/i2c@a8c000/qcom,pm8008@9/qcom,pm8008-regulator/qcom,pm8008-l4@4300
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (avoid_default_addr_size): Relying on default #size-cells value for /soc/i2c@a8c000/qcom,pm8008@9/qcom,pm8008-regulator/qcom,pm8008-l4@4300
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (avoid_default_addr_size): Relying on default #address-cells value for /soc/i2c@a8c000/qcom,pm8008@9/qcom,pm8008-regulator/qcom,pm8008-l5@4400
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (avoid_default_addr_size): Relying on default #size-cells value for /soc/i2c@a8c000/qcom,pm8008@9/qcom,pm8008-regulator/qcom,pm8008-l5@4400
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (avoid_default_addr_size): Relying on default #address-cells value for /soc/i2c@a8c000/qcom,pm8008@9/qcom,pm8008-regulator/qcom,pm8008-l6@4400
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (avoid_default_addr_size): Relying on default #size-cells value for /soc/i2c@a8c000/qcom,pm8008@9/qcom,pm8008-regulator/qcom,pm8008-l6@4400
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (avoid_default_addr_size): Relying on default #address-cells value for /soc/i2c@a8c000/qcom,pm8008@9/qcom,pm8008-regulator/qcom,pm8008-l7@4400
arch/arm64/boot/dts/qcom/atoll-ab.dtb: Warning (avoid_default_addr_size): Relying on default #size-cells value for /soc/i2c@a8c000/qcom,pm8008@9/qcom,pm8008-regulator/qcom,pm8008-l7@4400
  DTC     arch/arm64/boot/dts/qcom/atoll-ab-atp-overlay.dtbo
Error: ../arch/arm64/boot/dts/qcom/dsi-panel-rm69299-visionox-amoled-fhd-plus-video.dtsi:13.1-10 syntax error
FATAL ERROR: Unable to parse input tree
scripts/Makefile.dtbo:24: recipe for target 'arch/arm64/boot/dts/qcom/atoll-ab-atp-overlay.dtbo' failed
make(3): *** (arch/arm64/boot/dts/qcom/atoll-ab-atp-overlay.dtbo) Error 1
../scripts/Makefile.build:676: recipe for target 'arch/arm64/boot/dts/qcom' failed
make(2): *** (arch/arm64/boot/dts/qcom) Error 2
arch/arm64/Makefile:187: recipe for target 'dtbs' failed
make(1): *** (dtbs) Error 2
make(1): Leaving directory '/home/jordan/Xiaomi_Kernel_OpenSource/out'
Makefile:146: recipe for target 'sub-make' failed
make: *** (sub-make) Error 2

I have verified the md5sum of the .dtsi file as well it is not a matter of file corruption.

tree – Having a question about SQL

Consider the relations:
EMPLOYEE(ID, SURNAME, LINE_ID)
CAR(EID, MAKE)
For each employee, we store their unique ID and the ID of their line manager (if exists)
LINE_ID. If an employee has a line manager then the corresponding LINE_ID is not NULL.
A line manager does not have a line manager, i.e., the corresponding LINE_ID is NULL. The
LINE_ID is a foreign key referencing to the ID primary key in the relation Employee. In the
relation Car, we store the car(s) make of an employee, if exist(s). Specifically, for each car, we
store its make (e.g., BMW, Jaguar, Aston Martin, Toyota) and the ID of its owner/employee
(EID). The EID is a foreign key referencing to the ID in the relation Employee. The primary
keys are underlined.
Assume the following query:
SELECT E.SURNAME, L.SURNAME
FROM EMPLOYEE E, EMPLOYEE L, CAR C
WHERE E.LINE_ID = L.ID AND C.EID = L.ID
We know that: (i) there are 20 line managers, each one being the line manager of 10 employees;
(ii) there are 120 employees, who have 1 car each, i.e., the CAR relation has 120 tuples, each
one corresponds to different employee.
(a) Provide the canonical tree of the query and estimate the expected number of tuples
retrieved.

merkle tree – Is the hash of ZMQ channel blockhash a merkleroot hash?

As the name suggests, it is the block hash, not the merkle root hash. It is the hash of the block header which includes the merkle root hash. To learn whether your tx is included in a block, you will need to fetch the block with that hash and then search for your transaction within that block. You can do this by using the getblock RPC after receiving the ZMQ message. You could also use the rawblock ZMQ channel and receive the entire block in full, but that will also mean that you need to implement block parsing.

Even if you could just get the merkle root, the merkle root itself does not contain sufficient information to determine whether a particular transaction is included in that block. You still need to get the full block and search the transactions list for your transaction.