<commit_before>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_PMESH
#define MFEM_PMESH

#include "../config/config.hpp"

#ifdef MFEM_USE_MPI

#include "../general/communication.hpp"
#include "../general/globals.hpp"
#include "mesh.hpp"
#include "pncmesh.hpp"
#include <iostream>

namespace mfem
{
#ifdef MFEM_USE_PUMI
class ParPumiMesh;
#endif

/// Class for parallel meshes
class ParMesh : public Mesh
{
protected:
   ParMesh() : MyComm(0), NRanks(0), MyRank(-1),
      have_face_nbr_data(false), pncmesh(NULL) {}

   MPI_Comm MyComm;
   int NRanks, MyRank;

   struct Vert3
   {
      int v[3];
      Vert3() { }
      Vert3(int v0, int v1, int v2) { v[0] = v0; v[1] = v1; v[2] = v2; }
      void Set(int v0, int v1, int v2) { v[0] = v0; v[1] = v1; v[2] = v2; }
      void Set(const int *w) { v[0] = w[0]; v[1] = w[1]; v[2] = w[2]; }
   };

   struct Vert4
   {
      int v[4];
      Vert4() { }
      Vert4(int v0, int v1, int v2, int v3)
      { v[0] = v0; v[1] = v1; v[2] = v2; v[3] = v3; }
      void Set(int v0, int v1, int v2, int v3)
      { v[0] = v0; v[1] = v1; v[2] = v2; v[3] = v3; }
      void Set(const int *w)
      { v[0] = w[0]; v[1] = w[1]; v[2] = w[2]; v[3] = w[3]; }
   };

   Array<Element *> shared_edges;
   // shared face id 'i' is:
   //   * triangle id 'i',                  if i < shared_trias.Size()
   //   * quad id 'i-shared_trias.Size()',  otherwise
   Array<Vert3> shared_trias;
   Array<Vert4> shared_quads;

   /// Shared objects in each group.
   Table group_svert;
   Table group_sedge;
   Table group_stria;  // contains shared triangle indices
   Table group_squad;  // contains shared quadrilateral indices

   /// Shared to local index mapping.
   Array<int> svert_lvert;
   Array<int> sedge_ledge;
   // sface ids: all triangles first, then all quads
   Array<int> sface_lface;

   /// Create from a nonconforming mesh.
   ParMesh(const ParNCMesh &pncmesh);

   // Convert the local 'meshgen' to a global one.
   void ReduceMeshGen();

   // Determine sedge_ledge and sface_lface.
   void FinalizeParTopo();

   // Mark all tets to ensure consistency across MPI tasks; also mark the
   // shared and boundary triangle faces using the consistently marked tets.
   virtual void MarkTetMeshForRefinement(DSTable &v_to_v);

   /// Return a number(0-1) identifying how the given edge has been split
   int GetEdgeSplittings(Element *edge, const DSTable &v_to_v, int *middle);
   /// Append codes identifying how the given face has been split to @a codes
   void GetFaceSplittings(const int *fv, const HashTable<Hashed2> &v_to_v,
                          Array<unsigned> &codes);

   bool DecodeFaceSplittings(HashTable<Hashed2> &v_to_v, const int *v,
                             const Array<unsigned> &codes, int &pos);

   ElementTransformation* GetGhostFaceTransformation(
      FaceElementTransformations* FETr, Element::Type face_type,
      Geometry::Type face_geom);

   /// Update the groups after triangle refinement
   void RefineGroups(const DSTable &v_to_v, int *middle);

   /// Update the groups after tetrahedron refinement
   void RefineGroups(int old_nv, const HashTable<Hashed2> &v_to_v);

   void UniformRefineGroups2D(int old_nv);

   // f2qf can be NULL if all faces are quads or there are no quad faces
   void UniformRefineGroups3D(int old_nv, int old_nedges,
                              const DSTable &old_v_to_v,
                              const STable3D &old_faces,
                              Array<int> *f2qf);

   void ExchangeFaceNbrData(Table *gr_sface, int *s2l_face);

   /// Refine a mixed 2D mesh uniformly.
   virtual void UniformRefinement2D();

   /// Refine a mixed 3D mesh uniformly.
   virtual void UniformRefinement3D();

   virtual void NURBSUniformRefinement();

   /// This function is not public anymore. Use GeneralRefinement instead.
   virtual void LocalRefinement(const Array<int> &marked_el, int type = 3);

   /// This function is not public anymore. Use GeneralRefinement instead.
   virtual void NonconformingRefinement(const Array<Refinement> &refinements,
                                        int nc_limit = 0);

   virtual bool NonconformingDerefinement(Array<double> &elem_error,
                                          double threshold, int nc_limit = 0,
                                          int op = 1);

   void RebalanceImpl(const Array<int> *partition);

   void DeleteFaceNbrData();

   bool WantSkipSharedMaster(const NCMesh::Master &master) const;

   /// Fills out partitioned Mesh::vertices
   int BuildLocalVertices(const Mesh& global_mesh, const int *partitioning,
                          Array<int> &vert_global_local);

   /// Fills out partitioned Mesh::elements
   int BuildLocalElements(const Mesh& global_mesh, const int *partitioning,
                          const Array<int> &vert_global_local);

   /// Fills out partitioned Mesh::boundary
   int BuildLocalBoundary(const Mesh& global_mesh, const int *partitioning,
                          const Array<int> &vert_global_local,
                          Array<bool>& activeBdrElem,
                          Table* &edge_element);

   void FindSharedFaces(const Mesh &mesh, const int* partition,
                        Array<int>& face_group,
                        ListOfIntegerSets& groups);

   int FindSharedEdges(const Mesh &mesh, const int* partition,
                       Table* &edge_element, ListOfIntegerSets& groups);

   int FindSharedVertices(const int *partition, Table* vertex_element,
                          ListOfIntegerSets& groups);

   void BuildFaceGroup(int ngroups, const Mesh &mesh,
                       const Array<int>& face_group,
                       int &nstria, int &nsquad);

   void BuildEdgeGroup(int ngroups, const Table& edge_element);

   void BuildVertexGroup(int ngroups, const Table& vert_element);

   void BuildSharedFaceElems(int ntri_faces, int nquad_faces,
                             const Mesh &mesh, int *partitioning,
                             const STable3D *faces_tbl,
                             const Array<int> &face_group,
                             const Array<int> &vert_global_local);

   void BuildSharedEdgeElems(int nedges, Mesh &mesh,
                             const Array<int> &vert_global_local,
                             const Table *edge_element);

   void BuildSharedVertMapping(int nvert, const Table* vert_element,
                               const Array<int> &vert_global_local);

   /// Ensure that bdr_attributes and attributes agree across processors
   void DistributeAttributes(Array<int> &attr);

public:
   /** Copy constructor. Performs a deep copy of (almost) all data, so that the
       source mesh can be modified (e.g. deleted, refined) without affecting the
       new mesh. If 'copy_nodes' is false, use a shallow (pointer) copy for the
       nodes, if present. */
   explicit ParMesh(const ParMesh &pmesh, bool copy_nodes = true);

   ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_ = NULL,
           int part_method = 1);

   /// Read a parallel mesh, each MPI rank from its own file/stream.
   /** The @a refine parameter is passed to the method Mesh::Finalize(). */
   ParMesh(MPI_Comm comm, std::istream &input, bool refine = true);

   /// Create a uniformly refined (by any factor) version of @a orig_mesh.
   /** @param[in] orig_mesh  The starting coarse mesh.
       @param[in] ref_factor The refinement factor, an integer > 1.
       @param[in] ref_type   Specify the positions of the new vertices. The
                             options are BasisType::ClosedUniform or
                             BasisType::GaussLobatto.

       The refinement data which can be accessed with GetRefinementTransforms()
       is set to reflect the performed refinements.

       @note The constructed ParMesh is linear, i.e. it does not have nodes. */
   ParMesh(ParMesh *orig_mesh, int ref_factor, int ref_type);

   virtual void Finalize(bool refine = false, bool fix_orientation = false);

   virtual void SetAttributes();

   MPI_Comm GetComm() const { return MyComm; }
   int GetNRanks() const { return NRanks; }
   int GetMyRank() const { return MyRank; }

   GroupTopology gtopo;

   // Face-neighbor elements and vertices
   bool             have_face_nbr_data;
   Array<int>       face_nbr_group;
   Array<int>       face_nbr_elements_offset;
   Array<int>       face_nbr_vertices_offset;
   Array<Element *> face_nbr_elements;
   Array<Vertex>    face_nbr_vertices;
   // Local face-neighbor elements and vertices ordered by face-neighbor
   Table            send_face_nbr_elements;
   Table            send_face_nbr_vertices;

   ParNCMesh* pncmesh;

   int GetNGroups() const { return gtopo.NGroups(); }

   ///@{ @name These methods require group > 0
   int GroupNVertices(int group) { return group_svert.RowSize(group-1); }
   int GroupNEdges(int group)    { return group_sedge.RowSize(group-1); }
   int GroupNTriangles(int group) { return group_stria.RowSize(group-1); }
   int GroupNQuadrilaterals(int group) { return group_squad.RowSize(group-1); }

   int GroupVertex(int group, int i)
   { return svert_lvert[group_svert.GetRow(group-1)[i]]; }
   void GroupEdge(int group, int i, int &edge, int &o);
   void GroupTriangle(int group, int i, int &face, int &o);
   void GroupQuadrilateral(int group, int i, int &face, int &o);
   ///@}

   void GenerateOffsets(int N, HYPRE_Int loc_sizes[],
                        Array<HYPRE_Int> *offsets[]) const;

   void ExchangeFaceNbrData();
   void ExchangeFaceNbrNodes();

   virtual void SetCurvature(int order, bool discont = false, int space_dim = -1,
                             int ordering = 1);

   int GetNFaceNeighbors() const { return face_nbr_group.Size(); }
   int GetFaceNbrGroup(int fn) const { return face_nbr_group[fn]; }
   int GetFaceNbrRank(int fn) const;

   void GetFaceNbrElementTransformation(
      int i, IsoparametricTransformation *ElTr);

   /** Similar to Mesh::GetFaceToElementTable with added face-neighbor elements
       with indices offset by the local number of elements. */
   Table *GetFaceToAllElementTable() const;

   /** Get the FaceElementTransformations for the given shared face (edge 2D).
       In the returned object, 1 and 2 refer to the local and the neighbor
       elements, respectively. */
   FaceElementTransformations *
   GetSharedFaceTransformations(int sf, bool fill2 = true);

   /// Return the number of shared faces (3D), edges (2D), vertices (1D)
   int GetNSharedFaces() const;

   /// Return the local face index for the given shared face.
   int GetSharedFace(int sface) const;

   /// See the remarks for the serial version in mesh.hpp
   virtual void ReorientTetMesh();

   /// Utility function: sum integers from all processors (Allreduce).
   virtual long ReduceInt(int value) const;

   /** Load balance the mesh by equipartitioning the global space-filling
       sequence of elements. Works for nonconforming meshes only. */
   void Rebalance();

   /** Load balance a nonconforming mesh using a user-defined partition.
       Each local element 'i' is migrated to processor rank 'partition[i]',
       for 0 <= i < GetNE(). */
   void Rebalance(const Array<int> &partition);

