// OpenSTA, Static Timing Analyzer
// Copyright (c) 2026, Parallax Software, Inc.
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// 
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
// 
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 
// This notice may not be removed or altered from any source distribution.

#pragma once

#include <map>
#include <string>
#include <string_view>
#include <vector>

#include "ArcDelayCalc.hh"
#include "CircuitSim.hh"
#include "GraphClass.hh"
#include "LibertyClass.hh"
#include "NetworkClass.hh"
#include "ParasiticsClass.hh"
#include "PowerClass.hh"
#include "Property.hh"
#include "RiseFallMinMaxDelay.hh"
#include "Scene.hh"
#include "SdcClass.hh"
#include "SearchClass.hh"
#include "StaState.hh"
#include "StringUtil.hh"
#include "Variables.hh"
#include "VertexVisitor.hh"

struct Tcl_Interp;

namespace sta {

// Don't include headers to minimize dependencies.
class MinMax;
class MinMaxAll;
class RiseFallBoth;
class RiseFall;
class VerilogReader;
class ReportPath;
class CheckTiming;
class CheckSlews;
class CheckFanouts;
class CheckCapacitances;
class CheckMinPulseWidths;
class CheckMinPeriods;
class CheckMaxSkews;
class PatternMatch;
class CheckPeriods;
class LibertyReader;
class SearchPred;
class Scene;
class ClkSkews;
class ReportField;
class EquivCells;
class StaSimObserver;
class LevelizeObserver;
class GraphLoop;

using ModeNameMap = std::map<std::string, Mode*, std::less<>>;
using SceneNameMap = std::map<std::string, Scene*>;
using SlowDrvrIterator = Iterator<Instance*>;
using CheckError = StringSeq;
using CheckErrorSeq = std::vector<CheckError*>;
enum class CmdNamespace { sta, sdc };
using ParasiticsNameMap = std::map<std::string, Parasitics*, std::less<>>;
using GraphLoopSeq = std::vector<GraphLoop*>;
using ReportFieldGetValue = std::function<std::string (const Path *path,
                                                       const StaState *sta)>;

// Initialize sta functions that are not part of the Sta class.
void initSta();

// Call before exit to make leak detection simpler for purify and valgrind.
void
deleteAllMemory();

// The Lord, God, King, Master of the Timing Universe.
// This class is a FACADE used to present an API to the collection of
// objects that hold the collective state of the static timing analyzer.
// It should only hold pointers to objects so that only the referenced
// class declarations and not their definitions are needed by this header.
//
// The report object is not owned by the sta object.
class Sta : public StaState
{
public:
  // The Sta is a FACTORY for the components.
  // makeComponents calls the make{Component} virtual functions.
  // Ideally this would be called by the Sta constructor, but a
  // virtual function called in a base class constructor does not
  // call the derived class function.
  virtual void makeComponents();
  // Call copyState for each component to notify it that some
  // pointers to some components have changed.
  // This must be called after changing any of the StaState components.
  virtual void updateComponentsState();
  ~Sta() override;

  // Singleton accessor used by tcl command interpreter.
  static Sta *sta();
  static void setSta(Sta *sta);

  // Default number of threads to use.
  virtual int defaultThreadCount() const;
  void setThreadCount(int thread_count);

  // define_corners compatibility.
  void makeScenes(const StringSeq &scene_names);
  void makeScene(const std::string &name,
                 const std::string &mode_name,
                 const StringSeq &liberty_min_files,
                 const StringSeq &liberty_max_files,
                 const std::string &spef_min_file,
                 const std::string &spef_max_file);
  Scene *findScene(const std::string &name) const;
  // Pattern match name.
  SceneSeq findScenes(const std::string &name) const;
  SceneSeq findScenes(const std::string &name,
                      ModeSeq &modes) const;
  Scene *cmdScene() const;
  void setCmdScene(Scene *scene);
  SceneSeq makeSceneSeq(Scene *scene) const;

  Mode *cmdMode() const { return cmd_mode_; }
  const std::string &cmdModeName();
  void setCmdMode(std::string_view mode_name);
  Mode *findMode(std::string_view mode_name) const;
  ModeSeq findModes(const std::string &mode_name) const;
  Sdc *cmdSdc() const;

  virtual LibertyLibrary *readLiberty(std::string_view filename,
                                      Scene *scene,
                                      const MinMaxAll *min_max,
                                      bool infer_latches);
  // tmp public
  void readLibertyAfter(LibertyLibrary *liberty,
                        Scene *scene,
                        const MinMaxAll *min_max);
  bool readVerilog(std::string_view filename);
  // Network readers call this to notify the Sta to delete any previously
  // linked network.
  void readNetlistBefore();
  // Return true if successful.
  bool linkDesign(const char *top_cell_name,
                  bool make_black_boxes);

  bool readSdf(std::string_view filename,
               std::string_view path,
               Scene *scene,
               bool unescaped_dividers,
               bool incremental_only,
               MinMaxAll *cond_use);

