package hierarchy

import (
	
	
	
	

	
	
)

func newRankProblem( *layoutgraph.Graph,  *limits.OptimizationWorkGuard) (*rankProblem, error) {
	if  == nil {
		return nil, errors.New("graph is required")
	}
	if len(.Nodes) > limits.MaxEngineNodes {
		return nil, fmt.Errorf("node count exceeds limit %d", limits.MaxEngineNodes)
	}
	if len(.Edges) > limits.MaxEngineEdges {
		return nil, fmt.Errorf("edge count exceeds limit %d", limits.MaxEngineEdges)
	}

	 := slices.Clone(.Nodes)
	if  := .AddSort(len());  != nil {
		return nil, 
	}
	slices.SortFunc(, func(,  *layoutgraph.Node) int {
		if  == nil {
			if  == nil {
				return 0
			}
			return -1
		}
		if  == nil {
			return 1
		}
		return cmp.Compare(.ID, .ID)
	})

	 := make(map[*layoutgraph.Node]int, len())
	for ,  := range  {
		if  := .Step();  != nil {
			return nil, 
		}
		if  == nil {
			return nil, errors.New("nil node")
		}
		if  > 0 && [-1].ID == .ID {
			return nil, fmt.Errorf("duplicate node ID %d", .ID)
		}
		if ,  := [];  {
			return nil, fmt.Errorf("duplicate node %s", .DebugID())
		}
		[] = 
	}

	type  struct {
		     *layoutgraph.Edge
		,  int
	}
	 := make([], 0, len(.Edges))
	 := make(map[*layoutgraph.Edge]struct{}, len(.Edges))
	 := make(map[layoutgraph.EntityID]struct{}, len(.Edges))
	type  struct{ ,  int }
	 := make(map[]struct{}, len(.Edges))
	for ,  := range .Edges {
		if  := .Step();  != nil {
			return nil, 
		}
		if  == nil || .From == nil || .To == nil {
			return nil, errors.New("edge has a nil endpoint")
		}
		,  := [.From]
		,  := [.To]
		if ! || ! {
			return nil, fmt.Errorf("edge %d references a node outside the graph", .ID)
		}
		if  ==  {
			return nil, fmt.Errorf("self edge on %s", .From.DebugID())
		}
		if .HasSourceArrow() || !.HasTargetArrow() {
			return nil, errors.New("canonical source-to-target directed edges required")
		}
		 := .HierarchyRankWeight()
		if  <= 0 ||  > limits.MaxEngineEdges {
			return nil, fmt.Errorf("edge %d has invalid rank weight %d", .ID, )
		}
		if ,  := [];  {
			return nil, fmt.Errorf("duplicate edge reference %d", .ID)
		}
		if ,  := [.ID];  {
			return nil, fmt.Errorf("duplicate edge ID %d", .ID)
		}
		 := {: , : }
		if ,  := [];  {
			return nil, fmt.Errorf("duplicate directed edge %s -> %s", .From.DebugID(), .To.DebugID())
		}
		[] = struct{}{}
		[.ID] = struct{}{}
		[] = struct{}{}
		 = append(, {: , : , : })
	}

	if  := .AddSort(len());  != nil {
		return nil, 
	}
	slices.SortFunc(, func(,  ) int {
		if  := cmp.Compare(., .);  != 0 {
			return 
		}
		if  := cmp.Compare(., .);  != 0 {
			return 
		}
		return cmp.Compare(..ID, ..ID)
	})

	type  struct{ ,  int }
	 := make(map[*layoutgraph.Edge], len())
	 := 0
	for ,  := range  {
		for ,  := range .Edges {
			if  := .Step();  != nil {
				return nil, 
			}
			++
			if  > limits.MaxEngineEdges*2 {
				return nil, fmt.Errorf("incident edge references exceed limit %d", limits.MaxEngineEdges*2)
			}
			if  == nil || (.From !=  && .To != ) {
				return nil, fmt.Errorf("malformed incident edge on %s", .DebugID())
			}
			if ,  := []; ! {
				return nil, fmt.Errorf("node %s references an edge outside the graph", .DebugID())
			}
			 := []
			if .From ==  {
				.++
			} else {
				.++
			}
			[] = 
		}
	}
	for ,  := range  {
		if  := .Step();  != nil {
			return nil, 
		}
		 := [.]
		if  != ({: 1, : 1}) {
			return nil, fmt.Errorf("edge %d must appear once on each endpoint; got source=%d target=%d", ..ID, ., .)
		}
	}

	if len() > 1 {
		 := make([]bool, len())
		[0] = true
		 := []int{0}
		for  := 0;  < len(); ++ {
			 := []
			for ,  := range [].Edges {
				if  := .Step();  != nil {
					return nil, 
				}
				 := [[].Adjacent()]
				if ![] {
					[] = true
					 = append(, )
				}
			}
		}
		if len() != len() {
			return nil, errors.New("input graph is disconnected")
		}
	}

	 := make([]rankEdge, len())
	 := make([]int, len()+1)
	for ,  := range  {
		if  := .Step();  != nil {
			return nil, 
		}
		[] = rankEdge{from: ., to: ., weight: int64(..HierarchyRankWeight()), id: ..ID}
		[.+1]++
	}
	for  := range  {
		if  := .Step();  != nil {
			return nil, 
		}
		[+1] += []
	}
	 := make([]int, len())
	for  := range  {
		if  := .Step();  != nil {
			return nil, 
		}
		[] = 
	}
	if  := .AddSort(len());  != nil {
		return nil, 
	}
	slices.SortFunc(, func(,  int) int {
		return cmp.Compare([].id, [].id)
	})
	return &rankProblem{nodes: , edges: , outgoingStart: , pivotOrder: }, nil
}

func ( *rankProblem) ( *limits.OptimizationWorkGuard) ([]int64, error) {
	 := make([]int, len(.nodes))
	for ,  := range .edges {
		if  := .Step();  != nil {
			return nil, 
		}
		[.to]++
	}

	 := make(nodeMinHeap, 0, len(.nodes))
	for ,  := range  {
		if  := .Step();  != nil {
			return nil, 
		}
		if  == 0 {
			.push()
			if  := .Step();  != nil {
				return nil, 
			}
		}
	}

	 := make([]int64, len(.nodes))
	 := 0
	for len() > 0 {
		if  := .Step();  != nil {
			return nil, 
		}
		 := .pop()
		++
		for  := .outgoingStart[];  < .outgoingStart[+1]; ++ {
			if  := .Step();  != nil {
				return nil, 
			}
			 := .edges[]
			,  := checkedAddInt64([], rankMinSpan)
			if ! {
				return nil, errors.New("initial level overflow")
			}
			[.to] = max([.to], )
			[.to]--
			if [.to] == 0 {
				.push(.to)
				if  := .Step();  != nil {
					return nil, 
				}
			}
		}
	}
	if  != len(.nodes) {
		return nil, errors.New("input graph contains a directed cycle")
	}
	return , nil
}