EgtNumKernel 2.7l1 :

- in Machining Optimization aggiunta ottimizzazione mirata ai singoli gruppi.
This commit is contained in:
Riccardo Elitropi
2025-12-16 15:44:29 +01:00
parent 6d34e7accb
commit f258acefd0
3 changed files with 259 additions and 62 deletions
+252 -62
View File
@@ -59,6 +59,7 @@ MachOptimization::MachOptimization( void)
m_dFeedL = 1. ;
m_dFeedA = 1. ;
m_bAllMandatory = false ;
m_bOptInGroup = false ;
}
//----------------------------------------------------------------------------
@@ -233,6 +234,14 @@ MachOptimization::SetAllGroupsAsMandatory( bool bAllMandatory)
return true ;
}
//----------------------------------------------------------------------------
bool
MachOptimization::SetOptimizationForGroups( bool bOptForGroups)
{
m_bOptInGroup = bOptForGroups ;
return true ;
}
//----------------------------------------------------------------------------
/* Funzione che assegna le dipendenze suggerite in base ai Gruppi */
bool
@@ -469,6 +478,14 @@ MachOptimization::CalcMachTime( int nInd1, int nInd2, int& nTime)
MachOptm& Lav1 = m_vMachOptm[nInd1] ;
MachOptm& Lav2 = m_vMachOptm[nInd2] ;
return ( CalcMachTime( Lav1, Lav2, nTime)) ;
}
//----------------------------------------------------------------------------
/* Funzione per calcolare il tempo nel passare da una lavorazione all'altra */
bool
MachOptimization::CalcMachTime( const MachOptm& Lav1, const MachOptm& Lav2, int& nTime)
{
// Se l'utensile è lo stesso
if ( Lav1.nIdTool == Lav2.nIdTool)
nTime = int( max( CalcTimeLavLav( Lav1, Lav2, true), CalcTimeLavLav( Lav1, Lav2, false))) ;
@@ -494,8 +511,6 @@ bool
MachOptimization::ComputeTimeMatrix( INTMATRIX& mTimes)
{
// Creo una copia dei vettori delle dipendenze ( le cancello di volta in volta che le assegno)
INTINTVECTOR vDep = m_vDependences ;
INTINTVECTOR vSuggDep = m_vSuggDependences ;
const int N = int( m_vMachOptm.size()) ;
// Matrice NxN ( con Flag per cella già calcolata)
mTimes.clear() ;
@@ -573,6 +588,70 @@ MachOptimization::GetIndById( int nId)
return -1 ;
}
//----------------------------------------------------------------------------
/* Funzione per separare le lavorazioni e le dipendenze a seconda dei gruppi */
bool
MachOptimization::SplitMachOptsInGroups( MACHOPTMMATRIX& matMachOpt, vector<INTINTVECTOR>& matDep,
vector<INTINTVECTOR>& matSuggDep)
{
// Se non ho lavorazioni, non faccio nulla
if ( m_vMachOptm.empty())
return true ;
// Se non devo ottimizzare per gruppi, errore
if ( ! m_bOptInGroup)
return false ;
// Ordino le lavorazioni in base al gruppo
sort( m_vMachOptm.begin(), m_vMachOptm.end(), []( const MachOptm& MachA, const MachOptm& MachB) {
return ( MachA.nGroup > MachB.nGroup) ;
}) ;
// Separo le lavorazioni
int nHighestPriority = m_vMachOptm[0].nGroup ;
matMachOpt.emplace_back( MACHOPTMVECTOR{}) ;
matMachOpt.back().emplace_back( m_vMachOptm[0]) ;
for ( int i = 1 ; i < int( m_vMachOptm.size()) ; ++ i) {
if ( m_vMachOptm[i].nGroup < nHighestPriority) {
matMachOpt.emplace_back( MACHOPTMVECTOR{}) ;
nHighestPriority = m_vMachOptm[i].nGroup ;
}
matMachOpt.back().emplace_back( m_vMachOptm[i]) ;
}
// Recupero le Dipendeze Obbligatorie e Suggerite tra i vari gruppi
BOOLVECTOR vbDep( m_vDependences.size(), false) ;
BOOLVECTOR vbSuggDep( m_vSuggDependences.size(), false) ;
for ( const MACHOPTMVECTOR& vMachOpt : matMachOpt) {
// Recupero gli Id delle lavorazioni correnti
INTVECTOR vId ; vId.reserve( vMachOpt.size()) ;
for ( const MachOptm& Lav : vMachOpt)
vId.push_back( Lav.nId) ;
// Inizializzo i vettori delle dipendenze
matDep.emplace_back( INTINTVECTOR{}) ;
matSuggDep.emplace_back( INTINTVECTOR{}) ;
// Recupero le dipendenze associate a questo gruppo
// NB. Devono essere solamente dipendenze interne al gruppo ( le altre vengono scartate a priori)
for ( int i = 0 ; i < int( m_vDependences.size()) ; ++ i) {
if ( ! vbDep[i] &&
find( vId.begin(), vId.end(), m_vDependences[i].first) != vId.end() &&
find( vId.begin(), vId.end(), m_vDependences[i].second) != vId.end()) {
matDep.back().emplace_back( m_vDependences[i]) ;
vbDep[i] = true ;
}
}
for ( int i = 0 ; i < int( m_vSuggDependences.size()) ; ++ i) {
if ( ! vbSuggDep[i] &&
find( vId.begin(), vId.end(), m_vSuggDependences[i].first) != vId.end() &&
find( vId.begin(), vId.end(), m_vSuggDependences[i].second) != vId.end()){
matSuggDep.back().emplace_back( m_vSuggDependences[i]) ;
vbSuggDep[i] = true ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
MachOptimization::GetResult( INTVECTOR& vIds)
@@ -586,73 +665,184 @@ MachOptimization::GetResult( INTVECTOR& vIds)
vIds.push_back( m_vMachOptm[0].nId) ;
return true ;
}
// Inserisco le lavorazioni per ordine di inserimento
for ( const MachOptm& myLav : m_vMachOptm)
vIds.push_back( myLav.nId) ;
// Inizializzo le dipendenze suggerite dai gruppi di lavorazione
if ( ! SetGroupDependences()) {
LOG_ERROR( GetENkLogger(), "Error in defining Group depedences") ;
return false ;
}
// Calcolo la matrice dei tempi
INTMATRIX mTimes ;
if ( ! ComputeTimeMatrix( mTimes)) {
LOG_ERROR( GetENkLogger(), "Error in Computing Time Matrix") ;
return false ;
}
// Istanzio il Problema ShortesPath con vincoli
PtrOwner<IShortestPath> mySP( CreateShortestPath()) ;
if ( IsNull( mySP))
return false ;
// Per ogni lavorazione inserisco gli estremi
for ( const MachOptm& Lav : m_vMachOptm) {
if ( ! mySP->AddPoint( Lav.dX_Start, Lav.dY_Start, Lav.dZ_End, 0., 0.,
Lav.dX_End, Lav.dY_End, Lav.dZ_End, 0., 0.)) {
LOG_ERROR( GetENkLogger(), "Error adding Machining Bounds") ;
// --- Se richiesta ottimizzazione solo interna per i gruppi
if ( m_bOptInGroup) {
// Recupero tutti i gruppi e le dipendenze separatamente ed ordinate per priorità di gruppo
MACHOPTMMATRIX matMachOpt ;
vector<INTINTVECTOR> matDep, matSuggDep ;
if ( ! SplitMachOptsInGroups( matMachOpt, matDep, matSuggDep))
return false ;
// Per ognuna di esse eseguo l'algoritmo di ShortestPath
MachOptm LastMach ;
for ( int i = 0 ; i < int( matMachOpt.size()) ; ++ i) {
m_vMachOptm.clear() ;
m_vDependences.clear() ;
m_vSuggDependences.clear() ;
if ( matMachOpt.empty())
continue ;
m_vMachOptm = matMachOpt[i] ;
m_vDependences = matDep[i] ;
m_vSuggDependences = matSuggDep[i] ;
// Calcolo la matrice dei tempi
INTMATRIX mTimes ;
if ( ! ComputeTimeMatrix( mTimes)) {
LOG_ERROR( GetENkLogger(), "Error in Computing Time Matrix") ;
return false ;
}
// Istanzio il Problema ShortesPath con vincoli
PtrOwner<IShortestPath> mySP( CreateShortestPath()) ;
if ( IsNull( mySP))
return false ;
// Per ogni lavorazione inserisco gli estremi
for ( const MachOptm& Lav : m_vMachOptm) {
if ( ! mySP->AddPoint( Lav.dX_Start, Lav.dY_Start, Lav.dZ_End, 0., 0.,
Lav.dX_End, Lav.dY_End, Lav.dZ_End, 0., 0.)) {
LOG_ERROR( GetENkLogger(), "Error adding Machining Bounds") ;
return false ;
}
}
// Assegno la matrice delle distanze calcolata in precedenza
if ( ! mySP->SetDistMatrix( mTimes)) {
LOG_ERROR( GetENkLogger(), "Error setting distances matrix") ;
return false ;
}
// Se ho una lavorazione impostata in precedenza
if ( LastMach.nId != -1) {
// Cerco le lavorazioni che non presentano precedenze
MACHOPTMVECTOR vLav ; vLav.reserve( m_vMachOptm.size()) ;
if ( m_vDependences.empty())
vLav = m_vMachOptm ;
else {
INTSET setSecondDep ;
for ( const INTINT& Dep : m_vDependences)
setSecondDep.insert( Dep.second) ;
for ( int i = 0 ; i < int( m_vMachOptm.size()) ; ++ i) {
if ( setSecondDep.find( m_vMachOptm[i].nId) == setSecondDep.end())
vLav.emplace_back( m_vMachOptm[i]) ;
}
}
// Tra quelle valide cerco la migliore da cui partire
int nBestLavId = 0 ;
int nBestTime = MAXTIME ;
for ( int i = 0 ; i < int( vLav.size()) ; ++ i) {
int nCurrTime = MAXTIME ;
CalcMachTime( LastMach, vLav[i], nCurrTime) ;
if ( nCurrTime < nBestTime) {
nBestTime = nCurrTime ;
nBestLavId = vLav[i].nId ;
}
}
// Imposto la prima lavorazione
if ( ! SetFirstMachining( nBestLavId))
return false ;
}
// Per ogni dipendeza obbligatoria assegno un vincolo
for ( const INTINT& nnDep : m_vDependences) {
if ( ! mySP->SetConstraintOrder( GetIndById( nnDep.first), GetIndById( nnDep.second))) {
LOG_ERROR( GetENkLogger(), "Error in adding Constraints") ;
return false ;
}
}
// Aggiungo le dipendenza suggerite
for ( const INTINT& nnSuggDep : m_vSuggDependences) {
if ( ! mySP->SetSuggestedOrder( GetIndById( nnSuggDep.first), GetIndById( nnSuggDep.second))) {
LOG_ERROR( GetENkLogger(), "Error in adding Suggested Dependence") ;
return false ;
}
}
// Calcolo la soluzione
#if _TIME_DEBUG
PerformanceCounter PC ; PC.Start() ;
#endif
if ( ! mySP->Calculate( IShortestPath::SP_OPEN)) {
LOG_ERROR( GetENkLogger(), "Error in computing solution") ;
return false ;
}
// Recupero l'ordine
INTVECTOR U ;
if ( ! mySP->GetOrder( U)) {
LOG_ERROR( GetENkLogger(), "Error in ordering") ;
return false ;
}
// Restituisco gli Id ordinati
for ( int nInd = 0 ; nInd < int( U.size()) ; ++ nInd)
vIds.emplace_back( m_vMachOptm[U[nInd]].nId) ;
// Memorizzo l'ultima lavorazione per il gruppo successivo
LastMach = ( U.empty() ? MachOptm() : m_vMachOptm[U.back()]) ;
}
}
// Assegno la matrice delle distanze calcolata in precedenza
if ( ! mySP->SetDistMatrix( mTimes)) {
LOG_ERROR( GetENkLogger(), "Error setting distances matrix") ;
return false ;
}
// Per ogni dipendeza obbligatoria assegno un vincolo
for ( const INTINT& nnDep : m_vDependences) {
if ( ! mySP->SetConstraintOrder( GetIndById( nnDep.first), GetIndById( nnDep.second))) {
LOG_ERROR( GetENkLogger(), "Error in adding Constraints") ;
//--- Se invece ottimizzazione globale
else {
// Inserisco le lavorazioni per ordine di inserimento
for ( const MachOptm& myLav : m_vMachOptm)
vIds.push_back( myLav.nId) ;
// Inizializzo le dipendenze suggerite dai gruppi di lavorazione
if ( ! SetGroupDependences()) {
LOG_ERROR( GetENkLogger(), "Error in defining Group depedences") ;
return false ;
}
}
// Aggiungo le dipendenza suggerite
for ( const INTINT& nnSuggDep : m_vSuggDependences) {
if ( ! mySP->SetSuggestedOrder( GetIndById( nnSuggDep.first), GetIndById( nnSuggDep.second))) {
LOG_ERROR( GetENkLogger(), "Error in adding Suggested Dependence") ;
// Calcolo la matrice dei tempi
INTMATRIX mTimes ;
if ( ! ComputeTimeMatrix( mTimes)) {
LOG_ERROR( GetENkLogger(), "Error in Computing Time Matrix") ;
return false ;
}
// Istanzio il Problema ShortesPath con vincoli
PtrOwner<IShortestPath> mySP( CreateShortestPath()) ;
if ( IsNull( mySP))
return false ;
// Per ogni lavorazione inserisco gli estremi
for ( const MachOptm& Lav : m_vMachOptm) {
if ( ! mySP->AddPoint( Lav.dX_Start, Lav.dY_Start, Lav.dZ_End, 0., 0.,
Lav.dX_End, Lav.dY_End, Lav.dZ_End, 0., 0.)) {
LOG_ERROR( GetENkLogger(), "Error adding Machining Bounds") ;
return false ;
}
}
// Assegno la matrice delle distanze calcolata in precedenza
if ( ! mySP->SetDistMatrix( mTimes)) {
LOG_ERROR( GetENkLogger(), "Error setting distances matrix") ;
return false ;
}
// Per ogni dipendeza obbligatoria assegno un vincolo
for ( const INTINT& nnDep : m_vDependences) {
if ( ! mySP->SetConstraintOrder( GetIndById( nnDep.first), GetIndById( nnDep.second))) {
LOG_ERROR( GetENkLogger(), "Error in adding Constraints") ;
return false ;
}
}
// Aggiungo le dipendenza suggerite
for ( const INTINT& nnSuggDep : m_vSuggDependences) {
if ( ! mySP->SetSuggestedOrder( GetIndById( nnSuggDep.first), GetIndById( nnSuggDep.second))) {
LOG_ERROR( GetENkLogger(), "Error in adding Suggested Dependence") ;
return false ;
}
}
// Calcolo la soluzione
#if _TIME_DEBUG
PerformanceCounter PC ; PC.Start() ;
#endif
if ( ! mySP->Calculate( IShortestPath::SP_OPEN)) {
LOG_ERROR( GetENkLogger(), "Error in computing solution") ;
return false ;
}
#if _TIME_DEBUG
string sTime = string( to_string( m_vDependences.size()) + string( "Time : ") + ToString( PC.Stop())) ;
LOG_INFO( GetENkLogger(), sTime.c_str()) ;
#endif
// Recupero l'ordine
INTVECTOR U ;
if ( ! mySP->GetOrder( U)) {
LOG_ERROR( GetENkLogger(), "Error in ordering") ;
return false ;
}
// Restituisco gli Id ordinati
vIds.resize( m_vMachOptm.size()) ;
for ( int nInd = 0 ; nInd < int( U.size()) ; ++ nInd)
vIds[nInd] = m_vMachOptm[U[nInd]].nId ;
}
// Calcolo la soluzione
#if _TIME_DEBUG
PerformanceCounter PC ; PC.Start() ;
#endif
if ( ! mySP->Calculate( IShortestPath::SP_OPEN)) {
LOG_ERROR( GetENkLogger(), "Error in computing solution") ;
return false ;
}
#if _TIME_DEBUG
string sTime = string( to_string( m_vDependences.size()) + string( "Time : ") + ToString( PC.Stop())) ;
LOG_INFO( GetENkLogger(), sTime.c_str()) ;
#endif
// Recupero l'ordine
INTVECTOR U ;
if ( ! mySP->GetOrder( U)) {
LOG_ERROR( GetENkLogger(), "Error in ordering") ;
return false ;
}
// Restituisco gli Id ordinati
vIds.resize( m_vMachOptm.size()) ;
for ( int nInd = 0 ; nInd < int( U.size()) ; ++ nInd)
vIds[nInd] = m_vMachOptm[U[nInd]].nId ;
return true ;
}