  // SDC Swig API.
  Instance *currentInstance() const;
  void setCurrentInstance(Instance *inst);
  virtual void setAnalysisType(AnalysisType analysis_type,
                               Sdc *sdc);
  void setOperatingConditions(OperatingConditions *op_cond,
                              const MinMaxAll *min_max,
                              Sdc *sdc);
  void setTimingDerate(TimingDerateType type,
                       PathClkOrData clk_data,
                       const RiseFallBoth *rf,
                       const EarlyLate *early_late,
                       float derate,
                       Sdc *sdc);
  // Delay type is always net for net derating.
  void setTimingDerate(const Net *net,
                       PathClkOrData clk_data,
                       const RiseFallBoth *rf,
                       const EarlyLate *early_late,
                       float derate,
                       Sdc *sdc);
  void setTimingDerate(const Instance *inst,
                       TimingDerateCellType type,
                       PathClkOrData clk_data,
                       const RiseFallBoth *rf,
                       const EarlyLate *early_late,
                       float derate,
                       Sdc *sdc);
  void setTimingDerate(const LibertyCell *cell,
                       TimingDerateCellType type,
                       PathClkOrData clk_data,
                       const RiseFallBoth *rf,
                       const EarlyLate *early_late,
                       float derate,
                       Sdc *sdc);
  void unsetTimingDerate(Sdc *sdc);
  void setInputSlew(const Port *port,
                    const RiseFallBoth *rf,
                    const MinMaxAll *min_max,
                    float slew,
                    Sdc *sdc);
  // Set port external pin load (set_load -pin port).
  void setPortExtPinCap(const Port *port,
                        const RiseFallBoth *rf,
                        const MinMaxAll *min_max,
                        float cap,
                        Sdc *sdc);
  void portExtCaps(const Port *port,
                   const MinMax *min_max,
                   const Sdc *sdc,
                   float &pin_cap,
                   float &wire_cap,
                   int &fanout);
  // Set port external wire load (set_load -wire port).
  void setPortExtWireCap(const Port *port,
                         const RiseFallBoth *rf,
                         const MinMaxAll *min_max,
                         float cap,
                         Sdc *sdc);
  // Set net wire capacitance (set_load -wire net).
  void setNetWireCap(const Net *net,
                     bool subtract_pin_cap,
                     const MinMaxAll *min_max,
                     float cap,
                     Sdc *sdc);
  // Remove all "set_load net" annotations.
  void removeNetLoadCaps(Sdc *sdc) const;
  // Set port external fanout (used by wireload models).
  void setPortExtFanout(const Port *port,
                        int fanout,
                        const MinMaxAll *min_max,
                        Sdc *sdc);
  // Liberty port capacitance.
  float capacitance(const LibertyPort *port,
                    Scene *scene,
                    const MinMax *min_max);
  // pin_cap  = net pin capacitances + port external pin capacitance,
  // wire_cap = annotated net capacitance + port external wire capacitance.
  void connectedCap(const Pin *drvr_pin,
                    const RiseFall *rf,
                    const Scene *scene,
                    const MinMax *min_max,
                    float &pin_cap,
                    float &wire_cap) const;
  void connectedCap(const Net *net,
                    Scene *scene,
                    const MinMax *min_max,
                    float &pin_cap,
                    float &wire_cap) const;
  void setResistance(const Net *net,
                     const MinMaxAll *min_max,
                     float res,
                     Sdc *sdc);
  void setDriveCell(const LibertyLibrary *library,
                    const LibertyCell *cell,
                    const Port *port,
                    const LibertyPort *from_port,
                    const DriveCellSlews &from_slews,
                    const LibertyPort *to_port,
                    const RiseFallBoth *rf,
                    const MinMaxAll *min_max,
                    Sdc *sdc);
  void setDriveResistance(const Port *port,
                          const RiseFallBoth *rf,
                          const MinMaxAll *min_max,
                          float res,
                          Sdc *sdc);
  void setLatchBorrowLimit(const Pin *pin,
                           float limit,
                           Sdc *sdc);
  void setLatchBorrowLimit(const Instance *inst,
                           float limit,
                           Sdc *sdc);
  void setLatchBorrowLimit(const Clock *clk,
                           float limit,
                           Sdc *sdc);
  void setMinPulseWidth(const RiseFallBoth *rf,
                        float min_width,
                        Sdc *sdc);
  void setMinPulseWidth(const Pin *pin,
                        const RiseFallBoth *rf,
                        float min_width,
                        Sdc *sdc);
  void setMinPulseWidth(const Instance *inst,
                        const RiseFallBoth *rf,
                        float min_width,
                        Sdc *sdc);
  void setMinPulseWidth(const Clock *clk,
                        const RiseFallBoth *rf,
                        float min_width,
                        Sdc *sdc);
  void setWireload(Wireload *wireload,
                   const MinMaxAll *min_max,
                   Sdc *sdc);
  void setWireloadMode(WireloadMode mode,
                       Sdc *sdc);
  void setWireloadSelection(WireloadSelection *selection,
                            const MinMaxAll *min_max,
                            Sdc *sdc);
  void setSlewLimit(Clock *clk,
                    const RiseFallBoth *rf,
                    PathClkOrData clk_data,
                    const MinMax *min_max,
                    float slew,
                    Sdc *sdc);
  void setSlewLimit(Port *port,
                    const MinMax *min_max,
                    float slew,
                    Sdc *sdc);
  void setSlewLimit(Cell *cell,
                    const MinMax *min_max,
                    float slew,
                    Sdc *sdc);
  void setCapacitanceLimit(Cell *cell,
                           const MinMax *min_max,
                           float cap,
                           Sdc *sdc);
  void setCapacitanceLimit(Port *port,
                           const MinMax *min_max,
                           float cap,
                           Sdc *sdc);
  void setCapacitanceLimit(Pin *pin,
                           const MinMax *min_max,
                           float cap,
                           Sdc *sdc);
  void setFanoutLimit(Cell *cell,
                      const MinMax *min_max,
                      float fanout,
                      Sdc *sdc);
  void setFanoutLimit(Port *port,
                      const MinMax *min_max,
                      float fanout,
                      Sdc *sdc);
  void setMaxArea(float area,
                  Sdc *sdc);