   /** Print the part of the mesh in the calling processor adding the interface
       as boundary (for visualization purposes) using the mfem v1.0 format. */
   virtual void Print(std::ostream &out = mfem::out) const;

#ifdef MFEM_USE_ADIOS2
   /** Print the part of the mesh in the calling processor using adios2 bp
       format. */
   virtual void Print(adios2stream &out) const;
#endif

   /** Print the part of the mesh in the calling processor adding the interface
       as boundary (for visualization purposes) using Netgen/Truegrid format .*/
   virtual void PrintXG(std::ostream &out = mfem::out) const;

   /** Write the mesh to the stream 'out' on Process 0 in a form suitable for
       visualization: the mesh is written as a disjoint mesh and the shared
       boundary is added to the actual boundary; both the element and boundary
       attributes are set to the processor number.  */
   void PrintAsOne(std::ostream &out = mfem::out);

   /// Old mesh format (Netgen/Truegrid) version of 'PrintAsOne'
   void PrintAsOneXG(std::ostream &out = mfem::out);

   /// Returns the minimum and maximum corners of the mesh bounding box. For
   /// high-order meshes, the geometry is refined first "ref" times.
   void GetBoundingBox(Vector &p_min, Vector &p_max, int ref = 2);

   void GetCharacteristics(double &h_min, double &h_max,
                           double &kappa_min, double &kappa_max);

   /// Print various parallel mesh stats
   virtual void PrintInfo(std::ostream &out = mfem::out);

   /// Save the mesh in a parallel mesh format.
   void ParPrint(std::ostream &out) const;

   virtual int FindPoints(DenseMatrix& point_mat, Array<int>& elem_ids,
                          Array<IntegrationPoint>& ips, bool warn = true,
                          InverseElementTransformation *inv_trans = NULL);

   /// Debugging method
   void PrintSharedEntities(const char *fname_prefix) const;

   virtual ~ParMesh();

   friend class ParNCMesh;
#ifdef MFEM_USE_PUMI
   friend class ParPumiMesh;
#endif

#ifdef MFEM_USE_ADIOS2
   friend class adios2stream;
#endif
};

}

#endif // MFEM_USE_MPI

#endif
<commit_msg>Add `GetNFaceNeighborElements` to `ParMesh`<commit_after>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_PMESH
#define MFEM_PMESH

#include "../config/config.hpp"

#ifdef MFEM_USE_MPI

#include "../general/communication.hpp"
#include "../general/globals.hpp"
#include "mesh.hpp"
#include "pncmesh.hpp"
#include <iostream>

namespace mfem
{
#ifdef MFEM_USE_PUMI
class ParPumiMesh;
#endif

/// Class for parallel meshes
class ParMesh : public Mesh
{
protected:
   ParMesh() : MyComm(0), NRanks(0), MyRank(-1),
      have_face_nbr_data(false), pncmesh(NULL) {}

   MPI_Comm MyComm;
   int NRanks, MyRank;

   struct Vert3
   {
      int v[3];
      Vert3() { }
      Vert3(int v0, int v1, int v2) { v[0] = v0; v[1] = v1; v[2] = v2; }
      void Set(int v0, int v1, int v2) { v[0] = v0; v[1] = v1; v[2] = v2; }
      void Set(const int *w) { v[0] = w[0]; v[1] = w[1]; v[2] = w[2]; }
   };

   struct Vert4
   {
      int v[4];
      Vert4() { }
      Vert4(int v0, int v1, int v2, int v3)
      { v[0] = v0; v[1] = v1; v[2] = v2; v[3] = v3; }
      void Set(int v0, int v1, int v2, int v3)
      { v[0] = v0; v[1] = v1; v[2] = v2; v[3] = v3; }
      void Set(const int *w)
      { v[0] = w[0]; v[1] = w[1]; v[2] = w[2]; v[3] = w[3]; }
   };

   Array<Element *> shared_edges;
   // shared face id 'i' is:
   //   * triangle id 'i',                  if i < shared_trias.Size()
   //   * quad id 'i-shared_trias.Size()',  otherwise
   Array<Vert3> shared_trias;
   Array<Vert4> shared_quads;

   /// Shared objects in each group.
   Table group_svert;
   Table group_sedge;
   Table group_stria;  // contains shared triangle indices
   Table group_squad;  // contains shared quadrilateral indices

   /// Shared to local index mapping.
   Array<int> svert_lvert;
   Array<int> sedge_ledge;
   // sface ids: all triangles first, then all quads
   Array<int> sface_lface;

   /// Create from a nonconforming mesh.
   ParMesh(const ParNCMesh &pncmesh);

   // Convert the local 'meshgen' to a global one.
   void ReduceMeshGen();

   // Determine sedge_ledge and sface_lface.
   void FinalizeParTopo();

   // Mark all tets to ensure consistency across MPI tasks; also mark the
   // shared and boundary triangle faces using the consistently marked tets.
   virtual void MarkTetMeshForRefinement(DSTable &v_to_v);

   /// Return a number(0-1) identifying how the given edge has been split
   int GetEdgeSplittings(Element *edge, const DSTable &v_to_v, int *middle);
   /// Append codes identifying how the given face has been split to @a codes
   void GetFaceSplittings(const int *fv, const HashTable<Hashed2> &v_to_v,
                          Array<unsigned> &codes);

   bool DecodeFaceSplittings(HashTable<Hashed2> &v_to_v, const int *v,
                             const Array<unsigned> &codes, int &pos);

   ElementTransformation* GetGhostFaceTransformation(
      FaceElementTransformations* FETr, Element::Type face_type,
      Geometry::Type face_geom);

   /// Update the groups after triangle refinement
   void RefineGroups(const DSTable &v_to_v, int *middle);

   /// Update the groups after tetrahedron refinement
   void RefineGroups(int old_nv, const HashTable<Hashed2> &v_to_v);

   void UniformRefineGroups2D(int old_nv);

   // f2qf can be NULL if all faces are quads or there are no quad faces
   void UniformRefineGroups3D(int old_nv, int old_nedges,
                              const DSTable &old_v_to_v,
                              const STable3D &old_faces,
                              Array<int> *f2qf);

   void ExchangeFaceNbrData(Table *gr_sface, int *s2l_face);

   /// Refine a mixed 2D mesh uniformly.
   virtual void UniformRefinement2D();

   /// Refine a mixed 3D mesh uniformly.
   virtual void UniformRefinement3D();

   virtual void NURBSUniformRefinement();

   /// This function is not public anymore. Use GeneralRefinement instead.
   virtual void LocalRefinement(const Array<int> &marked_el, int type = 3);

   /// This function is not public anymore. Use GeneralRefinement instead.
   virtual void NonconformingRefinement(const Array<Refinement> &refinements,
                                        int nc_limit = 0);

   virtual bool NonconformingDerefinement(Array<double> &elem_error,
                                          double threshold, int nc_limit = 0,
                                          int op = 1);

   void RebalanceImpl(const Array<int> *partition);

   void DeleteFaceNbrData();

   bool WantSkipSharedMaster(const NCMesh::Master &master) const;

   /// Fills out partitioned Mesh::vertices
   int BuildLocalVertices(const Mesh& global_mesh, const int *partitioning,
                          Array<int> &vert_global_local);

   /// Fills out partitioned Mesh::elements
   int BuildLocalElements(const Mesh& global_mesh, const int *partitioning,
                          const Array<int> &vert_global_local);

   /// Fills out partitioned Mesh::boundary
   int BuildLocalBoundary(const Mesh& global_mesh, const int *partitioning,
                          const Array<int> &vert_global_local,
                          Array<bool>& activeBdrElem,
                          Table* &edge_element);

   void FindSharedFaces(const Mesh &mesh, const int* partition,
                        Array<int>& face_group,
                        ListOfIntegerSets& groups);

   int FindSharedEdges(const Mesh &mesh, const int* partition,
                       Table* &edge_element, ListOfIntegerSets& groups);

   int FindSharedVertices(const int *partition, Table* vertex_element,
                          ListOfIntegerSets& groups);

   void BuildFaceGroup(int ngroups, const Mesh &mesh,
                       const Array<int>& face_group,
                       int &nstria, int &nsquad);

   void BuildEdgeGroup(int ngroups, const Table& edge_element);

   void BuildVertexGroup(int ngroups, const Table& vert_element);

   void BuildSharedFaceElems(int ntri_faces, int nquad_faces,
                             const Mesh &mesh, int *partitioning,
                             const STable3D *faces_tbl,
                             const Array<int> &face_group,
                             const Array<int> &vert_global_local);

   void BuildSharedEdgeElems(int nedges, Mesh &mesh,
                             const Array<int> &vert_global_local,
                             const Table *edge_element);

   void BuildSharedVertMapping(int nvert, const Table* vert_element,
                               const Array<int> &vert_global_local);

   /// Ensure that bdr_attributes and attributes agree across processors
   void DistributeAttributes(Array<int> &attr);

public:
   /** Copy constructor. Performs a deep copy of (almost) all data, so that the
       source mesh can be modified (e.g. deleted, refined) without affecting the
       new mesh. If 'copy_nodes' is false, use a shallow (pointer) copy for the
       nodes, if present. */
   explicit ParMesh(const ParMesh &pmesh, bool copy_nodes = true);

   ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_ = NULL,
           int part_method = 1);

   /// Read a parallel mesh, each MPI rank from its own file/stream.
   /** The @a refine parameter is passed to the method Mesh::Finalize(). */
   ParMesh(MPI_Comm comm, std::istream &input, bool refine = true);

   /// Create a uniformly refined (by any factor) version of @a orig_mesh.
   /** @param[in] orig_mesh  The starting coarse mesh.
       @param[in] ref_factor The refinement factor, an integer > 1.
       @param[in] ref_type   Specify the positions of the new vertices. The
                             options are BasisType::ClosedUniform or
                             BasisType::GaussLobatto.

       The refinement data which can be accessed with GetRefinementTransforms()
       is set to reflect the performed refinements.

       @note The constructed ParMesh is linear, i.e. it does not have nodes. */
   ParMesh(ParMesh *orig_mesh, int ref_factor, int ref_type);

   virtual void Finalize(bool refine = false, bool fix_orientation = false);

   virtual void SetAttributes();

   MPI_Comm GetComm() const { return MyComm; }
   int GetNRanks() const { return NRanks; }
   int GetMyRank() const { return MyRank; }

   GroupTopology gtopo;

   // Face-neighbor elements and vertices
   bool             have_face_nbr_data;
   Array<int>       face_nbr_group;
   Array<int>       face_nbr_elements_offset;
   Array<int>       face_nbr_vertices_offset;
   Array<Element *> face_nbr_elements;
   Array<Vertex>    face_nbr_vertices;
   // Local face-neighbor elements and vertices ordered by face-neighbor
   Table            send_face_nbr_elements;
   Table            send_face_nbr_vertices;

   ParNCMesh* pncmesh;

   int GetNGroups() const { return gtopo.NGroups(); }

   ///@{ @name These methods require group > 0
   int GroupNVertices(int group) { return group_svert.RowSize(group-1); }
   int GroupNEdges(int group)    { return group_sedge.RowSize(group-1); }
   int GroupNTriangles(int group) { return group_stria.RowSize(group-1); }
   int GroupNQuadrilaterals(int group) { return group_squad.RowSize(group-1); }

   int GroupVertex(int group, int i)
   { return svert_lvert[group_svert.GetRow(group-1)[i]]; }
   void GroupEdge(int group, int i, int &edge, int &o);
   void GroupTriangle(int group, int i, int &face, int &o);
   void GroupQuadrilateral(int group, int i, int &face, int &o);
   ///@}

