196 lines
7.4 KiB
C#
196 lines
7.4 KiB
C#
using EgwCoreLib.Lux.Core.RestPayload;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace EgwCoreLib.Lux.Core.MachineCalc
|
|
{
|
|
public class Utils
|
|
{
|
|
#region Public Methods
|
|
|
|
/// <summary>
|
|
/// Calcolo delle intersezioni Macchine/Tags(Parts)
|
|
/// </summary>
|
|
/// <param name="machineResult"></param>
|
|
/// <returns></returns>
|
|
public static List<MachineTagDTO> CalculateIntersections(List<MachineCalcResultDTO> machineResult)
|
|
{
|
|
var results = new List<MachineTagDTO>();
|
|
if (machineResult != null && machineResult.Count > 0)
|
|
{
|
|
int numParts = machineResult.FirstOrDefault()?.NumParts ?? 0;
|
|
// Step 1: extract workable tags per machine
|
|
var machineTags = machineResult
|
|
.ToDictionary(
|
|
m => m.Name,
|
|
m => m.PartList
|
|
.Where(p => p.CalcResult == Enums.PartVerificationResult.MACHINABLE)
|
|
.ToList()
|
|
);
|
|
var machineNames = machineTags.Keys.ToList();
|
|
|
|
// Step 2: generate all combinations of machines
|
|
for (int size = 1; size <= machineNames.Count; size++)
|
|
{
|
|
foreach (var combo in GetCombinations(machineNames, size))
|
|
{
|
|
var comboList = combo.ToList();
|
|
|
|
// Intersection of tags across all machines in this combo
|
|
var intersectionTags = comboList
|
|
.Select(name => machineTags[name].Select(p => p.Tag).ToHashSet())
|
|
.Aggregate((set1, set2) => { set1.IntersectWith(set2); return set1; });
|
|
|
|
// Compute per-machine sums of Time for these tags
|
|
var sums = comboList.Select(name =>
|
|
machineTags[name]
|
|
.Where(p => intersectionTags.Contains(p.Tag))
|
|
.Sum(p => p.Time)
|
|
).ToList();
|
|
|
|
results.Add(new MachineTagDTO
|
|
{
|
|
TotParts = numParts,
|
|
Machines = comboList,
|
|
Tags = intersectionTags.ToList(),
|
|
MinTime = sums.Any() ? sums.Min() : 0,
|
|
MaxTime = sums.Any() ? sums.Max() : 0
|
|
});
|
|
}
|
|
}
|
|
|
|
// Step 3: add unique (non-intersecting) tags per machine
|
|
foreach (var name in machineNames)
|
|
{
|
|
var uniqueTags = machineTags[name]
|
|
.Select(p => p.Tag)
|
|
.Except(machineNames.Where(n => n != name)
|
|
.SelectMany(n => machineTags[n].Select(p => p.Tag)))
|
|
.ToList();
|
|
|
|
if (uniqueTags.Count > 0)
|
|
{
|
|
var sum = machineTags[name]
|
|
.Where(p => uniqueTags.Contains(p.Tag))
|
|
.Sum(p => p.Time);
|
|
|
|
results.Add(new MachineTagDTO
|
|
{
|
|
TotParts = numParts,
|
|
Machines = new List<string> { name },
|
|
Tags = uniqueTags,
|
|
MinTime = sum,
|
|
MaxTime = sum
|
|
});
|
|
}
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper generazione combinazioni di items per una data length (Distinct Combinations)
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="items"></param>
|
|
/// <param name="length"></param>
|
|
/// <returns></returns>
|
|
public static IEnumerable<IEnumerable<T>> GetCombinations<T>(IEnumerable<T> items, int length)
|
|
{
|
|
// Convert to a List to easily access elements by index.
|
|
List<T> itemList = items.ToList();
|
|
int n = itemList.Count;
|
|
|
|
// Base case: length 0 returns a collection containing an empty collection
|
|
if (length == 0)
|
|
{
|
|
yield return Enumerable.Empty<T>();
|
|
yield break;
|
|
}
|
|
|
|
// Check if enough items are available
|
|
if (length > n)
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
// Call the internal recursive helper function
|
|
foreach (var combination in GetCombinationsInternal(itemList, length, 0, n))
|
|
{
|
|
yield return combination;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper generazione permutazioni di items per una data length
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="items"></param>
|
|
/// <param name="length"></param>
|
|
/// <returns></returns>
|
|
public static IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<T> items, int length)
|
|
{
|
|
if (length == 1)
|
|
return items.Select(i => new T[] { i });
|
|
|
|
return GetCombinations(items, length - 1)
|
|
.SelectMany(c => items.Where(i => !c.Contains(i)),
|
|
(c, i) => c.Concat(new T[] { i }));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper calcolo Intersezione lista macchine
|
|
/// </summary>
|
|
/// <param name="machines"></param>
|
|
/// <param name="predicate"></param>
|
|
/// <returns></returns>
|
|
public static IEnumerable<string> IntersectTags(List<MachineCalcResultDTO> machines, Func<PartCalcDTO, bool> predicate)
|
|
{
|
|
return machines
|
|
.Select(m => m.PartList.Where(predicate).Select(p => p.Tag).ToHashSet())
|
|
.Aggregate((set1, set2) => { set1.IntersectWith(set2); return set1; });
|
|
}
|
|
|
|
#endregion Public Methods
|
|
|
|
#region Private Methods
|
|
|
|
private static IEnumerable<IEnumerable<T>> GetCombinationsInternal<T>(
|
|
List<T> items,
|
|
int length,
|
|
int startIndex,
|
|
int n)
|
|
{
|
|
// Base case: combination of length 1
|
|
if (length == 1)
|
|
{
|
|
// Select one item from startIndex up to the end
|
|
for (int i = startIndex; i < n; i++)
|
|
{
|
|
yield return new T[] { items[i] };
|
|
}
|
|
yield break;
|
|
}
|
|
|
|
// Recursive step
|
|
// Iterate over elements starting from startIndex
|
|
for (int i = startIndex; i <= n - length; i++)
|
|
{
|
|
T currentItem = items[i];
|
|
|
|
// Recursively find combinations of length - 1 starting from the next index (i + 1)
|
|
// This is the crucial step that prevents (a,b) and (b,a)
|
|
foreach (var subCombination in GetCombinationsInternal(items, length - 1, i + 1, n))
|
|
{
|
|
// Prepend the current item to the shorter combinations
|
|
yield return new T[] { currentItem }.Concat(subCombination);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion Private Methods
|
|
}
|
|
} |