diff --git a/.lock b/.lock new file mode 100644 index 0000000..e69de29 diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/crates.js b/crates.js new file mode 100644 index 0000000..e9d9053 --- /dev/null +++ b/crates.js @@ -0,0 +1 @@ +window.ALL_CRATES = ["metis","metis_sys"]; \ No newline at end of file diff --git a/help.html b/help.html new file mode 100644 index 0000000..b575de1 --- /dev/null +++ b/help.html @@ -0,0 +1,2 @@ +
pub const NOPTIONS: usize = _; // 40usize
The length of the options
array.
See Graph::set_options
for an example. It is also used in
+Mesh::set_options
.
pub enum Error {
+ Input,
+ Memory,
+ Other,
+}
Error type returned by METIS.
+Input is invalid.
+These bindings should check for most input errors, if not all.
+METIS hit an out-of-memory error.
+METIS returned an error but its meaning is unknown.
+#[non_exhaustive]pub enum NewGraphError {
+ NoConstraints,
+ NoParts,
+ TooLarge,
+ InvalidGraph(InvalidGraphError),
+}
Error type returned by Graph::new
.
Unlike Error
, this error originates from the Rust bindings.
ncon
must be greater than 1.
nparts
must be greater than 1.
Graph is too large. One of the array’s length doesn’t fit into Idx
.
The input arrays are malformed and cannot be safely passed to METIS.
+Note that these bindings do not check for all the invariants. Some might
+be raised during Graph::part_recursive
and Graph::part_kway
as
+Error::Input
.
#[non_exhaustive]pub enum NewMeshError {
+ NoParts,
+ TooLarge,
+ InvalidMesh(InvalidMeshError),
+}
nparts
must be greater than 1.
Mesh is too large. One of the array’s length doesn’t fit into Idx
.
The input arrays are malformed and cannot be safely passed to METIS.
+Note that these bindings do not check for all the invariants. Some might
+be raised during Mesh::part_dual
and Mesh::part_nodal
as
+Error::Input
.
This crate provides a thin but idiomatic API around libmetis.
+See Graph
for a usage example.
Graph::new
cannot be safely
+passed to METIS.Mesh::new
cannot be safely passed
+to METIS.Graph::new
.Mesh::new
.options
array.pub enum CType {
+ Rm,
+ Shem,
+}
Specifies the matching scheme to be used during coarsening.
+crate::Graph::set_options
and
+crate::Mesh::set_options
.crate::Graph::set_options
and crate::Mesh::set_options
.pub enum IpType {
+ Grow,
+ Random,
+ Edge,
+ Node,
+}
Determines the algorithm used during initial partitioning.
+Grows a bisection using a greedy strategy.
+Compute a bisection at random followed by a refinement.
+Derives a separator from an edge cut.
+Grow a bisection using a greedy node-based strategy.
+crate::Graph::set_options
and
+crate::Mesh::set_options
.crate::Graph::set_options
and crate::Mesh::set_options
.pub enum ObjType {
+ Cut,
+ Vol,
+}
Specifies the type of objective.
+crate::Graph::set_options
and
+crate::Mesh::set_options
.crate::Graph::set_options
and crate::Mesh::set_options
.pub enum PType {
+ Rb,
+ Kway,
+}
Specifies the partitioning method.
+crate::Graph::set_options
and
+crate::Mesh::set_options
.crate::Graph::set_options
and crate::Mesh::set_options
.pub enum RType {
+ Fm,
+ Greedy,
+ Sep2Sided,
+ Sep1Sided,
+}
Determines the algorithm used for refinement.
+FM-based cut refinement.
+Greedy-based cut and volume refinement.
+Two-sided FM refinement.
+One-sided FM refinement.
+crate::Graph::set_options
and
+crate::Mesh::set_options
.crate::Graph::set_options
and crate::Mesh::set_options
.Fine-tuning parameter types.
+For options that take an integer value, should this value be negative, the +default will be used, if any.
+pub struct CCOrder(pub bool);
Specifies if the connected components of the graph should first be +identified and ordered separately.
+0: bool
crate::Graph::set_options
and
+crate::Mesh::set_options
.crate::Graph::set_options
and crate::Mesh::set_options
.pub struct Compress(pub bool);
Specifies that the graph should be compressed by combining vertices +that have identical adjacency lists.
+0: bool
crate::Graph::set_options
and
+crate::Mesh::set_options
.crate::Graph::set_options
and crate::Mesh::set_options
.pub struct Contig(pub bool);
Specifies that the partitioning routines should try to produce partitions +that are contiguous.
+Note that if the input graph is not connected this option is ignored.
+0: bool
crate::Graph::set_options
and
+crate::Mesh::set_options
.crate::Graph::set_options
and crate::Mesh::set_options
.pub struct DbgLvl {
+ pub info: bool,
+ pub time: bool,
+ pub coarsen: bool,
+ pub refine: bool,
+ pub ipart: bool,
+ pub move_info: bool,
+ pub sep_info: bool,
+ pub conn_info: bool,
+ pub contig_info: bool,
+}
Specifies the amount of progress/debugging information will be printed +during the execution of the algorithms.
+The default value is false for every field (no debugging/progress +information).
+info: bool
Prints various diagnostic messages.
+time: bool
Performs timing analysis.
+coarsen: bool
Displays various statistics during coarsening.
+refine: bool
Displays various statistics during refinement.
+ipart: bool
Displays various statistics during initial partitioning.
+move_info: bool
Display detailed information about vertex moves during refinement.
+sep_info: bool
Display detailed information about vertex separators.
+conn_info: bool
Display information related to the minimization of subdomain +connectivity.
+contig_info: bool
Display information related to the elimination of connected components.
+crate::Graph::set_options
and
+crate::Mesh::set_options
.crate::Graph::set_options
and crate::Mesh::set_options
.pub struct MinConn(pub bool);
Specifies that the partitioning routines should try to minimize the maximum +degree of the subdomain graph.
+I.e., the graph in which each partition is a node, and edges connect +subdomains with a shared interface.
+0: bool
crate::Graph::set_options
and
+crate::Mesh::set_options
.crate::Graph::set_options
and crate::Mesh::set_options
.pub struct NCuts(pub Idx);
Specifies the number of different partitions that it will compute. The +final partition is the one that achieves the best edge cut or +communication volume. Default is 1.
+0: Idx
crate::Graph::set_options
and
+crate::Mesh::set_options
.crate::Graph::set_options
and crate::Mesh::set_options
.pub struct NIter(pub Idx);
Specifies the number of iterations for the refinement algorithms at each +stage of the uncoarsening process.
+Default is 10.
+0: Idx
crate::Graph::set_options
and
+crate::Mesh::set_options
.crate::Graph::set_options
and crate::Mesh::set_options
.pub struct NSeps(pub Idx);
Specifies the number of different separators that it will compute at each +level of nested dissection.
+The final separator that is used is the smallest one. Default is 1.
+0: Idx
crate::Graph::set_options
and
+crate::Mesh::set_options
.crate::Graph::set_options
and crate::Mesh::set_options
.pub struct No2Hop(pub bool);
Specifies that the coarsening will not perform any 2-hop matching when the +standards matching approach fails to sufficiently coarsen the graph.
+The 2-hop matching is very effective for graphs with power-law degree +distributions.
+0: bool
crate::Graph::set_options
and
+crate::Mesh::set_options
.crate::Graph::set_options
and crate::Mesh::set_options
.pub struct PFactor(pub Idx);
Specifies the minimum degree of the vertices that will be ordered last.
+If the specified value is x > 0
, then any vertices with a degree greater
+than 0.1*x*(average degree)
are removed from the graph, an ordering of the
+rest of the vertices is computed, and an overall ordering is computed by
+ordering the removed vertices at the end of the overall ordering. For
+example if x == 40
, and the average degree is 5, then the algorithm will
+remove all vertices with degree greater than 20. The vertices that are
+removed are ordered last (i.e., they are automatically placed in the
+top-level separator). Good values are often in the range of 60 to 200 (i.e.,
+6 to 20 times more than the average). Default value is 0, indicating that no
+vertices are removed.
Used to control whether the ordering algorithm should remove any +vertices with high degree (i.e., dense columns). This is particularly +helpful for certain classes of LP matrices, in which there a few vertices +that are connected to many other vertices. By removing these vertices prior +to ordering, the quality and the amount of time required to do the ordering +improves.
+0: Idx
crate::Graph::set_options
and
+crate::Mesh::set_options
.crate::Graph::set_options
and crate::Mesh::set_options
.pub struct Seed(pub Idx);
Specifies the seed for the random number generator.
+0: Idx
crate::Graph::set_options
and
+crate::Mesh::set_options
.crate::Graph::set_options
and crate::Mesh::set_options
.pub struct UFactor(pub Idx);
Specifies the maximum allowed load imbalance among the partitions.
+A value of x
indicates that the allowed load imbalance is (1 + x)/1000
.
+The load imbalance for the j
th constraint is defined to be
+max_i(w[j,i]/t[j,i])
, where w[j,i]
is the fraction of the overall
+weight of the j
th constraint that is assigned to thei
th partition and
+t[j,i]
is the desired target weight of the j
th constraint for the i
th
+partition (i.e., that specified via -tpwgts
). For -ptype=rb
, the default
+value is 1 (i.e., load imbalance of 1.001) and for -ptype=kway
, the
+default value is 30 (i.e., load imbalance of 1.03).
0: Idx
crate::Graph::set_options
and
+crate::Mesh::set_options
.crate::Graph::set_options
and crate::Mesh::set_options
.pub trait Opt: Sealed {
+ const INDEX: usize;
+
+ // Required method
+ fn value(self) -> Idx;
+}
Trait implemented by METIS’ options.
+See crate::Graph::set_options
for an example. It is also used in
+crate::Mesh::set_options
.
Index of the option in the array from crate::Graph::set_options
and
+crate::Mesh::set_options
.
Convert the value into metis’ format, for use with
+crate::Graph::set_options
and crate::Mesh::set_options
.
pub struct Dual { /* private fields */ }
The dual of a mesh.
+Result of mesh_to_dual
.
pub struct Graph<'a> { /* private fields */ }
Builder structure to set up a graph partition computation.
+This structure holds the required arguments for METIS to compute a +partition. It also offers methods to easily set any optional argument.
+// Make a graph with two vertices and an edge between the two.
+let xadj = &mut [0, 1, 2];
+let adjncy = &mut [1, 0];
+
+// Allocate the partition array which stores the partition of each vertex.
+let mut part = [0, 0];
+
+// There are one constraint and two parts. The partitioning algorithm used
+// is recursive bisection. The k-way algorithm can also be used.
+Graph::new(1, 2, xadj, adjncy)?
+ .part_recursive(&mut part)?;
+
+// The two vertices are placed in different parts.
+assert_ne!(part[0], part[1]);
Creates a new Graph
object to be partitioned.
ncon
is the number of constraints on each vertex (at least 1),nparts
is the number of parts wanted in the graph partition.CSR (Compressed Sparse Row) is a data structure for representing sparse
+matrices and is the primary data structure used by METIS. A CSR
+formatted graph is represented with two slices: an adjacency list
+(adjcny
) and an index list (xadj
). The nodes adjacent to node n
+are adjncy[xadj[n]..xadj[n + 1]]
. Additionally, metis requires that
+graphs are undirected: if (u, v)
is in the graph, then (v, u)
must
+also be in the graph.
Consider translating this simple graph to CSR format:
+ +// 5 - 3 - 4 - 0
+// | | /
+// 2 - 1
+let adjncy = [1, 4, 0, 2, 4, 1, 3, 2, 4, 5, 0, 1, 3, 3];
+let xadj = [0, 2, 5, 7, 10, 13, 14];
+
+// iterate over adjacent nodes
+let mut it = xadj
+ .windows(2)
+ .map(|x| &adjncy[x[0]..x[1]]);
+
+// node 0 is adjacent to nodes 1 and 4
+assert_eq!(it.next().unwrap(), &[1, 4]);
+
+// node 1 is adjacent to nodes 0, 2, and 4
+assert_eq!(it.next().unwrap(), &[0, 2, 4]);
+
+// node 2 is adjacent to nodes 1 and 3
+assert_eq!(it.next().unwrap(), &[1, 3]);
+
+// node 3 is adjacent to nodes 2, 4, and 5
+assert_eq!(it.next().unwrap(), &[2, 4, 5]);
+
+// node 4 is adjacent to nodes 0, 1, and 3
+assert_eq!(it.next().unwrap(), &[0, 1, 3]);
+
+// node 5 is adjacent to node 3
+assert_eq!(it.next().unwrap(), &[3]);
+
+assert!(it.next().is_none());
More info can be found at: +https://en.wikipedia.org/wiki/Sparse_matrix#Compressed_sparse_row_(CSR,_CRS_or_Yale_format)
+The following invariants must be held, otherwise this function returns +an error:
+Idx
,ncon
is strictly greater than zero,nparts
is strictly greater than zero,xadj
has at least one element (its length is the one more than the
+number of vertices),xadj
is sorted,xadj
are positive,xadj
is the length of adjncy
,adjncy
are within zero and the number of vertices.Graph::part_kway
and Graph::part_recursive
may mutate the
+contents of xadj
and adjncy
, but should revert all changes before
+returning.
Creates a new Graph
object to be partitioned (unchecked version).
ncon
is the number of constraints on each vertex (at least 1),nparts
is the number of parts wanted in the graph partition.xadj
and adjncy
are the CSR encoding of the adjacency matrix
+that represents the graph. xadj
is the row index and adjncy
is the
+column index.
This function still does some checks listed in “Panics” below. However,
+the caller is reponsible for upholding all invariants listed in the
+“Errors” section of Graph::new
. Otherwise, the behavior of this
+function is undefined.
This function panics if:
+Idx
, orncon
is not strictly greater than zero, ornparts
is not strictly greater than zero, orxadj
is empty, oradjncy
is different from the last element of xadj
.Graph::part_kway
and Graph::part_recursive
may mutate the
+contents of xadj
and adjncy
, but should revert all changes before
+returning.
Sets the computational weights of the vertices.
+By default, all vertices have the same weight.
+The ncon
weights of the i
th vertex must be located in
+vwgt[i*ncon..(i+1)*ncon]
, and all elements of vwgt
must be positive.
This function panics if the length of vwgt
is not ncon
times the
+number of vertices.
Sets the communication weights of the vertices.
+By default, all vertices have the same communication weight.
+Vertices can only have one communication weight. The length of vsize
+does not depend on ncon
.
This function panics if the length of vsize
is not the number of
+vertices.
Sets the weights of the edges.
+By default, all edges have the same weight.
+All elements of adjwgt
must be positive.
This function panics if the length of adjwgt
is not equal to the
+length of adjncy
.
Sets the target partition weights for each part and constraint.
+By default, the graph is divided equally.
+The target partition weight for the i
th part and j
th constraint is
+specified at tpwgts[i*ncon+j]
. For each constraint j
, the sum of the
+target partition weights must be 1.0. Meaning
+(0..nparts).map(|i| tpwgts[i*ncon+j]).sum() == 1.0
.
This function panics if the length of tpwgts
is not equal to ncon
+times nparts
.
Sets the load imbalance tolerance for each constraint.
+By default, it equals to 1.001 if ncon
equals 1 and 1.01 otherwise.
For the i
th partition and j
th constraint the allowed weight is the
+ubvec[j]*tpwgts[i*ncon+j]
fraction of the j
th’s constraint total
+weight. The load imbalances must be greater than 1.0.
This function panics if the length of ubvec
is not equal to ncon
.
Sets the fine-tuning parameters for this partitioning.
+When few options are to be set, Graph::set_option
might be a
+better fit.
See the option module for the list of available parameters. Note that +not all are applicable to a given partitioning method. Refer to the +documentation of METIS (link) for more info on this.
+use metis::option::Opt as _;
+
+let xadj = &[0, 1, 2];
+let adjncy = &[1, 0];
+let mut part = [0, 0];
+
+// -1 is the default value.
+let mut options = [-1; metis::NOPTIONS];
+
+// four refinement iterations instead of the default 10.
+options[metis::option::NIter::INDEX] = 4;
+
+Graph::new(1, 2, xadj, adjncy)?
+ .set_options(&options)
+ .part_recursive(&mut part)?;
+
+// The two vertices are placed in different parts.
+assert_ne!(part[0], part[1]);
Sets a fine-tuning parameter for this partitioning.
+When options are to be set in batches, Graph::set_options
might be a
+better fit.
See the option module for the list of available parameters. Note that +not all are applicable to a given partitioning method. Refer to the +documentation of METIS (link) for more info on this.
+let xadj = &[0, 1, 2];
+let adjncy = &[1, 0];
+let mut part = [0, 0];
+
+Graph::new(1, 2, xadj, adjncy)?
+ .set_option(metis::option::NIter(4))
+ .part_recursive(&mut part)?;
+
+// The two vertices are placed in different parts.
+assert_ne!(part[0], part[1]);
Partition the graph using multilevel recursive bisection.
+Returns the edge-cut, the total communication volume of the +partitioning solution.
+Equivalent of METIS_PartGraphRecursive
.
This function panics if the length of part
is not the number of
+vertices.
Partition the graph using multilevel k-way partitioning.
+Returns the edge-cut, the total communication volume of the +partitioning solution.
+Equivalent of METIS_PartGraphKway
.
This function panics if the length of part
is not the number of
+vertices.
pub struct InvalidGraphError { /* private fields */ }
Error raised when the graph data fed to Graph::new
cannot be safely
+passed to METIS.
Graph data must follow the format described in Graph::new
.
pub struct InvalidMeshError { /* private fields */ }
pub struct Mesh<'a> { /* private fields */ }
Creates a new Mesh
object to be partitioned.
nparts
is the number of parts wanted in the mesh partition.
The length of eptr
is n + 1
, where n
is the number of elements in
+the mesh. The length of eind
is the sum of the number of nodes in all
+the elements of the mesh. The list of nodes belonging to the i
th
+element of the mesh are stored in consecutive locations of eind
+starting at position eptr[i]
up to (but not including) position
+eptr[i+1]
.
The following invariants must be held, otherwise this function returns +an error:
+nparts
is strictly greater than zero,eptr
has at least one element (its length is the one more than the
+number of mesh elements),eptr
is sorted,eptr
are positive,eptr
is the length of eind
,Idx
.Mesh::part_dual
and Mesh::part_nodal
may mutate the contents of
+eptr
and eind
, but should revert all changes before returning.
Creates a new Mesh
object to be partitioned (unchecked version).
nn
is the number of nodes in the mesh,nparts
is the number of parts wanted in the mesh partition.See Mesh::new
.
This function still does some checks listed in “Panics” below. However,
+the caller is reponsible for upholding all invariants listed in the
+“Errors” section of Mesh::new
. Otherwise, the behavior of this
+function is undefined.
This function panics if:
+Idx
, ornn
is not strictly greater than zero, ornparts
is not strictly greater than zero, oreptr
is empty, oreind
is different from the last element of eptr
.While nothing should be modified by the Mesh
structure, METIS
+doesn’t specify any const
modifier, so everything must be mutable on
+Rust’s side.
Sets the computational weights of the elements.
+By default, all elements have the same weight.
+All elements of vwgt
must be positive.
This function panics if the length of vwgt
is not the number of
+elements.
Sets the communication weights of the elements.
+By default, all elements have the same communication weight.
+This function panics if the length of vsize
is not the number of
+elements.
Sets the target partition weights for each part.
+By default, the mesh is divided equally.
+The sum of the target partition weights must be 1.0.
+This function panics if the length of tpwgts
is not equal to nparts
.
Sets the fine-tuning parameters for this partitioning.
+When few options are to be set, Mesh::set_option
might be a
+better fit.
See the option module for the list of available parameters. Note that +not all are applicable to a given partitioning method. Refer to the +documentation of METIS (link) for more info on this.
+See Graph::set_options
for a usage example.
Sets a fine-tuning parameter for this partitioning.
+When options are to be set in batches, Mesh::set_options
might be a
+better fit.
See the option module for the list of available parameters. Note that +not all are applicable to a given partitioning method. Refer to the +documentation of METIS (link) for more info on this.
+See Graph::set_option
for a usage example.
Partition the mesh using its dual graph.
+Returns the edge-cut, the total communication volume of the +partitioning solution.
+Equivalent of METIS_PartMeshDual
.
This function panics if the length of epart
is not the number of
+elements, or if nparts
’s is not the number of nodes.
Partition the mesh using its nodal graph.
+Returns the edge-cut, the total communication volume of the +partitioning solution.
+Previous settings of ncommon
are not used by this function.
Equivalent of METIS_PartMeshNodal
.
This function panics if the length of epart
is not the number of
+elements, or if nparts
’s is not the number of nodes.
pub const METIS_NOPTIONS: u32 = 40;
pub const METIS_VER_MAJOR: u32 = 5;
pub const METIS_VER_MINOR: u32 = 2;
pub const METIS_VER_SUBMINOR: u32 = 1;
pub const mctype_et_METIS_CTYPE_RM: mctype_et = 0;
pub const mctype_et_METIS_CTYPE_SHEM: mctype_et = 1;
pub const mdbglvl_et_METIS_DBG_COARSEN: mdbglvl_et = 4;
< Show the coarsening progress
+pub const mdbglvl_et_METIS_DBG_CONNINFO: mdbglvl_et = 128;
< Show info on minimization of subdomain connectivity
+pub const mdbglvl_et_METIS_DBG_CONTIGINFO: mdbglvl_et = 256;
< Show info on elimination of connected components
+pub const mdbglvl_et_METIS_DBG_INFO: mdbglvl_et = 1;
< Shows various diagnostic messages
+pub const mdbglvl_et_METIS_DBG_IPART: mdbglvl_et = 16;
< Show info on initial partitioning
+pub const mdbglvl_et_METIS_DBG_MEMORY: mdbglvl_et = 2048;
< Show info related to wspace allocation
+pub const mdbglvl_et_METIS_DBG_MOVEINFO: mdbglvl_et = 32;
< Show info on vertex moves during refinement
+pub const mdbglvl_et_METIS_DBG_REFINE: mdbglvl_et = 8;
< Show the refinement progress
+pub const mdbglvl_et_METIS_DBG_SEPINFO: mdbglvl_et = 64;
< Show info on vertex moves during sep refinement
+pub const mdbglvl_et_METIS_DBG_TIME: mdbglvl_et = 2;
< Perform timing analysis
+pub const mgtype_et_METIS_GTYPE_DUAL: mgtype_et = 0;
pub const mgtype_et_METIS_GTYPE_NODAL: mgtype_et = 1;
pub const miptype_et_METIS_IPTYPE_EDGE: miptype_et = 2;
pub const miptype_et_METIS_IPTYPE_GROW: miptype_et = 0;
pub const miptype_et_METIS_IPTYPE_METISRB: miptype_et = 4;
pub const miptype_et_METIS_IPTYPE_NODE: miptype_et = 3;
pub const miptype_et_METIS_IPTYPE_RANDOM: miptype_et = 1;
pub const mobjtype_et_METIS_OBJTYPE_CUT: mobjtype_et = 0;
pub const mobjtype_et_METIS_OBJTYPE_NODE: mobjtype_et = 2;
pub const mobjtype_et_METIS_OBJTYPE_VOL: mobjtype_et = 1;
pub const moptions_et_METIS_OPTION_BALANCE: moptions_et = 27;
pub const moptions_et_METIS_OPTION_CCORDER: moptions_et = 14;
pub const moptions_et_METIS_OPTION_COMPRESS: moptions_et = 13;
pub const moptions_et_METIS_OPTION_CONTIG: moptions_et = 12;
pub const moptions_et_METIS_OPTION_CTYPE: moptions_et = 2;
pub const moptions_et_METIS_OPTION_DBGLVL: moptions_et = 5;
pub const moptions_et_METIS_OPTION_DROPEDGES: moptions_et = 19;
pub const moptions_et_METIS_OPTION_FAST: moptions_et = 22;
pub const moptions_et_METIS_OPTION_GTYPE: moptions_et = 28;
pub const moptions_et_METIS_OPTION_HELP: moptions_et = 23;
pub const moptions_et_METIS_OPTION_IPTYPE: moptions_et = 3;
pub const moptions_et_METIS_OPTION_MINCONN: moptions_et = 11;
pub const moptions_et_METIS_OPTION_NCOMMON: moptions_et = 25;
pub const moptions_et_METIS_OPTION_NCUTS: moptions_et = 8;
pub const moptions_et_METIS_OPTION_NIPARTS: moptions_et = 6;
pub const moptions_et_METIS_OPTION_NITER: moptions_et = 7;
pub const moptions_et_METIS_OPTION_NO2HOP: moptions_et = 20;
pub const moptions_et_METIS_OPTION_NOOUTPUT: moptions_et = 26;
pub const moptions_et_METIS_OPTION_NSEPS: moptions_et = 16;
pub const moptions_et_METIS_OPTION_NUMBERING: moptions_et = 18;
pub const moptions_et_METIS_OPTION_OBJTYPE: moptions_et = 1;
pub const moptions_et_METIS_OPTION_ONDISK: moptions_et = 10;
pub const moptions_et_METIS_OPTION_PFACTOR: moptions_et = 15;
pub const moptions_et_METIS_OPTION_PTYPE: moptions_et = 0;
pub const moptions_et_METIS_OPTION_RTYPE: moptions_et = 4;
pub const moptions_et_METIS_OPTION_SEED: moptions_et = 9;
pub const moptions_et_METIS_OPTION_TPWGTS: moptions_et = 24;
pub const moptions_et_METIS_OPTION_TWOHOP: moptions_et = 21;
pub const moptions_et_METIS_OPTION_UBVEC: moptions_et = 29;
pub const moptions_et_METIS_OPTION_UFACTOR: moptions_et = 17;
pub const moptype_et_METIS_OP_KMETIS: moptype_et = 1;
pub const moptype_et_METIS_OP_OMETIS: moptype_et = 2;
pub const moptype_et_METIS_OP_PMETIS: moptype_et = 0;
pub const mptype_et_METIS_PTYPE_KWAY: mptype_et = 1;
pub const mptype_et_METIS_PTYPE_RB: mptype_et = 0;
pub const mrtype_et_METIS_RTYPE_FM: mrtype_et = 0;
pub const mrtype_et_METIS_RTYPE_GREEDY: mrtype_et = 1;
pub const mrtype_et_METIS_RTYPE_SEP1SIDED: mrtype_et = 3;
pub const mrtype_et_METIS_RTYPE_SEP2SIDED: mrtype_et = 2;
pub const rstatus_et_METIS_ERROR: rstatus_et = -4;
< Some other errors
+pub const rstatus_et_METIS_ERROR_INPUT: rstatus_et = -2;
< Returned due to erroneous inputs and/or options
+pub const rstatus_et_METIS_ERROR_MEMORY: rstatus_et = -3;
< Returned due to insufficient memory
+pub const rstatus_et_METIS_OK: rstatus_et = 1;
< Returned normally
+pub unsafe extern "C" fn METIS_PartGraphKway(
+ nvtxs: *mut idx_t,
+ ncon: *mut idx_t,
+ xadj: *mut idx_t,
+ adjncy: *mut idx_t,
+ vwgt: *mut idx_t,
+ vsize: *mut idx_t,
+ adjwgt: *mut idx_t,
+ nparts: *mut idx_t,
+ tpwgts: *mut real_t,
+ ubvec: *mut real_t,
+ options: *mut idx_t,
+ edgecut: *mut idx_t,
+ part: *mut idx_t
+) -> c_int
pub unsafe extern "C" fn METIS_PartGraphRecursive(
+ nvtxs: *mut idx_t,
+ ncon: *mut idx_t,
+ xadj: *mut idx_t,
+ adjncy: *mut idx_t,
+ vwgt: *mut idx_t,
+ vsize: *mut idx_t,
+ adjwgt: *mut idx_t,
+ nparts: *mut idx_t,
+ tpwgts: *mut real_t,
+ ubvec: *mut real_t,
+ options: *mut idx_t,
+ edgecut: *mut idx_t,
+ part: *mut idx_t
+) -> c_int
pub unsafe extern "C" fn METIS_PartMeshDual(
+ ne: *mut idx_t,
+ nn: *mut idx_t,
+ eptr: *mut idx_t,
+ eind: *mut idx_t,
+ vwgt: *mut idx_t,
+ vsize: *mut idx_t,
+ ncommon: *mut idx_t,
+ nparts: *mut idx_t,
+ tpwgts: *mut real_t,
+ options: *mut idx_t,
+ objval: *mut idx_t,
+ epart: *mut idx_t,
+ npart: *mut idx_t
+) -> c_int
pub unsafe extern "C" fn METIS_PartMeshNodal(
+ ne: *mut idx_t,
+ nn: *mut idx_t,
+ eptr: *mut idx_t,
+ eind: *mut idx_t,
+ vwgt: *mut idx_t,
+ vsize: *mut idx_t,
+ nparts: *mut idx_t,
+ tpwgts: *mut real_t,
+ options: *mut idx_t,
+ objval: *mut idx_t,
+ epart: *mut idx_t,
+ npart: *mut idx_t
+) -> c_int
pub type mdbglvl_et = c_int;
Debug Levels
+pub type miptype_et = c_int;
Initial partitioning schemes
+pub type mobjtype_et = c_int;
pub type moptions_et = c_int;
Options codes (i.e., options[])
+pub type moptype_et = c_int;
Operation type codes
+pub type rstatus_et = c_int;
Return codes
+i32
or an i64
.","Input is invalid.","The input arrays are malformed and cannot be safely passed …","Error raised when the graph data fed to Graph::new
cannot …","The input arrays are malformed and cannot be safely passed …","Error raised when the mesh data fed to Mesh::new
cannot be …","METIS hit an out-of-memory error.","Builder structure to set up a mesh partition computation.","The length of the options
array.","Error type returned by Graph::new
.","Error type returned by Mesh::new
.","ncon
must be greater than 1.","nparts
must be greater than 1.","nparts
must be greater than 1.","Contains the success value","METIS returned an error but its meaning is unknown.","Floating-point type used by METIS, can either be an f32
or …","The result of a partitioning.","Graph is too large. One of the array’s length doesn’t …","Mesh is too large. One of the array’s length doesn’t …","The adjacency array.","The adjacency index array, and the adjacency array as …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Generate the dual graph of a mesh.","Creates a new Graph
object to be partitioned.","Creates a new Mesh
object to be partitioned.","Creates a new Graph
object to be partitioned (unchecked …","Creates a new Mesh
object to be partitioned (unchecked …","Fine-tuning parameter types.","Partition the mesh using its dual graph.","Partition the graph using multilevel k-way partitioning.","Partition the mesh using its nodal graph.","Partition the graph using multilevel recursive bisection.","Sets the weights of the edges.","Sets a fine-tuning parameter for this partitioning.","Sets a fine-tuning parameter for this partitioning.","Sets the fine-tuning parameters for this partitioning.","Sets the fine-tuning parameters for this partitioning.","Sets the target partition weights for each part and …","Sets the target partition weights for each part.","Sets the load imbalance tolerance for each constraint.","Sets the communication weights of the vertices.","Sets the communication weights of the elements.","Sets the computational weights of the vertices.","Sets the computational weights of the elements.","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","The adjacency index array.","Specifies if the connected components of the graph should …","Specifies the matching scheme to be used during coarsening.","Specifies that the graph should be compressed by combining …","Specifies that the partitioning routines should try to …","Edge-cut minimization.","Specifies the amount of progress/debugging information …","Derives a separator from an edge cut.","FM-based cut refinement.","Greedy-based cut and volume refinement.","Grows a bisection using a greedy strategy.","Index of the option in the array from …","Determines the algorithm used during initial partitioning.","Multilevel k-way partitioning.","Specifies that the partitioning routines should try to …","Specifies the number of different partitions that it will …","Specifies the number of iterations for the refinement …","Specifies the number of different separators that it will …","Specifies that the coarsening will not perform any 2-hop …","Grow a bisection using a greedy node-based strategy.","Specifies the type of objective.","Trait implemented by METIS’ options.","Specifies the minimum degree of the vertices that will be …","Specifies the partitioning method.","Determines the algorithm used for refinement.","Compute a bisection at random followed by a refinement.","Multilevel recursive bisection.","Random matching.","Specifies the seed for the random number generator.","One-sided FM refinement.","Two-sided FM refinement.","Sorted heavy-edge matching.","Specifies the maximum allowed load imbalance among the …","Total communication volume minimization.","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Displays various statistics during coarsening.","Display information related to the minimization of …","Display information related to the elimination of …","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Prints various diagnostic messages.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Displays various statistics during initial partitioning.","Display detailed information about vertex moves during …","Displays various statistics during refinement.","Display detailed information about vertex separators.","Performs timing analysis.","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Convert the value into metis’ format, for use with …","","","","","","","","","","","","","","","","",""],"i":[0,15,0,0,0,5,12,0,14,0,5,0,0,0,0,12,12,14,15,5,0,0,12,14,1,1,5,11,12,7,13,14,8,1,5,11,12,7,13,14,8,1,1,5,7,8,1,5,5,11,11,12,12,7,13,13,14,14,8,1,5,5,5,11,12,7,13,14,8,1,5,11,12,7,13,14,8,1,0,7,8,7,8,0,8,7,8,7,7,7,8,7,8,7,8,7,7,8,7,8,5,11,12,13,14,5,11,12,7,13,14,8,1,5,11,12,7,13,14,8,1,5,11,12,7,13,14,8,1,1,0,0,0,0,23,0,25,26,26,25,17,0,22,0,0,0,0,0,25,0,0,0,0,0,25,22,24,0,26,26,24,0,23,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,38,38,38,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,38,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,38,38,38,38,38,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,17,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"f":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,[1,[[3,[2]]]],[1,[[4,[[3,[2]],[3,[2]]]]]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[1,4],[[5,5],6],[[7,7],6],[[8,8],6],[[1,1],6],[[5,9],10],[[5,9],10],[[11,9],10],[[11,9],10],[[12,9],10],[[12,9],10],[[7,9],10],[[13,9],10],[[13,9],10],[[14,9],10],[[14,9],10],[[8,9],10],[[1,9],10],[14,5],[12,5],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[[[3,[2]],[3,[2]],2],[[15,[1]]]],[[2,2,[3,[2]],[3,[2]]],[[16,[7,12]]]],[[2,[3,[2]],[3,[2]]],[[16,[8,14]]]],[[2,2,[3,[2]],[3,[2]]],7],[[2,2,[3,[2]],[3,[2]]],8],0,[[8,[3,[2]],[3,[2]]],[[15,[2]]]],[[7,[3,[2]]],[[15,[2]]]],[[8,[3,[2]],[3,[2]]],[[15,[2]]]],[[7,[3,[2]]],[[15,[2]]]],[[7,[3,[2]]],7],[[7,-1],7,17],[[8,-1],8,17],[[7,[18,[2]]],7],[[8,[18,[2]]],8],[[7,[3,[19]]],7],[[8,[3,[19]]],8],[[7,[3,[19]]],7],[[7,[3,[2]]],7],[[8,[3,[2]]],8],[[7,[3,[2]]],7],[[8,[3,[2]]],8],[-1,20,[]],[-1,20,[]],[-1,20,[]],[-1,20,[]],[-1,20,[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,21,[]],[-1,21,[]],[-1,21,[]],[-1,21,[]],[-1,21,[]],[-1,21,[]],[-1,21,[]],[-1,21,[]],[1,[[3,[2]]]],0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],0,0,0,[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],0,[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],0,0,0,0,0,[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,21,[]],[-1,21,[]],[-1,21,[]],[-1,21,[]],[-1,21,[]],[-1,21,[]],[-1,21,[]],[-1,21,[]],[-1,21,[]],[-1,21,[]],[-1,21,[]],[-1,21,[]],[-1,21,[]],[-1,21,[]],[-1,21,[]],[-1,21,[]],[-1,21,[]],[17,2],[22,2],[23,2],[24,2],[25,2],[26,2],[27,2],[28,2],[29,2],[30,2],[31,2],[32,2],[33,2],[34,2],[35,2],[36,2],[37,2],[38,2]],"c":[],"p":[[5,"Dual",0],[8,"Idx",0],[1,"slice"],[1,"tuple"],[6,"Error",0],[1,"bool"],[5,"Graph",0],[5,"Mesh",0],[5,"Formatter",309],[8,"Result",309],[5,"InvalidGraphError",0],[6,"NewGraphError",0],[5,"InvalidMeshError",0],[6,"NewMeshError",0],[8,"Result",0],[6,"Result",310],[10,"Opt",130],[1,"array"],[8,"Real",0],[5,"String",311],[5,"TypeId",312],[6,"PType",130],[6,"ObjType",130],[6,"CType",130],[6,"IpType",130],[6,"RType",130],[5,"NCuts",130],[5,"NSeps",130],[5,"NIter",130],[5,"Seed",130],[5,"MinConn",130],[5,"No2Hop",130],[5,"Contig",130],[5,"Compress",130],[5,"CCOrder",130],[5,"PFactor",130],[5,"UFactor",130],[5,"DbgLvl",130]],"b":[[47,"impl-Debug-for-Error"],[48,"impl-Display-for-Error"],[49,"impl-Debug-for-InvalidGraphError"],[50,"impl-Display-for-InvalidGraphError"],[51,"impl-Debug-for-NewGraphError"],[52,"impl-Display-for-NewGraphError"],[54,"impl-Debug-for-InvalidMeshError"],[55,"impl-Display-for-InvalidMeshError"],[56,"impl-Display-for-NewMeshError"],[57,"impl-Debug-for-NewMeshError"],[60,"impl-From%3CNewMeshError%3E-for-Error"],[61,"impl-From%3CNewGraphError%3E-for-Error"]]}],\
+["metis_sys",{"doc":"","t":"HHHHHSHHHHHHHHSSSIISSISSSSSSSSSSISSISSSSSISSSISSSSSSSSSSSSSSSSSSSSSSSSSSSSSSISSSISSISSSSIISSSS","n":["METIS_CacheFriendlyReordering","METIS_ComputeVertexSeparator","METIS_Free","METIS_MeshToDual","METIS_MeshToNodal","METIS_NOPTIONS","METIS_NodeND","METIS_NodeNDP","METIS_NodeRefine","METIS_PartGraphKway","METIS_PartGraphRecursive","METIS_PartMeshDual","METIS_PartMeshNodal","METIS_SetDefaultOptions","METIS_VER_MAJOR","METIS_VER_MINOR","METIS_VER_SUBMINOR","idx_t","mctype_et","mctype_et_METIS_CTYPE_RM","mctype_et_METIS_CTYPE_SHEM","mdbglvl_et","mdbglvl_et_METIS_DBG_COARSEN","mdbglvl_et_METIS_DBG_CONNINFO","mdbglvl_et_METIS_DBG_CONTIGINFO","mdbglvl_et_METIS_DBG_INFO","mdbglvl_et_METIS_DBG_IPART","mdbglvl_et_METIS_DBG_MEMORY","mdbglvl_et_METIS_DBG_MOVEINFO","mdbglvl_et_METIS_DBG_REFINE","mdbglvl_et_METIS_DBG_SEPINFO","mdbglvl_et_METIS_DBG_TIME","mgtype_et","mgtype_et_METIS_GTYPE_DUAL","mgtype_et_METIS_GTYPE_NODAL","miptype_et","miptype_et_METIS_IPTYPE_EDGE","miptype_et_METIS_IPTYPE_GROW","miptype_et_METIS_IPTYPE_METISRB","miptype_et_METIS_IPTYPE_NODE","miptype_et_METIS_IPTYPE_RANDOM","mobjtype_et","mobjtype_et_METIS_OBJTYPE_CUT","mobjtype_et_METIS_OBJTYPE_NODE","mobjtype_et_METIS_OBJTYPE_VOL","moptions_et","moptions_et_METIS_OPTION_BALANCE","moptions_et_METIS_OPTION_CCORDER","moptions_et_METIS_OPTION_COMPRESS","moptions_et_METIS_OPTION_CONTIG","moptions_et_METIS_OPTION_CTYPE","moptions_et_METIS_OPTION_DBGLVL","moptions_et_METIS_OPTION_DROPEDGES","moptions_et_METIS_OPTION_FAST","moptions_et_METIS_OPTION_GTYPE","moptions_et_METIS_OPTION_HELP","moptions_et_METIS_OPTION_IPTYPE","moptions_et_METIS_OPTION_MINCONN","moptions_et_METIS_OPTION_NCOMMON","moptions_et_METIS_OPTION_NCUTS","moptions_et_METIS_OPTION_NIPARTS","moptions_et_METIS_OPTION_NITER","moptions_et_METIS_OPTION_NO2HOP","moptions_et_METIS_OPTION_NOOUTPUT","moptions_et_METIS_OPTION_NSEPS","moptions_et_METIS_OPTION_NUMBERING","moptions_et_METIS_OPTION_OBJTYPE","moptions_et_METIS_OPTION_ONDISK","moptions_et_METIS_OPTION_PFACTOR","moptions_et_METIS_OPTION_PTYPE","moptions_et_METIS_OPTION_RTYPE","moptions_et_METIS_OPTION_SEED","moptions_et_METIS_OPTION_TPWGTS","moptions_et_METIS_OPTION_TWOHOP","moptions_et_METIS_OPTION_UBVEC","moptions_et_METIS_OPTION_UFACTOR","moptype_et","moptype_et_METIS_OP_KMETIS","moptype_et_METIS_OP_OMETIS","moptype_et_METIS_OP_PMETIS","mptype_et","mptype_et_METIS_PTYPE_KWAY","mptype_et_METIS_PTYPE_RB","mrtype_et","mrtype_et_METIS_RTYPE_FM","mrtype_et_METIS_RTYPE_GREEDY","mrtype_et_METIS_RTYPE_SEP1SIDED","mrtype_et_METIS_RTYPE_SEP2SIDED","real_t","rstatus_et","rstatus_et_METIS_ERROR","rstatus_et_METIS_ERROR_INPUT","rstatus_et_METIS_ERROR_MEMORY","rstatus_et_METIS_OK"],"q":[[0,"metis_sys"]],"d":["","","","","","","","","","","","","","","","","","","Coarsening Schemes","","","Debug Levels","< Show the coarsening progress","< Show info on minimization of subdomain connectivity","< Show info on elimination of connected components","< Shows various diagnostic messages","< Show info on initial partitioning","< Show info related to wspace allocation","< Show info on vertex moves during refinement","< Show the refinement progress","< Show info on vertex moves during sep refinement","< Perform timing analysis","Graph types for meshes","","","Initial partitioning schemes","","","","","","","","","","Options codes (i.e., options[])","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Operation type codes","","","","Partitioning Schemes","","","Refinement schemes","","","","","","Return codes","< Some other errors","< Returned due to erroneous inputs and/or options","< Returned due to insufficient memory","< Returned normally"],"i":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"f":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"c":[],"p":[],"b":[]}]\
+]'));
+if (typeof exports !== 'undefined') exports.searchIndex = searchIndex;
+else if (window.initSearch) window.initSearch(searchIndex);
diff --git a/settings.html b/settings.html
new file mode 100644
index 0000000..c5871ba
--- /dev/null
+++ b/settings.html
@@ -0,0 +1,2 @@
+1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784 +785 +786 +787 +788 +789 +790 +791 +792 +793 +794 +795 +796 +797 +798 +799 +800 +801 +802 +803 +804 +805 +806 +807 +808 +809 +810 +811 +812 +813 +814 +815 +816 +817 +818 +819 +820 +821 +822 +823 +824 +825 +826 +827 +828 +829 +830 +831 +832 +833 +834 +835 +836 +837 +838 +839 +840 +841 +842 +843 +844 +845 +846 +847 +848 +849 +850 +851 +852 +853 +854 +855 +856 +857 +858 +859 +860 +861 +862 +863 +864 +865 +866 +867 +868 +869 +870 +871 +872 +873 +874 +875 +876 +877 +878 +879 +880 +881 +882 +883 +884 +885 +886 +887 +888 +889 +890 +891 +892 +893 +894 +895 +896 +897 +898 +899 +900 +901 +902 +903 +904 +905 +906 +907 +908 +909 +910 +911 +912 +913 +914 +915 +916 +917 +918 +919 +920 +921 +922 +923 +924 +925 +926 +927 +928 +929 +930 +931 +932 +933 +934 +935 +936 +937 +938 +939 +940 +941 +942 +943 +944 +945 +946 +947 +948 +949 +950 +951 +952 +953 +954 +955 +956 +957 +958 +959 +960 +961 +962 +963 +964 +965 +966 +967 +968 +969 +970 +971 +972 +973 +974 +975 +976 +977 +978 +979 +980 +981 +982 +983 +984 +985 +986 +987 +988 +989 +990 +991 +992 +993 +994 +995 +996 +997 +998 +999 +1000 +1001 +1002 +1003 +1004 +1005 +1006 +1007 +1008 +1009 +1010 +1011 +1012 +1013 +1014 +1015 +1016 +1017 +1018 +1019 +1020 +1021 +1022 +1023 +1024 +1025 +1026 +1027 +1028 +1029 +1030 +1031 +1032 +1033 +1034 +1035 +1036 +1037 +1038 +1039 +1040 +1041 +1042 +1043 +1044 +1045 +1046 +1047 +1048 +1049 +1050 +1051 +1052 +1053 +1054 +1055 +1056 +1057 +1058 +1059 +1060 +1061 +1062 +1063 +1064 +1065 +1066 +1067 +1068 +1069 +1070 +1071 +1072 +1073 +1074 +1075 +1076 +1077 +1078 +1079 +1080 +1081 +1082 +1083 +1084 +1085 +1086 +1087 +1088 +1089 +1090 +1091 +1092 +1093 +1094 +1095 +1096 +1097 +1098 +1099 +1100 +1101 +1102 +1103 +1104 +1105 +1106 +1107 +1108 +1109 +1110 +1111 +1112 +1113 +1114 +1115 +1116 +1117 +1118 +1119 +1120 +1121 +1122 +1123 +1124 +1125 +1126 +1127 +1128 +1129 +1130 +1131 +1132 +1133 +1134 +1135 +1136 +1137 +1138 +1139 +1140 +1141 +1142 +1143 +1144 +1145 +1146 +1147 +1148 +1149 +1150 +1151 +1152 +1153 +1154 +1155 +1156 +1157 +1158 +1159 +1160 +1161 +1162 +1163 +1164 +1165 +1166 +1167 +1168 +1169 +1170 +1171 +1172 +1173 +1174 +1175 +1176 +1177 +1178 +1179 +1180 +1181 +1182 +1183 +1184 +1185 +1186 +1187 +1188 +1189 +1190 +1191 +1192 +
//! This crate provides a thin but idiomatic API around libmetis.
+//!
+//! See [`Graph`] for a usage example.
+
+#![deny(missing_docs)]
+
+use crate::option::Opt;
+use metis_sys as m;
+use std::convert::TryFrom;
+use std::fmt;
+use std::mem;
+use std::os;
+use std::ptr;
+use std::result::Result as StdResult;
+use std::slice;
+
+pub mod option;
+
+#[cfg(target_pointer_width = "16")]
+compile_error!("METIS does not support 16-bit architectures");
+
+/// Integer type used by METIS, can either be an [`i32`] or an [`i64`].
+pub type Idx = m::idx_t;
+
+/// Floating-point type used by METIS, can either be an [`f32`] or an [`f64`].
+pub type Real = m::real_t;
+
+/// The length of the `options` array.
+///
+/// See [`Graph::set_options`] for an example. It is also used in
+/// [`Mesh::set_options`].
+pub const NOPTIONS: usize = m::METIS_NOPTIONS as usize;
+
+/// Error type returned by METIS.
+#[derive(Debug, PartialEq, Eq)]
+pub enum Error {
+ /// Input is invalid.
+ ///
+ /// These bindings should check for most input errors, if not all.
+ Input,
+
+ /// METIS hit an out-of-memory error.
+ Memory,
+
+ /// METIS returned an error but its meaning is unknown.
+ Other,
+}
+
+impl std::error::Error for Error {}
+
+impl From<NewGraphError> for Error {
+ fn from(_: NewGraphError) -> Self {
+ Self::Input
+ }
+}
+
+impl From<NewMeshError> for Error {
+ fn from(_: NewMeshError) -> Self {
+ Self::Input
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Error::Input => write!(f, "invalid input"),
+ Error::Memory => write!(f, "out of memory"),
+ Error::Other => write!(f, "METIS returned an error"),
+ }
+ }
+}
+
+/// The result of a partitioning.
+pub type Result<T> = StdResult<T, Error>;
+
+trait ErrorCode {
+ /// Makes a [`Result`] from a return code (int) from METIS.
+ fn wrap(self) -> Result<()>;
+}
+
+impl ErrorCode for m::rstatus_et {
+ fn wrap(self) -> Result<()> {
+ match self {
+ m::rstatus_et_METIS_OK => Ok(()),
+ m::rstatus_et_METIS_ERROR_INPUT => Err(Error::Input),
+ m::rstatus_et_METIS_ERROR_MEMORY => Err(Error::Memory),
+ m::rstatus_et_METIS_ERROR => Err(Error::Other),
+ other => panic!("unexpected error code ({}) from METIS", other),
+ }
+ }
+}
+
+/// Error raised when the graph data fed to [`Graph::new`] cannot be safely
+/// passed to METIS.
+///
+/// Graph data must follow the format described in [`Graph::new`].
+#[derive(Debug)]
+pub struct InvalidGraphError {
+ msg: &'static str,
+}
+
+impl fmt::Display for InvalidGraphError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.msg.fmt(f)
+ }
+}
+
+/// Error type returned by [`Graph::new`].
+///
+/// Unlike [`Error`], this error originates from the Rust bindings.
+#[derive(Debug)]
+#[non_exhaustive]
+pub enum NewGraphError {
+ /// `ncon` must be greater than 1.
+ NoConstraints,
+
+ /// `nparts` must be greater than 1.
+ NoParts,
+
+ /// Graph is too large. One of the array's length doesn't fit into [`Idx`].
+ TooLarge,
+
+ /// The input arrays are malformed and cannot be safely passed to METIS.
+ ///
+ /// Note that these bindings do not check for all the invariants. Some might
+ /// be raised during [`Graph::part_recursive`] and [`Graph::part_kway`] as
+ /// [`Error::Input`].
+ InvalidGraph(InvalidGraphError),
+}
+
+impl fmt::Display for NewGraphError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::NoConstraints => write!(f, "there must be at least one constraint"),
+ Self::NoParts => write!(f, "there must be at least one part"),
+ Self::TooLarge => write!(f, "graph is too large"),
+ Self::InvalidGraph(err) => write!(f, "invalid graph structure: {err}"),
+ }
+ }
+}
+
+impl std::error::Error for NewGraphError {}
+
+impl NewGraphError {
+ fn msg(msg: &'static str) -> Self {
+ Self::InvalidGraph(InvalidGraphError { msg })
+ }
+}
+
+/// Helper function to convert an immutable slice ref to a mutable pointer
+unsafe fn slice_to_mut_ptr<T>(slice: &[T]) -> *mut T {
+ slice.as_ptr() as *mut T
+}
+
+/// Builder structure to set up a graph partition computation.
+///
+/// This structure holds the required arguments for METIS to compute a
+/// partition. It also offers methods to easily set any optional argument.
+///
+/// # Example
+///
+/// ```rust
+/// # fn main() -> Result<(), metis::Error> {
+/// # use metis::Graph;
+/// // Make a graph with two vertices and an edge between the two.
+/// let xadj = &mut [0, 1, 2];
+/// let adjncy = &mut [1, 0];
+///
+/// // Allocate the partition array which stores the partition of each vertex.
+/// let mut part = [0, 0];
+///
+/// // There are one constraint and two parts. The partitioning algorithm used
+/// // is recursive bisection. The k-way algorithm can also be used.
+/// Graph::new(1, 2, xadj, adjncy)?
+/// .part_recursive(&mut part)?;
+///
+/// // The two vertices are placed in different parts.
+/// assert_ne!(part[0], part[1]);
+/// # Ok(())
+/// # }
+/// ```
+#[derive(Debug, PartialEq)]
+pub struct Graph<'a> {
+ /// The number of balancing constrains.
+ ncon: Idx,
+
+ /// The number of parts to partition the graph.
+ nparts: Idx,
+
+ /// The adjency structure of the graph (part 1).
+ xadj: &'a [Idx],
+
+ /// The adjency structure of the graph (part 2).
+ ///
+ /// Required size: xadj.last()
+ adjncy: &'a [Idx],
+
+ /// The computational weights of the vertices.
+ ///
+ /// Required size: ncon * (xadj.len()-1)
+ vwgt: Option<&'a [Idx]>,
+
+ /// The communication weights of the vertices.
+ ///
+ /// Required size: xadj.len()-1
+ vsize: Option<&'a [Idx]>,
+
+ /// The weight of the edges.
+ ///
+ /// Required size: xadj.last()
+ adjwgt: Option<&'a [Idx]>,
+
+ /// The target partition weights of the vertices.
+ ///
+ /// If `None` then the graph is equally divided among the partitions.
+ ///
+ /// Required size: ncon * nparts
+ tpwgts: Option<&'a [Real]>,
+
+ /// Imbalance tolerances for each constraint.
+ ///
+ /// Required size: ncon
+ ubvec: Option<&'a [Real]>,
+
+ /// Fine-tuning parameters.
+ options: [Idx; NOPTIONS],
+}
+
+impl<'a> Graph<'a> {
+ /// Creates a new [`Graph`] object to be partitioned.
+ ///
+ /// - `ncon` is the number of constraints on each vertex (at least 1),
+ /// - `nparts` is the number of parts wanted in the graph partition.
+ ///
+ /// # Input format
+ ///
+ /// CSR (Compressed Sparse Row) is a data structure for representing sparse
+ /// matrices and is the primary data structure used by METIS. A CSR
+ /// formatted graph is represented with two slices: an adjacency list
+ /// (`adjcny`) and an index list (`xadj`). The nodes adjacent to node `n`
+ /// are `adjncy[xadj[n]..xadj[n + 1]]`. Additionally, metis requires that
+ /// graphs are undirected: if `(u, v)` is in the graph, then `(v, u)` must
+ /// also be in the graph.
+ ///
+ /// Consider translating this simple graph to CSR format:
+ /// ```rust
+ /// // 5 - 3 - 4 - 0
+ /// // | | /
+ /// // 2 - 1
+ /// let adjncy = [1, 4, 0, 2, 4, 1, 3, 2, 4, 5, 0, 1, 3, 3];
+ /// let xadj = [0, 2, 5, 7, 10, 13, 14];
+ ///
+ /// // iterate over adjacent nodes
+ /// let mut it = xadj
+ /// .windows(2)
+ /// .map(|x| &adjncy[x[0]..x[1]]);
+ ///
+ /// // node 0 is adjacent to nodes 1 and 4
+ /// assert_eq!(it.next().unwrap(), &[1, 4]);
+ ///
+ /// // node 1 is adjacent to nodes 0, 2, and 4
+ /// assert_eq!(it.next().unwrap(), &[0, 2, 4]);
+ ///
+ /// // node 2 is adjacent to nodes 1 and 3
+ /// assert_eq!(it.next().unwrap(), &[1, 3]);
+ ///
+ /// // node 3 is adjacent to nodes 2, 4, and 5
+ /// assert_eq!(it.next().unwrap(), &[2, 4, 5]);
+ ///
+ /// // node 4 is adjacent to nodes 0, 1, and 3
+ /// assert_eq!(it.next().unwrap(), &[0, 1, 3]);
+ ///
+ /// // node 5 is adjacent to node 3
+ /// assert_eq!(it.next().unwrap(), &[3]);
+ ///
+ /// assert!(it.next().is_none());
+ /// ```
+ ///
+ /// More info can be found at:
+ /// <https://en.wikipedia.org/wiki/Sparse_matrix#Compressed_sparse_row_(CSR,_CRS_or_Yale_format)>
+ ///
+ /// # Errors
+ ///
+ /// The following invariants must be held, otherwise this function returns
+ /// an error:
+ ///
+ /// - all the arrays have a length that can be held by an [`Idx`],
+ /// - `ncon` is strictly greater than zero,
+ /// - `nparts` is strictly greater than zero,
+ /// - `xadj` has at least one element (its length is the one more than the
+ /// number of vertices),
+ /// - `xadj` is sorted,
+ /// - elements of `xadj` are positive,
+ /// - the last element of `xadj` is the length of `adjncy`,
+ /// - elements of `adjncy` are within zero and the number of vertices.
+ ///
+ /// # Mutability
+ ///
+ /// [`Graph::part_kway`] and [`Graph::part_recursive`] may mutate the
+ /// contents of `xadj` and `adjncy`, but should revert all changes before
+ /// returning.
+ pub fn new(
+ ncon: Idx,
+ nparts: Idx,
+ xadj: &'a [Idx],
+ adjncy: &'a [Idx],
+ ) -> StdResult<Graph<'a>, NewGraphError> {
+ if ncon <= 0 {
+ return Err(NewGraphError::NoConstraints);
+ }
+ if nparts <= 0 {
+ return Err(NewGraphError::NoParts);
+ }
+
+ let last_xadj = *xadj
+ .last()
+ .ok_or(NewGraphError::msg("index list is empty"))?;
+ let adjncy_len = Idx::try_from(adjncy.len()).map_err(|_| NewGraphError::TooLarge)?;
+ if last_xadj != adjncy_len {
+ return Err(NewGraphError::msg(
+ "length mismatch between index and adjacency lists",
+ ));
+ }
+
+ let nvtxs = match Idx::try_from(xadj.len()) {
+ Ok(xadj_len) => xadj_len - 1,
+ Err(_) => {
+ return Err(NewGraphError::TooLarge);
+ }
+ };
+
+ let mut prev = 0;
+ for x in &*xadj {
+ if prev > *x {
+ return Err(NewGraphError::msg("index list is not sorted"));
+ }
+ prev = *x;
+ }
+
+ for a in &*adjncy {
+ if *a < 0 || *a >= nvtxs {
+ return Err(NewGraphError::msg(
+ "some values in the adjacency list are out of bounds",
+ ));
+ }
+ }
+
+ Ok(unsafe { Graph::new_unchecked(ncon, nparts, xadj, adjncy) })
+ }
+
+ /// Creates a new [`Graph`] object to be partitioned (unchecked version).
+ ///
+ /// - `ncon` is the number of constraints on each vertex (at least 1),
+ /// - `nparts` is the number of parts wanted in the graph partition.
+ ///
+ /// # Input format
+ ///
+ /// `xadj` and `adjncy` are the [CSR encoding][0] of the adjacency matrix
+ /// that represents the graph. `xadj` is the row index and `adjncy` is the
+ /// column index.
+ ///
+ /// [0]: https://en.wikipedia.org/wiki/Sparse_matrix#Compressed_sparse_row_(CSR,_CRS_or_Yale_format)
+ ///
+ /// # Safety
+ ///
+ /// This function still does some checks listed in "Panics" below. However,
+ /// the caller is reponsible for upholding all invariants listed in the
+ /// "Errors" section of [`Graph::new`]. Otherwise, the behavior of this
+ /// function is undefined.
+ ///
+ /// # Panics
+ ///
+ /// This function panics if:
+ /// - any of the arrays have a length that cannot be held by an [`Idx`], or
+ /// - `ncon` is not strictly greater than zero, or
+ /// - `nparts` is not strictly greater than zero, or
+ /// - `xadj` is empty, or
+ /// - the length of `adjncy` is different from the last element of `xadj`.
+ ///
+ /// # Mutability
+ ///
+ /// [`Graph::part_kway`] and [`Graph::part_recursive`] may mutate the
+ /// contents of `xadj` and `adjncy`, but should revert all changes before
+ /// returning.
+ pub unsafe fn new_unchecked(
+ ncon: Idx,
+ nparts: Idx,
+ xadj: &'a [Idx],
+ adjncy: &'a [Idx],
+ ) -> Graph<'a> {
+ assert!(0 < ncon, "ncon must be strictly greater than zero");
+ assert!(0 < nparts, "nparts must be strictly greater than zero");
+ let _ = Idx::try_from(xadj.len()).expect("xadj array larger than Idx::MAX");
+ assert_ne!(xadj.len(), 0);
+ let adjncy_len = Idx::try_from(adjncy.len()).expect("adjncy array larger than Idx::MAX");
+ assert_eq!(adjncy_len, *xadj.last().unwrap());
+
+ Graph {
+ ncon,
+ nparts,
+ xadj,
+ adjncy,
+ vwgt: None,
+ vsize: None,
+ adjwgt: None,
+ tpwgts: None,
+ ubvec: None,
+ options: [-1; NOPTIONS],
+ }
+ }
+
+ /// Sets the computational weights of the vertices.
+ ///
+ /// By default, all vertices have the same weight.
+ ///
+ /// The `ncon` weights of the `i`th vertex must be located in
+ /// `vwgt[i*ncon..(i+1)*ncon]`, and all elements of `vwgt` must be positive.
+ ///
+ /// # Panics
+ ///
+ /// This function panics if the length of `vwgt` is not `ncon` times the
+ /// number of vertices.
+ pub fn set_vwgt(mut self, vwgt: &'a [Idx]) -> Graph<'a> {
+ let vwgt_len = Idx::try_from(vwgt.len()).expect("vwgt array too large");
+ assert_eq!(vwgt_len, self.ncon * (self.xadj.len() as Idx - 1));
+ self.vwgt = Some(vwgt);
+ self
+ }
+
+ /// Sets the communication weights of the vertices.
+ ///
+ /// By default, all vertices have the same communication weight.
+ ///
+ /// Vertices can only have one communication weight. The length of `vsize`
+ /// does not depend on `ncon`.
+ ///
+ /// # Panics
+ ///
+ /// This function panics if the length of `vsize` is not the number of
+ /// vertices.
+ pub fn set_vsize(mut self, vsize: &'a [Idx]) -> Graph<'a> {
+ let vsize_len = Idx::try_from(vsize.len()).expect("vsize array too large");
+ assert_eq!(vsize_len, self.xadj.len() as Idx - 1);
+ self.vsize = Some(vsize);
+ self
+ }
+
+ /// Sets the weights of the edges.
+ ///
+ /// By default, all edges have the same weight.
+ ///
+ /// All elements of `adjwgt` must be positive.
+ ///
+ /// # Panics
+ ///
+ /// This function panics if the length of `adjwgt` is not equal to the
+ /// length of `adjncy`.
+ pub fn set_adjwgt(mut self, adjwgt: &'a [Idx]) -> Graph<'a> {
+ let adjwgt_len = Idx::try_from(adjwgt.len()).expect("adjwgt array too large");
+ assert_eq!(adjwgt_len, *self.xadj.last().unwrap());
+ self.adjwgt = Some(adjwgt);
+ self
+ }
+
+ /// Sets the target partition weights for each part and constraint.
+ ///
+ /// By default, the graph is divided equally.
+ ///
+ /// The target partition weight for the `i`th part and `j`th constraint is
+ /// specified at `tpwgts[i*ncon+j]`. For each constraint `j`, the sum of the
+ /// target partition weights must be 1.0. Meaning
+ /// `(0..nparts).map(|i| tpwgts[i*ncon+j]).sum() == 1.0`.
+ ///
+ /// # Panics
+ ///
+ /// This function panics if the length of `tpwgts` is not equal to `ncon`
+ /// times `nparts`.
+ pub fn set_tpwgts(mut self, tpwgts: &'a [Real]) -> Graph<'a> {
+ let tpwgts_len = Idx::try_from(tpwgts.len()).expect("tpwgts array too large");
+ assert_eq!(tpwgts_len, self.ncon * self.nparts);
+ self.tpwgts = Some(tpwgts);
+ self
+ }
+
+ /// Sets the load imbalance tolerance for each constraint.
+ ///
+ /// By default, it equals to 1.001 if `ncon` equals 1 and 1.01 otherwise.
+ ///
+ /// For the `i`th partition and `j`th constraint the allowed weight is the
+ /// `ubvec[j]*tpwgts[i*ncon+j]` fraction of the `j`th's constraint total
+ /// weight. The load imbalances must be greater than 1.0.
+ ///
+ /// # Panics
+ ///
+ /// This function panics if the length of `ubvec` is not equal to `ncon`.
+ pub fn set_ubvec(mut self, ubvec: &'a [Real]) -> Graph<'a> {
+ let ubvec_len = Idx::try_from(ubvec.len()).expect("ubvec array too large");
+ assert_eq!(ubvec_len, self.ncon);
+ self.ubvec = Some(ubvec);
+ self
+ }
+
+ /// Sets the fine-tuning parameters for this partitioning.
+ ///
+ /// When few options are to be set, [`Graph::set_option`] might be a
+ /// better fit.
+ ///
+ /// See the [option] module for the list of available parameters. Note that
+ /// not all are applicable to a given partitioning method. Refer to the
+ /// documentation of METIS ([link]) for more info on this.
+ ///
+ /// [link]: http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/manual.pdf
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// # fn main() -> Result<(), metis::Error> {
+ /// # use metis::Graph;
+ /// use metis::option::Opt as _;
+ ///
+ /// let xadj = &[0, 1, 2];
+ /// let adjncy = &[1, 0];
+ /// let mut part = [0, 0];
+ ///
+ /// // -1 is the default value.
+ /// let mut options = [-1; metis::NOPTIONS];
+ ///
+ /// // four refinement iterations instead of the default 10.
+ /// options[metis::option::NIter::INDEX] = 4;
+ ///
+ /// Graph::new(1, 2, xadj, adjncy)?
+ /// .set_options(&options)
+ /// .part_recursive(&mut part)?;
+ ///
+ /// // The two vertices are placed in different parts.
+ /// assert_ne!(part[0], part[1]);
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn set_options(mut self, options: &[Idx; NOPTIONS]) -> Graph<'a> {
+ self.options.copy_from_slice(options);
+ self
+ }
+
+ /// Sets a fine-tuning parameter for this partitioning.
+ ///
+ /// When options are to be set in batches, [`Graph::set_options`] might be a
+ /// better fit.
+ ///
+ /// See the [option] module for the list of available parameters. Note that
+ /// not all are applicable to a given partitioning method. Refer to the
+ /// documentation of METIS ([link]) for more info on this.
+ ///
+ /// [link]: http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/manual.pdf
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// # fn main() -> Result<(), metis::Error> {
+ /// # use metis::Graph;
+ /// let xadj = &[0, 1, 2];
+ /// let adjncy = &[1, 0];
+ /// let mut part = [0, 0];
+ ///
+ /// Graph::new(1, 2, xadj, adjncy)?
+ /// .set_option(metis::option::NIter(4))
+ /// .part_recursive(&mut part)?;
+ ///
+ /// // The two vertices are placed in different parts.
+ /// assert_ne!(part[0], part[1]);
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn set_option<O>(mut self, option: O) -> Graph<'a>
+ where
+ O: option::Opt,
+ {
+ self.options[O::INDEX] = option.value();
+ self
+ }
+
+ /// Partition the graph using multilevel recursive bisection.
+ ///
+ /// Returns the edge-cut, the total communication volume of the
+ /// partitioning solution.
+ ///
+ /// Equivalent of `METIS_PartGraphRecursive`.
+ ///
+ /// # Panics
+ ///
+ /// This function panics if the length of `part` is not the number of
+ /// vertices.
+ pub fn part_recursive(mut self, part: &mut [Idx]) -> Result<Idx> {
+ self.options[option::Numbering::INDEX] = option::Numbering::C.value();
+ let part_len = Idx::try_from(part.len()).expect("part array larger than Idx::MAX");
+ assert_eq!(
+ part_len,
+ self.xadj.len() as Idx - 1,
+ "part.len() must be equal to the number of vertices",
+ );
+
+ if self.nparts == 1 {
+ // METIS does not handle this case well.
+ part.fill(0);
+ return Ok(0);
+ }
+
+ let nvtxs = self.xadj.len() as Idx - 1;
+ let mut edgecut = mem::MaybeUninit::uninit();
+ let part = part.as_mut_ptr();
+ unsafe {
+ m::METIS_PartGraphRecursive(
+ &nvtxs as *const Idx as *mut Idx,
+ &self.ncon as *const Idx as *mut Idx,
+ slice_to_mut_ptr(self.xadj),
+ slice_to_mut_ptr(self.adjncy),
+ self.vwgt
+ .map_or_else(ptr::null_mut, |s| slice_to_mut_ptr(s)),
+ self.vsize
+ .map_or_else(ptr::null_mut, |s| slice_to_mut_ptr(s)),
+ self.adjwgt
+ .map_or_else(ptr::null_mut, |s| slice_to_mut_ptr(s)),
+ &self.nparts as *const Idx as *mut Idx,
+ self.tpwgts
+ .map_or_else(ptr::null_mut, |s| slice_to_mut_ptr(s)),
+ self.ubvec
+ .map_or_else(ptr::null_mut, |s| slice_to_mut_ptr(s)),
+ slice_to_mut_ptr(&self.options),
+ edgecut.as_mut_ptr(),
+ part,
+ )
+ .wrap()?;
+ Ok(edgecut.assume_init())
+ }
+ }
+
+ /// Partition the graph using multilevel k-way partitioning.
+ ///
+ /// Returns the edge-cut, the total communication volume of the
+ /// partitioning solution.
+ ///
+ /// Equivalent of `METIS_PartGraphKway`.
+ ///
+ /// # Panics
+ ///
+ /// This function panics if the length of `part` is not the number of
+ /// vertices.
+ pub fn part_kway(self, part: &mut [Idx]) -> Result<Idx> {
+ let part_len = Idx::try_from(part.len()).expect("part array larger than Idx::MAX");
+ assert_eq!(
+ part_len,
+ self.xadj.len() as Idx - 1,
+ "part.len() must be equal to the number of vertices",
+ );
+
+ if self.nparts == 1 {
+ // METIS does not handle this case well.
+ part.fill(0);
+ return Ok(0);
+ }
+
+ let nvtxs = self.xadj.len() as Idx - 1;
+ let mut edgecut = mem::MaybeUninit::uninit();
+ let part = part.as_mut_ptr();
+ unsafe {
+ m::METIS_PartGraphKway(
+ &nvtxs as *const Idx as *mut Idx,
+ &self.ncon as *const Idx as *mut Idx,
+ slice_to_mut_ptr(self.xadj),
+ slice_to_mut_ptr(self.adjncy),
+ self.vwgt
+ .map_or_else(ptr::null_mut, |s| slice_to_mut_ptr(s)),
+ self.vsize
+ .map_or_else(ptr::null_mut, |s| slice_to_mut_ptr(s)),
+ self.adjwgt
+ .map_or_else(ptr::null_mut, |s| slice_to_mut_ptr(s)),
+ &self.nparts as *const Idx as *mut Idx,
+ self.tpwgts
+ .map_or_else(ptr::null_mut, |s| slice_to_mut_ptr(s)),
+ self.ubvec
+ .map_or_else(ptr::null_mut, |s| slice_to_mut_ptr(s)),
+ slice_to_mut_ptr(&self.options),
+ edgecut.as_mut_ptr(),
+ part,
+ )
+ .wrap()?;
+ Ok(edgecut.assume_init())
+ }
+ }
+}
+
+/// Error raised when the mesh data fed to [`Mesh::new`] cannot be safely passed
+/// to METIS.
+///
+/// Mesh data must follow the format described in [`Mesh::new`].
+#[derive(Debug)]
+pub struct InvalidMeshError {
+ msg: &'static str,
+}
+
+impl fmt::Display for InvalidMeshError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.msg.fmt(f)
+ }
+}
+
+/// Error type returned by [`Mesh::new`].
+///
+/// Unlike [`Error`], this error originates from the Rust bindings.
+#[derive(Debug)]
+#[non_exhaustive]
+pub enum NewMeshError {
+ /// `nparts` must be greater than 1.
+ NoParts,
+
+ /// Mesh is too large. One of the array's length doesn't fit into [`Idx`].
+ TooLarge,
+
+ /// The input arrays are malformed and cannot be safely passed to METIS.
+ ///
+ /// Note that these bindings do not check for all the invariants. Some might
+ /// be raised during [`Mesh::part_dual`] and [`Mesh::part_nodal`] as
+ /// [`Error::Input`].
+ InvalidMesh(InvalidMeshError),
+}
+
+impl fmt::Display for NewMeshError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::NoParts => write!(f, "there must be at least one part"),
+ Self::TooLarge => write!(f, "mesh is too large"),
+ Self::InvalidMesh(err) => write!(f, "invalid mesh structure: {err}"),
+ }
+ }
+}
+
+impl std::error::Error for NewMeshError {}
+
+impl NewMeshError {
+ fn msg(msg: &'static str) -> Self {
+ Self::InvalidMesh(InvalidMeshError { msg })
+ }
+}
+
+/// Returns the number of elements and the number of nodes in the mesh.
+fn check_mesh_structure(eptr: &[Idx], eind: &[Idx]) -> StdResult<(Idx, Idx), NewMeshError> {
+ let last_eptr = *eptr
+ .last()
+ .ok_or(NewMeshError::msg("element index is empty"))?;
+ let eind_len = Idx::try_from(eind.len()).map_err(|_| NewMeshError::TooLarge)?;
+ if last_eptr != eind_len {
+ return Err(NewMeshError::msg(
+ "length mismatch between element and node indices",
+ ));
+ }
+
+ let ne = Idx::try_from(eptr.len()).map_err(|_| NewMeshError::TooLarge)? - 1;
+
+ let mut prev = 0;
+ for x in eptr {
+ if prev > *x {
+ return Err(NewMeshError::msg("element index is not sorted"));
+ }
+ prev = *x;
+ }
+
+ let mut max_node = 0;
+ for a in eind {
+ if *a < 0 {
+ return Err(NewMeshError::msg(
+ "values in the node index are out of bounds",
+ ));
+ }
+ if *a > max_node {
+ max_node = *a;
+ }
+ }
+
+ Ok((ne, max_node + 1))
+}
+
+/// Builder structure to set up a mesh partition computation.
+///
+/// This structure holds the required arguments for METIS to compute a
+/// partition. It also offers methods to easily set any optional argument.
+///
+/// # Example
+///
+/// Usage is fairly similar to [`Graph`]. Refer to its documentation for
+/// details.
+#[derive(Debug, PartialEq)]
+pub struct Mesh<'a> {
+ /// The number of nodes in the mesh.
+ nn: Idx,
+
+ /// The number of parts to partition the mesh.
+ nparts: Idx,
+
+ /// The number of nodes two elements must share for an edge to appear in the
+ /// dual graph.
+ ncommon: Idx,
+
+ eptr: &'a [Idx], // mesh representation
+ eind: &'a [Idx], // mesh repr
+
+ /// The computational weights of the elements.
+ ///
+ /// Required size: ne
+ vwgt: Option<&'a [Idx]>,
+
+ /// The communication weights of the elements.
+ ///
+ /// Required size: ne
+ vsize: Option<&'a [Idx]>,
+
+ /// The target partition weights of the elements.
+ ///
+ /// If `None` then the mesh is equally divided among the partitions.
+ ///
+ /// Required size: nparts
+ tpwgts: Option<&'a [Real]>,
+
+ /// Fine-tuning parameters.
+ options: [Idx; NOPTIONS],
+}
+
+impl<'a> Mesh<'a> {
+ /// Creates a new [`Mesh`] object to be partitioned.
+ ///
+ /// `nparts` is the number of parts wanted in the mesh partition.
+ ///
+ /// # Input format
+ ///
+ /// The length of `eptr` is `n + 1`, where `n` is the number of elements in
+ /// the mesh. The length of `eind` is the sum of the number of nodes in all
+ /// the elements of the mesh. The list of nodes belonging to the `i`th
+ /// element of the mesh are stored in consecutive locations of `eind`
+ /// starting at position `eptr[i]` up to (but not including) position
+ /// `eptr[i+1]`.
+ ///
+ /// # Errors
+ ///
+ /// The following invariants must be held, otherwise this function returns
+ /// an error:
+ ///
+ /// - `nparts` is strictly greater than zero,
+ /// - `eptr` has at least one element (its length is the one more than the
+ /// number of mesh elements),
+ /// - `eptr` is sorted,
+ /// - elements of `eptr` are positive,
+ /// - the last element of `eptr` is the length of `eind`,
+ /// - all the arrays have a length that can be held by an [`Idx`].
+ ///
+ /// # Mutability
+ ///
+ /// [`Mesh::part_dual`] and [`Mesh::part_nodal`] may mutate the contents of
+ /// `eptr` and `eind`, but should revert all changes before returning.
+ pub fn new(nparts: Idx, eptr: &'a [Idx], eind: &'a [Idx]) -> StdResult<Mesh<'a>, NewMeshError> {
+ if nparts <= 0 {
+ return Err(NewMeshError::NoParts);
+ }
+ let (_ne, nn) = check_mesh_structure(&*eptr, &*eind)?;
+ Ok(unsafe { Mesh::new_unchecked(nn, nparts, eptr, eind) })
+ }
+
+ /// Creates a new [`Mesh`] object to be partitioned (unchecked version).
+ ///
+ /// - `nn` is the number of nodes in the mesh,
+ /// - `nparts` is the number of parts wanted in the mesh partition.
+ ///
+ /// # Input format
+ ///
+ /// See [`Mesh::new`].
+ ///
+ /// # Safety
+ ///
+ /// This function still does some checks listed in "Panics" below. However,
+ /// the caller is reponsible for upholding all invariants listed in the
+ /// "Errors" section of [`Mesh::new`]. Otherwise, the behavior of this
+ /// function is undefined.
+ ///
+ /// # Panics
+ ///
+ /// This function panics if:
+ /// - any of the arrays have a length that cannot be hold by an [`Idx`], or
+ /// - `nn` is not strictly greater than zero, or
+ /// - `nparts` is not strictly greater than zero, or
+ /// - `eptr` is empty, or
+ /// - the length of `eind` is different from the last element of `eptr`.
+ ///
+ /// # Mutability
+ ///
+ /// While nothing should be modified by the [`Mesh`] structure, METIS
+ /// doesn't specify any `const` modifier, so everything must be mutable on
+ /// Rust's side.
+ pub unsafe fn new_unchecked(
+ nn: Idx,
+ nparts: Idx,
+ eptr: &'a [Idx],
+ eind: &'a [Idx],
+ ) -> Mesh<'a> {
+ assert!(0 < nn, "nn must be strictly greater than zero");
+ assert!(0 < nparts, "nparts must be strictly greater than zero");
+ let _ = Idx::try_from(eptr.len()).expect("eptr array larger than Idx::MAX");
+ assert_ne!(eptr.len(), 0);
+ let eind_len = Idx::try_from(eind.len()).expect("eind array larger than Idx::MAX");
+ assert_eq!(eind_len, *eptr.last().unwrap());
+
+ Mesh {
+ nn,
+ nparts,
+ ncommon: 1,
+ eptr,
+ eind,
+ vwgt: None,
+ vsize: None,
+ tpwgts: None,
+ options: [-1; NOPTIONS],
+ }
+ }
+
+ /// Sets the computational weights of the elements.
+ ///
+ /// By default, all elements have the same weight.
+ ///
+ /// All elements of `vwgt` must be positive.
+ ///
+ /// # Panics
+ ///
+ /// This function panics if the length of `vwgt` is not the number of
+ /// elements.
+ pub fn set_vwgt(mut self, vwgt: &'a [Idx]) -> Mesh<'a> {
+ let vwgt_len = Idx::try_from(vwgt.len()).expect("vwgt array too large");
+ assert_eq!(vwgt_len, self.eptr.len() as Idx - 1);
+ self.vwgt = Some(vwgt);
+ self
+ }
+
+ /// Sets the communication weights of the elements.
+ ///
+ /// By default, all elements have the same communication weight.
+ ///
+ /// # Panics
+ ///
+ /// This function panics if the length of `vsize` is not the number of
+ /// elements.
+ pub fn set_vsize(mut self, vsize: &'a [Idx]) -> Mesh<'a> {
+ let vsize_len = Idx::try_from(vsize.len()).expect("vsize array too large");
+ assert_eq!(vsize_len, self.eptr.len() as Idx - 1);
+ self.vsize = Some(vsize);
+ self
+ }
+
+ /// Sets the target partition weights for each part.
+ ///
+ /// By default, the mesh is divided equally.
+ ///
+ /// The sum of the target partition weights must be 1.0.
+ ///
+ /// # Panics
+ ///
+ /// This function panics if the length of `tpwgts` is not equal to `nparts`.
+ pub fn set_tpwgts(mut self, tpwgts: &'a [Real]) -> Mesh<'a> {
+ let tpwgts_len = Idx::try_from(tpwgts.len()).expect("tpwgts array too large");
+ assert_eq!(tpwgts_len, self.nparts);
+ self.tpwgts = Some(tpwgts);
+ self
+ }
+
+ /// Sets the fine-tuning parameters for this partitioning.
+ ///
+ /// When few options are to be set, [`Mesh::set_option`] might be a
+ /// better fit.
+ ///
+ /// See the [option] module for the list of available parameters. Note that
+ /// not all are applicable to a given partitioning method. Refer to the
+ /// documentation of METIS ([link]) for more info on this.
+ ///
+ /// See [`Graph::set_options`] for a usage example.
+ ///
+ /// [link]: http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/manual.pdf
+ pub fn set_options(mut self, options: &[Idx; NOPTIONS]) -> Mesh<'a> {
+ self.options.copy_from_slice(options);
+ self
+ }
+
+ /// Sets a fine-tuning parameter for this partitioning.
+ ///
+ /// When options are to be set in batches, [`Mesh::set_options`] might be a
+ /// better fit.
+ ///
+ /// See the [option] module for the list of available parameters. Note that
+ /// not all are applicable to a given partitioning method. Refer to the
+ /// documentation of METIS ([link]) for more info on this.
+ ///
+ /// See [`Graph::set_option`] for a usage example.
+ ///
+ /// [link]: http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/manual.pdf
+ pub fn set_option<O>(mut self, option: O) -> Mesh<'a>
+ where
+ O: option::Opt,
+ {
+ self.options[O::INDEX] = option.value();
+ self
+ }
+
+ /// Partition the mesh using its dual graph.
+ ///
+ /// Returns the edge-cut, the total communication volume of the
+ /// partitioning solution.
+ ///
+ /// Equivalent of `METIS_PartMeshDual`.
+ ///
+ /// # Panics
+ ///
+ /// This function panics if the length of `epart` is not the number of
+ /// elements, or if `nparts`'s is not the number of nodes.
+ pub fn part_dual(mut self, epart: &mut [Idx], npart: &mut [Idx]) -> Result<Idx> {
+ self.options[option::Numbering::INDEX] = option::Numbering::C.value();
+ let epart_len = Idx::try_from(epart.len()).expect("epart array larger than Idx::MAX");
+ assert_eq!(
+ epart_len,
+ self.eptr.len() as Idx - 1,
+ "epart.len() must be equal to the number of elements",
+ );
+ let npart_len = Idx::try_from(npart.len()).expect("npart array larger than Idx::MAX");
+ assert_eq!(
+ npart_len, self.nn,
+ "npart.len() must be equal to the number of nodes",
+ );
+
+ if self.nparts == 1 {
+ // METIS does not handle this case well.
+ epart.fill(0);
+ npart.fill(0);
+ return Ok(0);
+ }
+
+ let ne = self.eptr.len() as Idx - 1;
+ let mut edgecut = mem::MaybeUninit::uninit();
+ unsafe {
+ m::METIS_PartMeshDual(
+ &ne as *const Idx as *mut Idx,
+ &self.nn as *const Idx as *mut Idx,
+ slice_to_mut_ptr(self.eptr),
+ slice_to_mut_ptr(self.eind),
+ self.vwgt
+ .map_or_else(ptr::null_mut, |s| slice_to_mut_ptr(s)),
+ self.vsize
+ .map_or_else(ptr::null_mut, |s| slice_to_mut_ptr(s)),
+ &self.ncommon as *const Idx as *mut Idx,
+ &self.nparts as *const Idx as *mut Idx,
+ self.tpwgts
+ .map_or_else(ptr::null_mut, |s| slice_to_mut_ptr(s)),
+ slice_to_mut_ptr(&self.options),
+ edgecut.as_mut_ptr(),
+ epart.as_mut_ptr(),
+ npart.as_mut_ptr(),
+ )
+ .wrap()?;
+ Ok(edgecut.assume_init())
+ }
+ }
+
+ /// Partition the mesh using its nodal graph.
+ ///
+ /// Returns the edge-cut, the total communication volume of the
+ /// partitioning solution.
+ ///
+ /// Previous settings of `ncommon` are not used by this function.
+ ///
+ /// Equivalent of `METIS_PartMeshNodal`.
+ ///
+ /// # Panics
+ ///
+ /// This function panics if the length of `epart` is not the number of
+ /// elements, or if `nparts`'s is not the number of nodes.
+ pub fn part_nodal(mut self, epart: &mut [Idx], npart: &mut [Idx]) -> Result<Idx> {
+ self.options[option::Numbering::INDEX] = option::Numbering::C.value();
+ let epart_len = Idx::try_from(epart.len()).expect("epart array larger than Idx::MAX");
+ assert_eq!(
+ epart_len,
+ self.eptr.len() as Idx - 1,
+ "epart.len() must be equal to the number of elements",
+ );
+ let npart_len = Idx::try_from(npart.len()).expect("npart array larger than Idx::MAX");
+ assert_eq!(
+ npart_len, self.nn,
+ "npart.len() must be equal to the number of nodes",
+ );
+
+ if self.nparts == 1 {
+ // METIS does not handle this case well.
+ epart.fill(0);
+ npart.fill(0);
+ return Ok(0);
+ }
+
+ let ne = self.eptr.len() as Idx - 1;
+ let mut edgecut = mem::MaybeUninit::uninit();
+ unsafe {
+ m::METIS_PartMeshNodal(
+ &ne as *const Idx as *mut Idx,
+ &self.nn as *const Idx as *mut Idx,
+ slice_to_mut_ptr(self.eptr),
+ slice_to_mut_ptr(self.eind),
+ self.vwgt
+ .map_or_else(ptr::null_mut, |s| slice_to_mut_ptr(s)),
+ self.vsize
+ .map_or_else(ptr::null_mut, |s| slice_to_mut_ptr(s)),
+ &self.nparts as *const Idx as *mut Idx,
+ self.tpwgts
+ .map_or_else(ptr::null_mut, |s| slice_to_mut_ptr(s)),
+ slice_to_mut_ptr(&self.options),
+ edgecut.as_mut_ptr(),
+ epart.as_mut_ptr(),
+ npart.as_mut_ptr(),
+ )
+ .wrap()?;
+ Ok(edgecut.assume_init())
+ }
+ }
+}
+
+/// The dual of a mesh.
+///
+/// Result of [`mesh_to_dual`].
+#[derive(Debug, PartialEq, Eq)]
+pub struct Dual {
+ xadj: &'static mut [Idx],
+ adjncy: &'static mut [Idx],
+}
+
+impl Dual {
+ /// The adjacency index array.
+ pub fn xadj(&self) -> &[Idx] {
+ self.xadj
+ }
+
+ /// The adjacency array.
+ pub fn adjncy(&self) -> &[Idx] {
+ self.adjncy
+ }
+
+ /// The adjacency index array, and the adjacency array as mutable slices.
+ pub fn as_mut(&mut self) -> (&mut [Idx], &mut [Idx]) {
+ (self.xadj, self.adjncy)
+ }
+}
+
+impl Drop for Dual {
+ fn drop(&mut self) {
+ unsafe {
+ m::METIS_Free(self.xadj.as_mut_ptr() as *mut os::raw::c_void);
+ m::METIS_Free(self.adjncy.as_mut_ptr() as *mut os::raw::c_void);
+ }
+ }
+}
+
+/// Generate the dual graph of a mesh.
+///
+/// # Errors
+///
+/// This function returns an error if `eptr` and `eind` don't follow the mesh
+/// format given in [`Mesh::new`].
+pub fn mesh_to_dual(eptr: &[Idx], eind: &[Idx], ncommon: Idx) -> Result<Dual> {
+ let (ne, nn) = check_mesh_structure(&*eptr, &*eind)?;
+ let mut xadj = mem::MaybeUninit::uninit();
+ let mut adjncy = mem::MaybeUninit::uninit();
+ let numbering_flag = 0;
+
+ // SAFETY: METIS_MeshToDual allocates the xadj and adjncy arrays.
+ // SAFETY: hopefully those arrays are of correct length.
+ unsafe {
+ m::METIS_MeshToDual(
+ &ne as *const Idx as *mut Idx,
+ &nn as *const Idx as *mut Idx,
+ slice_to_mut_ptr(eptr),
+ slice_to_mut_ptr(eind),
+ &ncommon as *const Idx as *mut Idx,
+ &numbering_flag as *const Idx as *mut Idx,
+ xadj.as_mut_ptr(),
+ adjncy.as_mut_ptr(),
+ )
+ .wrap()?;
+ let xadj = xadj.assume_init();
+ let xadj = slice::from_raw_parts_mut(xadj, eptr.len());
+ let adjncy = adjncy.assume_init();
+ let adjncy = slice::from_raw_parts_mut(adjncy, xadj[xadj.len() - 1] as usize);
+ Ok(Dual { xadj, adjncy })
+ }
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +
//! Fine-tuning parameter types.
+//!
+//! For options that take an integer value, should this value be negative, the
+//! default will be used, if any.
+
+// Idx and Real can be 32 or 64 bits. Make sure to suppress warnings when
+// casts turn out to be trivial.
+#![allow(trivial_numeric_casts)]
+
+use crate::m;
+use crate::Idx;
+
+mod private {
+ pub trait Sealed {}
+}
+
+/// Trait implemented by METIS' options.
+///
+/// See [`crate::Graph::set_options`] for an example. It is also used in
+/// [`crate::Mesh::set_options`].
+pub trait Opt: private::Sealed {
+ /// Index of the option in the array from [`crate::Graph::set_options`] and
+ /// [`crate::Mesh::set_options`].
+ const INDEX: usize;
+
+ /// Convert the value into metis' format, for use with
+ /// [`crate::Graph::set_options`] and [`crate::Mesh::set_options`].
+ fn value(self) -> Idx;
+}
+
+/// Specifies the partitioning method.
+pub enum PType {
+ /// Multilevel recursive bisection.
+ Rb,
+
+ /// Multilevel k-way partitioning.
+ Kway,
+}
+
+impl private::Sealed for PType {}
+impl Opt for PType {
+ const INDEX: usize = m::moptions_et_METIS_OPTION_PTYPE as usize;
+
+ fn value(self) -> Idx {
+ match self {
+ PType::Rb => m::mptype_et_METIS_PTYPE_RB as Idx,
+ PType::Kway => m::mptype_et_METIS_PTYPE_KWAY as Idx,
+ }
+ }
+}
+
+/// Specifies the type of objective.
+pub enum ObjType {
+ /// Edge-cut minimization.
+ Cut,
+
+ /// Total communication volume minimization.
+ Vol,
+}
+
+impl private::Sealed for ObjType {}
+impl Opt for ObjType {
+ const INDEX: usize = m::moptions_et_METIS_OPTION_OBJTYPE as usize;
+
+ fn value(self) -> Idx {
+ match self {
+ ObjType::Cut => m::mobjtype_et_METIS_OBJTYPE_CUT as Idx,
+ ObjType::Vol => m::mobjtype_et_METIS_OBJTYPE_VOL as Idx,
+ }
+ }
+}
+
+/// Specifies the matching scheme to be used during coarsening.
+pub enum CType {
+ /// Random matching.
+ Rm,
+
+ /// Sorted heavy-edge matching.
+ Shem,
+}
+
+impl private::Sealed for CType {}
+impl Opt for CType {
+ const INDEX: usize = m::moptions_et_METIS_OPTION_CTYPE as usize;
+
+ fn value(self) -> Idx {
+ match self {
+ CType::Rm => m::mctype_et_METIS_CTYPE_RM as Idx,
+ CType::Shem => m::mctype_et_METIS_CTYPE_SHEM as Idx,
+ }
+ }
+}
+
+/// Determines the algorithm used during initial partitioning.
+pub enum IpType {
+ /// Grows a bisection using a greedy strategy.
+ Grow,
+
+ /// Compute a bisection at random followed by a refinement.
+ Random,
+
+ /// Derives a separator from an edge cut.
+ Edge,
+
+ /// Grow a bisection using a greedy node-based strategy.
+ Node,
+}
+
+impl private::Sealed for IpType {}
+impl Opt for IpType {
+ const INDEX: usize = m::moptions_et_METIS_OPTION_IPTYPE as usize;
+
+ fn value(self) -> Idx {
+ match self {
+ IpType::Grow => m::miptype_et_METIS_IPTYPE_GROW as Idx,
+ IpType::Random => m::miptype_et_METIS_IPTYPE_RANDOM as Idx,
+ IpType::Edge => m::miptype_et_METIS_IPTYPE_EDGE as Idx,
+ IpType::Node => m::miptype_et_METIS_IPTYPE_NODE as Idx,
+ }
+ }
+}
+
+/// Determines the algorithm used for refinement.
+pub enum RType {
+ /// FM-based cut refinement.
+ Fm,
+
+ /// Greedy-based cut and volume refinement.
+ Greedy,
+
+ /// Two-sided FM refinement.
+ Sep2Sided,
+
+ /// One-sided FM refinement.
+ Sep1Sided,
+}
+
+impl private::Sealed for RType {}
+impl Opt for RType {
+ const INDEX: usize = m::moptions_et_METIS_OPTION_RTYPE as usize;
+
+ fn value(self) -> Idx {
+ match self {
+ RType::Fm => m::mrtype_et_METIS_RTYPE_FM as Idx,
+ RType::Greedy => m::mrtype_et_METIS_RTYPE_GREEDY as Idx,
+ RType::Sep2Sided => m::mrtype_et_METIS_RTYPE_SEP2SIDED as Idx,
+ RType::Sep1Sided => m::mrtype_et_METIS_RTYPE_SEP1SIDED as Idx,
+ }
+ }
+}
+
+/// Specifies the number of different partitions that it will compute. The
+/// final partition is the one that achieves the best edge cut or
+/// communication volume. Default is 1.
+pub struct NCuts(pub Idx);
+
+impl private::Sealed for NCuts {}
+impl Opt for NCuts {
+ const INDEX: usize = m::moptions_et_METIS_OPTION_NCUTS as usize;
+
+ fn value(self) -> Idx {
+ self.0
+ }
+}
+
+/// Specifies the number of different separators that it will compute at each
+/// level of nested dissection.
+///
+/// The final separator that is used is the smallest one. Default is 1.
+pub struct NSeps(pub Idx);
+
+impl private::Sealed for NSeps {}
+impl Opt for NSeps {
+ const INDEX: usize = m::moptions_et_METIS_OPTION_NSEPS as usize;
+
+ fn value(self) -> Idx {
+ self.0
+ }
+}
+
+/// Used to indicate which numbering scheme is used for the adjacency structure
+/// of a graph or the element-node structure of a mesh.
+#[allow(dead_code)]
+pub(crate) enum Numbering {
+ /// C-style numbering which is assumed to start from 0.
+ C,
+
+ /// Fortran-style numbering which is assumed to start from 1.
+ Fortran,
+}
+
+impl private::Sealed for Numbering {}
+impl Opt for Numbering {
+ const INDEX: usize = m::moptions_et_METIS_OPTION_NUMBERING as usize;
+
+ fn value(self) -> Idx {
+ match self {
+ Numbering::C => 0,
+ Numbering::Fortran => 1,
+ }
+ }
+}
+
+/// Specifies the number of iterations for the refinement algorithms at each
+/// stage of the uncoarsening process.
+///
+/// Default is 10.
+pub struct NIter(pub Idx);
+
+impl private::Sealed for NIter {}
+impl Opt for NIter {
+ const INDEX: usize = m::moptions_et_METIS_OPTION_NITER as usize;
+
+ fn value(self) -> Idx {
+ self.0
+ }
+}
+
+/// Specifies the seed for the random number generator.
+pub struct Seed(pub Idx);
+
+impl private::Sealed for Seed {}
+impl Opt for Seed {
+ const INDEX: usize = m::moptions_et_METIS_OPTION_SEED as usize;
+
+ fn value(self) -> Idx {
+ self.0
+ }
+}
+
+/// Specifies that the partitioning routines should try to minimize the maximum
+/// degree of the subdomain graph.
+///
+/// I.e., the graph in which each partition is a node, and edges connect
+/// subdomains with a shared interface.
+pub struct MinConn(pub bool);
+
+impl private::Sealed for MinConn {}
+impl Opt for MinConn {
+ const INDEX: usize = m::moptions_et_METIS_OPTION_MINCONN as usize;
+
+ fn value(self) -> Idx {
+ self.0 as Idx
+ }
+}
+
+/// Specifies that the coarsening will not perform any 2-hop matching when the
+/// standards matching approach fails to sufficiently coarsen the graph.
+///
+/// The 2-hop matching is very effective for graphs with power-law degree
+/// distributions.
+pub struct No2Hop(pub bool);
+
+impl private::Sealed for No2Hop {}
+impl Opt for No2Hop {
+ const INDEX: usize = m::moptions_et_METIS_OPTION_NO2HOP as usize;
+
+ fn value(self) -> Idx {
+ self.0 as Idx
+ }
+}
+
+/// Specifies that the partitioning routines should try to produce partitions
+/// that are contiguous.
+///
+/// Note that if the input graph is not connected this option is ignored.
+pub struct Contig(pub bool);
+
+impl private::Sealed for Contig {}
+impl Opt for Contig {
+ const INDEX: usize = m::moptions_et_METIS_OPTION_CONTIG as usize;
+
+ fn value(self) -> Idx {
+ self.0 as Idx
+ }
+}
+
+/// Specifies that the graph should be compressed by combining vertices
+/// that have identical adjacency lists.
+pub struct Compress(pub bool);
+
+impl private::Sealed for Compress {}
+impl Opt for Compress {
+ const INDEX: usize = m::moptions_et_METIS_OPTION_COMPRESS as usize;
+
+ fn value(self) -> Idx {
+ self.0 as Idx
+ }
+}
+
+/// Specifies if the connected components of the graph should first be
+/// identified and ordered separately.
+pub struct CCOrder(pub bool);
+
+impl private::Sealed for CCOrder {}
+impl Opt for CCOrder {
+ const INDEX: usize = m::moptions_et_METIS_OPTION_CCORDER as usize;
+
+ fn value(self) -> Idx {
+ self.0 as Idx
+ }
+}
+
+/// Specifies the minimum degree of the vertices that will be ordered last.
+///
+/// If the specified value is `x > 0`, then any vertices with a degree greater
+/// than `0.1*x*(average degree)` are removed from the graph, an ordering of the
+/// rest of the vertices is computed, and an overall ordering is computed by
+/// ordering the removed vertices at the end of the overall ordering. For
+/// example if `x == 40`, and the average degree is 5, then the algorithm will
+/// remove all vertices with degree greater than 20. The vertices that are
+/// removed are ordered last (i.e., they are automatically placed in the
+/// top-level separator). Good values are often in the range of 60 to 200 (i.e.,
+/// 6 to 20 times more than the average). Default value is 0, indicating that no
+/// vertices are removed.
+///
+/// Used to control whether the ordering algorithm should remove any
+/// vertices with high degree (i.e., dense columns). This is particularly
+/// helpful for certain classes of LP matrices, in which there a few vertices
+/// that are connected to many other vertices. By removing these vertices prior
+/// to ordering, the quality and the amount of time required to do the ordering
+/// improves.
+pub struct PFactor(pub Idx);
+
+impl private::Sealed for PFactor {}
+impl Opt for PFactor {
+ const INDEX: usize = m::moptions_et_METIS_OPTION_PFACTOR as usize;
+
+ fn value(self) -> Idx {
+ self.0
+ }
+}
+
+/// Specifies the maximum allowed load imbalance among the partitions.
+///
+/// A value of `x` indicates that the allowed load imbalance is `(1 + x)/1000`.
+/// The load imbalance for the `j`th constraint is defined to be
+/// `max_i(w[j,i]/t[j,i])`, where `w[j,i]` is the fraction of the overall
+/// weight of the `j`th constraint that is assigned to the`i`th partition and
+/// `t[j,i]` is the desired target weight of the `j`th constraint for the `i`th
+/// partition (i.e., that specified via `-tpwgts`). For `-ptype=rb`, the default
+/// value is 1 (i.e., load imbalance of 1.001) and for `-ptype=kway`, the
+/// default value is 30 (i.e., load imbalance of 1.03).
+pub struct UFactor(pub Idx);
+
+impl private::Sealed for UFactor {}
+impl Opt for UFactor {
+ const INDEX: usize = m::moptions_et_METIS_OPTION_UFACTOR as usize;
+
+ fn value(self) -> Idx {
+ self.0
+ }
+}
+
+/// Specifies the amount of progress/debugging information will be printed
+/// during the execution of the algorithms.
+///
+/// The default value is false for every field (no debugging/progress
+/// information).
+pub struct DbgLvl {
+ /// Prints various diagnostic messages.
+ pub info: bool,
+
+ /// Performs timing analysis.
+ pub time: bool,
+
+ /// Displays various statistics during coarsening.
+ pub coarsen: bool,
+
+ /// Displays various statistics during refinement.
+ pub refine: bool,
+
+ /// Displays various statistics during initial partitioning.
+ pub ipart: bool,
+
+ /// Display detailed information about vertex moves during refinement.
+ pub move_info: bool,
+
+ /// Display detailed information about vertex separators.
+ pub sep_info: bool,
+
+ /// Display information related to the minimization of subdomain
+ /// connectivity.
+ pub conn_info: bool,
+
+ /// Display information related to the elimination of connected components.
+ pub contig_info: bool,
+}
+
+impl private::Sealed for DbgLvl {}
+impl Opt for DbgLvl {
+ const INDEX: usize = m::moptions_et_METIS_OPTION_DBGLVL as usize;
+
+ fn value(self) -> Idx {
+ let mut dbglvl = 0;
+ if self.info {
+ dbglvl |= 1;
+ }
+ if self.time {
+ dbglvl |= 2;
+ }
+ if self.coarsen {
+ dbglvl |= 4;
+ }
+ if self.refine {
+ dbglvl |= 8;
+ }
+ if self.ipart {
+ dbglvl |= 16;
+ }
+ if self.move_info {
+ dbglvl |= 32;
+ }
+ if self.sep_info {
+ dbglvl |= 64;
+ }
+ if self.conn_info {
+ dbglvl |= 128;
+ }
+ if self.contig_info {
+ dbglvl |= 256;
+ }
+ dbglvl
+ }
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +
/* automatically generated by rust-bindgen 0.66.1 */
+
+pub const METIS_VER_MAJOR: u32 = 5;
+pub const METIS_VER_MINOR: u32 = 2;
+pub const METIS_VER_SUBMINOR: u32 = 1;
+pub const METIS_NOPTIONS: u32 = 40;
+pub type idx_t = i32;
+pub type real_t = f32;
+extern "C" {
+ pub fn METIS_PartGraphRecursive(
+ nvtxs: *mut idx_t,
+ ncon: *mut idx_t,
+ xadj: *mut idx_t,
+ adjncy: *mut idx_t,
+ vwgt: *mut idx_t,
+ vsize: *mut idx_t,
+ adjwgt: *mut idx_t,
+ nparts: *mut idx_t,
+ tpwgts: *mut real_t,
+ ubvec: *mut real_t,
+ options: *mut idx_t,
+ edgecut: *mut idx_t,
+ part: *mut idx_t,
+ ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ pub fn METIS_PartGraphKway(
+ nvtxs: *mut idx_t,
+ ncon: *mut idx_t,
+ xadj: *mut idx_t,
+ adjncy: *mut idx_t,
+ vwgt: *mut idx_t,
+ vsize: *mut idx_t,
+ adjwgt: *mut idx_t,
+ nparts: *mut idx_t,
+ tpwgts: *mut real_t,
+ ubvec: *mut real_t,
+ options: *mut idx_t,
+ edgecut: *mut idx_t,
+ part: *mut idx_t,
+ ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ pub fn METIS_MeshToDual(
+ ne: *mut idx_t,
+ nn: *mut idx_t,
+ eptr: *mut idx_t,
+ eind: *mut idx_t,
+ ncommon: *mut idx_t,
+ numflag: *mut idx_t,
+ r_xadj: *mut *mut idx_t,
+ r_adjncy: *mut *mut idx_t,
+ ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ pub fn METIS_MeshToNodal(
+ ne: *mut idx_t,
+ nn: *mut idx_t,
+ eptr: *mut idx_t,
+ eind: *mut idx_t,
+ numflag: *mut idx_t,
+ r_xadj: *mut *mut idx_t,
+ r_adjncy: *mut *mut idx_t,
+ ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ pub fn METIS_PartMeshNodal(
+ ne: *mut idx_t,
+ nn: *mut idx_t,
+ eptr: *mut idx_t,
+ eind: *mut idx_t,
+ vwgt: *mut idx_t,
+ vsize: *mut idx_t,
+ nparts: *mut idx_t,
+ tpwgts: *mut real_t,
+ options: *mut idx_t,
+ objval: *mut idx_t,
+ epart: *mut idx_t,
+ npart: *mut idx_t,
+ ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ pub fn METIS_PartMeshDual(
+ ne: *mut idx_t,
+ nn: *mut idx_t,
+ eptr: *mut idx_t,
+ eind: *mut idx_t,
+ vwgt: *mut idx_t,
+ vsize: *mut idx_t,
+ ncommon: *mut idx_t,
+ nparts: *mut idx_t,
+ tpwgts: *mut real_t,
+ options: *mut idx_t,
+ objval: *mut idx_t,
+ epart: *mut idx_t,
+ npart: *mut idx_t,
+ ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ pub fn METIS_NodeND(
+ nvtxs: *mut idx_t,
+ xadj: *mut idx_t,
+ adjncy: *mut idx_t,
+ vwgt: *mut idx_t,
+ options: *mut idx_t,
+ perm: *mut idx_t,
+ iperm: *mut idx_t,
+ ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ pub fn METIS_Free(ptr: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ pub fn METIS_SetDefaultOptions(options: *mut idx_t) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ pub fn METIS_NodeNDP(
+ nvtxs: idx_t,
+ xadj: *mut idx_t,
+ adjncy: *mut idx_t,
+ vwgt: *mut idx_t,
+ npes: idx_t,
+ options: *mut idx_t,
+ perm: *mut idx_t,
+ iperm: *mut idx_t,
+ sizes: *mut idx_t,
+ ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ pub fn METIS_ComputeVertexSeparator(
+ nvtxs: *mut idx_t,
+ xadj: *mut idx_t,
+ adjncy: *mut idx_t,
+ vwgt: *mut idx_t,
+ options: *mut idx_t,
+ sepsize: *mut idx_t,
+ part: *mut idx_t,
+ ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ pub fn METIS_NodeRefine(
+ nvtxs: idx_t,
+ xadj: *mut idx_t,
+ vwgt: *mut idx_t,
+ adjncy: *mut idx_t,
+ where_: *mut idx_t,
+ hmarker: *mut idx_t,
+ ubfactor: real_t,
+ ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ pub fn METIS_CacheFriendlyReordering(
+ nvtxs: idx_t,
+ xadj: *mut idx_t,
+ adjncy: *mut idx_t,
+ part: *mut idx_t,
+ old2new: *mut idx_t,
+ ) -> ::std::os::raw::c_int;
+}
+#[doc = "< Returned normally"]
+pub const rstatus_et_METIS_OK: rstatus_et = 1;
+#[doc = "< Returned due to erroneous inputs and/or options"]
+pub const rstatus_et_METIS_ERROR_INPUT: rstatus_et = -2;
+#[doc = "< Returned due to insufficient memory"]
+pub const rstatus_et_METIS_ERROR_MEMORY: rstatus_et = -3;
+#[doc = "< Some other errors"]
+pub const rstatus_et_METIS_ERROR: rstatus_et = -4;
+#[doc = " Return codes"]
+pub type rstatus_et = ::std::os::raw::c_int;
+pub const moptype_et_METIS_OP_PMETIS: moptype_et = 0;
+pub const moptype_et_METIS_OP_KMETIS: moptype_et = 1;
+pub const moptype_et_METIS_OP_OMETIS: moptype_et = 2;
+#[doc = " Operation type codes"]
+pub type moptype_et = ::std::os::raw::c_int;
+pub const moptions_et_METIS_OPTION_PTYPE: moptions_et = 0;
+pub const moptions_et_METIS_OPTION_OBJTYPE: moptions_et = 1;
+pub const moptions_et_METIS_OPTION_CTYPE: moptions_et = 2;
+pub const moptions_et_METIS_OPTION_IPTYPE: moptions_et = 3;
+pub const moptions_et_METIS_OPTION_RTYPE: moptions_et = 4;
+pub const moptions_et_METIS_OPTION_DBGLVL: moptions_et = 5;
+pub const moptions_et_METIS_OPTION_NIPARTS: moptions_et = 6;
+pub const moptions_et_METIS_OPTION_NITER: moptions_et = 7;
+pub const moptions_et_METIS_OPTION_NCUTS: moptions_et = 8;
+pub const moptions_et_METIS_OPTION_SEED: moptions_et = 9;
+pub const moptions_et_METIS_OPTION_ONDISK: moptions_et = 10;
+pub const moptions_et_METIS_OPTION_MINCONN: moptions_et = 11;
+pub const moptions_et_METIS_OPTION_CONTIG: moptions_et = 12;
+pub const moptions_et_METIS_OPTION_COMPRESS: moptions_et = 13;
+pub const moptions_et_METIS_OPTION_CCORDER: moptions_et = 14;
+pub const moptions_et_METIS_OPTION_PFACTOR: moptions_et = 15;
+pub const moptions_et_METIS_OPTION_NSEPS: moptions_et = 16;
+pub const moptions_et_METIS_OPTION_UFACTOR: moptions_et = 17;
+pub const moptions_et_METIS_OPTION_NUMBERING: moptions_et = 18;
+pub const moptions_et_METIS_OPTION_DROPEDGES: moptions_et = 19;
+pub const moptions_et_METIS_OPTION_NO2HOP: moptions_et = 20;
+pub const moptions_et_METIS_OPTION_TWOHOP: moptions_et = 21;
+pub const moptions_et_METIS_OPTION_FAST: moptions_et = 22;
+pub const moptions_et_METIS_OPTION_HELP: moptions_et = 23;
+pub const moptions_et_METIS_OPTION_TPWGTS: moptions_et = 24;
+pub const moptions_et_METIS_OPTION_NCOMMON: moptions_et = 25;
+pub const moptions_et_METIS_OPTION_NOOUTPUT: moptions_et = 26;
+pub const moptions_et_METIS_OPTION_BALANCE: moptions_et = 27;
+pub const moptions_et_METIS_OPTION_GTYPE: moptions_et = 28;
+pub const moptions_et_METIS_OPTION_UBVEC: moptions_et = 29;
+#[doc = " Options codes (i.e., options[])"]
+pub type moptions_et = ::std::os::raw::c_int;
+pub const mptype_et_METIS_PTYPE_RB: mptype_et = 0;
+pub const mptype_et_METIS_PTYPE_KWAY: mptype_et = 1;
+#[doc = " Partitioning Schemes"]
+pub type mptype_et = ::std::os::raw::c_int;
+pub const mgtype_et_METIS_GTYPE_DUAL: mgtype_et = 0;
+pub const mgtype_et_METIS_GTYPE_NODAL: mgtype_et = 1;
+#[doc = " Graph types for meshes"]
+pub type mgtype_et = ::std::os::raw::c_int;
+pub const mctype_et_METIS_CTYPE_RM: mctype_et = 0;
+pub const mctype_et_METIS_CTYPE_SHEM: mctype_et = 1;
+#[doc = " Coarsening Schemes"]
+pub type mctype_et = ::std::os::raw::c_int;
+pub const miptype_et_METIS_IPTYPE_GROW: miptype_et = 0;
+pub const miptype_et_METIS_IPTYPE_RANDOM: miptype_et = 1;
+pub const miptype_et_METIS_IPTYPE_EDGE: miptype_et = 2;
+pub const miptype_et_METIS_IPTYPE_NODE: miptype_et = 3;
+pub const miptype_et_METIS_IPTYPE_METISRB: miptype_et = 4;
+#[doc = " Initial partitioning schemes"]
+pub type miptype_et = ::std::os::raw::c_int;
+pub const mrtype_et_METIS_RTYPE_FM: mrtype_et = 0;
+pub const mrtype_et_METIS_RTYPE_GREEDY: mrtype_et = 1;
+pub const mrtype_et_METIS_RTYPE_SEP2SIDED: mrtype_et = 2;
+pub const mrtype_et_METIS_RTYPE_SEP1SIDED: mrtype_et = 3;
+#[doc = " Refinement schemes"]
+pub type mrtype_et = ::std::os::raw::c_int;
+#[doc = "< Shows various diagnostic messages"]
+pub const mdbglvl_et_METIS_DBG_INFO: mdbglvl_et = 1;
+#[doc = "< Perform timing analysis"]
+pub const mdbglvl_et_METIS_DBG_TIME: mdbglvl_et = 2;
+#[doc = "< Show the coarsening progress"]
+pub const mdbglvl_et_METIS_DBG_COARSEN: mdbglvl_et = 4;
+#[doc = "< Show the refinement progress"]
+pub const mdbglvl_et_METIS_DBG_REFINE: mdbglvl_et = 8;
+#[doc = "< Show info on initial partitioning"]
+pub const mdbglvl_et_METIS_DBG_IPART: mdbglvl_et = 16;
+#[doc = "< Show info on vertex moves during refinement"]
+pub const mdbglvl_et_METIS_DBG_MOVEINFO: mdbglvl_et = 32;
+#[doc = "< Show info on vertex moves during sep refinement"]
+pub const mdbglvl_et_METIS_DBG_SEPINFO: mdbglvl_et = 64;
+#[doc = "< Show info on minimization of subdomain connectivity"]
+pub const mdbglvl_et_METIS_DBG_CONNINFO: mdbglvl_et = 128;
+#[doc = "< Show info on elimination of connected components"]
+pub const mdbglvl_et_METIS_DBG_CONTIGINFO: mdbglvl_et = 256;
+#[doc = "< Show info related to wspace allocation"]
+pub const mdbglvl_et_METIS_DBG_MEMORY: mdbglvl_et = 2048;
+#[doc = " Debug Levels"]
+pub type mdbglvl_et = ::std::os::raw::c_int;
+pub const mobjtype_et_METIS_OBJTYPE_CUT: mobjtype_et = 0;
+pub const mobjtype_et_METIS_OBJTYPE_VOL: mobjtype_et = 1;
+pub const mobjtype_et_METIS_OBJTYPE_NODE: mobjtype_et = 2;
+pub type mobjtype_et = ::std::os::raw::c_int;
+
fn:
) to \
+ restrict the search to a given item kind.","Accepted kinds are: fn
, mod
, struct
, \
+ enum
, trait
, type
, macro
, \
+ and const
.","Search functions by type signature (e.g., vec -> usize
or \
+ -> vec
or String, enum:Cow -> bool
)","You can look for items with an exact name by putting double quotes around \
+ your request: \"string\"
","Look for functions that accept or return \
+ slices and \
+ arrays by writing \
+ square brackets (e.g., -> [u8]
or [] -> Option
)","Look for items inside another one by searching for a path: vec::Vec
",].map(x=>""+x+"
").join("");const div_infos=document.createElement("div");addClass(div_infos,"infos");div_infos.innerHTML="${value.replaceAll(" ", " ")}
`}else{error[index]=value}});output+=`Returns true
if the result is Ok
and the value inside of it matches a predicate.
let x: Result<u32, &str> = Ok(2);\nassert_eq!(x.is_ok_and(|x| x > 1), true);\n\nlet x: Result<u32, &str> = Ok(0);\nassert_eq!(x.is_ok_and(|x| x > 1), false);\n\nlet x: Result<u32, &str> = Err(\"hey\");\nassert_eq!(x.is_ok_and(|x| x > 1), false);
Returns true
if the result is Err
and the value inside of it matches a predicate.
use std::io::{Error, ErrorKind};\n\nlet x: Result<u32, Error> = Err(Error::new(ErrorKind::NotFound, \"!\"));\nassert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), true);\n\nlet x: Result<u32, Error> = Err(Error::new(ErrorKind::PermissionDenied, \"!\"));\nassert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), false);\n\nlet x: Result<u32, Error> = Ok(123);\nassert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), false);
Converts from Result<T, E>
to Option<E>
.
Converts self
into an Option<E>
, consuming self
,\nand discarding the success value, if any.
let x: Result<u32, &str> = Ok(2);\nassert_eq!(x.err(), None);\n\nlet x: Result<u32, &str> = Err(\"Nothing here\");\nassert_eq!(x.err(), Some(\"Nothing here\"));
Converts from &Result<T, E>
to Result<&T, &E>
.
Produces a new Result
, containing a reference\ninto the original, leaving the original in place.
let x: Result<u32, &str> = Ok(2);\nassert_eq!(x.as_ref(), Ok(&2));\n\nlet x: Result<u32, &str> = Err(\"Error\");\nassert_eq!(x.as_ref(), Err(&\"Error\"));
Converts from &mut Result<T, E>
to Result<&mut T, &mut E>
.
fn mutate(r: &mut Result<i32, i32>) {\n match r.as_mut() {\n Ok(v) => *v = 42,\n Err(e) => *e = 0,\n }\n}\n\nlet mut x: Result<i32, i32> = Ok(2);\nmutate(&mut x);\nassert_eq!(x.unwrap(), 42);\n\nlet mut x: Result<i32, i32> = Err(13);\nmutate(&mut x);\nassert_eq!(x.unwrap_err(), 0);
Maps a Result<T, E>
to Result<U, E>
by applying a function to a\ncontained Ok
value, leaving an Err
value untouched.
This function can be used to compose the results of two functions.
\nPrint the numbers on each line of a string multiplied by two.
\n\nlet line = \"1\\n2\\n3\\n4\\n\";\n\nfor num in line.lines() {\n match num.parse::<i32>().map(|i| i * 2) {\n Ok(n) => println!(\"{n}\"),\n Err(..) => {}\n }\n}
Returns the provided default (if Err
), or\napplies a function to the contained value (if Ok
).
Arguments passed to map_or
are eagerly evaluated; if you are passing\nthe result of a function call, it is recommended to use map_or_else
,\nwhich is lazily evaluated.
let x: Result<_, &str> = Ok(\"foo\");\nassert_eq!(x.map_or(42, |v| v.len()), 3);\n\nlet x: Result<&str, _> = Err(\"bar\");\nassert_eq!(x.map_or(42, |v| v.len()), 42);
Maps a Result<T, E>
to U
by applying fallback function default
to\na contained Err
value, or function f
to a contained Ok
value.
This function can be used to unpack a successful result\nwhile handling an error.
\nlet k = 21;\n\nlet x : Result<_, &str> = Ok(\"foo\");\nassert_eq!(x.map_or_else(|e| k * 2, |v| v.len()), 3);\n\nlet x : Result<&str, _> = Err(\"bar\");\nassert_eq!(x.map_or_else(|e| k * 2, |v| v.len()), 42);
Maps a Result<T, E>
to Result<T, F>
by applying a function to a\ncontained Err
value, leaving an Ok
value untouched.
This function can be used to pass through a successful result while handling\nan error.
\nfn stringify(x: u32) -> String { format!(\"error code: {x}\") }\n\nlet x: Result<u32, u32> = Ok(2);\nassert_eq!(x.map_err(stringify), Ok(2));\n\nlet x: Result<u32, u32> = Err(13);\nassert_eq!(x.map_err(stringify), Err(\"error code: 13\".to_string()));
Converts from Result<T, E>
(or &Result<T, E>
) to Result<&<T as Deref>::Target, &E>
.
Coerces the Ok
variant of the original Result
via Deref
\nand returns the new Result
.
let x: Result<String, u32> = Ok(\"hello\".to_string());\nlet y: Result<&str, &u32> = Ok(\"hello\");\nassert_eq!(x.as_deref(), y);\n\nlet x: Result<String, u32> = Err(42);\nlet y: Result<&str, &u32> = Err(&42);\nassert_eq!(x.as_deref(), y);
Converts from Result<T, E>
(or &mut Result<T, E>
) to Result<&mut <T as DerefMut>::Target, &mut E>
.
Coerces the Ok
variant of the original Result
via DerefMut
\nand returns the new Result
.
let mut s = \"HELLO\".to_string();\nlet mut x: Result<String, u32> = Ok(\"hello\".to_string());\nlet y: Result<&mut str, &mut u32> = Ok(&mut s);\nassert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y);\n\nlet mut i = 42;\nlet mut x: Result<String, u32> = Err(42);\nlet y: Result<&mut str, &mut u32> = Err(&mut i);\nassert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y);
Returns an iterator over the possibly contained value.
\nThe iterator yields one value if the result is Result::Ok
, otherwise none.
let x: Result<u32, &str> = Ok(7);\nassert_eq!(x.iter().next(), Some(&7));\n\nlet x: Result<u32, &str> = Err(\"nothing!\");\nassert_eq!(x.iter().next(), None);
Returns a mutable iterator over the possibly contained value.
\nThe iterator yields one value if the result is Result::Ok
, otherwise none.
let mut x: Result<u32, &str> = Ok(7);\nmatch x.iter_mut().next() {\n Some(v) => *v = 40,\n None => {},\n}\nassert_eq!(x, Ok(40));\n\nlet mut x: Result<u32, &str> = Err(\"nothing!\");\nassert_eq!(x.iter_mut().next(), None);
Returns the contained Ok
value, consuming the self
value.
Because this function may panic, its use is generally discouraged.\nInstead, prefer to use pattern matching and handle the Err
\ncase explicitly, or call unwrap_or
, unwrap_or_else
, or\nunwrap_or_default
.
Panics if the value is an Err
, with a panic message including the\npassed message, and the content of the Err
.
let x: Result<u32, &str> = Err(\"emergency failure\");\nx.expect(\"Testing expect\"); // panics with `Testing expect: emergency failure`
We recommend that expect
messages are used to describe the reason you\nexpect the Result
should be Ok
.
let path = std::env::var(\"IMPORTANT_PATH\")\n .expect(\"env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`\");
Hint: If you’re having trouble remembering how to phrase expect\nerror messages remember to focus on the word “should” as in “env\nvariable should be set by blah” or “the given binary should be available\nand executable by the current user”.
\nFor more detail on expect message styles and the reasoning behind our recommendation please\nrefer to the section on “Common Message\nStyles” in the\nstd::error
module docs.
Returns the contained Ok
value, consuming the self
value.
Because this function may panic, its use is generally discouraged.\nInstead, prefer to use pattern matching and handle the Err
\ncase explicitly, or call unwrap_or
, unwrap_or_else
, or\nunwrap_or_default
.
Panics if the value is an Err
, with a panic message provided by the\nErr
’s value.
Basic usage:
\n\nlet x: Result<u32, &str> = Ok(2);\nassert_eq!(x.unwrap(), 2);
let x: Result<u32, &str> = Err(\"emergency failure\");\nx.unwrap(); // panics with `emergency failure`
Returns the contained Ok
value or a default
Consumes the self
argument then, if Ok
, returns the contained\nvalue, otherwise if Err
, returns the default value for that\ntype.
Converts a string to an integer, turning poorly-formed strings\ninto 0 (the default value for integers). parse
converts\na string to any other type that implements FromStr
, returning an\nErr
on error.
let good_year_from_input = \"1909\";\nlet bad_year_from_input = \"190blarg\";\nlet good_year = good_year_from_input.parse().unwrap_or_default();\nlet bad_year = bad_year_from_input.parse().unwrap_or_default();\n\nassert_eq!(1909, good_year);\nassert_eq!(0, bad_year);
Returns the contained Err
value, consuming the self
value.
Panics if the value is an Ok
, with a panic message including the\npassed message, and the content of the Ok
.
let x: Result<u32, &str> = Ok(10);\nx.expect_err(\"Testing expect_err\"); // panics with `Testing expect_err: 10`
Returns the contained Err
value, consuming the self
value.
Panics if the value is an Ok
, with a custom panic message provided\nby the Ok
’s value.
let x: Result<u32, &str> = Ok(2);\nx.unwrap_err(); // panics with `2`
let x: Result<u32, &str> = Err(\"emergency failure\");\nassert_eq!(x.unwrap_err(), \"emergency failure\");
unwrap_infallible
)Returns the contained Ok
value, but never panics.
Unlike unwrap
, this method is known to never panic on the\nresult types it is implemented for. Therefore, it can be used\ninstead of unwrap
as a maintainability safeguard that will fail\nto compile if the error type of the Result
is later changed\nto an error that can actually occur.
\nfn only_good_news() -> Result<String, !> {\n Ok(\"this is fine\".into())\n}\n\nlet s: String = only_good_news().into_ok();\nprintln!(\"{s}\");
unwrap_infallible
)Returns the contained Err
value, but never panics.
Unlike unwrap_err
, this method is known to never panic on the\nresult types it is implemented for. Therefore, it can be used\ninstead of unwrap_err
as a maintainability safeguard that will fail\nto compile if the ok type of the Result
is later changed\nto a type that can actually occur.
\nfn only_bad_news() -> Result<!, String> {\n Err(\"Oops, it failed\".into())\n}\n\nlet error: String = only_bad_news().into_err();\nprintln!(\"{error}\");
Returns res
if the result is Ok
, otherwise returns the Err
value of self
.
Arguments passed to and
are eagerly evaluated; if you are passing the\nresult of a function call, it is recommended to use and_then
, which is\nlazily evaluated.
let x: Result<u32, &str> = Ok(2);\nlet y: Result<&str, &str> = Err(\"late error\");\nassert_eq!(x.and(y), Err(\"late error\"));\n\nlet x: Result<u32, &str> = Err(\"early error\");\nlet y: Result<&str, &str> = Ok(\"foo\");\nassert_eq!(x.and(y), Err(\"early error\"));\n\nlet x: Result<u32, &str> = Err(\"not a 2\");\nlet y: Result<&str, &str> = Err(\"late error\");\nassert_eq!(x.and(y), Err(\"not a 2\"));\n\nlet x: Result<u32, &str> = Ok(2);\nlet y: Result<&str, &str> = Ok(\"different result type\");\nassert_eq!(x.and(y), Ok(\"different result type\"));
Calls op
if the result is Ok
, otherwise returns the Err
value of self
.
This function can be used for control flow based on Result
values.
fn sq_then_to_string(x: u32) -> Result<String, &'static str> {\n x.checked_mul(x).map(|sq| sq.to_string()).ok_or(\"overflowed\")\n}\n\nassert_eq!(Ok(2).and_then(sq_then_to_string), Ok(4.to_string()));\nassert_eq!(Ok(1_000_000).and_then(sq_then_to_string), Err(\"overflowed\"));\nassert_eq!(Err(\"not a number\").and_then(sq_then_to_string), Err(\"not a number\"));
Often used to chain fallible operations that may return Err
.
use std::{io::ErrorKind, path::Path};\n\n// Note: on Windows \"/\" maps to \"C:\\\"\nlet root_modified_time = Path::new(\"/\").metadata().and_then(|md| md.modified());\nassert!(root_modified_time.is_ok());\n\nlet should_fail = Path::new(\"/bad/path\").metadata().and_then(|md| md.modified());\nassert!(should_fail.is_err());\nassert_eq!(should_fail.unwrap_err().kind(), ErrorKind::NotFound);
Returns res
if the result is Err
, otherwise returns the Ok
value of self
.
Arguments passed to or
are eagerly evaluated; if you are passing the\nresult of a function call, it is recommended to use or_else
, which is\nlazily evaluated.
let x: Result<u32, &str> = Ok(2);\nlet y: Result<u32, &str> = Err(\"late error\");\nassert_eq!(x.or(y), Ok(2));\n\nlet x: Result<u32, &str> = Err(\"early error\");\nlet y: Result<u32, &str> = Ok(2);\nassert_eq!(x.or(y), Ok(2));\n\nlet x: Result<u32, &str> = Err(\"not a 2\");\nlet y: Result<u32, &str> = Err(\"late error\");\nassert_eq!(x.or(y), Err(\"late error\"));\n\nlet x: Result<u32, &str> = Ok(2);\nlet y: Result<u32, &str> = Ok(100);\nassert_eq!(x.or(y), Ok(2));
Calls op
if the result is Err
, otherwise returns the Ok
value of self
.
This function can be used for control flow based on result values.
\nfn sq(x: u32) -> Result<u32, u32> { Ok(x * x) }\nfn err(x: u32) -> Result<u32, u32> { Err(x) }\n\nassert_eq!(Ok(2).or_else(sq).or_else(sq), Ok(2));\nassert_eq!(Ok(2).or_else(err).or_else(sq), Ok(2));\nassert_eq!(Err(3).or_else(sq).or_else(err), Ok(9));\nassert_eq!(Err(3).or_else(err).or_else(err), Err(3));
Returns the contained Ok
value or a provided default.
Arguments passed to unwrap_or
are eagerly evaluated; if you are passing\nthe result of a function call, it is recommended to use unwrap_or_else
,\nwhich is lazily evaluated.
let default = 2;\nlet x: Result<u32, &str> = Ok(9);\nassert_eq!(x.unwrap_or(default), 9);\n\nlet x: Result<u32, &str> = Err(\"error\");\nassert_eq!(x.unwrap_or(default), default);
Returns the contained Ok
value, consuming the self
value,\nwithout checking that the value is not an Err
.
Calling this method on an Err
is undefined behavior.
let x: Result<u32, &str> = Ok(2);\nassert_eq!(unsafe { x.unwrap_unchecked() }, 2);
let x: Result<u32, &str> = Err(\"emergency failure\");\nunsafe { x.unwrap_unchecked(); } // Undefined behavior!
Returns the contained Err
value, consuming the self
value,\nwithout checking that the value is not an Ok
.
Calling this method on an Ok
is undefined behavior.
let x: Result<u32, &str> = Ok(2);\nunsafe { x.unwrap_err_unchecked() }; // Undefined behavior!
let x: Result<u32, &str> = Err(\"emergency failure\");\nassert_eq!(unsafe { x.unwrap_err_unchecked() }, \"emergency failure\");
Maps a Result<&mut T, E>
to a Result<T, E>
by copying the contents of the\nOk
part.
let mut val = 12;\nlet x: Result<&mut i32, i32> = Ok(&mut val);\nassert_eq!(x, Ok(&mut 12));\nlet copied = x.copied();\nassert_eq!(copied, Ok(12));
Maps a Result<&mut T, E>
to a Result<T, E>
by cloning the contents of the\nOk
part.
let mut val = 12;\nlet x: Result<&mut i32, i32> = Ok(&mut val);\nassert_eq!(x, Ok(&mut 12));\nlet cloned = x.cloned();\nassert_eq!(cloned, Ok(12));
Transposes a Result
of an Option
into an Option
of a Result
.
Ok(None)
will be mapped to None
.\nOk(Some(_))
and Err(_)
will be mapped to Some(Ok(_))
and Some(Err(_))
.
#[derive(Debug, Eq, PartialEq)]\nstruct SomeErr;\n\nlet x: Result<Option<i32>, SomeErr> = Ok(Some(5));\nlet y: Option<Result<i32, SomeErr>> = Some(Ok(5));\nassert_eq!(x.transpose(), y);
result_flattening
)Converts from Result<Result<T, E>, E>
to Result<T, E>
#![feature(result_flattening)]\nlet x: Result<Result<&'static str, u32>, u32> = Ok(Ok(\"hello\"));\nassert_eq!(Ok(\"hello\"), x.flatten());\n\nlet x: Result<Result<&'static str, u32>, u32> = Ok(Err(6));\nassert_eq!(Err(6), x.flatten());\n\nlet x: Result<Result<&'static str, u32>, u32> = Err(6);\nassert_eq!(Err(6), x.flatten());
Flattening only removes one level of nesting at a time:
\n\n#![feature(result_flattening)]\nlet x: Result<Result<Result<&'static str, u32>, u32>, u32> = Ok(Ok(Ok(\"hello\")));\nassert_eq!(Ok(Ok(\"hello\")), x.flatten());\nassert_eq!(Ok(\"hello\"), x.flatten().flatten());
self
and other
) and is used by the <=
\noperator. Read moreTakes each element in the Iterator
: if it is an Err
, no further\nelements are taken, and the Err
is returned. Should no Err
\noccur, the product of all elements is returned.
This multiplies each number in a vector of strings,\nif a string could not be parsed the operation returns Err
:
let nums = vec![\"5\", \"10\", \"1\", \"2\"];\nlet total: Result<usize, _> = nums.iter().map(|w| w.parse::<usize>()).product();\nassert_eq!(total, Ok(100));\nlet nums = vec![\"5\", \"10\", \"one\", \"2\"];\nlet total: Result<usize, _> = nums.iter().map(|w| w.parse::<usize>()).product();\nassert!(total.is_err());
try_trait_v2
)Residual
type. Read moretry_trait_v2
)?
when not short-circuiting.try_trait_v2
)FromResidual::from_residual
\nas part of ?
when short-circuiting. Read moretry_trait_v2
)Output
type. Read moretry_trait_v2
)?
to decide whether the operator should produce a value\n(because this returned ControlFlow::Continue
)\nor propagate a value back to the caller\n(because this returned ControlFlow::Break
). Read moreTakes each element in the Iterator
: if it is an Err
, no further\nelements are taken, and the Err
is returned. Should no Err
occur, a\ncontainer with the values of each Result
is returned.
Here is an example which increments every integer in a vector,\nchecking for overflow:
\n\nlet v = vec![1, 2];\nlet res: Result<Vec<u32>, &'static str> = v.iter().map(|x: &u32|\n x.checked_add(1).ok_or(\"Overflow!\")\n).collect();\nassert_eq!(res, Ok(vec![2, 3]));
Here is another example that tries to subtract one from another list\nof integers, this time checking for underflow:
\n\nlet v = vec![1, 2, 0];\nlet res: Result<Vec<u32>, &'static str> = v.iter().map(|x: &u32|\n x.checked_sub(1).ok_or(\"Underflow!\")\n).collect();\nassert_eq!(res, Err(\"Underflow!\"));
Here is a variation on the previous example, showing that no\nfurther elements are taken from iter
after the first Err
.
let v = vec![3, 2, 1, 10];\nlet mut shared = 0;\nlet res: Result<Vec<u32>, &'static str> = v.iter().map(|x: &u32| {\n shared += x;\n x.checked_sub(2).ok_or(\"Underflow!\")\n}).collect();\nassert_eq!(res, Err(\"Underflow!\"));\nassert_eq!(shared, 6);
Since the third element caused an underflow, no further elements were taken,\nso the final value of shared
is 6 (= 3 + 2 + 1
), not 16.
Returns a consuming iterator over the possibly contained value.
\nThe iterator yields one value if the result is Result::Ok
, otherwise none.
let x: Result<u32, &str> = Ok(5);\nlet v: Vec<u32> = x.into_iter().collect();\nassert_eq!(v, [5]);\n\nlet x: Result<u32, &str> = Err(\"nothing!\");\nlet v: Vec<u32> = x.into_iter().collect();\nassert_eq!(v, []);
Takes each element in the Iterator
: if it is an Err
, no further\nelements are taken, and the Err
is returned. Should no Err
\noccur, the sum of all elements is returned.
This sums up every integer in a vector, rejecting the sum if a negative\nelement is encountered:
\n\nlet f = |&x: &i32| if x < 0 { Err(\"Negative element found\") } else { Ok(x) };\nlet v = vec![1, 2];\nlet res: Result<i32, _> = v.iter().map(f).sum();\nassert_eq!(res, Ok(3));\nlet v = vec![1, -2];\nlet res: Result<i32, _> = v.iter().map(f).sum();\nassert_eq!(res, Err(\"Negative element found\"));