   void GenerateOffsets(int N, HYPRE_Int loc_sizes[],
                        Array<HYPRE_Int> *offsets[]) const;

   void ExchangeFaceNbrData();
   void ExchangeFaceNbrNodes();

   virtual void SetCurvature(int order, bool discont = false, int space_dim = -1,
                             int ordering = 1);

   int GetNFaceNeighbors() const { return face_nbr_group.Size(); }
   int GetNFaceNeighborElements() const { return face_nbr_elements.Size(); }
   int GetFaceNbrGroup(int fn) const { return face_nbr_group[fn]; }
   int GetFaceNbrRank(int fn) const;

   void GetFaceNbrElementTransformation(
      int i, IsoparametricTransformation *ElTr);

   /** Similar to Mesh::GetFaceToElementTable with added face-neighbor elements
       with indices offset by the local number of elements. */
   Table *GetFaceToAllElementTable() const;

   /** Get the FaceElementTransformations for the given shared face (edge 2D).
       In the returned object, 1 and 2 refer to the local and the neighbor
       elements, respectively. */
   FaceElementTransformations *
   GetSharedFaceTransformations(int sf, bool fill2 = true);

   /// Return the number of shared faces (3D), edges (2D), vertices (1D)
   int GetNSharedFaces() const;

   /// Return the local face index for the given shared face.
   int GetSharedFace(int sface) const;

   /// See the remarks for the serial version in mesh.hpp
   virtual void ReorientTetMesh();

   /// Utility function: sum integers from all processors (Allreduce).
   virtual long ReduceInt(int value) const;

   /** Load balance the mesh by equipartitioning the global space-filling
       sequence of elements. Works for nonconforming meshes only. */
   void Rebalance();

   /** Load balance a nonconforming mesh using a user-defined partition.
       Each local element 'i' is migrated to processor rank 'partition[i]',
       for 0 <= i < GetNE(). */
   void Rebalance(const Array<int> &partition);

   /** Print the part of the mesh in the calling processor adding the interface
       as boundary (for visualization purposes) using the mfem v1.0 format. */
   virtual void Print(std::ostream &out = mfem::out) const;

#ifdef MFEM_USE_ADIOS2
   /** Print the part of the mesh in the calling processor using adios2 bp
       format. */
   virtual void Print(adios2stream &out) const;
#endif

   /** Print the part of the mesh in the calling processor adding the interface
       as boundary (for visualization purposes) using Netgen/Truegrid format .*/
   virtual void PrintXG(std::ostream &out = mfem::out) const;

   /** Write the mesh to the stream 'out' on Process 0 in a form suitable for
       visualization: the mesh is written as a disjoint mesh and the shared
       boundary is added to the actual boundary; both the element and boundary
       attributes are set to the processor number.  */
   void PrintAsOne(std::ostream &out = mfem::out);

   /// Old mesh format (Netgen/Truegrid) version of 'PrintAsOne'
   void PrintAsOneXG(std::ostream &out = mfem::out);

   /// Returns the minimum and maximum corners of the mesh bounding box. For
   /// high-order meshes, the geometry is refined first "ref" times.
   void GetBoundingBox(Vector &p_min, Vector &p_max, int ref = 2);

   void GetCharacteristics(double &h_min, double &h_max,
                           double &kappa_min, double &kappa_max);

   /// Print various parallel mesh stats
   virtual void PrintInfo(std::ostream &out = mfem::out);

   /// Save the mesh in a parallel mesh format.
   void ParPrint(std::ostream &out) const;

   virtual int FindPoints(DenseMatrix& point_mat, Array<int>& elem_ids,
                          Array<IntegrationPoint>& ips, bool warn = true,
                          InverseElementTransformation *inv_trans = NULL);

   /// Debugging method
   void PrintSharedEntities(const char *fname_prefix) const;

   virtual ~ParMesh();

   friend class ParNCMesh;
#ifdef MFEM_USE_PUMI
   friend class ParPumiMesh;
#endif

#ifdef MFEM_USE_ADIOS2
   friend class adios2stream;
#endif
};

}

#endif // MFEM_USE_MPI

#endif
<|endoftext|>


<commit_before>#include "Configurator.h"
#include <qapplication.h>

const QString Configurator::s_version("0.0.1.2");
QSharedPointer <QSettings>   Configurator::s_settings;

Configurator::Configurator()
{
    QApplication::setOrganizationName("TEKO");
    QApplication::setApplicationName("AirCoolController");

    QString settingsFile = QApplication::applicationDirPath();
    settingsFile += "/settings.ini";
    s_settings = QSharedPointer <QSettings> (new QSettings(settingsFile, QSettings::IniFormat));
   // QApplication::restoreGeometry(s_settings->value("Main/Geometry").toByteArray());
}

Configurator::~Configurator()
{
    //s_settings->setValue("Main/Geometry", saveGeometry());
    s_settings->sync();
}

const QString& Configurator::getVersion()
{
    return s_version;
}

const QVariant Configurator::getSettings(const QString& key)
{
    if (s_settings == NULL)
        return QVariant();

    return s_settings->value(key);
}

void Configurator::setSettings(const QString& key, const QVariant& value)
{
    if (s_settings != NULL)
    {
        s_settings->setValue(key, value);
    }
}

QString Configurator::getConfigFilesPath()
{
    return QApplication::applicationDirPath() + "/configs/";
}<commit_msg>Изменен номер версии<commit_after>#include "Configurator.h"
#include <qapplication.h>

const QString Configurator::s_version("0.0.1.3");
QSharedPointer <QSettings>   Configurator::s_settings;

Configurator::Configurator()
{
    QApplication::setOrganizationName("TEKO");
    QApplication::setApplicationName("AirCoolController");

    QString settingsFile = QApplication::applicationDirPath();
    settingsFile += "/settings.ini";
    s_settings = QSharedPointer <QSettings> (new QSettings(settingsFile, QSettings::IniFormat));
   // QApplication::restoreGeometry(s_settings->value("Main/Geometry").toByteArray());
}

Configurator::~Configurator()
{
    //s_settings->setValue("Main/Geometry", saveGeometry());
    s_settings->sync();
}

const QString& Configurator::getVersion()
{
    return s_version;
}

const QVariant Configurator::getSettings(const QString& key)
{
    if (s_settings == NULL)
        return QVariant();

    return s_settings->value(key);
}

void Configurator::setSettings(const QString& key, const QVariant& value)
{
    if (s_settings != NULL)
    {
        s_settings->setValue(key, value);
    }
}

QString Configurator::getConfigFilesPath()
{
    return QApplication::applicationDirPath() + "/configs/";
}<|endoftext|>


<commit_before>#include "xUnitTestRunner.h"
#include <atomic>
#include <chrono>
#include <future>
#include <limits>
#include <mutex>
#include <random>
#include <stdexcept>
#include <vector>
#include "IOutput.h"
#include "TestCollection.h"
#include "TestDetails.h"
#include "xUnitAssert.h"
#include "xUnitTime.h"

namespace
{

class ActiveTests
{
public:

    ActiveTests(std::function<bool(const xUnitpp::TestDetails &)> filter, const std::vector<xUnitpp::xUnitTest> &tests)
    {
        for (auto &test : tests)
        {
            if (filter(test.TestDetails()))
            {
                mTests.push_back(test);
            }
        }

        std::shuffle(mTests.begin(), mTests.end(), std::default_random_engine(std::random_device()()));
    }

    std::vector<xUnitpp::xUnitTest>::iterator begin()
    {
        return mTests.begin();
    }

    std::vector<xUnitpp::xUnitTest>::iterator end()
    {
        return mTests.end();
    }

private:
    std::vector<xUnitpp::xUnitTest> mTests;
};

}

namespace xUnitpp
{

class TestRunner::Impl
{
public:
    Impl(IOutput &testReporter)
        : mTestReporter(testReporter)
    {
    }

    void OnTestStart(const TestDetails &details)
    {
        std::lock_guard<std::mutex> guard(mStartMtx);
        mTestReporter.ReportStart(details);
    }

    void OnTestFailure(const TestDetails &details, const std::string &message, const LineInfo &lineInfo)
    {
        std::lock_guard<std::mutex> guard(mFailureMtx);
        mTestReporter.ReportFailure(details, message, lineInfo);
    }

    void OnTestSkip(const TestDetails &details, const std::string &reason)
    {
        mTestReporter.ReportSkip(details, reason);
    }

    void OnTestFinish(const TestDetails &details, Time::Duration time)
    {
        std::lock_guard<std::mutex> guard(mFinishMtx);
        mTestReporter.ReportFinish(details, time);
    }

    void OnAllTestsComplete(int total, int skipped, int failed, Time::Duration totalTime)
    {
        mTestReporter.ReportAllTestsComplete(total, skipped, failed, totalTime);
    }

private:
    Impl(const Impl &);
    Impl &operator=(Impl);

private:
    IOutput &mTestReporter;

