I'm trying to find a solution to a problem using Microsoft Solver Foundation in C# and I'm having trouble setting up all the constraints I need. My basic model is I have a list of bays and I need to load each bay so that the total of all the bays is maximised. I'm currently doing it like this
var solver = SolverContext.GetContext();
var model = solver.CreateModel();
var decisions =
bays.Select(b => new Decision(Domain.IntegerNonnegative, "B"+b.bay.getShortName()));
model.AddDecisions(decisions.ToArray());
foreach (BayPositionLoading bay in bays)
{
model.AddConstraint(
"B" + bay.bay.getShortName() + "Cons",
model.Decisions
.First(d => d.Name == "B" + bay.bay.getShortName()) <= bay.bay.maxLoad);
}
What I really would like to be able to do is add a constraint that a certain function returns true. The function would be something like this
public bool isValid (List<Bay> bays)
{
return blah;
}
But I can't figure out how to create the list of bays to pass to this function. I would like to do something like but this keeps throwing an exception when I say ToDouble or GetDouble.
foreach(Bay b in bays)
{
var dec= model.Decisions.First(it => it.Name == "B" + bay.bay.getShortName());
b.actualLoad = dec.ToDouble(); // Or GetDouble
}
model.AddConstraint("func", isValid(bays) == true);
Can anyone suggest how this can be done?
Thanks!
you need to use the math provided with OML language only, I do not think custom functions like you try to use are supported in MSF.
Related
I'm trying to replicate results from Gensim in C# to compare results and see if we need to bother trying to get Python to work within our broader C# context. I have been programming in C# for about a week, am usually a Python coder. I managed to get LDA to function and assign topics with C#, but there is no Catalyst model (that I could find) that does Doc2Vec explicitly, but rather I need to do something with FastText as they have in their sample code:
// Training a new FastText word2vec embedding model is as simple as this:
var nlp = await Pipeline.ForAsync(Language.English);
var ft = new FastText(Language.English, 0, "wiki-word2vec");
ft.Data.Type = FastText.ModelType.CBow;
ft.Data.Loss = FastText.LossType.NegativeSampling;
ft.Train(nlp.Process(GetDocs()));
ft.StoreAsync();
The claim is that it is simple, and fair enough... but what do I do with this? I am using my own data, a list of IDocuments, each with a label attached:
using (var csv = CsvDataReader.Create("Jira_Export_Combined.csv", new CsvDataReaderOptions
{
BufferSize = 0x20000
}))
{
while (await csv.ReadAsync())
{
var a = csv.GetString(1); // issue key
var b = csv.GetString(14); // the actual bug
// if (jira_base.Keys.ToList().Contains(a) == false)
if (jira.Keys.ToList().Contains(a) == false)
{ // not already in our dictionary... too many repeats
if (b.Contains("{panel"))
{
// get just the details/desc/etc
b = b.Substring(b.IndexOf("}") + 1, b.Length - b.IndexOf("}") - 1);
try { b = b.Substring(0, b.IndexOf("{panel}")); }
catch { }
}
b = b.Replace("\r\n", "");
jira.Add(a, nlp.ProcessSingle(new Document(b,Language.English)));
} // end if
} // end while loop
From a set of Jira Tasks and then I add labels:
foreach (KeyValuePair<string, IDocument> item in jira) { jira[item.Key].Labels.Add(item.Key); }
Then I add to a list (based on a breakdown from a topic model where I assign all docs that are at or above a threshold in that topic to the topic, jira_topics[n] where n is the topic numner, as such:
var training_lst = new List<IDocument>();
foreach (var doc in jira_topics[topic_num]) { training_lst.Add(jira[doc]); }
When I run the following code:
// FastText....
var ft = new FastText(Language.English, 0, $"vector-model-topic_{topic_num}");
ft.Data.Type = FastText.ModelType.Skipgram;
ft.Data.Loss = FastText.LossType.NegativeSampling;
ft.Train(training_lst);
var wtf = ft.PredictMax(training_lst[0]);
wtf is (null,NaN). [hence the name]
What am I missing? What else do I need to do to get Catalyst to vectorize my data? I want to grab the cosine similarities between the jira tasks and some other data I have, but I can't even get the Jira data into anything resembling a vectorization I can apply to something. Help!
Update:
So, Predict methods apparently only work for supervised learning in FastText (see comments below). And the following:
var wtf = ft.CompareDocuments(training_lst[0], training_lst[0]);
Throws an Implementation error (and only doesn't work with PVDM). How do I use PVDM, PVDCbow in Catalyst?
I am working off of the basic example for amending data (https://github.com/xBimTeam/XbimEssentials). The only thing I'm changing is within the code below, where I want to add an IfcPropertyTableValue instead of an IfcPropertySingleValue.
This code runs, but in XbimXplorer under the object's properties, nothing's there - it's blank.
To make sure, the example code, as well as other property types do work and do show up in Xplorer under properties.
var pSetRel = model.Instances.New<IfcRelDefinesByProperties>(r =>
{
r.GlobalId = Guid.NewGuid();
r.RelatingPropertyDefinition = model.Instances.New<IfcPropertySet>(pSet =>
{
pSet.Name = "Points";
// FOR EACH POINT i :
pSet.HasProperties.Add(model.Instances.New<IfcPropertyTableValue>(p =>
{
p.Name = "Points " + i;
// FOR EACH COORDINATE x :
p.DefiningValues.Add(new IfcText(x));
p.DefinedValues.Add(new IfcReal(-3.25));
}));
});
});
How can I make this work?
I have also tried using code to read the property, in case XbimXplorer just doesn't display tables. This code runs and prints zero lines (but works for other properties that are displayed in Xplorer):
// Try to read and print the new property
var nameObj = "my_object_name";
var checkObj = model.Instances.FirstOrDefault<IIfcBuildingElement>(d => d.Name == nameObj);
if (checkObj == null)
{
outputBox.AppendText(newLine + "Object: " + nameObj + " not found");
}
else
{
var properties = checkObj.IsDefinedBy
.Where(r => r.RelatingPropertyDefinition is IIfcPropertySet)
.SelectMany(r => ((IIfcPropertySet)r.RelatingPropertyDefinition).HasProperties)
.OfType<IIfcPropertySingleValue>();
foreach (var property in properties)
outputBox.AppendText($"Property: {property.Name}, Value: {property.NominalValue}");
}
It would also be convenient if I could add several defining/defined value pairs at once, for instance like this (similar to normal C# lists):
IEnumerable<IfcValue> definingValues = new IfcText() {"x", "y", "z", "k"};
p.DefinedValues.AddRange(definingValues);
IEnumerable<IfcValue> definedValues = new IfcReal() {0.0, 1.6, -2.5, 3.33};
p.DefinedValues.AddRange(definedValues);
However, {"x", "y", "z", "k"} is then marked with the error Cannot initialize type 'IfcText' with a collection initializer because it does not implement 'System.Collections.IEnumerable'.
I don't think xbim Xplorer displays IfcPropertyTableValues. Probably because very few BIM tools currently output TableValues so I guess it never got implemented (and you'd need to establish how to display the table in the Xplorer view - do you nest a table in a property grid?).
If you look at the Xplorer code you'll see it only supports SingleValues, ComplexValues and EnumeratedValues. You might be able to use Complex Values as a collection of multiple IfcPropertySingleValues as a workaround.
In your 2nd code sample to output the values, you're filtering out any IfcPropertyTableValues with the .OfType<IIfcPropertySingleValue>() clause so you'll never see the output. Take a look at the IFC specs for SimpleProperties: https://standards.buildingsmart.org/IFC/RELEASE/IFC4_1/FINAL/HTML/link/ifcsimpleproperty.htm
On the last question you're initializing the array with the wrong syntax. Try something like this:
var labels = new Ifc4.MeasureResource.IfcText[] { "x", "y" };
p.DefiningValues.AddRange(labels.Cast<IIfcValue>());
I'm trying to optimize the following method by having it return only the data my program actually needs for its calculations. In the past the dataset hasn't been that large so I haven't needed to optimize this too much. More recently, my dataset grew from about 30k records to 700k records, so I'm trying to optimize this further.
public void readRawThresholdsInList(int inputtedESourceID, DateTime maxDateTimeVal, List<int> hashKey)
{
log.Info("Reading in raw thresholds from db");
using (FAI db= new FAI ())
{
rawThresholds = (from thr in db.Thresholds
where thr.CalculatedDate == maxDateTimeVal
where thr.ErrorSourceId == inputtedESourceID
where hashKey.Contains(thr.HashKey)
select thr).ToList();
}
log.Info("Read in " + rawThresholds.Count() + " threshold records for error source id: " + inputtedESourceID + ".");
}
I got the method to return about 200k rows from 700k by adding the hashKey.Contains(thr.HashKey), but I want to take this one step further by doing the contains on a combination of 2 fields instead of just 1. The catch is that this has to happen on the DB for it to improve my runtimes. There is already post processing that only acts on the rows the program will need.
I want to be able to give the method the following as an input and have the contains (or something similar) act on the new HashKeyHostId object:
public HashKeyHostId{public int hashKey; public int hostId;}
public void readRawThresholdsInList(int inputtedESourceID, DateTime maxDateTimeVal, List<HashKeyHostId> hashKeyHostIdPairs){
}
There's probably a very simple way of doing this that I'm not thinking of.
Edit:
In response to James's comment - I don't believe this would work. The hashkey variable would now be an object containing pairs of integers instead of just 1 integer. This alone would prevent you from doing a .contains because it's no longer a primitive. It'd be the "public HashKeyHostId{public int hashKey; public int hostId;}" object I posted above. The new requirement is that a hashkey/hostId combo have to match up to 1 record in the DB.
If you're suggesting I do what Janne said (give it a list of hash keys and a list of host ids), I'm fairly certain this would return all results where the hashkey belongs to any of the hostids in the second list (aka, any combination of the two lists). I need it to only return rows with the specified combinations, not combinations of anything in the two lists.
Edit2: Sample dataset:
Hashkeys = 100,101,102,103
HostIds = 1,2,3,4,5,6,...,10000
I'd give it a list like
List<HashKeyHostId> data = new List<HashKeyHostId>()
{new HashKeyHostId(100,1),new HashKeyHostId(101,5)}
I believe the query Janne/James are suggesting would return records for any of those combinations (100,1; 100,5; 101,1; 101,5;). I need it to only return records for 100,1 and 101,5.
edit3:
I tried doing a where hashkeyHostIdpair.Any(o=> o.hashkey==thr.HashKey && o.hostid==thr.HostId)", but that errored out with the same "Unable to create a constant value of type 'RTM_DB.HashKeyHostId'. Only primitive types are supported in this context." message. It doesnt look like you can do a .Any or a .contains on a list of non-primitive types. I even tried making my own .Any with a where clause and that threw the same exception. (where hashkeyHostIdpair.Where(o=>o.hostid==thr.HostId && o.hashkey==thr.HashKey).Count()>0))
edit4: Per Josh's suggestion I tried this:
rawThresholds=fai.Thresholds.Where(o=>o.CalculatedDate==maxDateTimeVal)
.Where(o=>o.ErrorSourceId==inputtedESourceID)
.Where(o=> hashkeyHostIdpair.Contains(new HashKeyHostId(){ hashkey=o.HashKey, hostid = o.HostId})).ToList();
but it errored out with {System.NotSupportedException: Unable to create a constant value of type 'RTM_DB.HashKeyHostId'. Only primitive types ('such as Int32, String, and Guid') are supported in this context
There's probably a very simple way of doing this that I'm not thinking of.
Yeah, there is
where hashKey.Contains(someValue) && hashKey.Contains(someOtherValue)
Something along this would maybe be what you want to do?
public void readRawThresholdsInList(int inputtedESourceID, DateTime maxDateTimeVal, List<int> hashKeys, List<int> hostIds)
{
log.Info("Reading in raw thresholds from db");
using (var db = new FAI())
{
var rths = (from thr in db.Thresholds
where thr.CalculatedDate == maxDateTimeVal
&& thr.ErrorSourceId == inputtedESourceID
select thr);
if (hashKeys != null && hashKeys.Count() > 0)
rths = rths.Where(rth => hashKeys.Contains(rth.HashKey))
if (hostIds != null && hostIds.Count() > 0)
rths = rths.Where(rth => hostIds.Contains(rth.HostId)) // FieldName?
rawThresholds = rths.ToList();
}
log.Info("Read in " + rawThresholds.Count() + " threshold records for error source id: " + inputtedESourceID + ".");
}
-- edit --
You could do something like this, but I wouldnt recommend it. Figure out a value which you can multiply the HashKey safely so HostId will always be in the last digits
var filters = new int[] { 100 * 100 + 1 , 101 * 100 + 5 }; // 10001 & 10105
var rths = (from rth in db.Thresholds
where rth.CalculatedDate == maxDateTimeVal
&& rth.ErrorSourceId == inputtedESourceID
&& filters.Contains(rth.HashKey * 100 + rth.HostId)
select rth).ToList();
If you have something like
List<HashKeyHostId> data = new List<HashKeyHostId>() {
new HashKeyHostId { hashKey = 100, hostId = 1 },
new HashKeyHostId { hashKey = 101, hostId = 5 }
}
You can use it in a contains like this:
<somequery>.Where(x => data.Contains(new HashKeyHostId { hashKey = x.HashKey, hostId = x.HostId }))
Note the use of the object initializer syntax instead of a constructor.
This should get translated to SQL with each item in the list being appended to the WHERE clause like:
WHERE ([t0].[HashKey] = #p0 AND [t0].[HostId] = #p1) OR
([t0].[HashKey] = #p2 AND [t0].[HostId] = #p3) OR ...
I've got an application I'm developing that displays information about the various function headers in the C99 Standard Library. As you can imagine, some of these headers contain quite a few functions... more than I care to put on the main screen. I think a better way of handling it would be to create groups for each header ( has a summary ITEM then a functions GROUP that contains function ITEMS inside), so they're on their own page.
However, I'm having trouble doing this programmatically with the Microsoft-provided template.
Here's the code I have for the group "complex.h", which would ideally contain a summary item and then a group named "ComplexConstituents":
var complexGroup = new SampleDataGroup("<complex.h>",
"<complex.h>",
"complex arithmetic",
"Assets/LightGray.png",
"Group Description: ");
complexGroup.Items.Add(new SampleDataItem("Group-2-Item-1",
"Summary",
"summary of <complex.h>",
"Assets/DarkGray.png",
"Item Description: summary of <complex.h>",
ITEM_CONTENT,
complexGroup));
this.AllGroups.Add(complexGroup);
var complexConstituents = new SampleDataGroup("<complex.h> functions",
"<complex.h> functions",
"functions included in the <complex.h> header",
"Assets/MediumGray.png",
"Group description: blah");
this.ComplexConstituents.Add(complexConstituents);
You may have noticed that I've added a second type of group to supplement "AllGroups" here. It's "ComplexConstituents", and is supposed to be a group inside that contains the constituent functions of . Here's the constructor for it, with the constructor for "AllGroups" for comparison:
private ObservableCollection<SampleDataGroup> _allGroups = new ObservableCollection<SampleDataGroup>();
public ObservableCollection<SampleDataGroup> AllGroups
{
get { return this._allGroups; }
}
private ObservableCollection<SampleDataGroup> _complexConstituents = new ObservableCollection<SampleDataGroup>();
public ObservableCollection<SampleDataGroup> ComplexConstituents
{
get { return this._complexConstituents; }
}
I would think this is enough, but for whatever reason, it is not. I get the error at the end of this post (pictured). What do I need to do to fix this?
EDIT:
Here's the GetItem method requested by some:
public static SampleDataItem GetItem(string uniqueId)
{
// Simple linear search is acceptable for small data sets
var matches = _sampleDataSource.AllGroups.SelectMany(group => group.Items).Where((item) => item.UniqueId.Equals(uniqueId));
if (matches.Count() == 1) return matches.First();
return null;
}
In your GetItem method you must make changes becouse you use ComplexConstituents as data source.
Edit like this:
var matches = _sampleDataSource.ComplexConstituents.SelectMany(group => group.Items).Where((item) => item.UniqueId.Equals(uniqueId));
var matches2 = _sampleDataSource.AllGroups.SelectMany(group => group.Items).Where((item) => item.UniqueId.Equals(uniqueId));
if (matches.Count() == 1)
return matches.First();
else if(matches2.Count() == 1)
return matches2.First();
else
return null;
I'm using LINQ to SQL to pull records from a database, sort them by a string field, then perform some other work on them. Unfortunately the Name field that I'm sorting by comes out of the database like this
Name
ADAPT1
ADAPT10
ADAPT11
...
ADAPT2
ADAPT3
I'd like to sort the Name field in numerical order. Right now I'm using the Regex object to replace "ADAPT1" with "ADAPT01", etc. I then sort the records again using another LINQ query. The code I have for this looks like
var adaptationsUnsorted = from aun in dbContext.Adaptations
where aun.EventID == iep.EventID
select new Adaptation
{
StudentID = aun.StudentID,
EventID = aun.EventID,
Name = Regex.Replace(aun.Name,
#"ADAPT([0-9])$", #"ADAPT0$1"),
Value = aun.Value
};
var adaptationsSorted = from ast in adaptationsUnsorted
orderby ast.Name
select ast;
foreach(Adaptation adaptation in adaptationsSorted)
{
// do real work
}
The problem I have is that the foreach loop throws the exception
System.NotSupportedException was unhandled
Message="Method 'System.String Replace(System.String, System.String,
System.String)' has no supported translation to SQL."
Source="System.Data.Linq"
I'm also wondering if there's a cleaner way to do this with just one LINQ query. Any suggestions would be appreciated.
Force the hydration of the elements by enumerating the query (call ToList). From that point on, your operations will be against in-memory objects and those operations will not be translated into SQL.
List<Adaptation> result =
dbContext.Adaptation
.Where(aun => aun.EventID = iep.EventID)
.ToList();
result.ForEach(aun =>
aun.Name = Regex.Replace(aun.Name,
#"ADAPT([0-9])$", #"ADAPT0$1")
);
result = result.OrderBy(aun => aun.Name).ToList();
Implement a IComparer<string> with your logic:
var adaptationsUnsorted = from aun in dbContext.Adaptations
where aun.EventID == iep.EventID
select new Adaptation
{
StudentID = aun.StudentID,
EventID = aun.EventID,
Name = aun.Name,
Value = aun.Value
};
var adaptationsSorted = adaptationsUnsorted.ToList<Adaptation>().OrderBy(a => a.Name, new AdaptationComparer ());
foreach (Adaptation adaptation in adaptationsSorted)
{
// do real work
}
public class AdaptationComparer : IComparer<string>
{
public int Compare(string x, string y)
{
string x1 = Regex.Replace(x, #"ADAPT([0-9])$", #"ADAPT0$1");
string y1 = Regex.Replace(y, #"ADAPT([0-9])$", #"ADAPT0$1");
return Comparer<string>.Default.Compare(x1, y1);
}
}
I didn't test this code but it should do the job.
I wonder if you can add a calculated+persisted+indexed field to the database, that does this for you. It would be fairly trivial to write a UDF that gets the value as an integer (just using string values), but then you can sort on this column at the database. This would allow you to use Skip and Take effectively, rather than constantly fetching all the data to the .NET code (which simply doesn't scale).