  void makeClock(std::string_view name,
                 const PinSet &pins,
                 bool add_to_pins,
                 float period,
                 const FloatSeq &waveform,
                 std::string_view comment,
                 const Mode *mode);
  // edges size must be 3.
  void makeGeneratedClock(std::string_view name,
                          const PinSet &pins,
                          bool add_to_pins,
                          Pin *src_pin,
                          Clock *master_clk,
                          int divide_by,
                          int multiply_by,
                          float duty_cycle,
                          bool invert,
                          bool combinational,
                          const IntSeq &edges,
                          const FloatSeq &edge_shifts,
                          std::string_view comment,
                          const Mode *mode);
  void removeClock(Clock *clk,
                   Sdc *sdc);
  // Update period/waveform for generated clocks from source pin clock.
  void updateGeneratedClks();
  // True if pin is defined as a clock source (pin may be hierarchical).
  bool isClockSrc(const Pin *pin,
                  const Sdc *sdc) const;
  // Propagated (non-ideal) clocks.
  void setPropagatedClock(Clock *clk,
                          const Mode *mode);
  void removePropagatedClock(Clock *clk,
                             const Mode *mode);
  void setPropagatedClock(Pin *pin,
                          const Mode *mode);
  void removePropagatedClock(Pin *pin,
                             const Mode *mode);
  void setClockSlew(Clock *clk,
                    const RiseFallBoth *rf,
                    const MinMaxAll *min_max,
                    float slew,
                    Sdc *sdc);
  void removeClockSlew(Clock *clk,
                       Sdc *sdc);
  // Clock latency.
  // Latency can be on a clk, pin, or clk/pin combination.
  void setClockLatency(Clock *clk,
                       Pin *pin,
                       const RiseFallBoth *rf,
                       const MinMaxAll *min_max,
                       float delay,
                       Sdc *sdc);
  void removeClockLatency(const Clock *clk,
                          const Pin *pin,
                          Sdc *sdc);
  // Clock insertion delay (source latency).
  void setClockInsertion(const Clock *clk,
                         const Pin *pin,
                         const RiseFallBoth *rf,
                         const MinMaxAll *min_max,
                         const EarlyLateAll *early_late,
                         float delay,
                         Sdc *sdc);
  void removeClockInsertion(const Clock *clk,
                            const Pin *pin,
                            Sdc *sdc);
  // Clock uncertainty.
  void setClockUncertainty(Clock *clk,
                           const SetupHoldAll *setup_hold,
                           float uncertainty);
  void removeClockUncertainty(Clock *clk,
                              const SetupHoldAll *setup_hold);
  void setClockUncertainty(Pin *pin,
                           const SetupHoldAll *setup_hold,
                           float uncertainty,
                           Sdc *sdc);
  void removeClockUncertainty(Pin *pin,
                              const SetupHoldAll *setup_hold,
                              Sdc *sdc);
  // Inter-clock uncertainty.
  void setClockUncertainty(Clock *from_clk,
                           const RiseFallBoth *from_rf,
                           Clock *to_clk,
                           const RiseFallBoth *to_rf,
                           const SetupHoldAll *setup_hold,
                           float uncertainty,
                           Sdc *sdc);
  void removeClockUncertainty(Clock *from_clk,
                              const RiseFallBoth *from_rf,
                              Clock *to_clk,
                              const RiseFallBoth *to_rf,
                              const SetupHoldAll *setup_hold,
                              Sdc *sdc);
  ClockGroups *makeClockGroups(std::string_view name,
                               bool logically_exclusive,
                               bool physically_exclusive,
                               bool asynchronous,
                               bool allow_paths,
                               std::string_view comment,
                               Sdc *sdc);
  void removeClockGroupsLogicallyExclusive(Sdc *sdc);
  void removeClockGroupsLogicallyExclusive(const std::string &name,
                                           Sdc *sdc);
  void removeClockGroupsPhysicallyExclusive(Sdc *sdc);
  void removeClockGroupsPhysicallyExclusive(const std::string &name,
                                            Sdc *sdc);
  void removeClockGroupsAsynchronous(Sdc *sdc);
  void removeClockGroupsAsynchronous(const std::string &name,
                                     Sdc *sdc);
  void makeClockGroup(ClockGroups *clk_groups,
                      ClockSet *clks,
                      Sdc *sdc);
  void setClockSense(PinSet *pins,
                     ClockSet *clks,
                     ClockSense sense,
                     Sdc *sdc);
  void setClockGatingCheck(const RiseFallBoth *rf,
                           const SetupHold *setup_hold,
                           float margin,
                           Sdc *sdc);
  void setClockGatingCheck(Clock *clk,
                           const RiseFallBoth *rf,
                           const SetupHold *setup_hold,
                           float margin,
                           Sdc *sdc);
  void setClockGatingCheck(Instance *inst,
                           const RiseFallBoth *rf,
                           const SetupHold *setup_hold,
                           float margin,
                           LogicValue active_value,
                           Sdc *sdc);
  void setClockGatingCheck(Pin *pin,
                           const RiseFallBoth *rf,
                           const SetupHold *setup_hold,
                           float margin,
                           LogicValue active_value,
                           Sdc *sdc);
  void setDataCheck(Pin *from,
                    const RiseFallBoth *from_rf,
                    Pin *to,
                    const RiseFallBoth *to_rf,
                    Clock *clk,
                    const SetupHoldAll *setup_hold,
                    float margin,
                    Sdc *sdc);
  void removeDataCheck(Pin *from,
                       const RiseFallBoth *from_rf,
                       Pin *to,
                       const RiseFallBoth *to_rf,
                       Clock *clk,
                       const SetupHoldAll *setup_hold,
                       Sdc *sdc);
  // set_disable_timing cell [-from] [-to]
  // Disable all edges thru cell if from/to are null.
  // Bus and bundle ports are NOT supported.
  void disable(LibertyCell *cell,
               LibertyPort *from,
               LibertyPort *to,
               Sdc *sdc);
  void removeDisable(LibertyCell *cell,
                     LibertyPort *from,
                     LibertyPort *to,
                     Sdc *sdc);
  // set_disable_timing liberty port.
  // Bus and bundle ports are NOT supported.
  void disable(LibertyPort *port,
               Sdc *sdc);
  void removeDisable(LibertyPort *port,
                     Sdc *sdc);
  // set_disable_timing port (top level instance port).
  // Bus and bundle ports are NOT supported.
  void disable(Port *port,
               Sdc *sdc);
  void removeDisable(Port *port,
                     Sdc *sdc);
  // set_disable_timing instance [-from] [-to].
  // Disable all edges thru instance if from/to are null.
  // Bus and bundle ports are NOT supported.
  // Hierarchical instances are NOT supported.
  void disable(Instance *inst,
               LibertyPort *from,
               LibertyPort *to,
               Sdc *sdc);
  void removeDisable(Instance *inst,
                     LibertyPort *from,
                     LibertyPort *to,
                     Sdc *sdc);
  // set_disable_timing pin
  void disable(Pin *pin,
               Sdc *sdc);
  void removeDisable(Pin *pin,
                     Sdc *sdc);
  // set_disable_timing [get_timing_arc -of_objects instance]]
  void disable(Edge *edge,
               Sdc *sdc);
  void removeDisable(Edge *edge,
                     Sdc *sdc);
  // set_disable_timing [get_timing_arc -of_objects lib_cell]]
  void disable(TimingArcSet *arc_set,
               Sdc *sdc);
  void removeDisable(TimingArcSet *arc_set,
                     Sdc *sdc);
  [[nodiscard]] bool isConstant(const Pin *pin,
                                const Mode *mode) const;
  // Edge is disabled by constant.
  [[nodiscard]] bool isDisabledConstant(Edge *edge,
                                        const Mode *mode);
  // Return a set of constant pins that disabled edge.
  // Caller owns the returned set.
  PinSet disabledConstantPins(Edge *edge,
                              const Mode *mode);
  // Edge timing sense with propagated constants.
  TimingSense simTimingSense(Edge *edge,
                             const Mode *mode);
  // Edge is disabled by set_disable_timing constraint.
  [[nodiscard]] bool isDisabledConstraint(Edge *edge,
                                          const Sdc *sdc);
  // Edge is disabled to break combinational loops.
  [[nodiscard]] bool isDisabledLoop(Edge *edge) const;
  // Edge is disabled bidirect net path.
  [[nodiscard]] bool isDisabledBidirectNetPath(Edge *edge) const;
  [[nodiscard]] bool isDisabledPresetClr(Edge *edge) const;
  // Return a vector of graph edges that are disabled, sorted by
  // from/to vertex names.  Caller owns the returned vector.
  EdgeSeq disabledEdges(const Mode *mode);
  EdgeSeq disabledEdgesSorted(const Mode *mode);
  void disableClockGatingCheck(Instance *inst,
                               Sdc *sdc);
  void disableClockGatingCheck(Pin *pin,
                               Sdc *sdc);
  void removeDisableClockGatingCheck(Instance *inst,
                                     Sdc *sdc);
  void removeDisableClockGatingCheck(Pin *pin,
                                     Sdc *sdc);
  void setLogicValue(Pin *pin,
                     LogicValue value,
                     Mode *mode);
  void setCaseAnalysis(Pin *pin,
                       LogicValue value,
                       Mode *mode);
  void removeCaseAnalysis(Pin *pin,
                          Mode *mode);
  void setInputDelay(const Pin *pin,
                     const RiseFallBoth *rf,
                     const Clock *clk,
                     const RiseFall *clk_rf,
                     const Pin *ref_pin,
                     bool source_latency_included,
                     bool network_latency_included,
                     const MinMaxAll *min_max,
                     bool add,
                     float delay,
                     Sdc *sdc);
  void removeInputDelay(const Pin *pin,
                        const RiseFallBoth *rf, 
                        const Clock *clk,
                        const RiseFall *clk_rf, 
                        const MinMaxAll *min_max,
                        Sdc *sdc);
  void setOutputDelay(const Pin *pin,
                      const RiseFallBoth *rf,
                      const Clock *clk,
                      const RiseFall *clk_rf,
                      const Pin *ref_pin,
                      bool source_latency_included,
                      bool network_latency_included,
                      const MinMaxAll *min_max,
                      bool add,
                      float delay,
                      Sdc *sdc);
  void removeOutputDelay(const Pin *pin,
                         const RiseFallBoth *rf, 
                         const Clock *clk,
                         const RiseFall *clk_rf, 
                         const MinMaxAll *min_max,
                         Sdc *sdc);
  void makeFalsePath(ExceptionFrom *from,
                     ExceptionThruSeq *thrus,
                     ExceptionTo *to,
                     const MinMaxAll *min_max,
                     std::string_view comment,
                     Sdc *sdc);
  void makeMulticyclePath(ExceptionFrom *from,
                          ExceptionThruSeq *thrus,
                          ExceptionTo *to,
                          const MinMaxAll *min_max,
                          bool use_end_clk,
                          int path_multiplier,
                          std::string_view comment,
                          Sdc *sdc);
  void makePathDelay(ExceptionFrom *from,
                     ExceptionThruSeq *thrus,
                     ExceptionTo *to,
                     const MinMax *min_max,
                     bool ignore_clk_latency,
                     bool break_path,
                     float delay,
                     std::string_view comment,
                     Sdc *sdc);
  void makeGroupPath(std::string_view name,
                     bool is_default,
                     ExceptionFrom *from,
                     ExceptionThruSeq *thrus,
                     ExceptionTo *to,
                     std::string_view comment,
                     Sdc *sdc);
  // Deprecated 10/24/2025
  bool isGroupPathName(std::string_view group_name,
                       const Sdc *sdc) __attribute__ ((deprecated));
  bool isPathGroupName(std::string_view group_name,
                       const Sdc *sdc) const;
  StringSeq pathGroupNames(const Sdc *sdc) const;
  void resetPath(ExceptionFrom *from,
                 ExceptionThruSeq *thrus,
                 ExceptionTo *to,
                 const MinMaxAll *min_max,
                 Sdc *sdc);
  // Make an exception -from specification.
  ExceptionFrom *makeExceptionFrom(PinSet *from_pins,
                                   ClockSet *from_clks,
                                   InstanceSet *from_insts,
                                   const RiseFallBoth *from_rf,
                                   const Sdc *sdc);
  void checkExceptionFromPins(ExceptionFrom *from,
                              std::string_view filename,
                              int line,
                              const Sdc *sdc) const;
  void deleteExceptionFrom(ExceptionFrom *from);
  // Make an exception -through specification.
  ExceptionThru *makeExceptionThru(PinSet *pins,
                                   NetSet *nets,
                                   InstanceSet *insts,
                                   const RiseFallBoth *rf,
                                   const Sdc *sdc);
  void deleteExceptionThru(ExceptionThru *thru);
  // Make an exception -to specification.
  ExceptionTo *makeExceptionTo(PinSet *to_pins,
                               ClockSet *to_clks,
                               InstanceSet *to_insts,
                               const RiseFallBoth *rf,
                               const RiseFallBoth *end_rf,
                               const Sdc *sdc);
  void checkExceptionToPins(ExceptionTo *to,
                            const char *file,
                            int line,
                            const Sdc *sdc) const;
  void deleteExceptionTo(ExceptionTo *to);