    std::mutex mStartMtx;
    std::mutex mFailureMtx;
    std::mutex mFinishMtx;
};

TestRunner::TestRunner(IOutput &testReporter)
    : mImpl(new Impl(testReporter))
{
}

int TestRunner::RunTests(std::function<bool(const TestDetails &)> filter, const std::vector<xUnitTest> &tests, Time::Duration maxTestRunTime, size_t maxConcurrent)
{
    auto timeStart = std::chrono::system_clock::now();

    if (maxConcurrent == 0)
    {
        maxConcurrent = std::numeric_limits<decltype(maxConcurrent)>::max();
    }

    class ThreadCounter
    {
    public:
        ThreadCounter(size_t maxThreads)
            : maxThreads(maxThreads)
            , activeThreads(0)
        {
        }

        void operator++()
        {
            std::unique_lock<std::mutex> lock(mtx);
            condition.wait(lock, [&]() { return activeThreads < maxThreads; });

            ++activeThreads;
        }

        void operator--()
        {
            --activeThreads;
            condition.notify_one();
        }

    private:
        size_t maxThreads;
        std::atomic<size_t> activeThreads;
        std::mutex mtx;
        std::condition_variable condition;
    } threadCounter(maxConcurrent);

    std::atomic<int> failedTests = 0;
    int skippedTests = 0;

    std::vector<xUnitTest> activeTests;
    std::copy_if(tests.begin(), tests.end(), std::back_inserter(activeTests), [&filter](const xUnitTest &test) { return filter(test.TestDetails()); });

    std::vector<std::future<void>> futures;
    for (auto &test : activeTests)
    {
        {
            auto skip = test.TestDetails().Attributes.find("Skip");
            if (skip != test.TestDetails().Attributes.end())
            {
                skippedTests++;
                mImpl->OnTestSkip(test.TestDetails(), skip->second);
                continue;
            }
        }

        futures.push_back(std::async([&]()
            {
                struct CounterGuard
                {
                    CounterGuard(ThreadCounter &tc)
                        : tc(tc)
                    {
                        ++tc;
                    }

                    ~CounterGuard()
                    {
                        --tc;
                    }

                private:
                    CounterGuard &operator =(const CounterGuard &) { throw std::logic_error("not supported"); }
                    ThreadCounter &tc;
                } counterGuard(threadCounter);

                auto actualTest = [&](bool reportEnd) -> Time::TimeStamp
                    {
                        Time::TimeStamp testStart;
                        try
                        {
                            mImpl->OnTestStart(test.TestDetails());

                            testStart = Time::Clock::now();
                            test.Run();
                        }
                        catch (const xUnitAssert &e)
                        {
                            mImpl->OnTestFailure(test.TestDetails(), e.what(), e.LineInfo());
                        }
                        catch (const std::exception &e)
                        {
                            mImpl->OnTestFailure(test.TestDetails(), e.what(), LineInfo::empty());
                            ++failedTests;
                        }
                        catch (...)
                        {
                            mImpl->OnTestFailure(test.TestDetails(), "Unknown exception caught: test has crashed", LineInfo::empty());
                            ++failedTests;
                        }

                        if (reportEnd)
                        {
                            mImpl->OnTestFinish(test.TestDetails(), Time::ToDuration(Time::Clock::now() - testStart));
                        }

                        return testStart;
                    };

                auto testTimeLimit = test.TestDetails().TimeLimit;
                if (testTimeLimit < Time::Duration::zero())
                {
                    testTimeLimit = maxTestRunTime;
                }

                if (testTimeLimit > Time::Duration::zero())
                {
                    //
                    // note that forcing a test to run in under a certain amount of time is inherently fragile
                    // there's no guarantee that a thread, once started, actually gets `maxTestRunTime` nanoseconds of CPU

                    Time::TimeStamp testStart;

                    std::mutex m;
                    std::unique_lock<std::mutex> gate(m);

                    auto threadStarted = std::make_shared<std::condition_variable>();
                    std::thread timedRunner([&, threadStarted]()
                        {
                            m.lock();
                            m.unlock();

                            testStart = actualTest(false);
                            threadStarted->notify_all();
                        });
                    timedRunner.detach();

                    if (threadStarted->wait_for(gate, std::chrono::duration_cast<std::chrono::nanoseconds>(testTimeLimit)) == std::cv_status::timeout)
                    {
                        mImpl->OnTestFailure(test.TestDetails(), "Test failed to complete within " + std::to_string(Time::ToMilliseconds(testTimeLimit).count()) + " milliseconds.", LineInfo::empty());
                        mImpl->OnTestFinish(test.TestDetails(), testTimeLimit);
                        ++failedTests;
                    }
                    else
                    {
                        mImpl->OnTestFinish(test.TestDetails(), Time::ToDuration(Time::Clock::now() - testStart));
                    }
                }
                else
                {
                    actualTest(true);
                }
            }));
    }

    for (auto &test : futures)
    {
        test.get();
    }

    mImpl->OnAllTestsComplete(futures.size(), skippedTests, failedTests, Time::ToDuration(Time::Clock::now() - timeStart));

    return -failedTests;
}

}
<commit_msg>removing unused code<commit_after>#include "xUnitTestRunner.h"
#include <atomic>
#include <chrono>
#include <future>
#include <limits>
#include <mutex>
#include <random>
#include <stdexcept>
#include <vector>
#include "IOutput.h"
#include "TestCollection.h"
#include "TestDetails.h"
#include "xUnitAssert.h"
#include "xUnitTime.h"

namespace xUnitpp
{

class TestRunner::Impl
{
public:
    Impl(IOutput &testReporter)
        : mTestReporter(testReporter)
    {
    }

    void OnTestStart(const TestDetails &details)
    {
        std::lock_guard<std::mutex> guard(mStartMtx);
        mTestReporter.ReportStart(details);
    }

    void OnTestFailure(const TestDetails &details, const std::string &message, const LineInfo &lineInfo)
    {
        std::lock_guard<std::mutex> guard(mFailureMtx);
        mTestReporter.ReportFailure(details, message, lineInfo);
    }

    void OnTestSkip(const TestDetails &details, const std::string &reason)
    {
        mTestReporter.ReportSkip(details, reason);
    }

    void OnTestFinish(const TestDetails &details, Time::Duration time)
    {
        std::lock_guard<std::mutex> guard(mFinishMtx);
        mTestReporter.ReportFinish(details, time);
    }

    void OnAllTestsComplete(int total, int skipped, int failed, Time::Duration totalTime)
    {
        mTestReporter.ReportAllTestsComplete(total, skipped, failed, totalTime);
    }

private:
    Impl(const Impl &);
    Impl &operator=(Impl);

private:
    IOutput &mTestReporter;

    std::mutex mStartMtx;
    std::mutex mFailureMtx;
    std::mutex mFinishMtx;
};

TestRunner::TestRunner(IOutput &testReporter)
    : mImpl(new Impl(testReporter))
{
}

int TestRunner::RunTests(std::function<bool(const TestDetails &)> filter, const std::vector<xUnitTest> &tests, Time::Duration maxTestRunTime, size_t maxConcurrent)
{
    auto timeStart = std::chrono::system_clock::now();

    if (maxConcurrent == 0)
    {
        maxConcurrent = std::numeric_limits<decltype(maxConcurrent)>::max();
    }

    class ThreadCounter
    {
    public:
        ThreadCounter(size_t maxThreads)
            : maxThreads(maxThreads)
            , activeThreads(0)
        {
        }

        void operator++()
        {
            std::unique_lock<std::mutex> lock(mtx);
            condition.wait(lock, [&]() { return activeThreads < maxThreads; });

            ++activeThreads;
        }

        void operator--()
        {
            --activeThreads;
            condition.notify_one();
        }

    private:
        size_t maxThreads;
        std::atomic<size_t> activeThreads;
        std::mutex mtx;
        std::condition_variable condition;
    } threadCounter(maxConcurrent);

    std::atomic<int> failedTests = 0;
    int skippedTests = 0;

    std::vector<xUnitTest> activeTests;
    std::copy_if(tests.begin(), tests.end(), std::back_inserter(activeTests), [&filter](const xUnitTest &test) { return filter(test.TestDetails()); });

    std::vector<std::future<void>> futures;
    for (auto &test : activeTests)
    {
        {
            auto skip = test.TestDetails().Attributes.find("Skip");
            if (skip != test.TestDetails().Attributes.end())
            {
                skippedTests++;
                mImpl->OnTestSkip(test.TestDetails(), skip->second);
                continue;
            }
        }

        futures.push_back(std::async([&]()
            {
                struct CounterGuard
                {
                    CounterGuard(ThreadCounter &tc)
                        : tc(tc)
                    {
                        ++tc;
                    }

                    ~CounterGuard()
                    {
                        --tc;
                    }

                private:
                    CounterGuard &operator =(const CounterGuard &) { throw std::logic_error("not supported"); }
                    ThreadCounter &tc;
                } counterGuard(threadCounter);

                auto actualTest = [&](bool reportEnd) -> Time::TimeStamp
                    {
                        Time::TimeStamp testStart;
                        try
                        {
                            mImpl->OnTestStart(test.TestDetails());

                            testStart = Time::Clock::now();
                            test.Run();
                        }
                        catch (const xUnitAssert &e)
                        {
                            mImpl->OnTestFailure(test.TestDetails(), e.what(), e.LineInfo());
                        }
                        catch (const std::exception &e)
                        {
                            mImpl->OnTestFailure(test.TestDetails(), e.what(), LineInfo::empty());
                            ++failedTests;
                        }
                        catch (...)
                        {
                            mImpl->OnTestFailure(test.TestDetails(), "Unknown exception caught: test has crashed", LineInfo::empty());
                            ++failedTests;
                        }

                        if (reportEnd)
                        {
                            mImpl->OnTestFinish(test.TestDetails(), Time::ToDuration(Time::Clock::now() - testStart));
                        }

                        return testStart;
                    };

                auto testTimeLimit = test.TestDetails().TimeLimit;
                if (testTimeLimit < Time::Duration::zero())
                {
                    testTimeLimit = maxTestRunTime;
                }

                if (testTimeLimit > Time::Duration::zero())
                {
                    //
                    // note that forcing a test to run in under a certain amount of time is inherently fragile
                    // there's no guarantee that a thread, once started, actually gets `maxTestRunTime` nanoseconds of CPU

                    Time::TimeStamp testStart;

                    std::mutex m;
                    std::unique_lock<std::mutex> gate(m);

                    auto threadStarted = std::make_shared<std::condition_variable>();
                    std::thread timedRunner([&, threadStarted]()
                        {
                            m.lock();
                            m.unlock();

                            testStart = actualTest(false);
                            threadStarted->notify_all();
                        });
                    timedRunner.detach();

                    if (threadStarted->wait_for(gate, std::chrono::duration_cast<std::chrono::nanoseconds>(testTimeLimit)) == std::cv_status::timeout)
                    {
                        mImpl->OnTestFailure(test.TestDetails(), "Test failed to complete within " + std::to_string(Time::ToMilliseconds(testTimeLimit).count()) + " milliseconds.", LineInfo::empty());
                        mImpl->OnTestFinish(test.TestDetails(), testTimeLimit);
                        ++failedTests;
                    }
                    else
                    {
                        mImpl->OnTestFinish(test.TestDetails(), Time::ToDuration(Time::Clock::now() - testStart));
                    }
                }
                else
                {
                    actualTest(true);
                }
            }));
    }

    for (auto &test : futures)
    {
        test.get();
    }

    mImpl->OnAllTestsComplete(futures.size(), skippedTests, failedTests, Time::ToDuration(Time::Clock::now() - timeStart));

    return -failedTests;
}

}
<|endoftext|>


<commit_before>#include "xUnitTestRunner.h"
#include <atomic>
#include <chrono>
#include <future>
#include <limits>
#include <mutex>
#include <random>
#include <stdexcept>
#include <vector>
#include "IOutput.h"
#include "TestCollection.h"
#include "TestDetails.h"
#include "xUnitAssert.h"
#include "xUnitTime.h"

#include <iostream>

namespace
{

class SharedOutput : public xUnitpp::IOutput
{
public:
    SharedOutput(xUnitpp::IOutput &testReporter)
        : mOutput(testReporter)
    {
    }

    virtual void ReportStart(const xUnitpp::TestDetails &details) override
    {
        std::lock_guard<std::mutex> guard(mLock);
        mOutput.get().ReportStart(details);
    }

    virtual void ReportEvent(const xUnitpp::TestDetails &details, const xUnitpp::TestEvent &evt) override
    {
        std::lock_guard<std::mutex> guard(mLock);
        mOutput.get().ReportEvent(details, evt);
    }

    virtual void ReportSkip(const xUnitpp::TestDetails &details, const std::string &reason) override
    {
        std::lock_guard<std::mutex> guard(mLock);
        mOutput.get().ReportSkip(details, reason);
    }

    virtual void ReportFinish(const xUnitpp::TestDetails &details, xUnitpp::Time::Duration time) override
    {
        std::lock_guard<std::mutex> guard(mLock);
        mOutput.get().ReportFinish(details, time);
    }

    virtual void ReportAllTestsComplete(size_t total, size_t skipped, size_t failed, xUnitpp::Time::Duration totalTime) override
    {
        mOutput.get().ReportAllTestsComplete(total, skipped, failed, totalTime);
    }

private:
    SharedOutput(const SharedOutput &);
    SharedOutput &operator =(SharedOutput);

private:
    std::mutex mLock;
    std::reference_wrapper<xUnitpp::IOutput> mOutput;
};

class AttachedOutput
{
public:
    AttachedOutput(SharedOutput &output)
        : mAttached(true)
        , mOutput(std::ref(output))
    {
    }

    void Detach()
    {
        std::lock_guard<std::mutex> guard(mLock);
        mAttached = false;
    }

