#define ValDistinct
|
#define DEBUG_TIME1
|
using Hydro.CommonBase;
|
using System;
|
using System.Collections.Generic;
|
using System.Threading;
|
using System.Threading.Tasks;
|
//using WaterDistributioinManager;
|
using AForge.Genetic;
|
using System.Linq;
|
using System.Diagnostics;
|
using System.Collections.Concurrent;
|
using System.Numerics;
|
using System.Data;
|
using Newtonsoft.Json.Linq;
|
using Hydro.CodeProvider;
|
using Hydro.HydraulicHelperNS;
|
|
namespace Hydro.ParrelControl
|
{
|
public class BigBinaryChromo : ChromosomeBase
|
{
|
|
|
|
public int Level;
|
|
public LogicModelParams param;
|
|
public WdnmoParam wParam;
|
|
public GeneticParams gParam;
|
|
public BigBinaryFunction fitnessFunction;
|
|
public static BigInteger originVal;
|
|
|
|
|
public int length;
|
|
|
|
protected BigInteger val;
|
|
public void setval(BigInteger v)
|
{
|
AttemptArray = null;
|
fitness = null;
|
_valid = false;
|
//_value = -1;
|
val = v;
|
}
|
|
public static int seed = 0;
|
public int GetSeed()
|
{
|
//将
|
seed += Environment.TickCount + DateTime.Now.Millisecond;
|
return seed;
|
}
|
//protected static Random rand = new Random();
|
|
public int Length => length;
|
|
//private BigInteger _value=-1;
|
public BigInteger Value
|
{
|
get
|
{
|
//var cmax = (BigBinaryNums.CMaxValue >> BigBinaryNums.CMaxLength - length);
|
|
//if (_value == -1) _value = val & cmax;
|
return val;
|
}
|
}
|
//=> val & (BigBinaryNums.CMaxValue >> BigBinaryNums.CMaxLength - length);
|
|
public BigInteger MaxValue => BigBinaryNums.CMaxValue >> BigBinaryNums.CMaxLength - length;
|
public string str_From = null;
|
#if ArrDistinct
|
public BigBinaryChromo(int length, int Level, HashSet<double[]> Hset, LogicModelParams param, WdnmoParam wParam, GeneticParams gParam, BigBinaryFunction fitnessFunction)
|
#elif ValDistinct
|
public BigBinaryChromo(int length, int Level, HashSet<BigInteger> Hset, LogicModelParams param, WdnmoParam wParam, GeneticParams gParam, BigBinaryFunction fitnessFunction)
|
#endif
|
|
{
|
this.wParam = wParam;
|
this.gParam = gParam;
|
this.fitnessFunction = fitnessFunction;
|
this.param = param;
|
this.Level = Level;
|
ID = Guid.NewGuid();
|
this.length = System.Math.Max(2, System.Math.Min(BigBinaryNums.CMaxLength, length));
|
this.distinctDict = Hset;
|
Generate();
|
str_From = "新建";
|
//AttemptArray = fitnessFunction.Translate(this);
|
if (distinctDict == null) throw new ArgumentNullException(nameof(distinctDict));
|
|
|
}
|
bool _is枚举 = false;
|
/// <summary>
|
/// 枚举时,使用此构造函数来指定值
|
/// </summary>
|
/// <param name="uVal"></param>
|
/// <param name="length"></param>
|
/// <param name="Level"></param>
|
/// <param name="param"></param>
|
/// <param name="wParam"></param>
|
/// <param name="gParam"></param>
|
/// <param name="fitnessFunction"></param>
|
#if ArrDistinct
|
public BigBinaryChromo(BigInteger uVal, int length, int Level, LogicModelParams param, WdnmoParam wParam, GeneticParams gParam, BigBinaryFunction fitnessFunction, HashSet<double[]> distinctDict)
|
#elif ValDistinct
|
public BigBinaryChromo(BigInteger uVal, int length, int Level, LogicModelParams param, WdnmoParam wParam, GeneticParams gParam, BigBinaryFunction fitnessFunction, HashSet<BigInteger> distinctDict)
|
#endif
|
|
{
|
this.wParam = wParam;
|
this.gParam = gParam;
|
this.fitnessFunction = fitnessFunction;
|
this.param = param;
|
this.Level = Level;
|
this.distinctDict = distinctDict;
|
ID = Guid.NewGuid();
|
this.length = System.Math.Max(2, System.Math.Min(BigBinaryNums.CMaxLength, length));
|
setval(uVal);
|
AttemptArray = fitnessFunction.Translate(this);
|
fitness = null;
|
_is枚举 = true;
|
str_From = "枚举生成";
|
if (distinctDict == null) throw new ArgumentNullException(nameof(distinctDict));
|
}
|
protected BigBinaryChromo(BigBinaryChromo source)
|
{
|
this.fitnessFunction = source.fitnessFunction;
|
this.wParam = source.wParam;
|
this.gParam = source.gParam;
|
this.Level = source.Level;
|
this.param = source.param;
|
ID = Guid.NewGuid();
|
length = source.length;
|
setval(source.val);
|
if (source.AttemptArray!=null) this.AttemptArray = source.AttemptArray.ToArray();
|
|
this.distinctDict = source.distinctDict;
|
str_From = "克隆";
|
//AttemptArray = fitnessFunction.Translate(this);
|
if (distinctDict==null) throw new ArgumentNullException(nameof(distinctDict));
|
|
|
}
|
|
|
|
|
/// <summary>
|
/// init=true后使用await方法
|
/// </summary>
|
public static bool tested = false;
|
|
/// <summary>
|
/// init=true后使用await方法
|
/// </summary>
|
public static bool isInited = false;
|
|
public override async void Evaluate(IFitnessFunction function)
|
{
|
//Log.Add("请求评估");
|
if (fitness != null) return;
|
|
|
await Task<double>.Run(() => function.Evaluate(this));
|
//Trace.WriteLine(val);
|
//if (!distinctDict.ContainsKey(val)) distinctDict.TryAdd(val, true);
|
//distinctDict.TryAdd(AttemptArray, true);
|
return;
|
|
|
}
|
public async void Evaluate()
|
{
|
|
if (fitness != null) return;
|
await Task<double>.Run(() => fitnessFunction.Evaluate(this));
|
return;
|
}
|
|
public override string ToString()
|
{
|
|
string s = "";
|
s += $"[{Value}]";
|
s += fitness == null ? "[]" : $"[{fitness}]";
|
|
|
if (AttemptArray != null)
|
{
|
for (int i = 0; i < AttemptArray.Length; i++)
|
{
|
s += "," + Math.Round(AttemptArray[i], 2).ToString();
|
}
|
}
|
return s;
|
}
|
#if ArrDistinct
|
public HashSet<double[]> distinctDict = null;
|
#elif ValDistinct
|
public HashSet<BigInteger> distinctDict = null;
|
#endif
|
public override void Generate()
|
{
|
#if DEBUG_TIME
|
DateTime time = DateTime.Now;
|
#endif
|
|
|
//byte[] array = new byte[BigBinaryNums.CMaxLength/8];
|
//[Cloudflight修改]2024-1-16 随机数生成器不是线程安全的,所以每次都new一个新的
|
//rand = new Random();
|
//lock (rand)
|
//{
|
// rand.NextBytes(array);
|
//}
|
|
//Random rand = new Random();
|
//Random rand = new Random(GetSeed());
|
//if (distinctDict == null) distinctDict = new HashSet<double[]>();
|
do
|
{
|
//rand.NextBytes(array);
|
//val = ToBigInteger(array);
|
////var bInt = ToByteArray(val);
|
//AttemptArray = null;
|
//_value = -1;
|
if (fitnessFunction.CreateRandomArray(param, wParam, gParam,out dynamic arr,out double[] result))
|
{
|
|
#if ValDistinct
|
var v = fitnessFunction.DisTranslate(result);
|
setval(v);
|
AttemptArray = result;
|
#endif
|
|
|
}
|
else
|
{
|
if (arr!=null)
|
{
|
wParam.ErrorMessage="随机生成方案错误,尝试信息如下:\r\n"+arr.ToString();
|
return;
|
}
|
}
|
|
}
|
while (!isValid());
|
|
|
#if DEBUG_TIME
|
HydraulicHelper.TimeSet["循环获取新数组"] += (DateTime.Now - time).TotalSeconds;
|
HydraulicHelper.TimeSetCount["循环获取新数组"]++;
|
#endif
|
}
|
|
bool compareArr(double[] a,double[] b)
|
{
|
//对比a、b两个数组
|
if (a.Length!=b.Length)
|
return false;
|
for (int i = 0; i < a.Length; i++)
|
{
|
if (a[i] != b[i]) return false;
|
}
|
|
return true;
|
}
|
//定义一个将byte[]转换为BigInteger的方法
|
|
public static BigInteger ToBigInteger(byte[] data)
|
{
|
if (data == null)
|
throw new ArgumentNullException(nameof(data));
|
|
Array.Reverse(data); // Reverse the array to match BigInteger's byte order
|
return new BigInteger(data);
|
}
|
//定义一个将BigInteger转换为byte[]的方法
|
public static byte[] ToByteArray(BigInteger value)
|
{
|
return value.ToByteArray();
|
}
|
public override bool isValid()
|
{
|
if (_valid) return true;
|
#if DEBUG_TIME
|
var time = DateTime.Now;
|
#endif
|
if (AttemptArray == null) return false;// throw new ArgumentNullException(nameof(AttemptArray));
|
|
if (AttemptArray.Any(x => double.IsNaN(x))) return false;
|
#if ArrDistinct
|
//枚举时,不检查重复
|
lock(distinctDict)
|
{
|
if (!_is枚举 && distinctDict.Contains(AttemptArray)) return false;
|
}
|
lock (distinctDict)
|
{
|
distinctDict.Add(AttemptArray);
|
}
|
#elif ValDistinct
|
if (!_is枚举 && distinctDict.Contains(val)) return false;
|
distinctDict.Add(val);
|
////枚举时,不检查重复
|
//lock (distinctDict)
|
//{
|
// if (!_is枚举 && distinctDict.Contains(val)) return false;
|
//}
|
//lock (distinctDict)
|
//{
|
// distinctDict.Add(val);
|
//}
|
#endif
|
|
|
calcParam c = new calcParam();
|
c.vars = AttemptArray.ToArray();
|
//for (int i=0;i<c.vars.Length;i++)
|
//{
|
// param.试算变量[i].Value_Set(0, (double)(c.vars[i]));
|
//}
|
|
bool flag = true;
|
if (param.ChromeFilter!=null)
|
{
|
var v = param.ChromeFilter;
|
if (!(v.Eval.ChangeParam(param, wParam, gParam, c) == 0)) flag = false;
|
}
|
|
#if DEBUG_TIME
|
HydraulicHelper.TimeSet["判断有效"] += (DateTime.Now - time).TotalSeconds;
|
HydraulicHelper.TimeSetCount["判断有效"]++;
|
#endif
|
if (!flag) return false;
|
_valid = true;
|
return true;
|
|
}
|
|
public override IChromosome CreateNew()
|
{
|
|
return new BigBinaryChromo(length, Level, distinctDict, param, wParam, gParam, fitnessFunction);
|
}
|
|
public BigBinaryChromo CreateNext(BigInteger value)
|
{
|
if (value == -1) value = Value;
|
var val1 = (value + 1 > MaxValue - 1) ? MaxValue - 1 : value + 1;
|
return new BigBinaryChromo(val1, length, Level, param, wParam, gParam, fitnessFunction, distinctDict);
|
}
|
|
public override IChromosome Clone()
|
{
|
return new BigBinaryChromo(this);
|
}
|
|
public override void Mutate()
|
{
|
//写一套遗传算法的突变逻辑
|
|
//fitnessFunction.SetMutateArr(AttemptArray);
|
if( fitnessFunction.CreateRandomArray(param, wParam, gParam, out dynamic arr,out double[] result,AttemptArray))
|
{
|
var v = fitnessFunction.DisTranslate(result);
|
setval(v);
|
AttemptArray = result;
|
|
}
|
|
|
}
|
|
public override void Crossover(IChromosome pair)
|
{
|
BigBinaryChromo binaryChromosome = (BigBinaryChromo)pair;
|
/*[Cloudflight修改]2024-6-21
|
* 重新定义交叉
|
*/
|
//if (binaryChromosome != null && binaryChromosome.length == length)
|
//{
|
// Random rand = new Random(GetSeed());
|
// int num = (BigBinaryNums.CMaxLength - 1) - rand.Next(length - 1);
|
// BigInteger num2 = BigBinaryNums.CMaxValue >> num;
|
// BigInteger num3 = ~num2;
|
// BigInteger num4 = val;
|
// BigInteger num5 = binaryChromosome.val;
|
// setval(((num4 & num2) | (num5 & num3)));
|
// AttemptArray = null;
|
// AttemptArray=fitnessFunction.Translate(this);
|
// binaryChromosome.setval(((num5 & num2) | (num4 & num3)));
|
// binaryChromosome.AttemptArray = fitnessFunction.Translate(this);
|
|
//}
|
//var arr = AttemptArray.ToArray();
|
//var arr1= binaryChromosome.AttemptArray.ToArray();
|
Random rand = new Random(GetSeed());
|
int num = rand.Next(AttemptArray.Length-1)+1;
|
for(int i= 0;i<AttemptArray.Length;i++)
|
{
|
if (rand.NextDouble()<0.5)
|
{
|
var temp = AttemptArray[i];
|
AttemptArray[i] = binaryChromosome.AttemptArray[i];
|
binaryChromosome.AttemptArray[i] = temp;
|
}
|
//else if (rand.NextDouble()<0.5)
|
//{
|
// AttemptArray[i]= AttemptArray[i]+ rand.NextDouble() * (binaryChromosome.AttemptArray[i]- AttemptArray[i]);
|
// binaryChromosome.AttemptArray[i] = AttemptArray[i] + rand.NextDouble() * (binaryChromosome.AttemptArray[i] - AttemptArray[i]);
|
//}
|
|
}
|
var arr1 = AttemptArray.ToArray();
|
var v1 = fitnessFunction.DisTranslate(arr1);
|
this.setval(v1);
|
this.AttemptArray = arr1;
|
//AttemptArray = null;
|
//AttemptArray = fitnessFunction.Translate(this);
|
var arr2 = AttemptArray.ToArray();
|
var v2 = fitnessFunction.DisTranslate(arr2);
|
binaryChromosome.setval(v2);
|
binaryChromosome.AttemptArray = arr2;
|
//binaryChromosome.AttemptArray = null;
|
//binaryChromosome.AttemptArray = fitnessFunction.Translate(binaryChromosome);
|
|
|
|
|
}
|
|
public BigInteger getval()
|
{
|
return val;
|
}
|
}
|
public class BigBinaryNums : IDisposable
|
{
|
/// <summary>
|
/// 当前数据的值
|
/// </summary>
|
public BigInteger ulongValue;
|
/// <summary>
|
/// 当前数据的长度
|
/// </summary>
|
public int length;
|
|
/// <summary>
|
/// 数据类型的最大值
|
/// </summary>
|
BigInteger MaxValue;
|
/// <summary>
|
/// 数据类型的最大长度
|
/// </summary>
|
int MaxLength;
|
|
|
|
public const int CMaxLength = 128;
|
|
private static BigInteger _CMaxValue = 0;
|
|
public static BigInteger CMaxValue
|
{
|
get
|
{
|
if (_CMaxValue == 0) _CMaxValue = BigInteger.Pow(2, CMaxLength)-1;
|
return _CMaxValue;
|
}
|
}
|
|
|
public double GetDoubleValue1D(int length_D, DRange range, double? accuracy = null)
|
{
|
if (length - length_D < 0) throw new Exception($"出现long->Arr转换错误,剩余位数{length}不足以进行长度为{length_D}的转换");
|
int length_Remain = length - length_D;//获取剩余的长度
|
BigInteger ulongMaxValue_1D = MaxValue >> MaxLength - length_D;//num3是取8位二进制的最大值(得到每一个维度的最大长度)
|
BigInteger bigValue_1D = And(ulongValue,ulongMaxValue_1D);//取最后8位二进制
|
|
|
if (bigValue_1D > ulong.MaxValue) throw new Exception("单个维度超出最大长度(64位)");
|
ulong ulongValue_1D = (ulong)bigValue_1D;
|
|
|
BigInteger ulongValueRemain = ulongValue >> length_D;//取剩余位数的值
|
|
|
length = length_Remain;
|
ulongValue = ulongValueRemain;
|
|
var acc=(double)accuracy;
|
double value=ulongValue_1D * acc;
|
|
#if DEBUG
|
if (value > range.Length)
|
{
|
throw new Exception($"出现long->Arr转换错误,[{value + range.Min}]超出范围[{range.Min},{range.Max}]");
|
return double.NaN;
|
|
}
|
|
#endif
|
|
|
return range.Min+ value;
|
|
/*[Cloudflight修改]2024-5-31
|
* */
|
//将ulongValue_1D转换为double类型
|
|
return range.Length / (double)ulongMaxValue_1D * (double)ulongValue_1D + range.Min;
|
// getRoundByDouble(range.Length * ulongValue_1D / (double)ulongMaxValue_1D + range.Min,range,accuracy);
|
|
/*[Cloudflight修改]2024-5-31
|
* 按照精度来取整数
|
*/
|
//return getRoundByDouble(range.Length * ulongValue_1D / (double)ulongMaxValue_1D + range.Min, range, (double)accuracy);
|
|
|
}
|
//定义方法,两个BigInteger的位运算与
|
public static BigInteger And(BigInteger a, BigInteger b)
|
{
|
//用其他方法实现与运算,不要用a & b
|
byte[] aBytes = a.ToByteArray();
|
byte[] bBytes = b.ToByteArray();
|
byte[] resultBytes = new byte[Math.Max(aBytes.Length, bBytes.Length)];
|
for (int i = 0; i < resultBytes.Length; i++)
|
{
|
byte aByte = i < aBytes.Length ? aBytes[i] : (byte)0;
|
byte bByte = i < bBytes.Length ? bBytes[i] : (byte)0;
|
resultBytes[i] = (byte)(aByte & bByte);
|
}
|
return new BigInteger(resultBytes);
|
}
|
|
public static double getRoundByDouble(double v, DRange range, double accuracy)
|
{
|
//精度为accuracy的倍数,且在range范围内,最小值为range.Min,取最接近v的值
|
if (accuracy == 0) return v;
|
if (v < range.Min) return range.Min;
|
if (v > range.Max) return range.Max;
|
|
var delta = v - range.Min;
|
double x = 0;
|
double yushu = delta % accuracy;
|
//比较v - delta % accuracy和v+accuracy-delta % accuracy哪个接近v,且在range范围内
|
if (yushu > accuracy / 2 && (x=v + accuracy - yushu) < range.Max)
|
{
|
return x;
|
}
|
else
|
{
|
return v - yushu;
|
}
|
}
|
|
public BigBinaryNums(BigInteger value, int length, BigInteger MaxValue, int MaxLength)
|
{
|
this.length = length;
|
this.MaxValue = MaxValue;
|
this.ulongValue = value;
|
this.MaxLength = MaxLength;
|
}
|
public void AddBinary(double value, int length_D, DRange range,double Accuray_D)
|
{
|
if (value>range.Max) throw new Exception($"出现Arr->long转换错误,[{value}]超出范围[{range.Min},{range.Max}]");
|
BigInteger ulongMaxValue_1D = MaxValue >> MaxLength - length_D;//num3是取8位二进制的最大值(得到每一个维度的最大长度)
|
if (double.IsNaN(value)) value =(int) (range.Min+range.Max)/2;
|
ulong ulongValue_1D = (ulong)((value - range.Min) / Accuray_D);
|
BigInteger ulongValueRemain = (ulongValue << length_D) + ulongValue_1D;//取剩余位数的值
|
int length_Remain = length + length_D;//获取剩余的长度
|
|
length = length_Remain;
|
ulongValue = ulongValueRemain;
|
|
}
|
|
public static BigInteger ArrToUlong(SaveSettings saveSettings, List<double> OriginValueList)
|
{
|
int COUNT_D = OriginValueList.Count;
|
|
BigInteger value = 0;
|
int length = 0;
|
BigBinaryNums bNum = new BigBinaryNums(value, length, BigBinaryNums.CMaxValue, CMaxLength);
|
|
double[] result = new double[COUNT_D];
|
///*[Cloudflight修改]2024-6-21
|
throw new NotImplementedException();
|
//for (int i = COUNT_D - 1; i >= 0; i--)
|
//{
|
// if (!saveSettings.list_Range[i].IsInside(OriginValueList[i])) return BigBinaryNums.CMaxValue;
|
// bNum.AddBinary(OriginValueList[i], saveSettings.Length_Ds[i], saveSettings.list_Range[i],saveSettings.);
|
//};
|
return bNum.ulongValue;
|
}
|
|
public static List<double> UlongToArr(SaveSettings saveSettings, BigInteger uValue)
|
{
|
List<double> result = new List<double>();
|
|
BigInteger value = uValue;//获取整数值
|
int length = saveSettings.COUNT_D;//长度
|
BigBinaryNums bNum = new BigBinaryNums(value, saveSettings.SumLength, BigBinaryNums.CMaxValue, CMaxLength);
|
|
|
for (int i = 1; i <= saveSettings.COUNT_D; i++)
|
{
|
double item = bNum.GetDoubleValue1D(saveSettings.Length_Ds[i - 1], saveSettings.list_Range[i - 1]);
|
result.Add(item);
|
};
|
return result;
|
}
|
|
public void Dispose()
|
{
|
|
}
|
}
|
}
|