  InstanceSet findRegisterInstances(ClockSet *clks,
                                    const RiseFallBoth *clk_rf,
                                    bool registers,
                                    bool latches,
                                    const Mode *mode);
  PinSet findRegisterDataPins(ClockSet *clks,
                              const RiseFallBoth *clk_rf,
                              bool registers,
                              bool latches,
                              const Mode *mode);
  PinSet findRegisterClkPins(ClockSet *clks,
                             const RiseFallBoth *clk_rf,
                             bool registers,
                             bool latches,
                             const Mode *mode);
  PinSet findRegisterAsyncPins(ClockSet *clks,
                               const RiseFallBoth *clk_rf,
                               bool registers,
                               bool latches,
                               const Mode *mode);
  PinSet findRegisterOutputPins(ClockSet *clks,
                                const RiseFallBoth *clk_rf,
                                bool registers,
                                bool latches,
                                const Mode *mode);
  PinSet findFaninPins(PinSeq *to,
                       bool flat,
                       bool startpoints_only,
                       int inst_levels,
                       int pin_levels,
                       bool thru_disabled,
                       bool thru_constants,
                       const Mode *mode);
  InstanceSet
  findFaninInstances(PinSeq *to,
                     bool flat,
                     bool startpoints_only,
                     int inst_levels,
                     int pin_levels,
                     bool thru_disabled,
                     bool thru_constants,
                     const Mode *mode);
  PinSet
  findFanoutPins(PinSeq *from,
                 bool flat,
                 bool endpoints_only,
                 int inst_levels,
                 int pin_levels,
                 bool thru_disabled,
                 bool thru_constants,
                 const Mode *mode);
  InstanceSet
  findFanoutInstances(PinSeq *from,
                      bool flat,
                      bool endpoints_only,
                      int inst_levels,
                      int pin_levels,
                      bool thru_disabled,
                      bool thru_constants,
                      const Mode *mode);

  // The set of clocks that arrive at vertex in the clock network.
  ClockSet clocks(const Pin *pin,
                  const Mode *mode);
  // Clock domains for a pin.
  ClockSet clockDomains(const Pin *pin,
                        const Mode *mode);

  ////////////////////////////////////////////////////////////////
  // net=null check all nets
  void reportSlewChecks(const Net *net,
                        size_t max_count,
                        bool violators,
                        bool verbose,
                        const SceneSeq &scenes,
                        const MinMax *min_max);
  void checkSlewsPreamble();
  // requires checkSlewsPreamble()
  void checkSlew(const Pin *pin,
                 const SceneSeq &scenes,
                 const MinMax *min_max,
                 bool check_clks,
                 // Return values.
                 Slew &slew,
                 float &limit,
                 float &slack,
                 const RiseFall *&rf,
                 const Scene *&Scene);
  void maxSlewCheck(// Return values.
                    const Pin *&pin,
                    Slew &slew,
                    float &slack,
                    float &limit);
  void findSlewLimit(const LibertyPort *port,
                     const Scene *scene,
                     const MinMax *min_max,
                     // Return values.
                     float &limit,
                     bool &exists);
  size_t maxSlewViolationCount();

  ////////////////////////////////////////////////////////////////
  // net == nullptr to check all.
  void reportFanoutChecks(const Net *net,
                          size_t max_count,
                          bool violators,
                          bool verbose,
                          const SceneSeq &scenes,
                          const MinMax *min_max);
  void checkFanoutPreamble();
  // requires checkFanoutPreamble()
  void checkFanout(const Pin *pin,
                   const Mode *mode,
                   const MinMax *min_max,
                   // Return values.
                   float &fanout,
                   float &limit,
                   float &slack);
  // Return the pin etc with max fanout check min slack.
  void maxFanoutMinSlackPin(const ModeSeq &modes,
                            // Return values.
                            const Pin *&pin,
                            float &fanout,
                            float &limit,
                            float &slack,
                            const Mode *&mode);
  size_t fanoutViolationCount(const MinMax *min_max,
                              const ModeSeq &modes);

  ////////////////////////////////////////////////////////////////
  // net=null check all nets
  void reportCapacitanceChecks(const Net *net,
                               size_t max_count,
                               bool violators,
                               bool verbose,
                               const SceneSeq &scenes,
                               const MinMax *min_max);
  size_t maxCapacitanceViolationCount();
  void checkCapacitancesPreamble(const SceneSeq &scenes);
  // requires checkCapacitanceLimitPreamble()
  void checkCapacitance(const Pin *pin,
                        const SceneSeq &scenes,
                        const MinMax *min_max,
                        // Return values.
                        float &capacitance,
                        float &limit,
                        float &slack,
                        const RiseFall *&rf,
                        const Scene *&scene);
  void maxCapacitanceCheck(// Return values.
                           const Pin *&pin,
                           float &capacitance,
                           float &slack,
                           float &limit);