    void ReportStart(const xUnitpp::TestDetails &details)
    {
        std::lock_guard<std::mutex> guard(mLock);

        if (mAttached)
        {
            mOutput.get().ReportStart(details);
        }
    }

    void ReportEvent(const xUnitpp::TestDetails &details, const xUnitpp::TestEvent &evt)
    {
        std::lock_guard<std::mutex> guard(mLock);

        if (mAttached)
        {
            mOutput.get().ReportEvent(details, evt);
        }
    }

    void ReportSkip(const xUnitpp::TestDetails &details, const std::string &reason)
    {
        std::lock_guard<std::mutex> guard(mLock);

        if (mAttached)
        {
            mOutput.get().ReportSkip(details, reason);
        }
    }

    void ReportFinish(const xUnitpp::TestDetails &details, xUnitpp::Time::Duration time)
    {
        std::lock_guard<std::mutex> guard(mLock);

        if (mAttached)
        {
            mOutput.get().ReportFinish(details, time);
        }
    }

    void ReportAllTestsComplete(size_t, size_t, size_t, xUnitpp::Time::Duration)
    {
        throw std::logic_error("No one holding an AttachedOutput object should be calling ReportAllTestsComplete.");
    }

private:
    AttachedOutput(const AttachedOutput &);
    AttachedOutput &operator =(AttachedOutput);

private:
    std::mutex mLock;
    bool mAttached;
    std::reference_wrapper<SharedOutput> mOutput;
};

}

namespace xUnitpp
{

int RunTests(IOutput &output, std::function<bool(const TestDetails &)> filter, const std::vector<std::shared_ptr<xUnitTest>> &tests, Time::Duration maxTestRunTime, size_t maxConcurrent)
{
    auto timeStart = std::chrono::system_clock::now();

    if (maxConcurrent == 0)
    {
        maxConcurrent = std::numeric_limits<decltype(maxConcurrent)>::max();
    }

    class ThreadCounter
    {
    public:
        ThreadCounter(size_t maxThreads)
            : maxThreads(maxThreads)
            , activeThreads(0)
        {
        }

        void operator++()
        {
            std::unique_lock<std::mutex> lock(mtx);
            condition.wait(lock, [&]() { return activeThreads < maxThreads; });

            ++activeThreads;
        }

        void operator--()
        {
            --activeThreads;
            condition.notify_one();
        }

    private:
        size_t maxThreads;
        std::atomic<size_t> activeThreads;
        std::mutex mtx;
        std::condition_variable condition;
    } threadCounter(maxConcurrent);

    std::atomic<int> failedTests(0);
    int skippedTests = 0;

    SharedOutput sharedOutput(output);

    std::vector<std::shared_ptr<xUnitTest>> activeTests;
    std::copy_if(tests.begin(), tests.end(), std::back_inserter(activeTests), [&filter](const std::shared_ptr<xUnitTest> &test) { return filter(test->TestDetails()); });

    std::random_shuffle(activeTests.begin(), activeTests.end());

    std::vector<std::future<void>> futures;
    for (auto &test : activeTests)
    {
        {
            auto skip = test->TestDetails().Attributes.Skipped();
            if (skip.first)
            {
                skippedTests++;
                sharedOutput.ReportSkip(test->TestDetails(), skip.second);
                continue;
            }
        }

        futures.push_back(std::async([&]()
            {
                struct CounterGuard
                {
                    CounterGuard(ThreadCounter &tc)
                        : tc(tc)
                    {
                        ++tc;
                    }

                    ~CounterGuard()
                    {
                        --tc;
                    }

                private:
                    CounterGuard &operator =(const CounterGuard &) { throw std::logic_error("not supported"); }
                    ThreadCounter &tc;
                } counterGuard(threadCounter);

                //
                // We are deliberately not capturing any values by reference, since the thread running this lambda may be detached
                // and abandoned by a timed test. If that were to happen, variables on the stack would get destroyed out from underneath us.
                // Instead, we're going to make copies that are guaranteed to outlive our method, and return the test status.
                // If the running thread is still valid, it can manage updating the count of failed threads if necessary.
                auto actualTest = [](std::shared_ptr<xUnitTest> runningTest, std::shared_ptr<AttachedOutput> output) -> TestResult
                    {
                        output->ReportStart(runningTest->TestDetails());

                        auto result = runningTest->Run();

                        for (auto &event : runningTest->TestEvents())
                        {
                            output->ReportEvent(runningTest->TestDetails(), event);
                        }

                        return result;
                    };

                auto testTimeLimit = test->TestDetails().TimeLimit;
                if (testTimeLimit < Time::Duration::zero())
                {
                    testTimeLimit = maxTestRunTime;
                }

                if (testTimeLimit > Time::Duration::zero())
                {
                    //
                    // note that forcing a test to run in under a certain amount of time is inherently fragile
                    // there's no guarantee that a thread, once started, actually gets `maxTestRunTime` nanoseconds of CPU

                    auto m = std::make_shared<std::mutex>();
                    std::unique_lock<std::mutex> gate(*m);

                    auto attachedOutput = std::make_shared<AttachedOutput>(sharedOutput);
                    auto threadStarted = std::make_shared<std::condition_variable>();
                    auto testResult = std::make_shared<TestResult>();
                    std::thread timedRunner([=]()
                        {
                            m->lock();
                            m->unlock();

                            *testResult = actualTest(test, attachedOutput);

                            threadStarted->notify_all();
                        });
                    timedRunner.detach();

                    if (threadStarted->wait_for(gate, std::chrono::duration_cast<std::chrono::nanoseconds>(testTimeLimit)) == std::cv_status::timeout)
                    {
                        attachedOutput->Detach();
                        sharedOutput.ReportEvent(test->TestDetails(), TestEvent(EventLevel::Fatal, "Test failed to complete within " + ToString(Time::ToMilliseconds(testTimeLimit).count()) + " milliseconds."));
                        sharedOutput.ReportFinish(test->TestDetails(), testTimeLimit);
                        ++failedTests;
                    }
                    else
                    {
                        sharedOutput.ReportFinish(test->TestDetails(), test->Duration());

                        if (*testResult == TestResult::Failure)
                        {
                            ++failedTests;
                        }
                    }
                }
                else
                {
                    auto result = actualTest(test, std::make_shared<AttachedOutput>(sharedOutput));

                    sharedOutput.ReportFinish(test->TestDetails(), test->Duration());

                    if (result == TestResult::Failure)
                    {
                        ++failedTests;
                    }
                }
            }));
    }

    for (auto &test : futures)
    {
        test.get();
    }

    sharedOutput.ReportAllTestsComplete((int)futures.size(), skippedTests, failedTests, Time::ToDuration(Time::Clock::now() - timeStart));

    return failedTests;
}

}
<commit_msg>should be using the typedef'd name, in case something changes<commit_after>#include "xUnitTestRunner.h"
#include <atomic>
#include <chrono>
#include <future>
#include <limits>
#include <mutex>
#include <random>
#include <stdexcept>
#include <vector>
#include "IOutput.h"
#include "TestCollection.h"
#include "TestDetails.h"
#include "xUnitAssert.h"
#include "xUnitTime.h"

#include <iostream>

namespace
{

class SharedOutput : public xUnitpp::IOutput
{
public:
    SharedOutput(xUnitpp::IOutput &testReporter)
        : mOutput(testReporter)
    {
    }

    virtual void ReportStart(const xUnitpp::TestDetails &details) override
    {
        std::lock_guard<std::mutex> guard(mLock);
        mOutput.get().ReportStart(details);
    }

    virtual void ReportEvent(const xUnitpp::TestDetails &details, const xUnitpp::TestEvent &evt) override
    {
        std::lock_guard<std::mutex> guard(mLock);
        mOutput.get().ReportEvent(details, evt);
    }

    virtual void ReportSkip(const xUnitpp::TestDetails &details, const std::string &reason) override
    {
        std::lock_guard<std::mutex> guard(mLock);
        mOutput.get().ReportSkip(details, reason);
    }

    virtual void ReportFinish(const xUnitpp::TestDetails &details, xUnitpp::Time::Duration time) override
    {
        std::lock_guard<std::mutex> guard(mLock);
        mOutput.get().ReportFinish(details, time);
    }

    virtual void ReportAllTestsComplete(size_t total, size_t skipped, size_t failed, xUnitpp::Time::Duration totalTime) override
    {
        mOutput.get().ReportAllTestsComplete(total, skipped, failed, totalTime);
    }

private:
    SharedOutput(const SharedOutput &);
    SharedOutput &operator =(SharedOutput);

private:
    std::mutex mLock;
    std::reference_wrapper<xUnitpp::IOutput> mOutput;
};

class AttachedOutput
{
public:
    AttachedOutput(SharedOutput &output)
        : mAttached(true)
        , mOutput(std::ref(output))
    {
    }

    void Detach()
    {
        std::lock_guard<std::mutex> guard(mLock);
        mAttached = false;
    }

    void ReportStart(const xUnitpp::TestDetails &details)
    {
        std::lock_guard<std::mutex> guard(mLock);

        if (mAttached)
        {
            mOutput.get().ReportStart(details);
        }
    }

    void ReportEvent(const xUnitpp::TestDetails &details, const xUnitpp::TestEvent &evt)
    {
        std::lock_guard<std::mutex> guard(mLock);

        if (mAttached)
        {
            mOutput.get().ReportEvent(details, evt);
        }
    }

    void ReportSkip(const xUnitpp::TestDetails &details, const std::string &reason)
    {
        std::lock_guard<std::mutex> guard(mLock);

        if (mAttached)
        {
            mOutput.get().ReportSkip(details, reason);
        }
    }

    void ReportFinish(const xUnitpp::TestDetails &details, xUnitpp::Time::Duration time)
    {
        std::lock_guard<std::mutex> guard(mLock);

        if (mAttached)
        {
            mOutput.get().ReportFinish(details, time);
        }
    }

    void ReportAllTestsComplete(size_t, size_t, size_t, xUnitpp::Time::Duration)
    {
        throw std::logic_error("No one holding an AttachedOutput object should be calling ReportAllTestsComplete.");
    }

private:
    AttachedOutput(const AttachedOutput &);
    AttachedOutput &operator =(AttachedOutput);

private:
    std::mutex mLock;
    bool mAttached;
    std::reference_wrapper<SharedOutput> mOutput;
};

}

namespace xUnitpp
{

int RunTests(IOutput &output, std::function<bool(const TestDetails &)> filter, const std::vector<std::shared_ptr<xUnitTest>> &tests, Time::Duration maxTestRunTime, size_t maxConcurrent)
{
    auto timeStart = Time::Clock::now();

    if (maxConcurrent == 0)
    {
        maxConcurrent = std::numeric_limits<decltype(maxConcurrent)>::max();
    }

    class ThreadCounter
    {
    public:
        ThreadCounter(size_t maxThreads)
            : maxThreads(maxThreads)
            , activeThreads(0)
        {
        }

        void operator++()
        {
            std::unique_lock<std::mutex> lock(mtx);
            condition.wait(lock, [&]() { return activeThreads < maxThreads; });

            ++activeThreads;
        }

        void operator--()
        {
            --activeThreads;
            condition.notify_one();
        }

    private:
        size_t maxThreads;
        std::atomic<size_t> activeThreads;
        std::mutex mtx;
        std::condition_variable condition;
    } threadCounter(maxConcurrent);

    std::atomic<int> failedTests(0);
    int skippedTests = 0;

    SharedOutput sharedOutput(output);

    std::vector<std::shared_ptr<xUnitTest>> activeTests;
    std::copy_if(tests.begin(), tests.end(), std::back_inserter(activeTests), [&filter](const std::shared_ptr<xUnitTest> &test) { return filter(test->TestDetails()); });

    std::random_shuffle(activeTests.begin(), activeTests.end());

    std::vector<std::future<void>> futures;
    for (auto &test : activeTests)
    {
        {
            auto skip = test->TestDetails().Attributes.Skipped();
            if (skip.first)
            {
                skippedTests++;
                sharedOutput.ReportSkip(test->TestDetails(), skip.second);
                continue;
            }
        }

        futures.push_back(std::async([&]()
            {
                struct CounterGuard
                {
                    CounterGuard(ThreadCounter &tc)
                        : tc(tc)
                    {
                        ++tc;
                    }

                    ~CounterGuard()
                    {
                        --tc;
                    }

                private:
                    CounterGuard &operator =(const CounterGuard &) { throw std::logic_error("not supported"); }
                    ThreadCounter &tc;
                } counterGuard(threadCounter);

                //
                // We are deliberately not capturing any values by reference, since the thread running this lambda may be detached
                // and abandoned by a timed test. If that were to happen, variables on the stack would get destroyed out from underneath us.
                // Instead, we're going to make copies that are guaranteed to outlive our method, and return the test status.
                // If the running thread is still valid, it can manage updating the count of failed threads if necessary.
                auto actualTest = [](std::shared_ptr<xUnitTest> runningTest, std::shared_ptr<AttachedOutput> output) -> TestResult
                    {
                        output->ReportStart(runningTest->TestDetails());

                        auto result = runningTest->Run();

                        for (auto &event : runningTest->TestEvents())
                        {
                            output->ReportEvent(runningTest->TestDetails(), event);
                        }

                        return result;
                    };

                auto testTimeLimit = test->TestDetails().TimeLimit;
                if (testTimeLimit < Time::Duration::zero())
                {
                    testTimeLimit = maxTestRunTime;
                }

                if (testTimeLimit > Time::Duration::zero())
                {
                    //
                    // note that forcing a test to run in under a certain amount of time is inherently fragile
                    // there's no guarantee that a thread, once started, actually gets `maxTestRunTime` nanoseconds of CPU

                    auto m = std::make_shared<std::mutex>();
                    std::unique_lock<std::mutex> gate(*m);

                    auto attachedOutput = std::make_shared<AttachedOutput>(sharedOutput);
                    auto threadStarted = std::make_shared<std::condition_variable>();
                    auto testResult = std::make_shared<TestResult>();
                    std::thread timedRunner([=]()
                        {
                            m->lock();
                            m->unlock();

                            *testResult = actualTest(test, attachedOutput);

                            threadStarted->notify_all();
                        });
                    timedRunner.detach();

                    if (threadStarted->wait_for(gate, std::chrono::duration_cast<std::chrono::nanoseconds>(testTimeLimit)) == std::cv_status::timeout)
                    {
                        attachedOutput->Detach();
                        sharedOutput.ReportEvent(test->TestDetails(), TestEvent(EventLevel::Fatal, "Test failed to complete within " + ToString(Time::ToMilliseconds(testTimeLimit).count()) + " milliseconds."));
                        sharedOutput.ReportFinish(test->TestDetails(), testTimeLimit);
                        ++failedTests;
                    }
                    else
                    {
                        sharedOutput.ReportFinish(test->TestDetails(), test->Duration());

                        if (*testResult == TestResult::Failure)
                        {
                            ++failedTests;
                        }
                    }
                }
                else
                {
                    auto result = actualTest(test, std::make_shared<AttachedOutput>(sharedOutput));

                    sharedOutput.ReportFinish(test->TestDetails(), test->Duration());

                    if (result == TestResult::Failure)
                    {
                        ++failedTests;
                    }
                }
            }));
    }

    for (auto &test : futures)
    {
        test.get();
    }

    sharedOutput.ReportAllTestsComplete((int)futures.size(), skippedTests, failedTests, Time::ToDuration(Time::Clock::now() - timeStart));

    return failedTests;
}

}
<|endoftext|>


<commit_before>#include "purpleline.hpp"

#include <iostream>

#include <protocol/TCompactProtocol.h>

#include <debug.h>
#include <sslconn.h>

#include "purplehttpclient.hpp"

static const char *LINE_HOST = "gd2.line.naver.jp";
static const char *LINE_PATH = "/S4";
static const int LINE_PORT = 443;

PurpleLine::PurpleLine(PurpleConnection *conn, PurpleAccount *acct)
    : conn(conn), acct(acct)
{

}

const char *PurpleLine::list_icon(PurpleBuddy *buddy)
{
    return "line";
}

GList *PurpleLine::status_types() {
    GList *types = NULL;
    PurpleStatusType *t;

    t = purple_status_type_new_full(PURPLE_STATUS_AVAILABLE, NULL, NULL, TRUE, TRUE, FALSE);
    types = g_list_append(types, t);

    t = purple_status_type_new_full(PURPLE_STATUS_OFFLINE, NULL, NULL, TRUE, TRUE, FALSE);
    types = g_list_append(types, t);

    return types;
}

void PurpleLine::login() {
    // Create http clients

    http_out = boost::make_shared<PurpleHttpClient>(acct, LINE_HOST, LINE_PORT, LINE_PATH);

    client_out = boost::make_shared<line::LineClient>(
        boost::make_shared<apache::thrift::protocol::TCompactProtocol>(http_out));

    http_in = boost::make_shared<PurpleHttpClient>(acct, LINE_HOST, LINE_PORT, LINE_PATH);

    client_in = boost::make_shared<line::LineClient>(
        boost::make_shared<apache::thrift::protocol::TCompactProtocol>(http_in));

    // Log in

    client_out->send_loginWithIdentityCredentialForCertificate(
        purple_account_get_username(acct),
        purple_account_get_password(acct),
        true,
        "127.0.0.1",
        "libpurple",
        line::IdentityProvider::LINE,
        "");
    http_out->send([this](int status) {
        if (status != 200) {
            purple_debug_warning("line", "Login status: %d", status);
            close();
            return;
        }

        line::LoginResult result;
        client_out->recv_loginWithIdentityCredentialForCertificate(result);

        http_out->set_auth_token(result.authToken);
        http_in->set_auth_token(result.authToken);

        get_profile();
    });
}

void PurpleLine::get_profile() {
    client_out->send_getProfile();
    http_out->send([this](int status) {
        line::Profile profile;
        client_out->recv_getProfile(profile);

        std::cout << "Your profile: " << std::endl
            << "  ID: " << profile.mid << std::endl
            << "  Display name: " << profile.displayName << std::endl
            << "  Phonetic name: " << profile.phoneticName << std::endl
            << "  Picture status name: " << profile.pictureStatus << std::endl
            << "  Thumbnail URL: " << profile.thumbnailUrl << std::endl
            << "  Status message: " << profile.statusMessage << std::endl;

        get_contacts();
    });
}

void PurpleLine::get_contacts() {
    client_out->send_getAllContactIds();
    http_out->send([this](int status) {
        std::vector<std::string> ids;
        client_out->recv_getAllContactIds(ids);

        client_out->send_getContacts(ids);
        http_out->send([this](int status) {
            std::vector<line::Contact> contacts;
            client_out->recv_getContacts(contacts);

            PurpleGroup *group = purple_find_group("LINE");

            for (line::Contact &c: contacts) {

                std::cout << "Contact " << c.mid << std::endl
                    //<< "  Type: " << line::_ContactType_VALUES_TO_NAMES.at(c.type) << std::endl
                    << "  Status: " << line::_ContactStatus_VALUES_TO_NAMES.at(c.status) << std::endl
                    //<< "  Relation: " << line::_ContactRelation_VALUES_TO_NAMES.at(c.relation) << std::endl
                    << "  Display name: " << c.displayName << std::endl
                    << "  Phonetic name: " << c.phoneticName << std::endl
                    << "  Picture status name: " << c.pictureStatus << std::endl
                    << "  Thumbnail URL: " << c.thumbnailUrl << std::endl
                    << "  Status message: " << c.statusMessage << std::endl;

                if (c.status == line::ContactStatus::FRIEND) {
                    if (!group)
                        group = purple_group_new("LINE");

                    PurpleBuddy *buddy = purple_find_buddy(acct, c.mid.c_str());
                    if (!buddy) {
                        buddy = purple_buddy_new(acct, c.mid.c_str(), c.displayName.c_str());
                        purple_blist_add_buddy(buddy, NULL, group, NULL);
                    }

                    purple_prpl_got_user_status(
                        acct,
                        c.mid.c_str(),
                        purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE),
                        NULL);

                    //purple_blist_alias_contact(PURPLE_CONTACT(buddy), c.displayName.c_str());

                    std::cout << " added " << std::endl;
                }
            }

            get_groups();
        });
    });
}

void PurpleLine::get_groups() {
    client_out->send_getGroupIdsJoined();
    http_out->send([this](int status) {
        std::vector<std::string> ids;
        client_out->recv_getGroupIdsJoined(ids);

        client_out->send_getGroups(ids);
        http_out->send([this](int status) {
            std::vector<line::Group> groups;
            client_out->recv_getGroups(groups);

            PurpleGroup *group = purple_find_group("LINE");

            for (line::Group &g: groups) {
                if (!group)
                    group = purple_group_new("LINE");

                std::cout << "Group " << g.id << std::endl
                    << "  Name: " << g.name << std::endl
                    << "  Creator: " << g.creator.displayName << std::endl
                    << "  Member count: " << g.members.size() << std::endl;
            }
        });
    });
}

void PurpleLine::close() {
    purple_debug_info("lineprpl", "close");

    http_out->close();
    http_in->close();
}
<commit_msg>Properly set connection as connected. Start implementing chats.<commit_after>#include "purpleline.hpp"

#include <iostream>

#include <protocol/TCompactProtocol.h>

#include <debug.h>
#include <sslconn.h>

#include "purplehttpclient.hpp"

static const char *LINE_HOST = "gd2.line.naver.jp";
static const char *LINE_PATH = "/S4";
static const int LINE_PORT = 443;

PurpleLine::PurpleLine(PurpleConnection *conn, PurpleAccount *acct)
    : conn(conn), acct(acct)
{

}

const char *PurpleLine::list_icon(PurpleBuddy *buddy)
{
    return "line";
}

GList *PurpleLine::status_types() {
    GList *types = NULL;
    PurpleStatusType *t;

    t = purple_status_type_new_full(PURPLE_STATUS_AVAILABLE, NULL, NULL, TRUE, TRUE, FALSE);
    types = g_list_append(types, t);

    t = purple_status_type_new_full(PURPLE_STATUS_OFFLINE, NULL, NULL, TRUE, TRUE, FALSE);
    types = g_list_append(types, t);

    return types;
}