  ////////////////////////////////////////////////////////////////
  void reportMinPulseWidthChecks(const Net *net,
                                 size_t max_count,
                                 bool violators,
                                 bool verbose,
                                 const SceneSeq &scenes);

  ////////////////////////////////////////////////////////////////
  void reportMinPeriodChecks(const Net *net,
                             size_t max_count,
                             bool violators,
                             bool verbose,
                             const SceneSeq &scenes);

  ////////////////////////////////////////////////////////////////
  void reportMaxSkewChecks(const Net *net,
                           size_t max_count,
                           bool violators,
                           bool verbose,
                           const SceneSeq &scenes);
  
  ////////////////////////////////////////////////////////////////
  // User visible but non SDC commands.

  // Clear all state except network, scenes and liberty libraries.
  void clear();
  // Clear all state except network, scenes liberty libraries, and sdc.
  void clearNonSdc();
  // Namespace used by command interpreter.
  CmdNamespace cmdNamespace();
  void setCmdNamespace(CmdNamespace namespc);
  OperatingConditions *operatingConditions(const MinMax *min_max,
                                           const Sdc *sdc) const;
  // Set the delay on a timing arc.
  // Required/arrival times are incrementally updated.
  void setArcDelay(Edge *edge,
                   TimingArc *arc,
                   const Scene *scene,
                   const MinMaxAll *min_max,
                   ArcDelay delay);
  // Set annotated slew on a vertex for delay calculation.
  void setAnnotatedSlew(Vertex *vertex,
                        const Scene *scene,
                        const MinMaxAll *min_max,
                        const RiseFallBoth *rf,
                        float slew);
  void unsetAnnotatedSlew(Vertex *vertex,
                          const Scene *scene,
                          const MinMaxAll *min_max,
                          const RiseFallBoth *rf);
  void writeSdf(std::string_view filename,
                const Scene *scene,
                char divider,
                bool include_typ,
                int digits,
                bool gzip,
                bool no_timestamp,
                bool no_version);
  // Remove all delay and slew annotations.
  void removeDelaySlewAnnotations();
  // Instance specific process/voltage/temperature.
  // Defaults to operating condition if instance is not annotated.
  const Pvt *pvt(Instance *inst,
                 const MinMax *min_max,
                 Sdc *sdc);
  void setPvt(Instance *inst,
              const MinMaxAll *min_max,
              float process,
              float voltage,
              float temperature,
              Sdc *sdc);
  // Pvt may be shared among multiple instances.
  void setPvt(const Instance *inst,
              const MinMaxAll *min_max,
              const Pvt &pvt,
              Sdc *sdc);
  void setVoltage(const MinMax *min_max,
                  float voltage,
                  Sdc *sdc);
  void setVoltage(const Net *net,
                  const MinMax *min_max,
                  float voltage,
                  Sdc *sdc);

  CheckErrorSeq &checkTiming(const Mode *mode,
                             bool no_input_delay,
                             bool no_output_delay,
                             bool reg_multiple_clks,
                             bool reg_no_clks,
                             bool unconstrained_endpoints,
                             bool loops,
                             bool generated_clks);
  // Path from/thrus/to filter.
  // from/thrus/to are owned and deleted by Search.
  // PathEnds in the returned PathEndSeq are owned by Search PathGroups
  // and deleted on next call.
  PathEndSeq findPathEnds(ExceptionFrom *from,
                          ExceptionThruSeq *thrus,
                          ExceptionTo *to,
                          bool unconstrained,
                          const SceneSeq &scenes,
                          // max for setup checks.
                          // min for hold checks.
                          // min_max for setup and hold checks.
                          const MinMaxAll *min_max,
                          // Number of path ends to report in
                          // each group.
                          int group_path_count,
                          // Number of paths to report for
                          // each endpoint.
                          int endpoint_path_count,
                          // endpoint_path_count paths report unique pins
                          // without rise/fall variations.
                          bool unique_pins,
                          // endpoint_path_count paths report paths with
                          // unique pins and rise/fall edges.
                          bool unique_edges,
                          // Min/max bounds for slack of
                          // returned path ends.
                          float slack_min,
                          float slack_max,
                          // Sort path ends by slack ignoring path groups.
                          bool sort_by_slack,
                          // Path groups to report.
                          // Empty list reports all groups.
                          StringSeq &group_names,
                          // Predicates to filter the type of path
                          // ends returned.
                          bool setup,
                          bool hold,
                          bool recovery,
                          bool removal,
                          bool clk_gating_setup,
                          bool clk_gating_hold);
  void setReportPathFormat(ReportPathFormat format);
  void setReportPathFieldOrder(const StringSeq &field_names);
  void setReportPathFields(const StringSeq &fields);
  ReportField *findReportPathField(std::string_view name);
  ReportField *findReportPathFieldAbrev(std::string_view name);
  void makeReportPathField(std::string_view name,
                           std::string_view name_abrev,
                           std::string_view title,
                           size_t width,
                           bool left_justify,
                           Unit *unit,
                           const ReportFieldGetValue &get_value);
  void setReportPathDigits(int digits);
  void setReportPathNoSplit(bool no_split);
  void reportPathEnd(PathEnd *end);
  void reportPathEnds(PathEndSeq *ends);
  ReportPath *reportPath() { return report_path_; }
  void reportPath(const Path *path);

  // Report clk skews for clks.
  void reportClkSkew(ConstClockSeq &clks,
                     const SceneSeq &scenes,
                     const SetupHold *setup_hold,
                     bool include_internal_latency,
                     int digits);
  Delay findWorstClkSkew(const SetupHold *setup_hold,
                         bool include_internal_latency);

  void reportClkLatency(ConstClockSeq &clks,
                        const SceneSeq &scenes,
                        bool include_internal_latency,
                        int digits);
  // Find min/max/rise/fall delays for clk.
  ClkDelays findClkDelays(const Clock *clk,
                          const Scene *scene,
                          bool include_internal_latency);

  // Update arrival times for all pins.
  // If necessary updateTiming propagates arrivals around latch
  // loops until the arrivals converge.
  // If full=false update arrivals incrementally.
  // If full=true update all arrivals from scratch.
  // NOTE WELL: There is rarely any reason to call updateTiming directly because
  // arrival/required/slack functions implicitly update timing incrementally.
  // If you are calling this function you are either very confused or there is
  // bug that should be reported.
  void updateTiming(bool full);
  // Invalidate all delay calculations. Arrivals also invalidated.
  void delaysInvalid() const;
  // Invalidate all arrival and required times.
  void arrivalsInvalid();
  PinSet startpointPins();
  PinSet endpointPins();
  VertexSet &endpoints();
  int endpointViolationCount(const MinMax *min_max);
  // Find all required times after updateTiming().
  void findRequireds();
  void findRequired(Vertex *vertex);
  std::string reportDelayCalc(Edge *edge,
                              TimingArc *arc,
                              const Scene *scene,
                              const MinMax *min_max,
                              int digits);
  void writeSdc(std::string_view filename,
                std::string_view mode_name,
                bool leaf,
                bool native,
                int digits,
                bool gzip,
                bool no_timestamp);
  void writeSdc(const Sdc *sdc,
                std::string_view filename,
                // Map hierarchical pins and instances to leaf pins and instances.
                bool leaf,
                // Replace non-sdc get functions with OpenSTA equivalents.
                bool native,
                int digits,
                bool gzip,
                bool no_timestamp);
  // The sum of all negative endpoints slacks.
  // Incrementally updated.
  Slack totalNegativeSlack(const MinMax *min_max);
  Slack totalNegativeSlack(const Scene *scene,
                           const MinMax *min_max);
  // Worst endpoint slack and vertex.
  // Incrementally updated.
  Slack worstSlack(const MinMax *min_max);
  void worstSlack(const MinMax *min_max,
                  // Return values.
                  Slack &worst_slack,
                  Vertex *&worst_vertex);
  void worstSlack(const Scene *scene,
                  const MinMax *min_max,
                  // Return values.
                  Slack &worst_slack,
                  Vertex *&worst_vertex);
  Path *vertexWorstArrivalPath(Vertex *vertex,
                               const RiseFall *rf,
                               const MinMax *min_max);
  Path *vertexWorstArrivalPath(Vertex *vertex,
                               const MinMax *min_max);
  Path *vertexWorstRequiredPath(Vertex *vertex,
                                const RiseFall *rf,
                                const MinMax *min_max);
  Path *vertexWorstRequiredPath(Vertex *vertex,
                                const MinMax *min_max);
  Path *vertexWorstSlackPath(Vertex *vertex,
                             const MinMax *min_max);
  Path *vertexWorstSlackPath(Vertex *vertex,
                             const RiseFall *rf,
                             const MinMax *min_max);

  // Find the min clock period for rise/rise and fall/fall paths of a clock
  // using the slack. This does NOT correctly predict min period when there
  // are paths between different clocks.
  float findClkMinPeriod(const Clock *clk,
                         bool include_port_paths);

  // The following arrival/required/slack functions incrementally
  // update timing to the level of the vertex.  They do NOT do multiple
  // passes required propagate arrivals around latch loops.
  // See Sta::updateTiming() to propagate arrivals around latch loops.
  Arrival arrival(const Pin *pin,
                  const RiseFallBoth *rf,
                  const MinMax *min_max);
  Arrival arrival(Vertex *vertex,
                  const RiseFallBoth *rf,
                  const SceneSeq &scenes,
                  const MinMax *min_max);

  Required required(Vertex *vertex,
                    const RiseFallBoth *rf,
                    const SceneSeq &scenes,
                    const MinMax *min_max);

  Slack slack(const Net *net,
              const MinMax *min_max);
  Slack slack(const Pin *pin,
              const RiseFallBoth *rf,
              const SceneSeq &scenes,
              const MinMax *min_max);

  Slack slack(Vertex *vertex,
              const MinMax *min_max);
  Slack slack(Vertex *vertex,
              const RiseFall *rf,
              const MinMax *min_max);
  Slack slack(Vertex *vertex,
              const RiseFallBoth *rf,
              const SceneSeq &scenes,
              const MinMax *min_max);

  void slacks(Vertex *vertex,
              Slack (&slacks)[RiseFall::index_count][MinMax::index_count]);
  // Worst slack for an endpoint in a path group.
  Slack endpointSlack(const Pin *pin,
                      std::string_view path_group_name,
                      const MinMax *min_max);

  void reportArrivalWrtClks(const Pin *pin,
                            const Scene *scene,
                            bool report_variance,
                            int digits);
  void reportRequiredWrtClks(const Pin *pin,
                             const Scene *scene,
                             bool report_variance,
                             int digits);
  void reportSlackWrtClks(const Pin *pin,
                          const Scene *scene,
                          bool report_variance,
                          int digits);

  Slew slew(Vertex *vertex,
            const RiseFallBoth *rf,
            const SceneSeq &scenes,
            const MinMax *min_max);

  ArcDelay arcDelay(Edge *edge,
                    TimingArc *arc,
                    DcalcAPIndex ap_index);
  // True if the timing arc has been back-annotated.
  bool arcDelayAnnotated(Edge *edge,
                         TimingArc *arc,
                         const Scene *scene,
                         const MinMax *min_max);
  // Set/unset the back-annotation flag for a timing arc.
  void setArcDelayAnnotated(Edge *edge,
                            TimingArc *arc,
                            const Scene *scene,
                            const MinMax *min_max,
                            bool annotated);
  // Make sure levels are up to date and return vertex level.
  Level vertexLevel(Vertex *vertex);
  GraphLoopSeq &graphLoops();
  TagIndex tagCount() const;
  TagGroupIndex tagGroupCount() const;
  int clkInfoCount() const;
  int pathCount() const;
  int vertexPathCount(Vertex  *vertex) const;
  Vertex *maxPathCountVertex() const;

  // Propagate liberty constant functions and pins tied high/low through
  // combinational logic and registers. This is mode/sdc independent.
  // Used by OpenROAD/Restructure.cpp
  void findLogicConstants();
  LogicValue simLogicValue(const Pin *pin,
                           const Mode *mode);
  // Clear propagated sim constants.
  void clearLogicConstants();

  // Instances sorted by max driver pin slew.
  InstanceSeq slowDrivers(int count);

  Parasitics *makeConcreteParasitics(std::string_view name,
                                     std::string_view filename);
  // Annotate hierarchical "instance" with parasitics.
  // The parasitic analysis point is ap_name.
  // The parasitic memory footprint is much smaller if parasitic
  // networks (dspf) are reduced and deleted after reading each net
  // with reduce_to and delete_after_reduce.
  // Return true if successful.
  bool readSpef(std::string_view name,
                std::string_view filename,
                Instance *instance,
                Scene *scene,
                const MinMaxAll *min_max,
                bool pin_cap_included,
                bool keep_coupling_caps,
                float coupling_cap_factor,
                bool reduce);
  Parasitics *findParasitics(const std::string &name);
  void reportParasiticAnnotation(const std::string &spef_name,
                                 bool report_unannotated);
  // Parasitics.
  void findPiElmore(Pin *drvr_pin,
                    const RiseFall *rf,
                    const MinMax *min_max,
                    float &c2,
                    float &rpi,
                    float &c1,
                    bool &exists) const;
  void findElmore(Pin *drvr_pin,
                  Pin *load_pin,
                  const RiseFall *rf,
                  const MinMax *min_max,
                  float &elmore,
                  bool &exists) const;
  void makePiElmore(Pin *drvr_pin,
                    const RiseFall *rf,
                    const MinMaxAll *min_max,
                    float c2,
                    float rpi,
                    float c1);
  void setElmore(Pin *drvr_pin,
                 Pin *load_pin,
                 const RiseFall *rf,
                 const MinMaxAll *min_max,
                 float elmore);
  void deleteParasitics();
  Parasitic *makeParasiticNetwork(const Net *net,
                                  bool includes_pin_caps,
                                  const Scene *scene,
                                  const MinMax *min_max);

  ////////////////////////////////////////////////////////////////
  // TCL network edit function support.

  virtual Instance *makeInstance(const char *name,
                                 LibertyCell *cell,
                                 Instance *parent);
  virtual void deleteInstance(Instance *inst);
  // replace_cell
  virtual void replaceCell(Instance *inst,
                           Cell *to_cell);
  virtual void replaceCell(Instance *inst,
                           LibertyCell *to_lib_cell);
  virtual Net *makeNet(const char *name,
                       Instance *parent);
  virtual void deleteNet(Net *net);
  // connect_net
  virtual void connectPin(Instance *inst,
                          Port *port,
                          Net *net);
  virtual void connectPin(Instance *inst,
                          LibertyPort *port,
                          Net *net);
  // disconnect_net
  virtual void disconnectPin(Pin *pin);
  virtual void makePortPin(const char *port_name,
                           PortDirection *dir);
  // Notify STA that the network has changed without using the network
  // editing API. For example, reading a netlist without using the
  // builtin network readers.
  void networkChanged();
  // Network changed but all SDC references to instance/net/pin/port are preserved.
  void networkChangedNonSdc();
  void deleteLeafInstanceBefore(const Instance *inst);
  void deleteInstancePinsBefore(const Instance *inst);