void PurpleLine::login() {
    // Create http clients

    http_out = boost::make_shared<PurpleHttpClient>(acct, LINE_HOST, LINE_PORT, LINE_PATH);

    client_out = boost::make_shared<line::LineClient>(
        boost::make_shared<apache::thrift::protocol::TCompactProtocol>(http_out));

    http_in = boost::make_shared<PurpleHttpClient>(acct, LINE_HOST, LINE_PORT, LINE_PATH);

    client_in = boost::make_shared<line::LineClient>(
        boost::make_shared<apache::thrift::protocol::TCompactProtocol>(http_in));

    purple_connection_set_state(conn, PURPLE_CONNECTING);
    purple_connection_update_progress(conn, "Connecting", 0, 2);

    // Log in

    client_out->send_loginWithIdentityCredentialForCertificate(
        purple_account_get_username(acct),
        purple_account_get_password(acct),
        true,
        "127.0.0.1",
        "libpurple",
        line::IdentityProvider::LINE,
        "");
    http_out->send([this](int status) {
        if (status != 200) {
            purple_debug_warning("line", "Login status: %d", status);
            close();
            return;
        }

        line::LoginResult result;
        client_out->recv_loginWithIdentityCredentialForCertificate(result);

        http_out->set_auth_token(result.authToken);
        http_in->set_auth_token(result.authToken);

        get_profile();
    });
}

void PurpleLine::get_profile() {
    client_out->send_getProfile();
    http_out->send([this](int status) {
        line::Profile profile;
        client_out->recv_getProfile(profile);

        std::cout << "Your profile: " << std::endl
            << "  ID: " << profile.mid << std::endl
            << "  Display name: " << profile.displayName << std::endl
            << "  Phonetic name: " << profile.phoneticName << std::endl
            << "  Picture status name: " << profile.pictureStatus << std::endl
            << "  Thumbnail URL: " << profile.thumbnailUrl << std::endl
            << "  Status message: " << profile.statusMessage << std::endl;

        purple_connection_set_state(conn, PURPLE_CONNECTED);
        purple_connection_update_progress(conn, "Connected", 1, 2);

        get_contacts();
    });
}

void PurpleLine::get_contacts() {
    client_out->send_getAllContactIds();
    http_out->send([this](int status) {
        std::vector<std::string> ids;
        client_out->recv_getAllContactIds(ids);

        client_out->send_getContacts(ids);
        http_out->send([this](int status) {
            std::vector<line::Contact> contacts;
            client_out->recv_getContacts(contacts);

            PurpleGroup *group = purple_find_group("LINE");

            for (line::Contact &c: contacts) {

                std::cout << "Contact " << c.mid << std::endl
                    //<< "  Type: " << line::_ContactType_VALUES_TO_NAMES.at(c.type) << std::endl
                    << "  Status: " << line::_ContactStatus_VALUES_TO_NAMES.at(c.status) << std::endl
                    //<< "  Relation: " << line::_ContactRelation_VALUES_TO_NAMES.at(c.relation) << std::endl
                    << "  Display name: " << c.displayName << std::endl
                    << "  Phonetic name: " << c.phoneticName << std::endl
                    << "  Picture status name: " << c.pictureStatus << std::endl
                    << "  Thumbnail URL: " << c.thumbnailUrl << std::endl
                    << "  Status message: " << c.statusMessage << std::endl;

                if (c.status == line::ContactStatus::FRIEND) {
                    if (!group)
                        group = purple_group_new("LINE");

                    PurpleBuddy *buddy = purple_find_buddy(acct, c.mid.c_str());
                    if (!buddy) {
                        buddy = purple_buddy_new(acct, c.mid.c_str(), c.displayName.c_str());
                        purple_blist_add_buddy(buddy, NULL, group, NULL);
                    }

                    purple_prpl_got_user_status(
                        acct,
                        c.mid.c_str(),
                        purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE),
                        NULL);

                    //purple_blist_alias_buddy(buddy, c.displayName.c_str());
                }
            }

            get_groups();
        });
    });
}

void PurpleLine::get_groups() {
    client_out->send_getGroupIdsJoined();
    http_out->send([this](int status) {
        std::vector<std::string> ids;
        client_out->recv_getGroupIdsJoined(ids);

        client_out->send_getGroups(ids);
        http_out->send([this](int status) {
            std::vector<line::Group> groups;
            client_out->recv_getGroups(groups);

            PurpleGroup *group = purple_find_group("LINE");

            for (line::Group &g: groups) {
                if (!group)
                    group = purple_group_new("LINE");

                //GHashTable *components = g_hash_table_new(g_str_hash, g_str_equal);
                //g_hash_table_insert(components, (gpointer)"id", (gpointer)g_strdup(g.id.c_str()));

                //PurpleChat *chat = purple_chat_new(acct, g.name.c_str(), components);

                //purple_blist_add_chat(chat, group, NULL);

                std::cout << "Group " << g.id << std::endl
                    << "  Name: " << g.name << std::endl
                    << "  Creator: " << g.creator.displayName << std::endl
                    << "  Member count: " << g.members.size() << std::endl;
            }
        });
    });
}

void PurpleLine::close() {
    purple_debug_info("lineprpl", "close");

    http_out->close();
    http_in->close();
}
<|endoftext|>


<commit_before>#include "xchainer/gradient_check.h"

#include <algorithm>
#include <memory>
#include <tuple>
#include <unordered_map>
#include <vector>

#include <gtest/gtest-spi.h>
#include <gtest/gtest.h>
#include <gsl/gsl>

#include "xchainer/array.h"
#include "xchainer/check_backward.h"
#include "xchainer/op_node.h"
#include "xchainer/shape.h"

namespace xchainer {
namespace {

using Arrays = std::vector<Array>;
using Fprop = std::function<std::vector<Array>(const std::vector<Array>&)>;

Arrays IncorrectBackwardUnaryFunc(const Arrays& inputs) {
    const Array& in = inputs[0];
    Array out = Array::EmptyLike(in);

    auto backward_function = [](const Array& gout, const GraphId&) { return gout * gout; };
    internal::SetUpOpNodes("incorrect_unary", {in}, out, {backward_function});

    VisitDtype(in.dtype(), [&](auto pt) {
        using T = typename decltype(pt)::type;
        int64_t total_size = in.total_size();
        auto* ldata = static_cast<const T*>(in.data().get());
        auto* odata = static_cast<T*>(out.data().get());
        for (int64_t i = 0; i < total_size; i++) {
            odata[i] = ldata[i];
        }
    });

    return {out};
}

Arrays IncorrectBackwardBinaryFunc(const Arrays& inputs) {
    const Array& lhs = inputs[0];
    const Array& rhs = inputs[1];
    CheckEqual(lhs.dtype(), rhs.dtype());
    CheckEqual(lhs.shape(), rhs.shape());
    Array out = Array::EmptyLike(lhs);

    auto lhs_backward_function = [other = rhs](const Array& gout, const GraphId& graph_id)->Array {
        return gout + other.AsConstant(CopyKind::kView, {graph_id});
    };
    auto rhs_backward_function = lhs_backward_function;
    internal::SetUpOpNodes("incorrect_binary", {lhs, rhs}, out, {lhs_backward_function, rhs_backward_function});

    VisitDtype(lhs.dtype(), [&](auto pt) {
        using T = typename decltype(pt)::type;
        int64_t total_size = lhs.total_size();
        auto* ldata = static_cast<const T*>(lhs.data().get());
        auto* rdata = static_cast<const T*>(rhs.data().get());
        auto* odata = static_cast<T*>(out.data().get());
        for (int64_t i = 0; i < total_size; i++) {
            odata[i] = ldata[i] * rdata[i];
        }
    });

    return {out};
}

class CheckBackwardBaseTest : public ::testing::Test {
protected:
    template <typename T>
    Array MakeArray(const Shape& shape, const T* data) const {
        int64_t size = shape.total_size();
        auto a = std::make_unique<T[]>(size);
        std::copy(data, data + size, a.get());
        return Array::FromBuffer(shape, TypeToDtype<T>, std::move(a));
    }

    void CheckBaseBackwardComputation(bool expect_correct, Fprop fprop, Arrays& inputs, const Arrays& grad_outputs, const Arrays& eps,
                                      double atol, double rtol, const GraphId& graph_id) {
        std::for_each(inputs.begin(), inputs.end(), [&graph_id](auto& input) { input.RequireGrad(graph_id); });

        if (!expect_correct &&
            std::any_of(inputs.begin(), inputs.end(), [graph_id](const Array& input) { return input.IsGradRequired(graph_id); })) {
            // Catch the gtest failure expected to be generated by CheckBackwardComputation but without failing this test
            EXPECT_NONFATAL_FAILURE(CheckBackwardComputation(fprop, inputs, grad_outputs, eps, atol, rtol, graph_id),
                                    "Backward check failure");
        } else {
            // We cannot expect any failures in case none of the input std::vector<Array> require gradients
            CheckBackwardComputation(fprop, inputs, grad_outputs, eps, atol, rtol, graph_id);
        }
    }
};

class CheckBackwardUnaryTest : public CheckBackwardBaseTest, public ::testing::WithParamInterface<bool> {
protected:
    void SetUp() override { requires_grad = GetParam(); }

    template <typename T>
    void CheckBackwardComputation(bool expect_correct, Fprop fprop, const Shape& shape, const T* input_data, const T* grad_output_data,
                                  const T* eps_data, double atol, double rtol, const GraphId& graph_id) {
        Arrays inputs{MakeArray(shape, input_data)};
        Arrays grad_outputs{MakeArray(shape, grad_output_data)};
        Arrays eps{MakeArray(shape, eps_data)};
        CheckBaseBackwardComputation(expect_correct, fprop, inputs, grad_outputs, eps, atol, rtol, graph_id);
    }

private:
    bool requires_grad;
};

class CheckBackwardBinaryTest : public CheckBackwardBaseTest, public ::testing::WithParamInterface<std::tuple<bool, bool>> {
protected:
    void SetUp() override { requires_grads = {std::get<0>(GetParam()), std::get<1>(GetParam())}; }

    template <typename T>
    void CheckBackwardComputation(bool expect_correct, Fprop fprop, const Shape& shape, const T* input_data1, const T* input_data2,
                                  const T* grad_output_data, const T* eps_data1, const T* eps_data2, double atol, double rtol,
                                  const GraphId& graph_id) {
        Arrays inputs{MakeArray(shape, input_data1), MakeArray(shape, input_data2)};
        Arrays grad_outputs{MakeArray(shape, grad_output_data)};
        Arrays eps{MakeArray(shape, eps_data1), MakeArray(shape, eps_data2)};
        CheckBaseBackwardComputation(expect_correct, fprop, inputs, grad_outputs, eps, atol, rtol, graph_id);
    }

private:
    std::vector<bool> requires_grads;
};

TEST_P(CheckBackwardUnaryTest, CorrectBackward) {
    float input_data[]{1.f, 2.f, 3.f};
    float grad_output_data[]{0.f, -2.f, 3.f};
    float eps_data[]{1.f, 2.f, 3.f};
    Fprop fprop = [](const Arrays& inputs) -> Arrays { return {inputs[0] * inputs[0]}; };
    CheckBackwardComputation(true, fprop, {1, 3}, input_data, grad_output_data, eps_data, 1e-5, 1e-4, "graph_1");
}

TEST_P(CheckBackwardUnaryTest, IncorrectBackward) {
    float input_data[]{-2.f, 3.f, 1.f};
    float grad_output_data[]{0.f, -2.f, 1.f};
    float eps_data[]{1.f, 2.f, 3.f};
    CheckBackwardComputation(false, &IncorrectBackwardUnaryFunc, {1, 3}, input_data, grad_output_data, eps_data, 1e-5, 1e-4, "graph_1");
}

TEST_P(CheckBackwardBinaryTest, CorrectBackward) {
    float input_data1[]{1.f, 2.f, 3.f};
    float input_data2[]{0.f, 1.f, 2.f};
    float eps_data1[]{1.f, 2.f, 3.f};
    float eps_data2[]{3.f, -2.f, 3.f};
    float grad_output_data[]{1.f, -2.f, 3.f};
    Fprop fprop = [](const Arrays& inputs) -> Arrays { return {inputs[0] * inputs[1]}; };
    CheckBackwardComputation(true, fprop, {1, 3}, input_data1, input_data2, grad_output_data, eps_data1, eps_data2, 1e-5, 1e-4, "graph_1");
}

TEST_P(CheckBackwardBinaryTest, IncorrectBackward) {
    float input_data1[]{3.f, -2.f, 1.f};
    float input_data2[]{0.f, 1.4f, 2.f};
    float eps_data1[]{1.f, 2.f, 3.8f};
    float eps_data2[]{3.f, -2.f, -3.f};
    float grad_output_data[]{4.f, -2.f, 3.f};
    CheckBackwardComputation(false, &IncorrectBackwardBinaryFunc, {1, 3}, input_data1, input_data2, grad_output_data, eps_data1, eps_data2,
                             1e-5, 1e-4, "graph_1");
}

INSTANTIATE_TEST_CASE_P(ForEachSingleSetRequiresGrad, CheckBackwardUnaryTest, ::testing::Bool());
INSTANTIATE_TEST_CASE_P(ForEachCombinedSetRequiresGrad, CheckBackwardBinaryTest, ::testing::Combine(::testing::Bool(), ::testing::Bool()));

}  // namespace
}  // namespace xchainer
<commit_msg>Realistic eps in test<commit_after>#include "xchainer/gradient_check.h"