  // Network edit before/after methods.
  void makeInstanceAfter(const Instance *inst);
  // Replace the instance cell with to_cell.
  // equivCells(from_cell, to_cell) must be true.
  virtual void replaceEquivCellBefore(const Instance *inst,
                                      const LibertyCell *to_cell);
  virtual void replaceEquivCellAfter(const Instance *inst);
  // Replace the instance cell with to_cell.
  // equivCellPorts(from_cell, to_cell) must be true.
  virtual void replaceCellBefore(const Instance *inst,
                                 const LibertyCell *to_cell);
  virtual void replaceCellAfter(const Instance *inst);
  virtual void makePortPinAfter(Pin *pin);
  virtual void connectPinAfter(const Pin *pin);
  virtual void disconnectPinBefore(const Pin *pin);
  virtual void deleteNetBefore(const Net *net);
  virtual void deleteInstanceBefore(const Instance *inst);
  virtual void deletePinBefore(const Pin *pin);

  ////////////////////////////////////////////////////////////////

  void ensureClkNetwork(const Mode *mode);
  void clkPinsInvalid(const Mode *mode);
  // The following functions assume ensureClkNetwork() has been called.
  bool isClock(const Pin *pin,
               const Mode *mode);
  bool isClock(const Net *net,
               const Mode *mode);
  bool isIdealClock(const Pin *pin,
                    const Mode *mode);
  bool isPropagatedClock(const Pin *pin,
                         const Mode *mode);
  const PinSet *pins(const Clock *clk,
                     const Mode *mode);

  ////////////////////////////////////////////////////////////////

  void setTclInterp(Tcl_Interp *interp);
  Tcl_Interp *tclInterp();
  // Ensure a network has been read, and linked.
  Network *ensureLinked();
  // Ensure a network has been read, linked and liberty libraries exist.
  Network *ensureLibLinked();
  void ensureLevelized();
  // Replace the Levelize observer. Takes ownership; deletes any prior
  // observer. Subclass StaLevelizeObserver to extend the default behavior
  // (Search + GraphDelayCalc forwarding) without re-implementing it.
  void setLevelizeObserver(LevelizeObserver *observer);
  // Ensure that the timing graph has been built.
  Graph *ensureGraph();
  void ensureClkArrivals();

  // Find all arc delays and vertex slews with delay calculator.
  virtual void findDelays();
  // Find arc delays and vertex slews thru to level of to_vertex.
  virtual void findDelays(Vertex *to_vertex);
  // Find arc delays and vertex slews thru to level.
  virtual void findDelays(Level level);
  // Percentage (0.0:1.0) change in delay that causes downstream
  // delays to be recomputed during incremental delay calculation.
  // Defaults to 0.0 for maximum accuracy and slowest incremental speed.
  void setIncrementalDelayTolerance(float tol);
  // Make graph and find delays.
  void searchPreamble();

  // Define the delay calculator implementation.
  void setArcDelayCalc(std::string_view delay_calc_name);

  void setDebugLevel(const char *what,
                     int level);

  // Delays and arrivals downsteam from inst are invalid.
  void delaysInvalidFrom(const Instance *inst);
  // Delays and arrivals downsteam from pin are invalid.
  void delaysInvalidFrom(const Pin *pin);
  void delaysInvalidFrom(Vertex *vertex);
  // Delays to driving pins of net (fanin) are invalid.
  // Arrivals downsteam from net are invalid.
  void delaysInvalidFromFanin(const Net *net);
  void delaysInvalidFromFanin(const Pin *pin);
  void delaysInvalidFromFanin(Vertex *vertex);
  void replaceCellPinInvalidate(const LibertyPort *from_port,
                                Vertex *vertex,
                                const LibertyCell *to_cell);

  // Power API.
  void reportPowerDesign(const Scene *scene,
                         int digits);
  void reportPowerInsts(const InstanceSeq &insts,
                        const Scene *scene,
                        int digits);
  void reportPowerHighestInsts(size_t count,
                               const Scene *scene,
                               int digits);
  void reportPowerDesignJson(const Scene *scene,
                             int digits);
  void reportPowerInstsJson(const InstanceSeq &insts,
                            const Scene *scene,
                            int digits);
  Power *power() { return power_; }
  const Power *power() const { return power_; }
  void power(const Scene *scene,
             // Return values.
             PowerResult &total,
             PowerResult &sequential,
             PowerResult &combinational,
             PowerResult &clock,
             PowerResult &macro,
             PowerResult &pad);
  PowerResult power(const Instance *inst,
                    const Scene *scene);
  PwrActivity activity(const Pin *pin,
                       const Scene *scene);

  void writeTimingModel(std::string_view lib_name,
                        std::string_view cell_name,
                        std::string_view filename,
                        const Scene *scene);

  // Find equivalent cells in equiv_libs.
  // Optionally add mappings for cells in map_libs.
  void makeEquivCells(LibertyLibrarySeq *equiv_libs,
                      LibertyLibrarySeq *map_libs);
  LibertyCellSeq *equivCells(LibertyCell *cell);

  void writePathSpice(const Path *path,
                      std::string_view spice_filename,
                      std::string_view subckt_filename,
                      std::string_view lib_subckt_filename,
                      std::string_view model_filename,
                      std::string_view power_name,
                      std::string_view gnd_name,
                      CircuitSim ckt_sim);

  ////////////////////////////////////////////////////////////////
  // TCL Variables

  // TCL variable sta_crpr_enabled.
  // Common Reconvergent Clock Removal (CRPR).
  // Timing check source/target common clock path overlap for search
  // with analysis mode on_chip_variation.
  bool crprEnabled() const;
  void setCrprEnabled(bool enabled);
  // TCL variable sta_crpr_mode.
  CrprMode crprMode() const;
  void setCrprMode(CrprMode mode);
  // TCL variable sta_pocv_mode.
  // Parametric on chip variation (statisical sta).
  PocvMode pocvMode() const;
  void setPocvMode(PocvMode mode);
  // Number of std deviations from mean to use for normal distributions.
  float pocvQuantile();
  void setPocvQuantile(float quantile);
  // TCL variable sta_propagate_gated_clock_enable.
  // Propagate gated clock enable arrivals.
  bool propagateGatedClockEnable() const;
  void setPropagateGatedClockEnable(bool enable);
  // TCL variable sta_preset_clear_arcs_enabled.
  // Enable search through preset/clear arcs.
  bool presetClrArcsEnabled() const;
  void setPresetClrArcsEnabled(bool enable);
  // TCL variable sta_cond_default_arcs_enabled.
  // Enable/disable default arcs when conditional arcs exist.
  bool condDefaultArcsEnabled() const;
  void setCondDefaultArcsEnabled(bool enabled);
  // TCL variable sta_internal_bidirect_instance_paths_enabled.
  // Enable/disable timing from bidirect pins back into the instance.
  bool bidirectInstPathsEnabled() const;
  void setBidirectInstPathsEnabled(bool enabled);
  // TCL variable sta_recovery_removal_checks_enabled.
  bool recoveryRemovalChecksEnabled() const;
  void setRecoveryRemovalChecksEnabled(bool enabled);
  // TCL variable sta_gated_clock_checks_enabled.
  bool gatedClkChecksEnabled() const;
  void setGatedClkChecksEnabled(bool enabled);
  // TCL variable sta_dynamic_loop_breaking.
  bool dynamicLoopBreaking() const;
  void setDynamicLoopBreaking(bool enable);
  // TCL variable sta_propagate_all_clocks.
  // Clocks defined after sta_propagate_all_clocks is true
  // are propagated (existing clocks are not effected).
  bool propagateAllClocks() const;
  void setPropagateAllClocks(bool prop);
  // TCL var sta_clock_through_tristate_enabled.
  bool clkThruTristateEnabled() const;
  void setClkThruTristateEnabled(bool enable);
  // TCL variable sta_input_port_default_clock.
  bool useDefaultArrivalClock() const;
  void setUseDefaultArrivalClock(bool enable);
  ////////////////////////////////////////////////////////////////

  Properties &properties() { return properties_; }

protected:
  // Default constructors that are called by makeComponents in the Sta
  // constructor.  These can be redefined by a derived class to
  // specialize the sta components.
  virtual void makeVariables();
  virtual void makeReport();
  virtual void makeDebug();
  virtual void makeUnits();
  virtual void makeNetwork();
  virtual void makeSdcNetwork();
  virtual void makeGraph();
  virtual void makeDefaultScene();
  virtual void makeLevelize();
  virtual void makeArcDelayCalc();
  virtual void makeGraphDelayCalc();
  virtual void makeSearch();
  virtual void makeLatches(); 
  virtual void makeCheckTiming();
  virtual void makeCheckSlews();
  virtual void makeCheckFanouts();
  virtual void makeCheckCapacitances();
  virtual void makeCheckMinPulseWidths();
  virtual void makeCheckMinPeriods();
  virtual void makeCheckMaxSkews();
  virtual void makeReportPath();
  virtual void makePower();
  virtual void makeClkSkews();
  virtual void makeObservers();
  NetworkEdit *networkCmdEdit();

  LibertyLibrary *readLibertyFile(std::string_view filename,
                                  Scene *scene,
                                  const MinMaxAll *min_max,
                                  bool infer_latches);
  void delayCalcPreamble();
  void delaysInvalidFrom(const Port *port);
  void delaysInvalidFromFanin(const Port *port);
  void deleteEdge(Edge *edge);
  void netParasiticCaps(Net *net,
                        const RiseFall *rf,
                        const MinMax *min_max,
                        float &pin_cap,
                        float &wire_cap) const;
  const Pin *findNetParasiticDrvrPin(const Net *net) const;
  void exprConstantPins(FuncExpr *expr,
                        const Instance *inst,
                        const Mode *mode,
                        // Return value.
                        PinSet &pins);

  void reportDelaysWrtClks(const Pin *pin,
                           const Scene *scene,
                           bool report_variance,
                           int digits,
                           bool find_required,
                           const PathDelayFunc &get_path_delay);
  void reportDelaysWrtClks(Vertex *vertex,
                           const Scene *scene,
                           bool report_variance,
                           int digits,
                           bool find_required,
                           const PathDelayFunc &get_path_delay);
  void reportDelaysWrtClks(const ClockEdge *clk_edge,
                           bool report_variance,
                           int digits,
                           DelaysWrtClks &clk_delays);
  std::string formatDelay(const RiseFall *rf,
                          const MinMax *min_max,
                          const RiseFallMinMaxDelay &delays,
                          bool report_variance,
                          int digits);

  void connectDrvrPinAfter(Vertex *vertex);
  void connectLoadPinAfter(Vertex *vertex);
  Path *latchEnablePath(Path *q_path,
                        Edge *d_q_edge,
                        const ClockEdge *en_clk_edge);
  void clockSlewChanged(Clock *clk);
  void maxSkewPreamble();
  bool idealClockMode();
  void disableAfter();
  void findFaninPins(Vertex *vertex,
                     bool flat,
                     bool startpoints_only,
                     int inst_levels,
                     int pin_levels,
                     PinSet &fanin,
                     SearchPred &pred,
                     const Mode *mode);
  void findFaninPins(Vertex *to,
                     bool flat,
                     int inst_levels,
                     int pin_levels,
                     VertexSet &visited,
                     SearchPred *pred,
                     int inst_level,
                     int pin_level,
                     const Mode *mode);
  void findFanoutPins(Vertex *vertex,
                      bool flat,
                      bool endpoints_only,
                      int inst_levels,
                      int pin_levels,
                      PinSet &fanout,
                      SearchPred &pred,
                      const Mode *mode);
  void findFanoutPins(Vertex *from,
                      bool flat,
                      int inst_levels,
                      int pin_levels,
                      VertexSet &visited,
                      SearchPred *pred,
                      int inst_level,
                      int pin_level,
                     const Mode *mode);
  void findRegisterPreamble(const Mode *mode);
  bool crossesHierarchy(Edge *edge) const;
  void powerPreamble();
  void powerPreamble(const Scene *scene);
  virtual void replaceCell(Instance *inst,
                           Cell *to_cell,
                           LibertyCell *to_lib_cell);
  void clkSkewPreamble();
  void setCmdNamespace1(CmdNamespace namespc);
  void setThreadCount1(int thread_count);
  void updateLibertyScenes();
  void updateSceneLiberty(Scene *scene,
                          const StringSeq &liberty_min_files,
                          const StringSeq &liberty_max_files);
  void updateSceneLiberty(Scene *scene,
                          const StringSeq &liberty_files,
                          const MinMaxAll *min_max);

  Scene *makeScene(const std::string &name,
                   Mode *mode,
                   Parasitics *parasitics_min,
                   Parasitics *parasitics_max);
  Scene *makeScene(const std::string &name,
                   Mode *mode,
                   Parasitics *parasitics);
  void deleteScenes();
  void checkLibrarayPocv();

  Scene *cmd_scene_{nullptr};
  Mode *cmd_mode_{nullptr};
  CmdNamespace cmd_namespace_{CmdNamespace::sdc};
  Instance *current_instance_{nullptr};
  SceneNameMap scene_name_map_;
  ModeNameMap mode_name_map_;
  ParasiticsNameMap parasitics_name_map_;
  VerilogReader *verilog_reader_{nullptr};
  CheckTiming *check_timing_{nullptr};
  CheckSlews *check_slews_{nullptr};
  CheckFanouts *check_fanouts_{nullptr};
  CheckCapacitances *check_capacitances_{nullptr};
  CheckMinPulseWidths *check_min_pulse_widths_{nullptr};
  CheckMinPeriods *check_min_periods_{nullptr};
  CheckMaxSkews *check_max_skews_{nullptr};
  ClkSkews *clk_skews_{nullptr};
  ReportPath *report_path_{nullptr};
  Power *power_{nullptr};
  Tcl_Interp *tcl_interp_{nullptr};
  bool update_genclks_{false};
  EquivCells *equiv_cells_{nullptr};
  Properties properties_{this};

  // Singleton sta used by tcl command interpreter.
  inline static Sta *sta_{nullptr};
};

} // namespace sta