#include <algorithm>
#include <memory>
#include <tuple>
#include <unordered_map>
#include <vector>

#include <gtest/gtest-spi.h>
#include <gtest/gtest.h>
#include <gsl/gsl>

#include "xchainer/array.h"
#include "xchainer/check_backward.h"
#include "xchainer/op_node.h"
#include "xchainer/shape.h"

namespace xchainer {
namespace {

using Arrays = std::vector<Array>;
using Fprop = std::function<std::vector<Array>(const std::vector<Array>&)>;

Arrays IncorrectBackwardUnaryFunc(const Arrays& inputs) {
    const Array& in = inputs[0];
    Array out = Array::EmptyLike(in);

    auto backward_function = [](const Array& gout, const GraphId&) { return gout * gout; };
    internal::SetUpOpNodes("incorrect_unary", {in}, out, {backward_function});

    VisitDtype(in.dtype(), [&](auto pt) {
        using T = typename decltype(pt)::type;
        int64_t total_size = in.total_size();
        auto* ldata = static_cast<const T*>(in.data().get());
        auto* odata = static_cast<T*>(out.data().get());
        for (int64_t i = 0; i < total_size; i++) {
            odata[i] = ldata[i];
        }
    });

    return {out};
}

Arrays IncorrectBackwardBinaryFunc(const Arrays& inputs) {
    const Array& lhs = inputs[0];
    const Array& rhs = inputs[1];
    CheckEqual(lhs.dtype(), rhs.dtype());
    CheckEqual(lhs.shape(), rhs.shape());
    Array out = Array::EmptyLike(lhs);

    auto lhs_backward_function = [other = rhs](const Array& gout, const GraphId& graph_id)->Array {
        return gout + other.AsConstant(CopyKind::kView, {graph_id});
    };
    auto rhs_backward_function = lhs_backward_function;
    internal::SetUpOpNodes("incorrect_binary", {lhs, rhs}, out, {lhs_backward_function, rhs_backward_function});

    VisitDtype(lhs.dtype(), [&](auto pt) {
        using T = typename decltype(pt)::type;
        int64_t total_size = lhs.total_size();
        auto* ldata = static_cast<const T*>(lhs.data().get());
        auto* rdata = static_cast<const T*>(rhs.data().get());
        auto* odata = static_cast<T*>(out.data().get());
        for (int64_t i = 0; i < total_size; i++) {
            odata[i] = ldata[i] * rdata[i];
        }
    });

    return {out};
}

class CheckBackwardBaseTest : public ::testing::Test {
protected:
    template <typename T>
    Array MakeArray(const Shape& shape, const T* data) const {
        int64_t size = shape.total_size();
        auto a = std::make_unique<T[]>(size);
        std::copy(data, data + size, a.get());
        return Array::FromBuffer(shape, TypeToDtype<T>, std::move(a));
    }

    void CheckBaseBackwardComputation(bool expect_correct, Fprop fprop, Arrays& inputs, const Arrays& grad_outputs, const Arrays& eps,
                                      double atol, double rtol, const GraphId& graph_id) {
        std::for_each(inputs.begin(), inputs.end(), [&graph_id](auto& input) { input.RequireGrad(graph_id); });

        if (!expect_correct &&
            std::any_of(inputs.begin(), inputs.end(), [graph_id](const Array& input) { return input.IsGradRequired(graph_id); })) {
            // Catch the gtest failure expected to be generated by CheckBackwardComputation but without failing this test
            EXPECT_NONFATAL_FAILURE(CheckBackwardComputation(fprop, inputs, grad_outputs, eps, atol, rtol, graph_id),
                                    "Backward check failure");
        } else {
            // We cannot expect any failures in case none of the input std::vector<Array> require gradients
            CheckBackwardComputation(fprop, inputs, grad_outputs, eps, atol, rtol, graph_id);
        }
    }
};

class CheckBackwardUnaryTest : public CheckBackwardBaseTest, public ::testing::WithParamInterface<bool> {
protected:
    void SetUp() override { requires_grad = GetParam(); }

    template <typename T>
    void CheckBackwardComputation(bool expect_correct, Fprop fprop, const Shape& shape, const T* input_data, const T* grad_output_data,
                                  const T* eps_data, double atol, double rtol, const GraphId& graph_id) {
        Arrays inputs{MakeArray(shape, input_data)};
        Arrays grad_outputs{MakeArray(shape, grad_output_data)};
        Arrays eps{MakeArray(shape, eps_data)};
        CheckBaseBackwardComputation(expect_correct, fprop, inputs, grad_outputs, eps, atol, rtol, graph_id);
    }

private:
    bool requires_grad;
};

class CheckBackwardBinaryTest : public CheckBackwardBaseTest, public ::testing::WithParamInterface<std::tuple<bool, bool>> {
protected:
    void SetUp() override { requires_grads = {std::get<0>(GetParam()), std::get<1>(GetParam())}; }

    template <typename T>
    void CheckBackwardComputation(bool expect_correct, Fprop fprop, const Shape& shape, const T* input_data1, const T* input_data2,
                                  const T* grad_output_data, const T* eps_data1, const T* eps_data2, double atol, double rtol,
                                  const GraphId& graph_id) {
        Arrays inputs{MakeArray(shape, input_data1), MakeArray(shape, input_data2)};
        Arrays grad_outputs{MakeArray(shape, grad_output_data)};
        Arrays eps{MakeArray(shape, eps_data1), MakeArray(shape, eps_data2)};
        CheckBaseBackwardComputation(expect_correct, fprop, inputs, grad_outputs, eps, atol, rtol, graph_id);
    }

private:
    std::vector<bool> requires_grads;
};

TEST_P(CheckBackwardUnaryTest, CorrectBackward) {
    float input_data[]{1.f, 2.f, 1.f};
    float grad_output_data[]{0.f, -2.f, 1.f};
    float eps_data[]{1e-3f, 1e-3f, 1e-3f};
    Fprop fprop = [](const Arrays& inputs) -> Arrays { return {inputs[0] * inputs[0]}; };
    CheckBackwardComputation(true, fprop, {1, 3}, input_data, grad_output_data, eps_data, 1e-5, 1e-4, "graph_1");
}

TEST_P(CheckBackwardUnaryTest, IncorrectBackward) {
    float input_data[]{-2.f, 3.f, 1.f};
    float grad_output_data[]{0.f, -2.f, 1.f};
    float eps_data[]{1e-3f, 1e-3f, 1e-3f};
    CheckBackwardComputation(false, &IncorrectBackwardUnaryFunc, {1, 3}, input_data, grad_output_data, eps_data, 1e-5, 1e-4, "graph_1");
}

TEST_P(CheckBackwardBinaryTest, CorrectBackward) {
    float input_data1[]{1.f, 2.f, 1.f};
    float input_data2[]{0.f, 1.f, 2.f};
    float eps_data1[]{1e-3f, 1e-3f, 1e-3f};
    float eps_data2[]{1e-3f, 1e-3f, 1e-3f};
    float grad_output_data[]{1.f, -2.f, 3.f};
    Fprop fprop = [](const Arrays& inputs) -> Arrays { return {inputs[0] * inputs[1]}; };
    CheckBackwardComputation(true, fprop, {1, 3}, input_data1, input_data2, grad_output_data, eps_data1, eps_data2, 1e-5, 1e-4, "graph_1");
}

TEST_P(CheckBackwardBinaryTest, IncorrectBackward) {
    float input_data1[]{1.f, -2.f, 1.f};
    float input_data2[]{0.f, 1.4f, 2.f};
    float eps_data1[]{1e-3f, 1e-3f, 1e-3f};
    float eps_data2[]{1e-3f, 1e-3f, 1e-3f};
    float grad_output_data[]{4.f, -2.f, 3.f};
    CheckBackwardComputation(false, &IncorrectBackwardBinaryFunc, {1, 3}, input_data1, input_data2, grad_output_data, eps_data1, eps_data2,
                             1e-5, 1e-4, "graph_1");
}

INSTANTIATE_TEST_CASE_P(ForEachSingleSetRequiresGrad, CheckBackwardUnaryTest, ::testing::Bool());
INSTANTIATE_TEST_CASE_P(ForEachCombinedSetRequiresGrad, CheckBackwardBinaryTest, ::testing::Combine(::testing::Bool(), ::testing::Bool()));

}  // namespace
}  // namespace xchainer
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: filebuff.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: vg $ $Date: 2006-09-25 13:27:10 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef X2C_FILEBUFF_HXX
#define X2C_FILEBUFF_HXX

class Buffer
{
  public:
                        Buffer()                : s(0) {}
                        ~Buffer()               { if (s) delete [] s; }
                        operator const char *() const
                                                { return s; }
    char *              Data()                  { return s; }
    void                SetSize(
                           unsigned long                i_size )
                                                { if (s) delete [] s; s = new char [i_size]; }
  private:
    char * s;
};

bool                LoadXmlFile(
                        Buffer &            o_rBuffer,
                        const char *        i_sXmlFilePath );

#endif
<commit_msg>INTEGRATION: CWS changefileheader (1.6.30); FILE MERGED 2008/03/31 13:06:37 rt 1.6.30.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: filebuff.hxx,v $
 * $Revision: 1.7 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef X2C_FILEBUFF_HXX
#define X2C_FILEBUFF_HXX

class Buffer
{
  public:
                        Buffer()                : s(0) {}
                        ~Buffer()               { if (s) delete [] s; }
                        operator const char *() const
                                                { return s; }
    char *              Data()                  { return s; }
    void                SetSize(
                           unsigned long                i_size )
                                                { if (s) delete [] s; s = new char [i_size]; }
  private:
    char * s;
};

bool                LoadXmlFile(
                        Buffer &            o_rBuffer,
                        const char *        i_sXmlFilePath );

#endif
<|endoftext|>